Secure Secrets Management in Terraform Part1: Leveraging AWS KMS

Secure Secrets Management in Terraform Part1: Leveraging AWS KMS

Secure Secrets Management in Terraform — Part1: Leveraging AWS KMS

One of the key principles of modern Infrastructure as Code is the secure management of sensitive information. In thins first part of our series about secure secrets management in Terraform/OpenTofu, we will focus on the use of AWS Key Management Service, better known as KMS, to securely encrypt and manage secrets with Terraform/OpenTofu.

Prerequisites

  • AWS Account with appropriate permissions
  • Terraform/OpenTofu installed
  • AWS CLI configured

AWS KMS

First, let’s create a KMS key with proper permissions and configurations:

    resource "aws_kms_key" "secrets_key" {  
      description             = "KMS key for encrypting application secrets"  
      deletion_window_in_days = 7  
      enable_key_rotation     = true  
    }  
      
    resource "aws_kms_alias" "secrets_key_alias" {  
      name          = "alias/awsmorocco-key"  
      target_key_id = aws_kms_key.secrets_key.key_id  
    }  
      
      
    resource "aws_kms_key_policy" "example" {  
      key_id = aws_kms_key.secrets_key.id  
      policy = jsonencode({  
        Id = "example"  
        Statement = [  
          {  
            Action = "kms:*"  
            Effect = "Allow"  
            Principal = {  
              AWS = "*"  
            }  
      
            Resource = "*"  
            Sid      = "Enable IAM User Permissions"  
          },  
        ]  
        Version = "2012-10-17"  
      })  
    }  

After applying this configuration, you can find the key in the AWS Console under KMS > Customer managed keys :

Encrypting Secrets with AWS CLI

Now that we have our KMS key set up, we can use it to encrypt sensitive values using the AWS CLI:

    aws kms encrypt \  
        --key-id alias/awsmorocco-key \  
        --plaintext fileb://<(echo -n "my-super-secret-password") \  
        --output text \  
        --query CiphertextBlob \  
        --region us-east-1

This command will output a base64-encoded encrypted string that you can safely store in your Terraform configurations

Using Encrypted Values in Terraform:

Create variables to store the encrypted values:

    # variables.tf  
    variable "encrypted_db_password" {  
      description = "KMS encrypted database password"  
      type        = string  
      default     = "AQICAHhw31bEpV7TSsANCrrf6ZKimnQvVlNeIPn2xFDmUQPjOAGLFV0lcS4XiuwfqRIC1YI+AAAAdjB0BgkqhkiG9w0BBwagZzBlAgEAMGAGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM/MZEgbuuMwVNBHJ1AgEQgDNUMmkSJO/f1t5w5JIWLc2MmGyU4/Az5IypmMuTTShUqRArmYsyzvA/G54jekuCyip7VmA="  
      
      # the best way is to use a valuesfiles: terraform.tfvars  
      # encrypted_db_password = "AQICAHhw31bEpV7TSsANCrrf6ZKimnQvVlNeIPn2xFDmUQPjOAGLFV0lcS4XiuwfqRIC1YI+AAAAdjB0BgkqhkiG9w0BBwagZzBlAgEAMGAGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM/MZEgbuuMwVNBHJ1AgEQgDNUMmkSJO/f1t5w5JIWLc2MmGyU4/Az5IypmMuTTShUqRArmYsyzvA/G54jekuCyip7VmA="  
    }  
      
    variable "encrypted_api_key" {  
      type    = string  
      default = ""  
    }

Create data sources to decrypt the values:

    ### data sources  
      
    data "aws_kms_secrets" "application_secrets" {  
      secret {  
        name    = "db_password"  
        payload = var.encrypted_db_password  
      }  
      
      # You can decrypt multiple secrets in one block  
      # secret {  
      #   name    = "api_key"  
      #   payload = var.encrypted_api_key  
      # }  
    }  
      
    # Access the decrypted value  
    locals {  
      db_password = data.aws_kms_secrets.application_secrets.plaintext["db_password"]  
      #api_key     = data.aws_kms_secrets.application_secrets.plaintext["api_key"]  
    }

Use the decrypted values in your resources:

    ### Provision resources and provide the decrypted values  
      
    resource "aws_db_instance" "db" {  
      identifier           = "awsmorocco-db"  
      engine               = "mysql"  
      instance_class       = "db.t3.micro"  
      username             = "awsmorocco-admin-user-1"  
      password             = local.db_password # Using the decrypted   
      parameter_group_name = "default.mysql8.0"  
      skip_final_snapshot  = true  
      allocated_storage    = 10  
    }

Best Practices for KMS Usage

1 — Key Rotation

  • Enable automatic key rotation as we did in our configuration
  • Consider using different keys for different environments

2 — Access Control

  • Implement least-privilege access in your key policies
  • Use separate keys for different applications or services

3 — Monitoring

  • Enable AWS CloudTrail to audit KMS key usage
  • Set up alerts for unauthorized access attempts

4 — Security

  • Never store unencrypted sensitive values in version control
  • Use separate key aliases for different environments
  • Implement proper backup and recovery procedures

Next Steps

In Part 2 of this series, we’ll explore how to integrate AWS Secrets Manager with our KMS setup for more advanced secrets management capabilities.

Conclusion

Using AWS KMS with Terraform provides a secure way to manage encrypted secrets in your infrastructure code. By following these practices, you can ensure that your sensitive data remains protected while still being accessible to your authorized applications and services.

ℹ️ Terraform code is available here


Secure Secrets Management in Terraform — Part1: Leveraging AWSKMS was originally published in AWSMorocco on Medium, where people are continuing the conversation by highlighting and responding to this story.

Related Posts

Machine learning on Elastic Search using Apache Spark and ES-Hadoop — Part 2

Machine learning on Elastic Search using Apache Spark and ES-Hadoop — Part 2

In the previous article (Part1), we installed the ELK stack along with the ES-Hadoop connector and spark, then we did some visualizations in Kibana with the houses price prediction data set from kaggle.

Read More
Terraform Infrastructure as Code: Essential Tools for Clean, Maintainable Production Environments

Terraform Infrastructure as Code: Essential Tools for Clean, Maintainable Production Environments

Managing cloud resources has really changed with the Infrastructure as Code (IaC) approach, and Terraform has become one of the best tools for the job.

Read More
Lessons Learned From Mounting Secrets to Pods on Kubernetes

Lessons Learned From Mounting Secrets to Pods on Kubernetes

Kubernetes secrets are objects conceived to hold sensitive information such as passwords, tokens and certificates that can be used by pods without the need to include this sensitive information in the application code or container image.

Read More