Skip to content

Commit e9a0ba1

Browse files
committed
fix: Allow KMS keys from other account
1 parent 185ee2b commit e9a0ba1

8 files changed

Lines changed: 86 additions & 5 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,10 @@ https://docs.datafold.com/datafold-deployment/dedicated-cloud/aws
269269
| <a name="input_backend_app_port"></a> [backend\_app\_port](#input\_backend\_app\_port) | The target port to use for the backend services | `number` | `80` | no |
270270
| <a name="input_backup_lifecycle_expiration_days"></a> [backup\_lifecycle\_expiration\_days](#input\_backup\_lifecycle\_expiration\_days) | Number of days after which clickhouse backup objects will expire and be deleted. | `number` | `6` | no |
271271
| <a name="input_ch_data_ebs_iops"></a> [ch\_data\_ebs\_iops](#input\_ch\_data\_ebs\_iops) | IOPS of EBS volume | `number` | `3000` | no |
272+
| <a name="input_ch_data_ebs_kms_key_arn"></a> [ch\_data\_ebs\_kms\_key\_arn](#input\_ch\_data\_ebs\_kms\_key\_arn) | Full ARN of an existing KMS key to encrypt the clickhouse data EBS volume with. Supports keys held in another account, provided the key policy grants this account use of the key. When null, the account default EBS encryption key is used. Must be a key ARN, not an alias: aliases do not resolve across accounts. Changing this on an existing volume forces replacement. | `string` | `null` | no |
272273
| <a name="input_ch_data_ebs_throughput"></a> [ch\_data\_ebs\_throughput](#input\_ch\_data\_ebs\_throughput) | Throughput of EBS volume | `number` | `1000` | no |
273274
| <a name="input_ch_logs_ebs_iops"></a> [ch\_logs\_ebs\_iops](#input\_ch\_logs\_ebs\_iops) | IOPS of EBS volume | `number` | `3000` | no |
275+
| <a name="input_ch_logs_ebs_kms_key_arn"></a> [ch\_logs\_ebs\_kms\_key\_arn](#input\_ch\_logs\_ebs\_kms\_key\_arn) | Full ARN of an existing KMS key to encrypt the clickhouse logs EBS volume with. Supports keys held in another account, provided the key policy grants this account use of the key. When null, the account default EBS encryption key is used. Must be a key ARN, not an alias: aliases do not resolve across accounts. Changing this on an existing volume forces replacement. | `string` | `null` | no |
274276
| <a name="input_ch_logs_ebs_throughput"></a> [ch\_logs\_ebs\_throughput](#input\_ch\_logs\_ebs\_throughput) | Throughput of EBS volume | `number` | `250` | no |
275277
| <a name="input_clickhouse_data_size"></a> [clickhouse\_data\_size](#input\_clickhouse\_data\_size) | EBS volume size for clickhouse data in GB | `number` | `40` | no |
276278
| <a name="input_clickhouse_logs_size"></a> [clickhouse\_logs\_size](#input\_clickhouse\_logs\_size) | EBS volume size for clickhouse logs in GB | `number` | `40` | no |
@@ -347,6 +349,7 @@ https://docs.datafold.com/datafold-deployment/dedicated-cloud/aws
347349
| <a name="input_rds_identifier"></a> [rds\_identifier](#input\_rds\_identifier) | Name of the RDS instance | `string` | `""` | no |
348350
| <a name="input_rds_instance"></a> [rds\_instance](#input\_rds\_instance) | EC2 insance type for PostgreSQL RDS database.<br/>Available instance groups: t3, m4, m5, r6i, m6i<br/>Available instance classes: medium and higher. | `string` | `"db.t3.medium"` | no |
349351
| <a name="input_rds_kms_key_alias"></a> [rds\_kms\_key\_alias](#input\_rds\_kms\_key\_alias) | RDS KMS key alias. | `string` | `"datafold-rds"` | no |
352+
| <a name="input_rds_kms_key_arn"></a> [rds\_kms\_key\_arn](#input\_rds\_kms\_key\_arn) | Full ARN of an existing KMS key to encrypt the RDS instance with. Supports keys held in another account, provided the key policy grants this account use of the key. Takes precedence over create\_rds\_kms\_key / rds\_kms\_key\_alias. Must be a key ARN, not an alias: aliases do not resolve across accounts. Changing this on an existing instance forces replacement. | `string` | `null` | no |
350353
| <a name="input_rds_maintenance_window"></a> [rds\_maintenance\_window](#input\_rds\_maintenance\_window) | RDS maintenance window | `string` | `"Mon:00:00-Mon:03:00"` | no |
351354
| <a name="input_rds_max_allocated_storage"></a> [rds\_max\_allocated\_storage](#input\_rds\_max\_allocated\_storage) | The upper limit the database can grow in GB | `number` | `100` | no |
352355
| <a name="input_rds_monitoring_interval"></a> [rds\_monitoring\_interval](#input\_rds\_monitoring\_interval) | RDS monitoring interval | `number` | `0` | no |
@@ -362,6 +365,7 @@ https://docs.datafold.com/datafold-deployment/dedicated-cloud/aws
362365
| <a name="input_rds_version"></a> [rds\_version](#input\_rds\_version) | Postgres RDS version to use. | `string` | `"15.5"` | no |
363366
| <a name="input_redis_data_size"></a> [redis\_data\_size](#input\_redis\_data\_size) | Redis EBS volume size in GB | `number` | `50` | no |
364367
| <a name="input_redis_ebs_iops"></a> [redis\_ebs\_iops](#input\_redis\_ebs\_iops) | IOPS of EBS redis volume | `number` | `3000` | no |
368+
| <a name="input_redis_ebs_kms_key_arn"></a> [redis\_ebs\_kms\_key\_arn](#input\_redis\_ebs\_kms\_key\_arn) | Full ARN of an existing KMS key to encrypt the redis data EBS volume with. Supports keys held in another account, provided the key policy grants this account use of the key. When null, the account default EBS encryption key is used. Must be a key ARN, not an alias: aliases do not resolve across accounts. Changing this on an existing volume forces replacement. | `string` | `null` | no |
365369
| <a name="input_redis_ebs_throughput"></a> [redis\_ebs\_throughput](#input\_redis\_ebs\_throughput) | Throughput of EBS redis volume | `number` | `125` | no |
366370
| <a name="input_s3_backup_bucket_name_override"></a> [s3\_backup\_bucket\_name\_override](#input\_s3\_backup\_bucket\_name\_override) | Bucket name override. | `string` | `""` | no |
367371
| <a name="input_s3_clickhouse_backup_tags"></a> [s3\_clickhouse\_backup\_tags](#input\_s3\_clickhouse\_backup\_tags) | The extra tags to be applied to the S3 clickhouse backup bucket | `map(any)` | `{}` | no |

main.tf

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,16 @@ module "eks" {
415415
clickhouse_backup_bucket_arn = local.clickhouse_backup_bucket_arn
416416
service_account_prefix = var.service_account_prefix
417417

418+
# The CSI driver needs explicit KMS permissions to attach volumes that are
419+
# encrypted with a non-default CMK (e.g. customer-held cross-account keys).
420+
ebs_csi_kms_cmk_arns = distinct([
421+
for arn in [
422+
var.ch_data_ebs_kms_key_arn,
423+
var.ch_logs_ebs_kms_key_arn,
424+
var.redis_ebs_kms_key_arn,
425+
] : arn if arn != null
426+
])
427+
418428
deploy_temporal = var.deploy_temporal
419429
temporal_backup_bucket_arn = local.temporal_backup_bucket_arn
420430
temporal_postgres_namespace = var.temporal_postgres_namespace
@@ -445,6 +455,7 @@ module "database" {
445455
create_rds_kms_key = var.create_rds_kms_key
446456
rds_kms_key_alias = var.rds_kms_key_alias
447457
use_default_rds_kms_key = var.use_default_rds_kms_key
458+
rds_kms_key_arn = var.rds_kms_key_arn
448459
database_name = var.database_name
449460
db_subnet_group_name = var.db_subnet_group_name
450461
db_parameter_group_name = var.db_parameter_group_name
@@ -486,6 +497,7 @@ resource "aws_ebs_volume" "clickhouse_data" {
486497
availability_zone = local.azs[var.az_index]
487498
size = var.clickhouse_data_size
488499
encrypted = true
500+
kms_key_id = var.ch_data_ebs_kms_key_arn
489501
type = var.ebs_type
490502
iops = var.ebs_type != "gp2" ? var.ch_data_ebs_iops : null
491503
throughput = var.ebs_type != "gp2" ? var.ch_data_ebs_throughput : null
@@ -499,6 +511,7 @@ resource "aws_ebs_volume" "clickhouse_logs" {
499511
availability_zone = local.azs[var.az_index]
500512
size = var.clickhouse_logs_size
501513
encrypted = true
514+
kms_key_id = var.ch_logs_ebs_kms_key_arn
502515
type = var.ebs_type
503516
iops = var.ebs_type != "gp2" ? var.ch_logs_ebs_iops : null
504517
throughput = var.ebs_type != "gp2" ? var.ch_logs_ebs_throughput : null
@@ -512,6 +525,7 @@ resource "aws_ebs_volume" "redis_data" {
512525
availability_zone = local.azs[var.az_index]
513526
size = var.redis_data_size
514527
encrypted = true
528+
kms_key_id = var.redis_ebs_kms_key_arn
515529
type = var.ebs_type
516530
iops = var.ebs_type != "gp2" ? var.redis_ebs_iops : null
517531
throughput = var.ebs_type != "gp2" ? var.redis_ebs_throughput : null

modules/database/main.tf

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ module "db" {
2929
allocated_storage = var.rds_allocated_storage
3030
max_allocated_storage = var.rds_max_allocated_storage
3131
storage_encrypted = true
32-
kms_key_id = var.use_default_rds_kms_key ? null : data.aws_kms_key.rds.arn
32+
kms_key_id = var.use_default_rds_kms_key ? null : local.rds_kms_key_arn
3333

3434
# NOTE: Do NOT use 'user' as the value for 'username' as it throws:
3535
# "Error creating DB Instance: InvalidParameterValue: MasterUsername
@@ -103,6 +103,8 @@ module "db" {
103103
locals {
104104
log_rds_automated_backups_replication_path = "${path.module}/../../logs/rds_automated_backups_replication.log"
105105
rds_password = var.rds_password_override != null ? var.rds_password_override : random_password.rds_master_password.result
106+
rds_kms_key_arn = var.rds_kms_key_arn != null ? var.rds_kms_key_arn : one(data.aws_kms_key.rds[*].arn)
107+
rds_kms_key_id = var.rds_kms_key_arn != null ? var.rds_kms_key_arn : one(data.aws_kms_key.rds[*].id)
106108
}
107109

108110
# https://docs.aws.amazon.com/cli/latest/reference/rds/start-db-instance-automated-backups-replication.html
@@ -113,7 +115,7 @@ resource "null_resource" "rds-automated-backups-replication" {
113115
command = <<-EOT
114116
aws rds start-db-instance-automated-backups-replication \
115117
--source-db-instance-arn ${one(module.db[*].db_instance_arn)} \
116-
--kms-key-id ${data.aws_kms_key.rds.id} \
118+
--kms-key-id ${local.rds_kms_key_id} \
117119
--source-region ${var.provider_region} \
118120
--region ${var.rds_backups_replication_target_region} \
119121
--backup-retention-period ${var.rds_backups_replication_retention_period} \

modules/database/secrets.tf

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
1-
# KMS key for encrypting RDS instance
1+
# KMS key for encrypting RDS instance.
2+
# Not created (and the alias not looked up) when an external key ARN is
3+
# passed in via rds_kms_key_arn — aliases only resolve in the caller's
4+
# account, so cross-account keys must be referenced by key ARN.
25
resource "aws_kms_key" "rds" {
3-
count = var.create_rds_kms_key ? 1 : 0
6+
count = var.create_rds_kms_key && var.rds_kms_key_arn == null ? 1 : 0
47
multi_region = true
58
description = "KMS key for RDS"
69
enable_key_rotation = true
710
}
811

912
resource "aws_kms_alias" "rds" {
10-
count = var.create_rds_kms_key ? 1 : 0
13+
count = var.create_rds_kms_key && var.rds_kms_key_arn == null ? 1 : 0
1114
name = "alias/${var.rds_kms_key_alias}"
1215
target_key_id = one(resource.aws_kms_key.rds[*].key_id)
1316
}
1417

1518
data "aws_kms_key" "rds" {
19+
count = var.rds_kms_key_arn == null ? 1 : 0
1620
key_id = "alias/${var.rds_kms_key_alias}"
1721

1822
depends_on = [

modules/database/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ variable "use_default_rds_kms_key" {
120120
description = "Flag weither or not to use the default RDS KMS encryption key. Not recommended to be used."
121121
}
122122

123+
variable "rds_kms_key_arn" {
124+
type = string
125+
default = null
126+
description = "Full ARN of an existing KMS key (possibly in another account) to encrypt the RDS instance with. Takes precedence over create_rds_kms_key / rds_kms_key_alias."
127+
}
128+
123129
variable "db_subnet_group_name" {
124130
type = string
125131
default = ""

modules/eks/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module "ebs_csi_irsa_role" {
66

77
name = "${var.deployment_name}-ebs-csi-controller"
88
attach_ebs_csi_policy = true
9+
ebs_csi_kms_cmk_arns = var.ebs_csi_kms_cmk_arns
910
use_name_prefix = false
1011
policy_name = "${var.deployment_name}-ebs-csi-controller"
1112

modules/eks/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,9 @@ variable "temporal_postgres_namespace" {
226226
default = "temporal"
227227
description = "Kubernetes namespace where the Temporal PostgreSQL CRD (and postgres-pod service account) is deployed."
228228
}
229+
230+
variable "ebs_csi_kms_cmk_arns" {
231+
type = list(string)
232+
default = []
233+
description = "KMS CMK ARNs the EBS CSI driver may use for encrypted volumes (grants + encrypt/decrypt). Needed when volumes are encrypted with a non-default CMK, including keys held in another account."
234+
}

variables.tf

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,17 @@ variable "use_default_rds_kms_key" {
531531
description = "Flag weither or not to use the default RDS KMS encryption key. Not recommended."
532532
}
533533

534+
variable "rds_kms_key_arn" {
535+
type = string
536+
default = null
537+
description = "Full ARN of an existing KMS key to encrypt the RDS instance with. Supports keys held in another account, provided the key policy grants this account use of the key. Takes precedence over create_rds_kms_key / rds_kms_key_alias. Must be a key ARN, not an alias: aliases do not resolve across accounts. Changing this on an existing instance forces replacement."
538+
539+
validation {
540+
condition = var.rds_kms_key_arn == null || can(regex("^arn:aws[a-z-]*:kms:[a-z0-9-]+:[0-9]{12}:key/", var.rds_kms_key_arn))
541+
error_message = "rds_kms_key_arn must be a full KMS key ARN (arn:aws:kms:<region>:<account-id>:key/<key-id>), not an alias."
542+
}
543+
}
544+
534545
variable "database_name" {
535546
type = string
536547
default = "datafold"
@@ -661,6 +672,17 @@ variable "ch_data_ebs_throughput" {
661672
description = "Throughput of EBS volume"
662673
}
663674

675+
variable "ch_data_ebs_kms_key_arn" {
676+
type = string
677+
default = null
678+
description = "Full ARN of an existing KMS key to encrypt the clickhouse data EBS volume with. Supports keys held in another account, provided the key policy grants this account use of the key. When null, the account default EBS encryption key is used. Must be a key ARN, not an alias: aliases do not resolve across accounts. Changing this on an existing volume forces replacement."
679+
680+
validation {
681+
condition = var.ch_data_ebs_kms_key_arn == null || can(regex("^arn:aws[a-z-]*:kms:[a-z0-9-]+:[0-9]{12}:key/", var.ch_data_ebs_kms_key_arn))
682+
error_message = "ch_data_ebs_kms_key_arn must be a full KMS key ARN (arn:aws:kms:<region>:<account-id>:key/<key-id>), not an alias."
683+
}
684+
}
685+
664686
variable "ch_logs_ebs_iops" {
665687
type = number
666688
default = 3000
@@ -673,6 +695,17 @@ variable "ch_logs_ebs_throughput" {
673695
description = "Throughput of EBS volume"
674696
}
675697

698+
variable "ch_logs_ebs_kms_key_arn" {
699+
type = string
700+
default = null
701+
description = "Full ARN of an existing KMS key to encrypt the clickhouse logs EBS volume with. Supports keys held in another account, provided the key policy grants this account use of the key. When null, the account default EBS encryption key is used. Must be a key ARN, not an alias: aliases do not resolve across accounts. Changing this on an existing volume forces replacement."
702+
703+
validation {
704+
condition = var.ch_logs_ebs_kms_key_arn == null || can(regex("^arn:aws[a-z-]*:kms:[a-z0-9-]+:[0-9]{12}:key/", var.ch_logs_ebs_kms_key_arn))
705+
error_message = "ch_logs_ebs_kms_key_arn must be a full KMS key ARN (arn:aws:kms:<region>:<account-id>:key/<key-id>), not an alias."
706+
}
707+
}
708+
676709
variable "s3_backup_bucket_name_override" {
677710
type = string
678711
default = ""
@@ -701,6 +734,17 @@ variable "redis_ebs_throughput" {
701734
description = "Throughput of EBS redis volume"
702735
}
703736

737+
variable "redis_ebs_kms_key_arn" {
738+
type = string
739+
default = null
740+
description = "Full ARN of an existing KMS key to encrypt the redis data EBS volume with. Supports keys held in another account, provided the key policy grants this account use of the key. When null, the account default EBS encryption key is used. Must be a key ARN, not an alias: aliases do not resolve across accounts. Changing this on an existing volume forces replacement."
741+
742+
validation {
743+
condition = var.redis_ebs_kms_key_arn == null || can(regex("^arn:aws[a-z-]*:kms:[a-z0-9-]+:[0-9]{12}:key/", var.redis_ebs_kms_key_arn))
744+
error_message = "redis_ebs_kms_key_arn must be a full KMS key ARN (arn:aws:kms:<region>:<account-id>:key/<key-id>), not an alias."
745+
}
746+
}
747+
704748
# ┏━╸╻┏ ┏━┓
705749
# ┣╸ ┣┻┓┗━┓
706750
# ┗━╸╹ ╹┗━┛

0 commit comments

Comments
 (0)