logo

Database

Non-encrypted confidential information

Need

Secure storage and encryption of confidential information and credentials in AWS infrastructure managed via Terraform

Context

• Usage of Terraform for Infrastructure as Code (IaC)

• Usage of the AWS SDK for interacting with Amazon Web Services (AWS) services

• Usage of aws_redshift_cluster for managing and interacting with Amazon Redshift clusters

Description

1. Non compliant code

# --- AWS Credentials ---
provider "aws" {
  region     = "us-west-2"
  access_key = "AKIAFODNN7EXAMPLE"
  secret_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
}

# --- Redshift Cluster ---...

**Hard-coded AWS credentials in the Terraform provider block.** The `access_key` and `secret_key` used to authenticate the Terraform AWS provider are stored as plain-text string literals directly in the source code — sometimes alongside a description that frames them as encoded (e.g. hexadecimal), even though the literal values shown are still plain text. Anyone who can access this code, including anyone browsing a version-controlled or public repository, gains access to these credentials and can use them for unauthorized access to the AWS account. **Redshift cluster created without encryption.** The `aws_redshift_cluster` resource does not set the `encrypted` attribute, so all data stored in the cluster is left unencrypted. Anyone who gains unauthorized access to the cluster can read the data directly, without needing any encryption key. **DynamoDB table created without a Customer Managed Key.** The `aws_dynamodb_table` resource does not include a `server_side_encryption`/`kms_key_arn` argument, so the table falls back to the default AWS-managed KMS key rather than a Customer Managed Key (CMK) that the account owner fully controls — including its creation, rotation, and access policy. **RDS database instance with a plain-text password, publicly accessible and unencrypted.** The `aws_db_instance` resource sets a plain-text `password`, is `publicly_accessible = true` so it can be reached from any IP address, and does not enable `storage_encrypted`, so the data at rest is not protected either. **EBS volume created without encryption.** The `aws_ebs_volume` resource explicitly sets `encrypted = false`, so any data written to the volume — user data, application data, or system data from an attached EC2 instance — is stored unprotected at rest. **EFS file system left on the default AWS-managed KMS key.** The `aws_efs_file_system` resource specifies no encryption configuration at all, so it is encrypted (if at all) only with the default AWS-managed key rather than a Customer Managed Key the account owner controls. **S3 bucket created without server-side encryption.** The `aws_s3_bucket` resource has no `server_side_encryption_configuration` block, so objects stored in the bucket are not encrypted at rest. If an attacker gains access to the bucket, they can read the stored objects directly.

2. Steps

• Remove the plain text AWS access key and secret key from the source code and store them in a secure location, such as AWS Secrets Manager, AWS Parameter Store, or HashiCorp Vault.

• Retrieve the AWS access key and secret key from the secure location at runtime, and encrypt the sensitive information before storing or transmitting it.

• Regularly rotate the access key and secret key to minimize the risk of unauthorized access, and monitor and log any access to the credentials to detect suspicious activity.

• Follow the organization's policies and best practices for encryption and secure storage of sensitive information.

• Enable encryption for the AWS Redshift cluster by setting the 'encrypted' attribute to 'true' and specifying a 'kms_key_id' referencing a Customer Managed Key (CMK) in AWS Key Management Service (KMS).

• Create a Customer Managed Key (CMK) in AWS KMS and specify it via the 'kms_key_arn' attribute to enable server-side encryption for the DynamoDB table.

• Enable encryption at rest for the database instance by setting 'storage_encrypted' to 'true' and specifying a 'kms_key_id'.

• Use SSL/TLS to encrypt data in transit between the application and the database.

• Implement strong access controls and authentication mechanisms for the database, and regularly update and patch the database software to address known vulnerabilities.

• Identify all EBS volumes in the infrastructure that are not encrypted, update their configuration to set the 'encrypted' property to 'true', and re-deploy or update the infrastructure to apply the changes.

• Enable encryption for the AWS Elastic File System (EFS) resource by creating a Customer Managed Key (CMK) and specifying its ARN in the 'kms_key_id' attribute.

• Modify the 'aws_s3_bucket' resource block to include a 'server_side_encryption_configuration' argument, choosing the appropriate encryption method (SSE-S3 or SSE-KMS) based on your requirements.

• Save the changes and apply the updated Terraform configuration to provision the resources with encryption enabled.

3. Secure code example

# --- AWS Credentials ---
provider "aws" {
  region     = "us-west-2"
  access_key = var.access_key
  secret_key = var.secret_key
}

variable "access_key" {...

**Hard-coded AWS credentials in the Terraform provider block (fix).** The plain-text `access_key` and `secret_key` are removed from the provider block and replaced with `var.access_key` and `var.secret_key`, declared as Terraform `variable` blocks. These variables should be populated at runtime from a secure location such as AWS Secrets Manager, AWS Parameter Store, or HashiCorp Vault, and the underlying credentials should be rotated regularly, with access to them monitored and logged. **Redshift cluster created without encryption (fix).** An `aws_kms_key` resource creates a Customer Managed Key, and the `aws_redshift_cluster` resource sets `encrypted = true` with `kms_key_id` pointing at that key's ARN, so all data in the cluster is encrypted and accessible only to entities with permission to use the key. **DynamoDB table created without a Customer Managed Key (fix).** An `aws_kms_key` resource creates a CMK, and the `aws_dynamodb_table` resource sets `kms_key_arn` to that key's ARN, so the table is encrypted using a key the account owner fully controls instead of the AWS-managed default. **RDS database instance with a plain-text password, publicly accessible and unencrypted (fix).** `storage_encrypted` is set to `true` with a `kms_key_id` to encrypt the data at rest, and a new `aws_db_option_group` resource enables `MARIADB_ENABLE_SSL` so data in transit between the application and the database is also encrypted. Strong access controls, authentication, and regular patching of the database software remain necessary beyond this snippet. **EBS volume created without encryption (fix).** The `aws_ebs_volume` resource sets `encrypted = true`, so the volume's data is encrypted at rest and unauthorized access to the underlying storage no longer exposes it in plain text. **EFS file system left on the default AWS-managed KMS key (fix).** An `aws_kms_key` resource creates a Customer Managed Key with a 7-day deletion window, and the `aws_efs_file_system` resource sets `kms_key_id` to that key's ARN with `encrypted = true`, giving the account owner full control over the file system's encryption key. **S3 bucket created without server-side encryption (fix).** A `server_side_encryption_configuration` block is added to the `aws_s3_bucket` resource, with `apply_server_side_encryption_by_default.sse_algorithm` set to `"AES256"`, so every new object written to the bucket is encrypted at rest by default.