Skip to content

feat: Enable object locking #593

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"files": "go.sum|^.secrets.baseline$",
"lines": null
},
"generated_at": "2024-03-25T14:13:22Z",
"generated_at": "2024-04-18T15:36:29Z",
"plugins_used": [
{
"name": "AWSKeyDetector"
Expand Down Expand Up @@ -90,7 +90,7 @@
"hashed_secret": "a7c93faaa770c377154ea9d4d0d17a9056dbfa95",
"is_secret": false,
"is_verified": false,
"line_number": 191,
"line_number": 195,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ You need the following permissions to run this module.
|------|------|
| [ibm_cos_bucket.cos_bucket](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/cos_bucket) | resource |
| [ibm_cos_bucket.cos_bucket1](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/cos_bucket) | resource |
| [ibm_cos_bucket_object_lock_configuration.lock_configuration](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/cos_bucket_object_lock_configuration) | resource |
| [ibm_iam_authorization_policy.policy](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource |
| [ibm_resource_instance.cos_instance](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/resource_instance) | resource |
| [ibm_resource_key.resource_keys](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/resource_key) | resource |
Expand Down Expand Up @@ -185,6 +186,9 @@ You need the following permissions to run this module.
| <a name="input_kms_encryption_enabled"></a> [kms\_encryption\_enabled](#input\_kms\_encryption\_enabled) | Set as true to use KMS key encryption to encrypt data in COS bucket (only applicable when var.create\_cos\_bucket is true). | `bool` | `true` | no |
| <a name="input_kms_key_crn"></a> [kms\_key\_crn](#input\_kms\_key\_crn) | CRN of the KMS key to use to encrypt the data in the COS bucket. Required if var.encryption\_enabled and var.create\_cos\_bucket are true. | `string` | `null` | no |
| <a name="input_management_endpoint_type_for_bucket"></a> [management\_endpoint\_type\_for\_bucket](#input\_management\_endpoint\_type\_for\_bucket) | The type of endpoint for the IBM terraform provider to use to manage the bucket. (public, private or direct) | `string` | `"public"` | no |
| <a name="input_object_lock_duration_days"></a> [object\_lock\_duration\_days](#input\_object\_lock\_duration\_days) | Specifies the default number of days for the retention lock duration. When setting 'object\_lock\_duration\_days' do not set 'object\_lock\_duration\_years'. Only used if 'create\_cos\_bucket' is true. | `number` | `0` | no |
| <a name="input_object_lock_duration_years"></a> [object\_lock\_duration\_years](#input\_object\_lock\_duration\_years) | Specifies the default number of years for the retention lock duration. When setting 'object\_lock\_duration\_years' do not set 'object\_lock\_duration\_days'. Only used if 'create\_cos\_bucket' is true. | `number` | `0` | no |
| <a name="input_object_locking_enabled"></a> [object\_locking\_enabled](#input\_object\_locking\_enabled) | Specifies if an object lock configuration should be created. Requires 'object\_versoning\_enabled' to be true. Only used if 'create\_cos\_bucket' is true. | `bool` | `false` | no |
| <a name="input_object_versioning_enabled"></a> [object\_versioning\_enabled](#input\_object\_versioning\_enabled) | Enable object versioning to keep multiple versions of an object in a bucket. Cannot be used with retention rule. Only used if 'create\_cos\_bucket' is true. | `bool` | `false` | no |
| <a name="input_region"></a> [region](#input\_region) | The region to provision the bucket. If you pass a value for this, do not pass one for var.cross\_region\_location or var.single\_site\_location. | `string` | `"us-south"` | no |
| <a name="input_resource_group_id"></a> [resource\_group\_id](#input\_resource\_group\_id) | The resource group ID where The COS instance will be provisioned. It is required if setting input variable create\_cos\_instance to true. | `string` | `null` | no |
Expand Down
77 changes: 57 additions & 20 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
##############################################################################

locals {
at_enabled = var.activity_tracker_crn == null ? [] : [1]
metrics_enabled = var.sysdig_crn == null ? [] : [1]
archive_enabled = var.archive_days == null ? [] : [1]
expire_enabled = var.expire_days == null ? [] : [1]
retention_enabled = var.retention_enabled ? [1] : []
object_versioning_enabled = var.object_versioning_enabled ? [1] : []
at_enabled = var.activity_tracker_crn == null ? [] : [1]
metrics_enabled = var.sysdig_crn == null ? [] : [1]
archive_enabled = var.archive_days == null ? [] : [1]
expire_enabled = var.expire_days == null ? [] : [1]
retention_enabled = var.retention_enabled ? [1] : []
object_lock_duration_days = var.object_lock_duration_days > 0 ? [1] : []
object_lock_duration_years = var.object_lock_duration_years > 0 ? [1] : []

# input variable validation
# tflint-ignore: terraform_unused_declarations
Expand Down Expand Up @@ -39,6 +40,12 @@ locals {
validate_cross_region_retention = var.cross_region_location != "us" && var.retention_enabled ? tobool("Retention is currently only supported in the `US` location for cross region buckets.") : true
# tflint-ignore: terraform_unused_declarations
validate_cross_region_kms = var.cross_region_location != "us" && var.cross_region_location != null ? can(regex(".*hs-crypto.*", var.kms_key_crn)) ? tobool("Support for using HPCS instance for KMS encryption in cross-regional bucket is only available in US region.") : true : true
# tflint-ignore: terraform_unused_declarations
validate_locking = var.object_locking_enabled && !var.object_versioning_enabled ? tobool("Object locking requires object versioning to be enabled.") : true
# tflint-ignore: terraform_unused_declarations
validate_lock_duration_both = var.object_locking_enabled && var.object_lock_duration_days != 0 && var.object_lock_duration_years != 0 ? tobool("Object lock duration days and years can not both be set.") : true
# tflint-ignore: terraform_unused_declarations
validate_lock_duration_none = var.object_locking_enabled && var.object_lock_duration_days == 0 && var.object_lock_duration_years == 0 ? tobool("Object lock duration days or years must be set.") : true
}

# workaround for https://github.com/IBM-Cloud/terraform-provider-ibm/issues/4478
Expand Down Expand Up @@ -129,6 +136,7 @@ resource "ibm_cos_bucket" "cos_bucket" {
key_protect = var.kms_key_crn
hard_quota = var.hard_quota
force_delete = var.force_delete
object_lock = var.object_locking_enabled
## This for_each block is NOT a loop to attach to multiple retention blocks.
## This block is only used to conditionally add retention block depending on retention is enabled.
dynamic "retention_rule" {
Expand Down Expand Up @@ -179,13 +187,8 @@ resource "ibm_cos_bucket" "cos_bucket" {
metrics_monitoring_crn = var.sysdig_crn
}
}
## This for_each block is NOT a loop to attach to multiple versioning blocks.
## This block is only used to conditionally attach a single versioning block.
dynamic "object_versioning" {
for_each = local.object_versioning_enabled
content {
enable = var.object_versioning_enabled
}
object_versioning {
enable = var.object_versioning_enabled
}
}

Expand All @@ -208,6 +211,7 @@ resource "ibm_cos_bucket" "cos_bucket1" {
storage_class = var.bucket_storage_class
hard_quota = var.hard_quota
force_delete = var.force_delete
object_lock = var.object_locking_enabled
## This for_each block is NOT a loop to attach to multiple retention blocks.
## This block is only used to conditionally add retention block depending on retention is enabled.
dynamic "retention_rule" {
Expand Down Expand Up @@ -258,13 +262,8 @@ resource "ibm_cos_bucket" "cos_bucket1" {
metrics_monitoring_crn = var.sysdig_crn
}
}
## This for_each block is NOT a loop to attach to multiple versioning blocks.
## This block is only used to conditionally attach a single versioning block.
dynamic "object_versioning" {
for_each = local.object_versioning_enabled
content {
enable = var.object_versioning_enabled
}
object_versioning {
enable = var.object_versioning_enabled
}
}

Expand All @@ -279,6 +278,44 @@ locals {
s3_endpoint_direct = var.create_cos_bucket ? (var.kms_encryption_enabled ? ibm_cos_bucket.cos_bucket[0].s3_endpoint_direct : ibm_cos_bucket.cos_bucket1[0].s3_endpoint_direct) : null
}

##############################################################################
# Bucket retention lock
##############################################################################

resource "ibm_cos_bucket_object_lock_configuration" "lock_configuration" {
count = var.object_locking_enabled ? 1 : 0
bucket_crn = local.bucket_crn
bucket_location = local.bucket_region
endpoint_type = var.management_endpoint_type_for_bucket

# This is not a loop. Include either the `days` or `years`.
dynamic "object_lock_configuration" {
for_each = local.object_lock_duration_days
content {
object_lock_enabled = "Enabled" # only accepts "Enabled"
object_lock_rule {
default_retention {
mode = "COMPLIANCE" # only accepts "COMPLIANCE"
days = var.object_lock_duration_days
}
}
}
}
# This is not a loop. Include either the `days` or `years`.
dynamic "object_lock_configuration" {
for_each = local.object_lock_duration_years
content {
object_lock_enabled = "Enabled" # only accepts "Enabled"
object_lock_rule {
default_retention {
mode = "COMPLIANCE" # only accepts "COMPLIANCE"
years = var.object_lock_duration_years
}
}
}
}
}

##############################################################################
# Context Based Restrictions
##############################################################################
Expand Down
2 changes: 1 addition & 1 deletion modules/buckets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ No resources.

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_bucket_configs"></a> [bucket\_configs](#input\_bucket\_configs) | Cloud Object Storage bucket configurations | <pre>list(object({<br> access_tags = optional(list(string), [])<br> add_bucket_name_suffix = optional(bool, false)<br> bucket_name = string<br> kms_encryption_enabled = optional(bool, true)<br> kms_guid = optional(string, null)<br> kms_key_crn = optional(string, null)<br> skip_iam_authorization_policy = optional(bool, false)<br> management_endpoint_type = optional(string, "public")<br> cross_region_location = optional(string, null)<br> storage_class = optional(string, "smart")<br> region_location = optional(string, null)<br> resource_instance_id = string<br> force_delete = optional(bool, true)<br> single_site_location = optional(string, null)<br> hard_quota = optional(number, null)<br><br> activity_tracking = optional(object({<br> read_data_events = optional(bool, true)<br> write_data_events = optional(bool, true)<br> activity_tracker_crn = optional(string, null)<br> }))<br> archive_rule = optional(object({<br> enable = optional(bool, false)<br> days = optional(number, 20)<br> type = optional(string, "Glacier")<br> }))<br> expire_rule = optional(object({<br> enable = optional(bool, false)<br> days = optional(number, 365)<br> }))<br> metrics_monitoring = optional(object({<br> usage_metrics_enabled = optional(bool, true)<br> request_metrics_enabled = optional(bool, true)<br> metrics_monitoring_crn = optional(string, null)<br> }))<br> object_versioning = optional(object({<br> enable = optional(bool, false)<br> }))<br> retention_rule = optional(object({<br> default = optional(number, 90)<br> maximum = optional(number, 350)<br> minimum = optional(number, 90)<br> permanent = optional(bool, false)<br> }))<br> cbr_rules = optional(list(object({<br> description = string<br> account_id = string<br> rule_contexts = list(object({<br> attributes = optional(list(object({<br> name = string<br> value = string<br> }))) }))<br> enforcement_mode = string<br> tags = optional(list(object({<br> name = string<br> value = string<br> })), [])<br> operations = optional(list(object({<br> api_types = list(object({<br> api_type_id = string<br> }))<br> })))<br> })), [])<br><br> }))</pre> | n/a | yes |
| <a name="input_bucket_configs"></a> [bucket\_configs](#input\_bucket\_configs) | Cloud Object Storage bucket configurations | <pre>list(object({<br> access_tags = optional(list(string), [])<br> add_bucket_name_suffix = optional(bool, false)<br> bucket_name = string<br> kms_encryption_enabled = optional(bool, true)<br> kms_guid = optional(string, null)<br> kms_key_crn = optional(string, null)<br> skip_iam_authorization_policy = optional(bool, false)<br> management_endpoint_type = optional(string, "public")<br> cross_region_location = optional(string, null)<br> storage_class = optional(string, "smart")<br> region_location = optional(string, null)<br> resource_instance_id = string<br> force_delete = optional(bool, true)<br> single_site_location = optional(string, null)<br> hard_quota = optional(number, null)<br> object_locking_enabled = optional(bool, false)<br> object_lock_duration_days = optional(number, 0)<br> object_lock_duration_years = optional(number, 0)<br><br> activity_tracking = optional(object({<br> read_data_events = optional(bool, true)<br> write_data_events = optional(bool, true)<br> activity_tracker_crn = optional(string, null)<br> }))<br> archive_rule = optional(object({<br> enable = optional(bool, false)<br> days = optional(number, 20)<br> type = optional(string, "Glacier")<br> }))<br> expire_rule = optional(object({<br> enable = optional(bool, false)<br> days = optional(number, 365)<br> }))<br> metrics_monitoring = optional(object({<br> usage_metrics_enabled = optional(bool, true)<br> request_metrics_enabled = optional(bool, true)<br> metrics_monitoring_crn = optional(string, null)<br> }))<br> object_versioning = optional(object({<br> enable = optional(bool, false)<br> }))<br> retention_rule = optional(object({<br> default = optional(number, 90)<br> maximum = optional(number, 350)<br> minimum = optional(number, 90)<br> permanent = optional(bool, false)<br> }))<br> cbr_rules = optional(list(object({<br> description = string<br> account_id = string<br> rule_contexts = list(object({<br> attributes = optional(list(object({<br> name = string<br> value = string<br> }))) }))<br> enforcement_mode = string<br> tags = optional(list(object({<br> name = string<br> value = string<br> })), [])<br> operations = optional(list(object({<br> api_types = list(object({<br> api_type_id = string<br> }))<br> })))<br> })), [])<br><br> }))</pre> | n/a | yes |

### Outputs

Expand Down
3 changes: 3 additions & 0 deletions modules/buckets/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ module "buckets" {
management_endpoint_type_for_bucket = each.value.management_endpoint_type
force_delete = each.value.force_delete
hard_quota = each.value.hard_quota
object_locking_enabled = each.value.object_locking_enabled
object_lock_duration_days = each.value.object_lock_duration_days
object_lock_duration_years = each.value.object_lock_duration_years

access_tags = can(each.value.access_tags) ? each.value.access_tags : []

Expand Down
3 changes: 3 additions & 0 deletions modules/buckets/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ variable "bucket_configs" {
force_delete = optional(bool, true)
single_site_location = optional(string, null)
hard_quota = optional(number, null)
object_locking_enabled = optional(bool, false)
object_lock_duration_days = optional(number, 0)
object_lock_duration_years = optional(number, 0)

activity_tracking = optional(object({
read_data_events = optional(bool, true)
Expand Down
Loading