Plaintext or hard-coded secrets can be found in many resources throughout AWS if there is poor hygiene in the management of secrets.
CloudFormation
CloudFormation is an AWS infrastructure-as-code solution written in JSON or YAML
# provides details of the stacks including parameter key/values
aws --region us-east-1 cloudformation describe-stacks
# view the source code for a specific stack
aws --region us-east-1 cloudformation get-template --stack-name execution | jq -r '.TemplateBody'
EC2 Instances
User-data
Secrets can end up hard-coded in EC2 user-data and can easily be discovered either with the action ec2:DescribeInstanceAttributeor by querying the IMDS service
# querying IMDSv1 (code execution on the instance is required)
curl http://169.254.169.254/latest/user-data
# output
echo "aws_access_key_id = AKIAZxxxxxxxxxx" >> ~/ec2-user/.aws/credentials
echo "aws_secret_access_key = T2a4SjDnqsPUxxxxxxx" >> ~/ec2-user/.aws/credentials
IMDSv2
Version 2 of IMDS requires obtaining a token first
# querying IMDSv2 (code execution on the instance is required)
TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/user-data
# output
echo "aws_access_key_id = AKIAZxxxxxxxxxx" >> ~/ec2-user/.aws/credentials
echo "aws_secret_access_key = T2a4SjDnqsPUxxxxxxx" >> ~/ec2-user/.aws/credentials
EC2 Launch Templates
EC2 Launch Templates allow for defining consistent configurations (Security Groups, IMDS, Instance types, User Data, etc.) for any EC2 that uses the template
# get parameter (can only decrypt if you have permission to the kms key)
aws --region us-west-2 ssm get-parameter --name uninstall_key --with-decryption
{
"Parameter": {
"Name": "uninstall_key",
"Type": "SecureString",
"Value": "34n34n393nndg0sng4",
"Version": 1,
"LastModifiedDate": "2025-01-03T18:36:21.900000-07:00",
"ARN": "arn:aws:ssm:us-west-2:111111111111:parameter/uninstall_key",
"DataType": "text"
}
}
Terraform State
While not an AWS resource, Terraform State files are commonly stored in AWS S3 buckets
If the data is not encrypted and/or you have access to decrypt the data, Terraform State files often contain secrets, credentials, and information about the cloud environment
# example of downloading terraform state from file
aws s3 cp s3://myterraformstatebucket/prod/prod-account-a/terraform.tfstate .
# output state to json to see sensitive values
terraform show -json | jq
{
"format_version": "1.0",
"terraform_version": "1.5.7",
"values": {
"root_module": {
"resources": [
{
"address": "aws_iam_access_key.admin",
"mode": "managed",
"type": "aws_iam_access_key",
"name": "admin",
"provider_name": "registry.terraform.io/hashicorp/aws",
"schema_version": 0,
"values": {
"create_date": "2025-01-04T01:17:57Z",
"encrypted_secret": null,
"encrypted_ses_smtp_password_v4": null,
"id": "AKIA[...]",
"key_fingerprint": null,
"pgp_key": null,
"secret": "dfY0XUrA[...]",
"ses_smtp_password_v4": "BBPzJ[...]",
"status": "Active",
"user": "admin"
},
"sensitive_values": {
"secret": true,
"ses_smtp_password_v4": true
}
}
]
}
}
}
# you can also just read the state file since it's json
cat terraform.tfstate | jq