AWS Secrets Manager Access Control Weaknesses: Scoping IAM Policies for GetSecretValue
Theory
Why This Matters
In 2021, researchers analysing a compromised AWS environment found that a single EC2 instance profile with secretsmanager:GetSecretValue on Resource: "*" had been used to exfiltrate credentials for a production database, a payment processing API key, and a third-party analytics service — all from a single compromised instance that nominally served a marketing microservice with no legitimate need for any of those secrets. AWS Secrets Manager centralises secret storage, but centralisation without access control creates a single high-value target: any principal with broad GetSecretValue permissions can drain the entire secret store. The service provides the tooling for granular access control; the vulnerability is in how IAM policies are written.
Core Concept
AWS Secrets Manager stores, rotates, and controls access to secrets such as database credentials, API keys, and OAuth tokens. Secrets are identified by a secret ARN and an optional human-readable name. Access is controlled at two levels: IAM identity-based policies (who can call which Secrets Manager APIs) and resource-based policies (a per-secret policy controlling cross-account access or providing additional conditions).
Key API actions for access control analysis:
- secretsmanager:GetSecretValue — retrieves the plaintext or binary secret value. This is the high-value action that must be tightly scoped.
- secretsmanager:ListSecrets — enumerates all secrets in the account (names, ARNs, metadata — not values). An attacker with only this permission can map the secret store.
- secretsmanager:DescribeSecret — retrieves metadata including rotation schedule and resource policy. Does not expose the secret value.
- secretsmanager:PutSecretValue / UpdateSecret — writes a new secret version. An attacker with write access can poison a secret to cause application malfunction or inject credentials they control.
Principle of least privilege for Secrets Manager means each application role should have GetSecretValue scoped to only the specific secret ARNs it needs, not to Resource: "*". AWS recommends using secret name prefixes (e.g., prod/myapp/*) and Resource ARN patterns to scope access while remaining maintainable as new secrets are added.
Automatic rotation is a key Secrets Manager feature: Lambda functions rotate secrets on a schedule, eliminating long-lived static credentials. A secret without rotation configured is a finding: static credentials exposed in a breach remain valid indefinitely.
Technical Deep-Dive
# Enumerate all secrets in the account (requires secretsmanager:ListSecrets)
aws secretsmanager list-secrets
--query 'SecretList[*].{Name:Name,ARN:ARN,Rotation:RotationEnabled,LastRotated:LastRotatedDate}'
--output table
# Describe a specific secret — metadata only, no value exposed
aws secretsmanager describe-secret --secret-id "prod/myapp/database"
--query '{ARN:ARN,Rotation:RotationEnabled,ResourcePolicy:exists(SecretValue)}'
# Retrieve the resource-based policy of a secret
aws secretsmanager get-resource-policy --secret-id "prod/myapp/database"
--query 'ResourcePolicy' --output text | python3 -m json.tool
# Attempt to retrieve the secret value (tests if current principal has access)
aws secretsmanager get-secret-value --secret-id "prod/myapp/database"
--query '{Name:Name,SecretString:SecretString}' --output json
# Check which IAM policies grant GetSecretValue with wildcard resources
# (run as admin — requires iam:GetPolicyVersion)
aws iam list-policies --scope Local
--query 'Policies[*].{Name:PolicyName,Arn:Arn}' --output text |
while read name arn; do
version=$(aws iam get-policy --policy-arn "$arn"
--query 'Policy.DefaultVersionId' --output text)
doc=$(aws iam get-policy-version --policy-arn "$arn"
--version-id "$version" --query 'PolicyVersion.Document' --output text)
if echo "$doc" | grep -q 'GetSecretValue'; then
resource=$(echo "$doc" | python3 -c
"import sys,json; doc=json.loads(sys.stdin.read())
[print(s.get('Resource')) for s in doc.get('Statement',[]) if 'GetSecretValue' in str(s.get('Action','))]")
echo "Policy: $name Resource: $resource"
fi
done
# Simulate whether a role can access a specific secret
aws iam simulate-principal-policy
--policy-source-arn "arn:aws:iam::ACCOUNT_ID:role/MarketingServiceRole"
--action-names secretsmanager:GetSecretValue
--resource-arns "arn:aws:secretsmanager:us-east-1:ACCOUNT_ID:secret:prod/payments/stripe-key"
--query 'EvaluationResults[*].{Action:EvalActionName,Decision:EvalDecision}'
--output table
Security Assessment Methodology
- Enumerate all secrets.
aws secretsmanager list-secretsshows names, ARNs, and rotation status. Secrets withRotationEnabled: falseand oldLastChangedDatevalues are static credentials — a finding independent of access control. - Identify which principals can call
GetSecretValue. Search IAM policies (inline and managed) forsecretsmanager:GetSecretValuestatements. Pay attention toResourcevalues —"*"is the highest-severity finding. Useiam simulate-principal-policyto confirm effective access. - Check resource-based secret policies. Retrieve the resource policy for each secret. Cross-account principals or
"Principal": "*"in a secret policy warrant immediate investigation. - Test access from each application role. For each application role in scope, attempt
GetSecretValueagainst secrets that role should not be able to access (e.g., a web tier role attempting to read payment processor credentials). Document successful retrievals. - Check for
ListSecretsexposure. Even withoutGetSecretValue, an attacker withListSecretscan enumerate all secret names, revealing the application architecture, third-party integrations, and naming conventions. ScopeListSecretsto application-specific prefixes. - Remediate by scoping all
GetSecretValuepolicies to specific secret ARNs or ARN patterns matching the application's required secrets. Enable automatic rotation for all database and API key secrets. Add resource-based policies withaws:SourceVpcoraws:PrincipalAccountconditions where applicable.
Common Assessment Errors
- Only testing GetSecretValue.
PutSecretValueandUpdateSecretare equally dangerous — an attacker who can write a secret can inject credentials they control, causing applications to authenticate to attacker-controlled services. Always check write permissions. - Ignoring the Lambda rotation function. The Lambda function used for secret rotation itself has an execution role. If that role has
GetSecretValueon all secrets (a common pattern for "simplicity"), it is an escalation path via Lambda code injection. - Missing KMS key access. Secrets Manager encrypts secrets using KMS. An attacker with
kms:Decrypton the key used to encrypt secrets, combined with direct access to the Secrets Manager storage bucket, could potentially decrypt secrets without going through the Secrets Manager API. Audit KMS key policies forkms:Decryptgrants. - Not checking CloudTrail for prior GetSecretValue calls. Even after discovering a misconfiguration, check whether it was exploited. CloudTrail logs
GetSecretValueAPI calls with caller identity, timestamp, and secret name. Historical access by unexpected principals is evidence of a breach. - Treating the secret name as non-sensitive. Secret names are returned by
ListSecretsand visible in CloudTrail without requiringGetSecretValue. Names likeprod/database/admin-passwordconfirm the existence of an admin database credential. Use generic naming conventions and treat ListSecrets access as sensitive.
NICE Framework Alignment
| Code | Knowledge/Skill/Task Statement | How This Card Develops It |
|---|---|---|
| K0053 | Knowledge of security risk management processes | Evaluating Secrets Manager access risk: centralised secret storage amplifies the impact of over-broad IAM policies, making access control critical |
| K0167 | Knowledge of system administration, network, and OS hardening techniques | Hardening Secrets Manager deployments: ARN-scoped GetSecretValue policies, automatic rotation, KMS CMK with minimal decrypt grants |
| S0073 | Skill in conducting vulnerability scans and recognizing vulnerabilities | Using list-secrets, simulate-principal-policy, and IAM policy scanning to identify roles with unauthorised access to secrets beyond their application scope |
| T0144 | Conduct penetration testing as required for new or updated applications | Testing Secrets Manager access from application roles during AWS assessments to identify credential over-exposure and lateral movement paths |
| T0395 | Write code to address security vulnerabilities | Writing least-privilege IAM policies scoping secretsmanager:GetSecretValue to specific secret ARNs using prefix-based Resource patterns |
Further Reading
- AWS Secrets Manager Best Practices — AWS Documentation (docs.aws.amazon.com/secretsmanager/latest/userguide/best-practices.html)
- Hacking the Cloud: Secrets Manager Enumeration — Nick Frichette (hackingthe.cloud)
- AWS Security Cookbook — Heartin Kanikathottu, Chapter 5: Secrets Management (Packt Publishing)
Challenge Lab
Reinforce your learning with a hands-on generated challenge based on this card's competency.