Skip to main content

Hard-Coded Secrets

Fixing Hard-coded Secrets

About Hard-Coded Secrets

What are Hard-coded Secrets?

Hard-coded secrets refer to the practice of embedding sensitive information, such as passwords, encryption keys, or API keys, directly in the source code of an application.

This practice can make it easy for attackers to identify and exploit these secrets, leading to security vulnerabilities and other types of security threats.

Hard-coded secrets are a security risk because they are often stored in plain text, making it easy for attackers to extract them from the source code. They can also be inadvertently disclosed or exposed through other security vulnerabilities, such as code injection or data leaks.

Hard-coded secrets can affect various types of applications, such as web applications, mobile applications, and desktop applications. They can also be found in infrastructure components, such as scripts, configuration files, and server software.

At GuardRails, we differentiate between different kinds of secrets and cover the below CWEs.

What is the impact of Hard-Coded Secrets?

Hard-coded secrets can lead to various security threats and risks, such as:

  • Information disclosure: Hard-coded secrets can expose sensitive information, such as passwords, keys, or other types of confidential information, to unauthorized parties.
  • Unauthorized access: Hard-coded secrets can allow attackers to gain unauthorized access to applications, systems, or networks, perform unauthorized actions, or modify data.
  • Data modification: Hard-coded secrets can allow attackers to modify data or system configurations, leading to data loss or corruption, or other types of system instability.

This has led to many high-profile breaches.

How to prevent Hard-Coded Secrets?

To prevent hard-coded secrets, implement appropriate security measures, such as:

  • Use environment variables: Use environment variables or configuration files to store sensitive information, such as passwords or keys, instead of hard-coding them in the source code.
  • Use secure storage: Store sensitive information in secure storage, such as a secure key vault, that provides additional security features, such as access controls and encryption.
  • Use encryption: Use encryption to protect sensitive information in transit and at rest, such as using TLS for network traffic and encrypting storage media.
  • Apply access controls: Apply access controls to limit the privileges and actions that users or applications can perform on sensitive information, such as using role-based access controls or fine-grained access controls.
  • Use secure coding practices: Follow secure coding practices, such as code reviews, vulnerability scanning and testing, and threat modeling, to ensure that the source code is free of vulnerabilities and that sensitive information is properly protected.

A list of popular secure key vault software can be found below:

  1. HashiCorp Vault
  2. AWS Secrets Manager
  3. GCP Cloud KMS
  4. Microsoft Azure Key Vault
  5. Confidant
  6. Keywhiz
  7. Knox

References

Taxonomies

Explanation & Prevention

Training

Avoiding hard-coded Secrets for use with Terraform Cloud or Terraform Enterprise

Secrets that are provided in configurations to Terraform are usually with significant write permissions that can modify your infrastructure in your cloud service provider (CSP).

Option A: Use Terraform Login

  1. # terraform login [hostname]
  2. By default, Terraform will obtain an API token and save it in plain text in a local CLI configuration file called credentials.tfrc.json

Option B: Use a Terraform CLI Configuration File

  1. Configure a Terraform CLI Configuration File:

    credentials "app.terraform.io" {
    token = "xxxxxx.atlasv1.zzzzzzzzzzzzz"
    }
  2. The location of the Terraform CLI configuration file can also be specified using the TF_CLI_CONFIG_FILE environment variable like:

    export TF_CLI_CONFIG_FILE="$HOME/.terraformrc-custom"

Option C: [Advanced] Write and Use Credentials Helper Plugin

  1. Write a Terraform Credentials Helpers

  2. Replace your configuration block with credentials_helper:

    credentials_helper "example" {
    args = []
    }

Avoid Hard-coded Secrets when Provisioning Infrastructure

Rule-specific references:

Option A: Use a Separate Variable File and add to .gitignore

  1. Go through the issues that GuardRails identified in the PR/MR

  2. An example main.tf file with a hard-coded secret is shown below:

    variable "db_password" {
    description = "The password of the db user."
    type = string
    default = "mydbpassword"
    }
    ...
  3. Remove the line 'default' and main.tf should look like the following:

    variable "db_password" {
    description = "The password of the db user."
    type = string
    }
    ...
  4. Create a new file named terraform.tfvars

  5. It should look like this:

    variable "db_password" {
    type = string
    default = "mydbpassword"
    }
    ... other variables
  6. Your directory should have 2 files: main.tf and terraform.tfvars

  7. If you're using git, add terraform.tfvars to your .gitignore file so git will ignore and not check this file into the repository:

    git rm --cached main.tf
    echo "terraform.tfvars" >> .gitignore
  8. Test it! Add a -var-file flag to your terraform command:

    terraform plan #-var-file=terraform.tfvars
    # If `terraform.tfvars` or any `*.auto.tfvars` files are present, they will be automatically loaded.
  9. Ship it 🚢 and relax 🌴

