Skip to content

Commit d8bc15d

Browse files
authored
Added IP-based statement in bucket policy (#216)
1 parent b497874 commit d8bc15d

File tree

4 files changed

+31
-0
lines changed

4 files changed

+31
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ Available targets:
314314
| <a name="input_s3_replication_permissions_boundary_arn"></a> [s3\_replication\_permissions\_boundary\_arn](#input\_s3\_replication\_permissions\_boundary\_arn) | Permissions boundary ARN for the created IAM replication role. | `string` | `null` | no |
315315
| <a name="input_s3_replication_rules"></a> [s3\_replication\_rules](#input\_s3\_replication\_rules) | Specifies the replication rules for S3 bucket replication if enabled. You must also set s3\_replication\_enabled to true. | <pre>list(object({<br> id = optional(string)<br> priority = optional(number)<br> prefix = optional(string)<br> status = optional(string, "Enabled")<br> # delete_marker_replication { status } had been flattened for convenience<br> delete_marker_replication_status = optional(string, "Disabled")<br> # Add the configuration as it appears in the resource, for consistency<br> # this nested version takes precedence if both are provided.<br> delete_marker_replication = optional(object({<br> status = string<br> }))<br><br> # destination_bucket is specified here rather than inside the destination object because before optional<br> # attributes, it made it easier to work with the Terraform type system and create a list of consistent type.<br> # It is preserved for backward compatibility, but the nested version takes priority if both are provided.<br> destination_bucket = optional(string) # destination bucket ARN, overrides s3_replica_bucket_arn<br><br> destination = object({<br> bucket = optional(string) # destination bucket ARN, overrides s3_replica_bucket_arn<br> storage_class = optional(string, "STANDARD")<br> # replica_kms_key_id at this level is for backward compatibility, and is overridden by the one in `encryption_configuration`<br> replica_kms_key_id = optional(string, "")<br> encryption_configuration = optional(object({<br> replica_kms_key_id = string<br> }))<br> access_control_translation = optional(object({<br> owner = string<br> }))<br> # account_id is for backward compatibility, overridden by account<br> account_id = optional(string)<br> account = optional(string)<br> # For convenience, specifying either metrics or replication_time enables both<br> metrics = optional(object({<br> event_threshold = optional(object({<br> minutes = optional(number, 15) # Currently 15 is the only valid number<br> }), { minutes = 15 })<br> status = optional(string, "Enabled")<br> }), { status = "Disabled" })<br> # To preserve backward compatibility, Replication Time Control (RTC) is automatically enabled<br> # when metrics are enabled. To enable metrics without RTC, you must explicitly configure<br> # replication_time.status = "Disabled".<br> replication_time = optional(object({<br> time = optional(object({<br> minutes = optional(number, 15) # Currently 15 is the only valid number<br> }), { minutes = 15 })<br> status = optional(string)<br> }))<br> })<br><br> source_selection_criteria = optional(object({<br> replica_modifications = optional(object({<br> status = string # Either Enabled or Disabled<br> }))<br> sse_kms_encrypted_objects = optional(object({<br> status = optional(string)<br> }))<br> }))<br> # filter.prefix overrides top level prefix<br> filter = optional(object({<br> prefix = optional(string)<br> tags = optional(map(string), {})<br> }))<br> }))</pre> | `null` | no |
316316
| <a name="input_s3_replication_source_roles"></a> [s3\_replication\_source\_roles](#input\_s3\_replication\_source\_roles) | Cross-account IAM Role ARNs that will be allowed to perform S3 replication to this bucket (for replication within the same AWS account, it's not necessary to adjust the bucket policy). | `list(string)` | `[]` | no |
317+
| <a name="input_source_ip_allow_list"></a> [source\_ip\_allow\_list](#input\_source\_ip\_allow\_list) | List of IP addresses to allow to perform all actions to the bucket | `list(string)` | `[]` | no |
317318
| <a name="input_source_policy_documents"></a> [source\_policy\_documents](#input\_source\_policy\_documents) | List of IAM policy documents (in JSON) that are merged together into the exported document.<br>Statements defined in source\_policy\_documents must have unique SIDs.<br>Statement having SIDs that match policy SIDs generated by this module will override them. | `list(string)` | `[]` | no |
318319
| <a name="input_sse_algorithm"></a> [sse\_algorithm](#input\_sse\_algorithm) | The server-side encryption algorithm to use. Valid values are `AES256` and `aws:kms` | `string` | `"AES256"` | no |
319320
| <a name="input_ssm_base_path"></a> [ssm\_base\_path](#input\_ssm\_base\_path) | The base path for SSM parameters where created IAM user's access key is stored | `string` | `"/s3_user/"` | no |

docs/terraform.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
| <a name="input_s3_replication_permissions_boundary_arn"></a> [s3\_replication\_permissions\_boundary\_arn](#input\_s3\_replication\_permissions\_boundary\_arn) | Permissions boundary ARN for the created IAM replication role. | `string` | `null` | no |
100100
| <a name="input_s3_replication_rules"></a> [s3\_replication\_rules](#input\_s3\_replication\_rules) | Specifies the replication rules for S3 bucket replication if enabled. You must also set s3\_replication\_enabled to true. | <pre>list(object({<br> id = optional(string)<br> priority = optional(number)<br> prefix = optional(string)<br> status = optional(string, "Enabled")<br> # delete_marker_replication { status } had been flattened for convenience<br> delete_marker_replication_status = optional(string, "Disabled")<br> # Add the configuration as it appears in the resource, for consistency<br> # this nested version takes precedence if both are provided.<br> delete_marker_replication = optional(object({<br> status = string<br> }))<br><br> # destination_bucket is specified here rather than inside the destination object because before optional<br> # attributes, it made it easier to work with the Terraform type system and create a list of consistent type.<br> # It is preserved for backward compatibility, but the nested version takes priority if both are provided.<br> destination_bucket = optional(string) # destination bucket ARN, overrides s3_replica_bucket_arn<br><br> destination = object({<br> bucket = optional(string) # destination bucket ARN, overrides s3_replica_bucket_arn<br> storage_class = optional(string, "STANDARD")<br> # replica_kms_key_id at this level is for backward compatibility, and is overridden by the one in `encryption_configuration`<br> replica_kms_key_id = optional(string, "")<br> encryption_configuration = optional(object({<br> replica_kms_key_id = string<br> }))<br> access_control_translation = optional(object({<br> owner = string<br> }))<br> # account_id is for backward compatibility, overridden by account<br> account_id = optional(string)<br> account = optional(string)<br> # For convenience, specifying either metrics or replication_time enables both<br> metrics = optional(object({<br> event_threshold = optional(object({<br> minutes = optional(number, 15) # Currently 15 is the only valid number<br> }), { minutes = 15 })<br> status = optional(string, "Enabled")<br> }), { status = "Disabled" })<br> # To preserve backward compatibility, Replication Time Control (RTC) is automatically enabled<br> # when metrics are enabled. To enable metrics without RTC, you must explicitly configure<br> # replication_time.status = "Disabled".<br> replication_time = optional(object({<br> time = optional(object({<br> minutes = optional(number, 15) # Currently 15 is the only valid number<br> }), { minutes = 15 })<br> status = optional(string)<br> }))<br> })<br><br> source_selection_criteria = optional(object({<br> replica_modifications = optional(object({<br> status = string # Either Enabled or Disabled<br> }))<br> sse_kms_encrypted_objects = optional(object({<br> status = optional(string)<br> }))<br> }))<br> # filter.prefix overrides top level prefix<br> filter = optional(object({<br> prefix = optional(string)<br> tags = optional(map(string), {})<br> }))<br> }))</pre> | `null` | no |
101101
| <a name="input_s3_replication_source_roles"></a> [s3\_replication\_source\_roles](#input\_s3\_replication\_source\_roles) | Cross-account IAM Role ARNs that will be allowed to perform S3 replication to this bucket (for replication within the same AWS account, it's not necessary to adjust the bucket policy). | `list(string)` | `[]` | no |
102+
| <a name="input_source_ip_allow_list"></a> [source\_ip\_allow\_list](#input\_source\_ip\_allow\_list) | List of IP addresses to allow to perform all actions to the bucket | `list(string)` | `[]` | no |
102103
| <a name="input_source_policy_documents"></a> [source\_policy\_documents](#input\_source\_policy\_documents) | List of IAM policy documents (in JSON) that are merged together into the exported document.<br>Statements defined in source\_policy\_documents must have unique SIDs.<br>Statement having SIDs that match policy SIDs generated by this module will override them. | `list(string)` | `[]` | no |
103104
| <a name="input_sse_algorithm"></a> [sse\_algorithm](#input\_sse\_algorithm) | The server-side encryption algorithm to use. Valid values are `AES256` and `aws:kms` | `string` | `"AES256"` | no |
104105
| <a name="input_ssm_base_path"></a> [ssm\_base\_path](#input\_ssm\_base\_path) | The base path for SSM parameters where created IAM user's access key is stored | `string` | `"/s3_user/"` | no |

main.tf

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,28 @@ data "aws_iam_policy_document" "bucket_policy" {
474474
}
475475
}
476476
}
477+
478+
dynamic "statement" {
479+
for_each = length(var.source_ip_allow_list) > 0 ? [1] : []
480+
481+
content {
482+
sid = "AllowIPPrincipals"
483+
effect = "Deny"
484+
actions = ["s3:*"]
485+
resources = [local.bucket_arn, "${local.bucket_arn}/*"]
486+
principals {
487+
identifiers = ["*"]
488+
type = "*"
489+
}
490+
condition {
491+
test = "NotIpAddress"
492+
variable = "aws:SourceIp"
493+
values = var.source_ip_allow_list
494+
}
495+
}
496+
497+
}
498+
477499
}
478500

479501
data "aws_iam_policy_document" "aggregated_policy" {

variables.tf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,13 @@ variable "privileged_principal_actions" {
411411
nullable = false
412412
}
413413

414+
variable "source_ip_allow_list" {
415+
type = list(string)
416+
default = []
417+
description = "List of IP addresses to allow to perform all actions to the bucket"
418+
nullable = false
419+
}
420+
414421
variable "transfer_acceleration_enabled" {
415422
type = bool
416423
default = false

0 commit comments

Comments
 (0)