DEV Community

Kanishka Halder
Kanishka Halder

Posted on

AWS KMS Customer Managed Key (CMK) for DB Integration

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.

Image description

  • 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.

Image description

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
}
Enter fullscreen mode Exit fullscreen mode

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)