Option B: Use the Provider's Credentials File

  1. Go through the issues that GuardRails identified in the PR/MR

  2. Using AWS (as a provider) for example, a file main.tf with hardcoded AWS secret is shown below:

    provider "aws" {
    region = "us-west-2"
    access_key = "my-access-key"
    secret_key = "my-secret-key"
    }
  3. Locate or create your AWS credentials file (default is "$HOME/.aws/credentials" on Linux and OS X, or "%USERPROFILE%\.aws\credentials" for Windows)

  4. Remove 'access_key' and 'secret_key', add 'profile' and 'shared_credentials_file'; main.tf should look like the following:

    provider "aws" {
    region = "us-west-2"
    shared_credentials_file = "/Users/tf_user/.aws/credentials"
    profile = "customprofile" # if you have multiple profiles, else default is used
    }
  5. Test it!

    terraform plan
  6. Ship it 🚢 and relax 🌴

User Data Contains Encoded Private Key

AWS ECS Launch Configuration User Data should not contain an encoded RSA Private Key. Encoding secrets does not protect them at all, it simply obscures them. Do not rely on obscurity as a technique to provide security.

Rule-specific references:

Option A: Make sure EC2 Launch Configuration User Data does not contain encoded RSA Private Key

If one of the following contains an encoded RSA private key:

  • aws_launch_configuration user_data_base64
  • module user_data_base64

