Encryption keys are a important security aspect that is often overlooked or often pawned off to the cloud provider to manage. But more often than not we have a need for generating and self-managing these Encryption keys, that maybe due to multiple reasons, maybe to enable/disable rotation period, have full access to key metadata and logs (or perhaps the need to assert your dominance on AWS ;).
I have given the simplest terraform script here to generate a Customer Managed Key (CMK) in AWS, setup a working policy for it so that it can be used to encrypt any AWS RDS database.
So firstly how do these encryption keys work:
- When we create a key (CMK) in AWS it generates a 256-bit AES key in a FIPS 140-2 validated HSM. This key never leaves the HSM for security.
- Now when we want to encrypt any data AWS doesn't directly use the CMK for encyption as that would either have to be done in the secure environment or you have to expose the CMK to a insecure environment. So here comes a Data key.
- A Data Key is another key generated inside the HMS and then encrypted by the CMK lets call that the EncryptedDataKey.
- When we want to encrypt any data we get both the plaintext Data Key and the EncryptedDataKey. Now with the plaintext Data Key the data is encrypted and in that data's metadata it puts the EncryptedDataKey.
- Later during decryption you fetch the encrypted data along with the EncryptedDataKey. For context the data itself is encrpyted using the Data Key and this Data key was encypted using our CMK. So during decryption the EncryptedDataKey is first decrypted in the secure environment using our CMK then this decrypted Data Key is then used for decrypting.
Terraform Script:
module "jd_rds_kms" {
source = "terraform-aws-modules/kms/aws"
version = "~> 1.5"
description = "CMK For RDS data encyption"
enable_key_rotation = true
multi_region = false
# Use module's built-in policy creation instead of custom policy
enable_default_policy = true
# Define key administrators (optional - you can add specific roles/users here)
key_administrators = [
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
]
# Define key users for RDS
key_users = [
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
]
# Allow AWS services to use the key - using empty list and relying on key_statements
key_service_users = []
# RDS-specific statement using the module's key_statements feature
key_statements = {
rds = {
sid = "Allow RDS use of the CMK"
actions = [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:CreateGrant",
"kms:ListGrants",
"kms:DescribeKey"
]
resources = ["*"]
principals = [{
type = "Service"
identifiers = ["rds.amazonaws.com"]
}]
conditions = [{
test = "StringEquals"
variable = "kms:CallerAccount"
values = [data.aws_caller_identity.current.account_id]
}]
}
}
# Aliases
aliases = ["db/rds-encryption-key"]
# Any tag to be added
tags = {
Terraform = "true"
}
}
# Get current AWS account ID
data "aws_caller_identity" "current" {}
output "rds_key_arn" {
description = "The ARN of the RDS KMS key"
value = module.jd_rds_kms.key_arn
}
output "rds_key_id" {
description = "The ID of the RDS KMS key"
value = module.jd_rds_kms.key_id
}
This is a simple implementation for a CMK using Terraform AWS module: https://registry.terraform.io/modules/terraform-aws-modules/kms/aws/1.5.0
We can now use this key to be used in RDS for encryption.
Top comments (0)