# Fix AWS Secrets Manager Access Denied
Your application or Lambda function can't retrieve secrets from Secrets Manager. You get "AccessDenied" or "User is not authorized to perform: secretsmanager:GetSecretValue" errors. The secret exists, you're authenticated, but something is blocking access to your sensitive data.
Secrets Manager access requires proper IAM permissions, and optionally resource-based policies. Let's diagnose and fix the access denied issues.
Diagnosis Commands
First, verify who you're authenticated as:
aws sts get-caller-identityCheck if the secret exists:
aws secretsmanager list-secrets \
--query 'SecretList[*].[Name,ARN]'Get secret metadata:
aws secretsmanager describe-secret \
--secret-id my-secret \
--query '[ARN,Name,Description,SecretVersionsToStages]'Try to retrieve the secret value:
aws secretsmanager get-secret-value \
--secret-id my-secret \
--query 'SecretString'Check your IAM policies:
```bash aws iam list-user-policies \ --user-name my-user
aws iam list-attached-user-policies \ --user-name my-user ```
Get specific policy content:
aws iam get-user-policy \
--user-name my-user \
--policy-name my-policy \
--query 'PolicyDocument'For roles, check role policies:
```bash aws iam list-role-policies \ --role-name my-role
aws iam get-role-policy \ --role-name my-role \ --policy-name secrets-policy ```
Check if the secret has a resource-based policy:
aws secretsmanager get-resource-policy \
--secret-id my-secret \
--query 'ResourcePolicy'Use policy simulator to test permissions:
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:user/my-user \
--action-names secretsmanager:GetSecretValue \
--resource-arns arn:aws:secretsmanager:us-east-1:123456789012:secret:my-secret-abc123Common Causes and Solutions
Missing IAM Policy Permissions
The identity doesn't have permission to access secrets:
aws iam get-role-policy \
--role-name my-role \
--policy-name my-policyAdd secrets manager permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret"
],
"Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-secret-*"
}
]
}Apply the policy:
aws iam put-role-policy \
--role-name my-role \
--policy-name SecretsAccess \
--policy-document file://secrets-policy.jsonFor more specific access by secret name:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": [
"arn:aws:secretsmanager:us-east-1:123456789012:secret:database-credentials-*",
"arn:aws:secretsmanager:us-east-1:123456789012:secret:api-keys-*"
]
}
]
}Resource Policy Blocking Access
Secrets Manager supports resource-based policies that can restrict access:
aws secretsmanager get-resource-policy \
--secret-id my-secret \
--query 'ResourcePolicy' \
--output text | jq .If there's a Deny statement, remove or modify it:
aws secretsmanager delete-resource-policy \
--secret-id my-secretOr put a more permissive policy:
aws secretsmanager put-resource-policy \
--secret-id my-secret \
--resource-policy '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/my-role"
},
"Action": "secretsmanager:GetSecretValue",
"Resource": "*"
}
]
}'Cross-Account Access Issues
To access a secret in another account, both sides need configuration:
- 1.In Account B (secret owner):
- 2.Add resource policy allowing Account A:
aws secretsmanager put-resource-policy \
--secret-id shared-secret \
--resource-policy '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT-A-ID:root"
},
"Action": "secretsmanager:GetSecretValue",
"Resource": "*"
}
]
}'- 1.In Account A (accessing account):
- 2.Add IAM policy allowing access to cross-account secret:
aws iam put-role-policy \
--role-name my-role \
--policy-name CrossAccountSecrets \
--policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:us-east-1:ACCOUNT-B-ID:secret:shared-secret-*"
}
]
}'Wrong Secret ARN
Secret ARNs include a random suffix after the name:
aws secretsmanager describe-secret \
--secret-id my-secret \
--query 'ARN'ARN format: arn:aws:secretsmanager:region:account:secret:name-6chars
The -6chars suffix is mandatory in the ARN. Use wildcard in IAM policies:
{
"Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:my-secret-*"
}Or use the secret name (not ARN) in CLI commands:
aws secretsmanager get-secret-value --secret-id my-secretVersion Stage Restrictions
Secret has multiple versions and you're accessing the wrong stage:
aws secretsmanager describe-secret \
--secret-id my-secret \
--query 'SecretVersionsToStages'Default stages: AWSCURRENT and AWSPENDING
Specify stage when retrieving:
aws secretsmanager get-secret-value \
--secret-id my-secret \
--version-stage AWSCURRENTKMS Key Access Issues
If the secret is encrypted with a custom KMS key:
aws secretsmanager describe-secret \
--secret-id my-secret \
--query 'KmsKeyId'You need KMS decrypt permission:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue",
"kms:Decrypt"
],
"Resource": [
"arn:aws:secretsmanager:us-east-1:123456789012:secret:my-secret-*",
"arn:aws:kms:us-east-1:123456789012:key/my-key-id"
]
}
]
}Check KMS key policy:
aws kms get-key-policy \
--key-id my-key-id \
--policy-name default \
--query 'Policy' \
--output text | jq .Lambda Execution Role
For Lambda functions accessing secrets:
aws lambda get-function-configuration \
--function-name my-function \
--query 'Role'Check role's policies:
ROLE_NAME=$(aws lambda get-function-configuration --function-name my-function --query 'Role' --output text | cut -d'/' -f2)
aws iam list-role-policies --role-name $ROLE_NAMEAdd secrets policy to execution role:
aws iam put-role-policy \
--role-name $ROLE_NAME \
--policy-name SecretsAccess \
--policy-document '{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:*:*:secret:*"
}
]
}'Permission Boundaries
IAM permission boundaries can limit maximum permissions:
aws iam get-role \
--role-name my-role \
--query 'Role.PermissionsBoundary'If a boundary is set, ensure it allows secretsmanager actions:
```bash aws iam get-policy \ --policy-arn arn:aws:iam::123456789012:policy/my-boundary \ --query 'Policy.DefaultVersionId'
aws iam get-policy-version \ --policy-arn arn:aws:iam::123456789012:policy/my-boundary \ --version-id v1 \ --query 'Document' ```
Secrets Rotation Lambda
For secrets with rotation, the rotation Lambda needs special permissions:
aws secretsmanager describe-secret \
--secret-id my-secret \
--query 'RotationConfiguration.LambdaFunctionARN'Check rotation Lambda permissions:
aws lambda get-function-configuration \
--function-name my-rotation-function \
--query 'Role'The rotation Lambda needs:
- secretsmanager:GetSecretValue
- secretsmanager:PutSecretValue
- secretsmanager:UpdateSecretVersionStage
- Permissions to update the target resource (database, service, etc.)
Request Denied by Secrets Manager
Some requests are blocked by Secrets Manager's internal rules:
# Check CloudTrail for denied events
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=GetSecretValue \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \
--max-items 20 \
--query 'Events[*].[EventTime,Username,Resources[0].ResourceName,ErrorCode]'Verification Steps
After making changes, verify access:
aws secretsmanager get-secret-value \
--secret-id my-secret \
--query '[Name,ARN,SecretString]'Test from Lambda or application:
```python import boto3
client = boto3.client('secretsmanager') try: response = client.get_secret_value(SecretId='my-secret') print(f"Successfully retrieved secret: {response['Name']}") except client.exceptions.AccessDeniedException as e: print(f"Access denied: {e}") ```
Create diagnostic script:
```bash #!/bin/bash SECRET_ID="my-secret"
echo "Secrets Manager Access Diagnostics" echo "=================================="
echo "1. Caller Identity:" aws sts get-caller-identity
echo "" echo "2. Secret Exists:" aws secretsmanager describe-secret \ --secret-id $SECRET_ID \ --query '[Name,ARN,Description]'
echo "" echo "3. Secret Resource Policy:" aws secretsmanager get-resource-policy \ --secret-id $SECRET_ID \ --query 'ResourcePolicy' \ --output text | jq . || echo "No resource policy"
echo "" echo "4. KMS Key (if custom):" KMS_KEY=$(aws secretsmanager describe-secret --secret-id $SECRET_ID --query 'KmsKeyId' --output text) if [ "$KMS_KEY" != "null" ] && [ -n "$KMS_KEY" ]; then echo "Custom KMS Key: $KMS_KEY" aws kms describe-key --key-id $KMS_KEY --query 'KeyMetadata.[KeyId,KeyState,Description]' else echo "Using default Secrets Manager encryption" fi
echo "" echo "5. Direct Access Test:" aws secretsmanager get-secret-value \ --secret-id $SECRET_ID \ --query '[Name,VersionId,VersionStages]' 2>&1
echo ""
echo "6. Recent Access Denied Events:"
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=GetSecretValue \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \
--query 'Events[?ErrorCode!=null].[EventTime,Username,ErrorCode,ErrorMessage]'
```
Set up monitoring for secret access:
aws cloudwatch put-metric-alarm \
--alarm-name secrets-access-denied \
--alarm-description "Secrets Manager access denied" \
--namespace AWS/SecretsManager \
--metric-name AccessDenied \
--dimensions Name=SecretName,Value=my-secret \
--statistic Sum \
--period 60 \
--threshold 1 \
--comparison-operator GreaterThanOrEqualToThreshold \
--evaluation-periods 1 \
--alarm-actions arn:aws:sns:us-east-1:123456789012:alerts