From d13956491f9509c5bce665e315fd3edde226bcde Mon Sep 17 00:00:00 2001 From: magreenbaum Date: Fri, 16 May 2025 12:01:54 -0400 Subject: [PATCH 1/2] s3 table and table bucket cmk encryption support --- examples/table-bucket/README.md | 6 ++-- examples/table-bucket/main.tf | 55 +++++++++++++++++++++++++++++++ examples/table-bucket/versions.tf | 2 +- modules/table-bucket/README.md | 5 +-- modules/table-bucket/main.tf | 2 ++ modules/table-bucket/variables.tf | 6 ++++ modules/table-bucket/versions.tf | 2 +- wrappers/table-bucket/main.tf | 1 + wrappers/table-bucket/versions.tf | 2 +- 9 files changed, 74 insertions(+), 7 deletions(-) diff --git a/examples/table-bucket/README.md b/examples/table-bucket/README.md index 874bd561..836464f5 100644 --- a/examples/table-bucket/README.md +++ b/examples/table-bucket/README.md @@ -20,20 +20,21 @@ Note that this example may create resources which cost money. Run `terraform des | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 5.83 | +| [aws](#requirement\_aws) | >= 5.98 | | [random](#requirement\_random) | >= 2.0 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.83 | +| [aws](#provider\_aws) | >= 5.98 | | [random](#provider\_random) | >= 2.0 | ## Modules | Name | Source | Version | |------|--------|---------| +| [kms](#module\_kms) | terraform-aws-modules/kms/aws | ~> 2.0 | | [table\_bucket](#module\_table\_bucket) | ../../modules/table-bucket | n/a | ## Resources @@ -43,6 +44,7 @@ Note that this example may create resources which cost money. Run `terraform des | [aws_s3tables_namespace.namespace](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3tables_namespace) | resource | | [random_pet.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/pet) | resource | | [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_region.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | ## Inputs diff --git a/examples/table-bucket/main.tf b/examples/table-bucket/main.tf index b69dcfb5..2708157a 100644 --- a/examples/table-bucket/main.tf +++ b/examples/table-bucket/main.tf @@ -13,11 +13,18 @@ locals { data "aws_caller_identity" "this" {} +data "aws_region" "this" {} + module "table_bucket" { source = "../../modules/table-bucket" table_bucket_name = local.bucket_name + encryption_configuration = { + kms_key_arn = module.kms.key_arn + sse_algorithm = "aws:kms" + } + maintenance_configuration = { iceberg_unreferenced_file_removal = { status = "enabled" @@ -49,6 +56,11 @@ module "table_bucket" { format = "ICEBERG" namespace = aws_s3tables_namespace.namespace.namespace + encryption_configuration = { + kms_key_arn = module.kms.key_arn + sse_algorithm = "aws:kms" + } + maintenance_configuration = { iceberg_compaction = { status = "enabled" @@ -103,3 +115,46 @@ resource "aws_s3tables_namespace" "namespace" { namespace = "example_namespace" table_bucket_arn = module.table_bucket.s3_table_bucket_arn } + +module "kms" { + source = "terraform-aws-modules/kms/aws" + version = "~> 2.0" + + description = "Key example for s3 table buckets" + deletion_window_in_days = 7 + + key_statements = [ + { + sid = "s3TablesMaintenancePolicy" + actions = [ + "kms:GenerateDataKey", + "kms:Decrypt" + ] + resources = ["*"] + + principals = [ + { + type = "Service" + identifiers = ["maintenance.s3tables.amazonaws.com"] + } + ] + + conditions = [ + { + test = "StringEquals" + variable = "aws:SourceAccount" + values = [ + data.aws_caller_identity.this.id, + ] + }, + { + test = "StringLike" + variable = "kms:EncryptionContext:aws:s3:arn" + values = [ + "arn:aws:s3tables:${data.aws_region.this.name}:${data.aws_caller_identity.this.account_id}:bucket/${local.bucket_name}/table/*" + ] + } + ] + } + ] +} diff --git a/examples/table-bucket/versions.tf b/examples/table-bucket/versions.tf index 9ef2d5d8..6d2b2999 100644 --- a/examples/table-bucket/versions.tf +++ b/examples/table-bucket/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.83" + version = ">= 5.98" } random = { source = "hashicorp/random" diff --git a/modules/table-bucket/README.md b/modules/table-bucket/README.md index 03e0b2b1..65b72703 100644 --- a/modules/table-bucket/README.md +++ b/modules/table-bucket/README.md @@ -8,13 +8,13 @@ Creates S3 Table Bucket and Tables with various configurations. | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0 | -| [aws](#requirement\_aws) | >= 5.83 | +| [aws](#requirement\_aws) | >= 5.98 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 5.83 | +| [aws](#provider\_aws) | >= 5.98 | ## Modules @@ -37,6 +37,7 @@ No modules. |------|-------------|------|---------|:--------:| | [create](#input\_create) | Whether to create s3 table resources | `bool` | `true` | no | | [create\_table\_bucket\_policy](#input\_create\_table\_bucket\_policy) | Whether to create s3 table bucket policy | `bool` | `false` | no | +| [encryption\_configuration](#input\_encryption\_configuration) | Map of encryption configurations | `any` | `null` | no | | [maintenance\_configuration](#input\_maintenance\_configuration) | Map of table bucket maintenance configurations | `any` | `{}` | no | | [table\_bucket\_name](#input\_table\_bucket\_name) | Name of the table bucket. Must be between 3 and 63 characters in length. Can consist of lowercase letters, numbers, and hyphens, and must begin and end with a lowercase letter or number | `string` | `null` | no | | [table\_bucket\_override\_policy\_documents](#input\_table\_bucket\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank `sid`s will override statements with the same `sid` | `list(string)` | `[]` | no | diff --git a/modules/table-bucket/main.tf b/modules/table-bucket/main.tf index f2eb65f1..bc30d703 100644 --- a/modules/table-bucket/main.tf +++ b/modules/table-bucket/main.tf @@ -2,6 +2,7 @@ resource "aws_s3tables_table_bucket" "this" { count = var.create ? 1 : 0 name = var.table_bucket_name + encryption_configuration = var.encryption_configuration maintenance_configuration = var.maintenance_configuration } @@ -67,6 +68,7 @@ resource "aws_s3tables_table" "this" { name = try(each.value.table_name, each.key) namespace = each.value.namespace table_bucket_arn = aws_s3tables_table_bucket.this[0].arn + encryption_configuration = try(each.value.encryption_configuration, null) maintenance_configuration = try(each.value.maintenance_configuration, null) } diff --git a/modules/table-bucket/variables.tf b/modules/table-bucket/variables.tf index 3d332407..337fdd81 100644 --- a/modules/table-bucket/variables.tf +++ b/modules/table-bucket/variables.tf @@ -10,6 +10,12 @@ variable "table_bucket_name" { default = null } +variable "encryption_configuration" { + description = "Map of encryption configurations" + type = any + default = null +} + variable "maintenance_configuration" { description = "Map of table bucket maintenance configurations" type = any diff --git a/modules/table-bucket/versions.tf b/modules/table-bucket/versions.tf index e0d68841..e1389835 100644 --- a/modules/table-bucket/versions.tf +++ b/modules/table-bucket/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.83" + version = ">= 5.98" } } } diff --git a/wrappers/table-bucket/main.tf b/wrappers/table-bucket/main.tf index b33d64b0..ddc8c465 100644 --- a/wrappers/table-bucket/main.tf +++ b/wrappers/table-bucket/main.tf @@ -5,6 +5,7 @@ module "wrapper" { create = try(each.value.create, var.defaults.create, true) create_table_bucket_policy = try(each.value.create_table_bucket_policy, var.defaults.create_table_bucket_policy, false) + encryption_configuration = try(each.value.encryption_configuration, var.defaults.encryption_configuration, null) maintenance_configuration = try(each.value.maintenance_configuration, var.defaults.maintenance_configuration, {}) table_bucket_name = try(each.value.table_bucket_name, var.defaults.table_bucket_name, null) table_bucket_override_policy_documents = try(each.value.table_bucket_override_policy_documents, var.defaults.table_bucket_override_policy_documents, []) diff --git a/wrappers/table-bucket/versions.tf b/wrappers/table-bucket/versions.tf index e0d68841..e1389835 100644 --- a/wrappers/table-bucket/versions.tf +++ b/wrappers/table-bucket/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 5.83" + version = ">= 5.98" } } } From 63449c4d2dc30be4ea88af8659f4e3f57a9d6b7c Mon Sep 17 00:00:00 2001 From: magreenbaum Date: Fri, 16 May 2025 12:19:28 -0400 Subject: [PATCH 2/2] default null for maintenance_configuration and add documentation link for permissions --- examples/table-bucket/main.tf | 1 + modules/table-bucket/README.md | 2 +- modules/table-bucket/variables.tf | 2 +- wrappers/table-bucket/main.tf | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/table-bucket/main.tf b/examples/table-bucket/main.tf index 2708157a..c6e51601 100644 --- a/examples/table-bucket/main.tf +++ b/examples/table-bucket/main.tf @@ -123,6 +123,7 @@ module "kms" { description = "Key example for s3 table buckets" deletion_window_in_days = 7 + # https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-tables-kms-permissions.html key_statements = [ { sid = "s3TablesMaintenancePolicy" diff --git a/modules/table-bucket/README.md b/modules/table-bucket/README.md index 65b72703..a4ae6942 100644 --- a/modules/table-bucket/README.md +++ b/modules/table-bucket/README.md @@ -38,7 +38,7 @@ No modules. | [create](#input\_create) | Whether to create s3 table resources | `bool` | `true` | no | | [create\_table\_bucket\_policy](#input\_create\_table\_bucket\_policy) | Whether to create s3 table bucket policy | `bool` | `false` | no | | [encryption\_configuration](#input\_encryption\_configuration) | Map of encryption configurations | `any` | `null` | no | -| [maintenance\_configuration](#input\_maintenance\_configuration) | Map of table bucket maintenance configurations | `any` | `{}` | no | +| [maintenance\_configuration](#input\_maintenance\_configuration) | Map of table bucket maintenance configurations | `any` | `null` | no | | [table\_bucket\_name](#input\_table\_bucket\_name) | Name of the table bucket. Must be between 3 and 63 characters in length. Can consist of lowercase letters, numbers, and hyphens, and must begin and end with a lowercase letter or number | `string` | `null` | no | | [table\_bucket\_override\_policy\_documents](#input\_table\_bucket\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank `sid`s will override statements with the same `sid` | `list(string)` | `[]` | no | | [table\_bucket\_policy](#input\_table\_bucket\_policy) | Amazon Web Services resource-based policy document in JSON format | `string` | `null` | no | diff --git a/modules/table-bucket/variables.tf b/modules/table-bucket/variables.tf index 337fdd81..d6f2a392 100644 --- a/modules/table-bucket/variables.tf +++ b/modules/table-bucket/variables.tf @@ -19,7 +19,7 @@ variable "encryption_configuration" { variable "maintenance_configuration" { description = "Map of table bucket maintenance configurations" type = any - default = {} + default = null } variable "create_table_bucket_policy" { diff --git a/wrappers/table-bucket/main.tf b/wrappers/table-bucket/main.tf index ddc8c465..89b98331 100644 --- a/wrappers/table-bucket/main.tf +++ b/wrappers/table-bucket/main.tf @@ -6,7 +6,7 @@ module "wrapper" { create = try(each.value.create, var.defaults.create, true) create_table_bucket_policy = try(each.value.create_table_bucket_policy, var.defaults.create_table_bucket_policy, false) encryption_configuration = try(each.value.encryption_configuration, var.defaults.encryption_configuration, null) - maintenance_configuration = try(each.value.maintenance_configuration, var.defaults.maintenance_configuration, {}) + maintenance_configuration = try(each.value.maintenance_configuration, var.defaults.maintenance_configuration, null) table_bucket_name = try(each.value.table_bucket_name, var.defaults.table_bucket_name, null) table_bucket_override_policy_documents = try(each.value.table_bucket_override_policy_documents, var.defaults.table_bucket_override_policy_documents, []) table_bucket_policy = try(each.value.table_bucket_policy, var.defaults.table_bucket_policy, null)