Hardcoded Secrets and Credentials
Hardcoded Secrets and Credentials
Hardcoded secrets in IaC templates represent one of the most dangerous yet preventable vulnerabilities. Passwords, API keys, and certificates embedded in templates are visible to anyone with repository access. Version control systems preserve these secrets in history even after removal. Automated scanning by attackers can quickly identify and exploit exposed credentials.
The pressure to quickly prototype or test functionality leads to temporary hardcoding that becomes permanent. Developers might hardcode credentials intending to replace them later but forget. Example code copied from documentation often contains placeholder credentials that make it into production. These practices create severe security vulnerabilities.
# DANGEROUS: Hardcoded secrets in Terraform
# VULNERABLE: Hardcoded database password
resource "aws_db_instance" "vulnerable" {
engine = "mysql"
username = "admin"
password = "SuperSecret123!" # DANGER: Hardcoded password
}
# VULNERABLE: Hardcoded API key
resource "aws_lambda_function" "vulnerable" {
function_name = "data-processor"
environment {
variables = {
API_KEY = "sk_live_4242424242424242" # DANGER: Hardcoded API key
DB_PASS = "ProductionPassword123" # DANGER: Hardcoded password
}
}
}
# VULNERABLE: Hardcoded SSH key
resource "aws_instance" "vulnerable" {
ami = "ami-12345678"
instance_type = "t2.micro"
user_data = <<-EOF
#!/bin/bash
echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQ..." >> /home/ubuntu/.ssh/authorized_keys
echo "-----BEGIN RSA PRIVATE KEY-----" > /root/.ssh/id_rsa
echo "MIIEpAIBAAKCAQEA..." >> /root/.ssh/id_rsa # DANGER: Private key in user data
echo "-----END RSA PRIVATE KEY-----" >> /root/.ssh/id_rsa
EOF
}
# SECURE: Using Secrets Manager
resource "aws_db_instance" "secure" {
engine = "mysql"
username = local.db_creds.username
password = local.db_creds.password
}
locals {
db_creds = jsondecode(
data.aws_secretsmanager_secret_version.db.secret_string
)
}
data "aws_secretsmanager_secret_version" "db" {
secret_id = aws_secretsmanager_secret.db.id
}
resource "aws_secretsmanager_secret" "db" {
name = "${var.environment}-db-credentials"
rotation_rules {
automatically_after_days = 30
}
}
# SECURE: Using SSM Parameter Store for API keys
resource "aws_lambda_function" "secure" {
function_name = "data-processor"
environment {
variables = {
API_KEY_PARAM = aws_ssm_parameter.api_key.name
DB_PASS_PARAM = aws_ssm_parameter.db_pass.name
}
}
}
resource "aws_ssm_parameter" "api_key" {
name = "/${var.environment}/api/key"
type = "SecureString"
value = var.api_key # Provided at runtime, not in code
}
# SECURE: Using AWS Systems Manager Session Manager instead of SSH keys
resource "aws_instance" "secure" {
ami = "ami-12345678"
instance_type = "t2.micro"
iam_instance_profile = aws_iam_instance_profile.ssm.name
# No SSH keys needed - access via Session Manager
metadata_options {
http_tokens = "required" # IMDSv2 only
}
}