Move it to a location that stores secret values in AWS such as the following:

  • AWS Systems Manager Parameter Store
  • AWS Secrets Manager
  1. Locate one of the following vulnerable patterns:

    Vulnerable resource aws_launch_configuration user_data_base64 contains private key pattern:

    resource "aws_launch_configuration" "positive1" {
    image_id = data.aws_ami.ubuntu.id
    instance_type = "m4.large"
    spot_price = "0.001"
    user_data_base64 = "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpzb21lS2V5" # someKey

    lifecycle {
    create_before_destroy = true
    }
    }

    Vulnerable module user_data_base64 contains private key pattern:

    module "positive2" {
    source = "terraform-aws-modules/autoscaling/aws"
    version = "1.0.4"

    # Launch configuration
    lc_name = "example-lc"

    image_id = "ami-ebd02392"
    instance_type = "t2.micro"
    security_groups = ["sg-12345678"]
    user_data_base64 = "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpzb21lS2V5"

    ebs_block_device = [
    {
    device_name = "/dev/xvdz"
    volume_type = "gp2"
    volume_size = "50"
    delete_on_termination = true
    },
    ]

    root_block_device = [
    {
    volume_size = "50"
    volume_type = "gp2"
    },
    ]

    # Auto scaling group
    asg_name = "example-asg"
    vpc_zone_identifier = ["subnet-1235678", "subnet-87654321"]
    health_check_type = "EC2"
    min_size = 0
    max_size = 1
    desired_capacity = 1
    wait_for_capacity_timeout = 0

    tags = [
    {
    key = "Environment"
    value = "dev"
    propagate_at_launch = true
    },
    {
    key = "Project"
    value = "megasecret"
    propagate_at_launch = true
    },
    ]
    }

    Vulnerable module user_data_base64 contains private key pattern:

    module "positive3" {
    source = "terraform-aws-modules/autoscaling/aws"
    version = "1.0.4"

    # Launch configuration
    lc_name = "example-lc"

    image_id = "ami-ebd02392"
    instance_type = "t2.micro"
    security_groups = ["sg-12345678"]
    user_data_base64 = "LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZIEJMT0NLLS0tLS0="

    ebs_block_device = [
    {
    device_name = "/dev/xvdz"
    volume_type = "gp2"
    volume_size = "50"
    delete_on_termination = true
    },
    ]

    root_block_device = [
    {
    volume_size = "50"
    volume_type = "gp2"
    },
    ]

    # Auto scaling group
    asg_name = "example-asg"
    vpc_zone_identifier = ["subnet-1235678", "subnet-87654321"]
    health_check_type = "EC2"
    min_size = 0
    max_size = 1
    desired_capacity = 1
    wait_for_capacity_timeout = 0

    tags = [
    {
    key = "Environment"
    value = "dev"
    propagate_at_launch = true
    },
    {
    key = "Project"
    value = "megasecret"
    propagate_at_launch = true
    },
    ]
    }
  2. Modify the config to something like the following:

    Replacement resource aws_launch_configuration with no user_data_base64 defined pattern:

    resource "aws_launch_configuration" "negative1" {
    image_id = data.aws_ami.ubuntu.id
    instance_type = "m4.large"
    spot_price = "0.001"

    lifecycle {
    create_before_destroy = true
    }
    }

    Replacement resource aws_launch_configuration with empty user_data_base64 pattern:

    resource "aws_launch_configuration" "negative2" {
    image_id = data.aws_ami.ubuntu.id
    instance_type = "m4.large"
    spot_price = "0.001"
    user_data_base64 = ""

    lifecycle {
    create_before_destroy = true
    }
    }

    Replacement resource aws_launch_configuration user_data_base64 containing non-vulnerable pattern:

    resource "aws_launch_configuration" "negative3" {
    image_id = data.aws_ami.ubuntu.id
    instance_type = "m4.large"
    spot_price = "0.001"
    user_data_base64 = "dGVzdA=="

    lifecycle {
    create_before_destroy = true
    }
    }

    Replacement resource aws_launch_configuration user_data_base64 containing null pattern:

    resource "aws_launch_configuration" "negative4" {
    image_id = data.aws_ami.ubuntu.id
    instance_type = "m4.large"
    spot_price = "0.001"
    user_data_base64 = null

    lifecycle {
    create_before_destroy = true
    }
    }

    Replacement module with no user_data_base64 defined pattern:

    module "asg" {
    source = "terraform-aws-modules/autoscaling/aws"
    version = "1.0.4"

    # Launch configuration
    lc_name = "example-lc"

    image_id = "ami-ebd02392"
    instance_type = "t2.micro"
    security_groups = ["sg-12345678"]

    ebs_block_device = [
    {
    device_name = "/dev/xvdz"
    volume_type = "gp2"
    volume_size = "50"
    delete_on_termination = true
    },
    ]

    root_block_device = [
    {
    volume_size = "50"
    volume_type = "gp2"
    },
    ]

    # Auto scaling group
    asg_name = "example-asg"
    vpc_zone_identifier = ["subnet-1235678", "subnet-87654321"]
    health_check_type = "EC2"
    min_size = 0
    max_size = 1
    desired_capacity = 1
    wait_for_capacity_timeout = 0

    tags = [
    {
    key = "Environment"
    value = "dev"
    propagate_at_launch = true
    },
    {
    key = "Project"
    value = "megasecret"
    propagate_at_launch = true
    },
    ]
    }

    Replacement module with empty user_data_base64 pattern:

    module "asg" {
    source = "terraform-aws-modules/autoscaling/aws"
    version = "1.0.4"

    # Launch configuration
    lc_name = "example-lc"

    image_id = "ami-ebd02392"
    instance_type = "t2.micro"
    security_groups = ["sg-12345678"]
    user_data_base64 = ""

    ebs_block_device = [
    {
    device_name = "/dev/xvdz"
    volume_type = "gp2"
    volume_size = "50"
    delete_on_termination = true
    },
    ]

    root_block_device = [
    {
    volume_size = "50"
    volume_type = "gp2"
    },
    ]

    # Auto scaling group
    asg_name = "example-asg"
    vpc_zone_identifier = ["subnet-1235678", "subnet-87654321"]
    health_check_type = "EC2"
    min_size = 0
    max_size = 1
    desired_capacity = 1
    wait_for_capacity_timeout = 0

    tags = [
    {
    key = "Environment"
    value = "dev"
    propagate_at_launch = true
    },
    {
    key = "Project"
    value = "megasecret"
    propagate_at_launch = true
    },
    ]
    }

    Replacement module user_data_base64 containing non-vulnerable pattern:

    module "asg" {
    source = "terraform-aws-modules/autoscaling/aws"
    version = "1.0.4"

    # Launch configuration
    lc_name = "example-lc"

    image_id = "ami-ebd02392"
    instance_type = "t2.micro"
    security_groups = ["sg-12345678"]
    user_data_base64 = "dGVzdA=="

    ebs_block_device = [
    {
    device_name = "/dev/xvdz"
    volume_type = "gp2"
    volume_size = "50"
    delete_on_termination = true
    },
    ]

    root_block_device = [
    {
    volume_size = "50"
    volume_type = "gp2"
    },
    ]

    # Auto scaling group
    asg_name = "example-asg"
    vpc_zone_identifier = ["subnet-1235678", "subnet-87654321"]
    health_check_type = "EC2"
    min_size = 0
    max_size = 1
    desired_capacity = 1
    wait_for_capacity_timeout = 0

    tags = [
    {
    key = "Environment"
    value = "dev"
    propagate_at_launch = true
    },
    {
    key = "Project"
    value = "megasecret"
    propagate_at_launch = true
    },
    ]
    }

    Replacement module user_data_base64 containing null pattern:

    module "asg" {
    source = "terraform-aws-modules/autoscaling/aws"
    version = "1.0.4"

    # Launch configuration
    lc_name = "example-lc"

    image_id = "ami-ebd02392"
    instance_type = "t2.micro"
    security_groups = ["sg-12345678"]
    user_data_base64 = null

    ebs_block_device = [
    {
    device_name = "/dev/xvdz"
    volume_type = "gp2"
    volume_size = "50"
    delete_on_termination = true
    },
    ]

    root_block_device = [
    {
    volume_size = "50"
    volume_type = "gp2"
    },
    ]

    # Auto scaling group
    asg_name = "example-asg"
    vpc_zone_identifier = ["subnet-1235678", "subnet-87654321"]
    health_check_type = "EC2"
    min_size = 0
    max_size = 1
    desired_capacity = 1
    wait_for_capacity_timeout = 0

    tags = [
    {
    key = "Environment"
    value = "dev"
    propagate_at_launch = true
    },
    {
    key = "Project"
    value = "megasecret"
    propagate_at_launch = true
    },
    ]
    }
  3. Test it

  4. Ship it 🚢 and relax 🌴