Identity & SecurityIntermediate14 min read

    AWS Secrets Manager Security Best Practices

    Tarek Cheikh

    Founder & AWS Security Expert

    View Security Card

    AWS Secrets Manager is the centralized service for storing, retrieving, and rotating sensitive credentials -- database passwords, API keys, OAuth tokens, and any other secret your applications depend on. When secrets are hardcoded, leaked, or stale, they become the fastest path to a breach. The 2025 Verizon DBIR confirmed that stolen credentials remain the top initial access vector, and a leaked secret on GitHub can be discovered and exploited within minutes.

    Secrets Manager eliminates the need to store credentials in code, environment variables, or configuration files. It integrates natively with RDS, Redshift, and DocumentDB for automatic rotation, and supports custom rotation via Lambda for any other secret type. Combined with KMS encryption, resource policies, and VPC endpoints, Secrets Manager provides a defense-in-depth approach to credential management.

    This guide covers 12 battle-tested Secrets Manager best practices, each with real AWS CLI commands, audit procedures, and the latest 2025-2026 updates from AWS.

    1. Never Hardcode Secrets -- Migrate from Environment Variables, Config Files, and Code

    Hardcoded secrets in source code, environment variables, and configuration files are the root cause of most credential leaks. Secrets committed to Git repositories are indexed by automated scanners within seconds. Environment variables are accessible to any process running on the same host and are routinely logged by monitoring tools.

    Migration Strategy

    • Audit existing secrets. Use tools like git-secrets, truffleHog, or Amazon CodeGuru Reviewer to scan repositories for embedded credentials.
    • Create secrets in Secrets Manager. Store each credential as a named secret with structured JSON values.
    • Update application code. Replace hardcoded values with SDK calls to GetSecretValue.
    • Remove secrets from environment variables and config files. Delete from .env, docker-compose.yml, task definitions, and CloudFormation parameters.
    # Create a secret with structured JSON
    aws secretsmanager create-secret \
      --name "prod/myapp/database" \
      --description "Production database credentials" \
      --secret-string '{"username":"admin","password":"SuperSecret123!","engine":"mysql","host":"mydb.cluster-xyz.us-east-1.rds.amazonaws.com","port":3306,"dbname":"myapp"}'
    
    # Retrieve a secret value
    aws secretsmanager get-secret-value \
      --secret-id "prod/myapp/database" \
      --query "SecretString" --output text

    Security Hub: [SecretsManager.3] flags secrets that have not been accessed within 90 days -- helping you identify orphaned secrets that should be cleaned up after migration.

    2. Enforce Automatic Rotation for Native Integrations

    Static credentials that never change provide an unlimited exploitation window. AWS Secrets Manager supports managed rotation for Amazon RDS (MySQL, PostgreSQL, MariaDB, Oracle, SQL Server), Amazon Redshift, and Amazon DocumentDB. Managed rotation uses AWS-provided Lambda functions that handle the full rotation lifecycle automatically.

    Rotation Strategies

    • Single-user strategy: Updates the credentials of one database user. Simpler but causes a brief period where existing connections using the old password may fail.
    • Alternating-users strategy: Creates a clone user and alternates between two users on each rotation. Ensures zero-downtime rotation because the old user remains valid until the next rotation cycle.
    # Enable managed rotation for an RDS secret (every 30 days)
    aws secretsmanager rotate-secret \
      --secret-id "prod/myapp/database" \
      --rotation-rules '{"AutomaticallyAfterDays":30}' \
      --rotation-lambda-arn arn:aws:lambda:us-east-1:123456789012:function:SecretsManagerRDSMySQLRotation
    
    # Check rotation status
    aws secretsmanager describe-secret \
      --secret-id "prod/myapp/database" \
      --query "{RotationEnabled:RotationEnabled,RotationRules:RotationRules,LastRotatedDate:LastRotatedDate}"
    
    # Trigger an immediate rotation
    aws secretsmanager rotate-secret \
      --secret-id "prod/myapp/database"

    Secrets Manager supports rotation intervals as short as every four hours. For production databases, 30-day rotation is the most common interval. The rotation process uses staging labels (AWSCURRENT and AWSPENDING) to ensure a safe, atomic transition.

    Security Hub: [SecretsManager.1] checks that automatic rotation is enabled. [SecretsManager.2] verifies that configured rotation is completing successfully. [SecretsManager.4] checks that secrets are rotated within the specified number of days.

    3. Write Custom Rotation Lambda Functions for Non-Native Integrations

    For secrets that do not have managed rotation templates -- third-party APIs, LDAP credentials, SSH keys, TLS certificates, or SaaS tokens -- you must write a custom rotation Lambda function. The function implements four steps that Secrets Manager invokes sequentially during rotation.

    The Four Rotation Steps

    • createSecret: Generate a new secret value and store it as AWSPENDING.
    • setSecret: Update the external service or database with the new credentials.
    • testSecret: Validate that the new credentials work by connecting to the service.
    • finishSecret: Move the AWSCURRENT label to the new version and remove AWSPENDING.
    # Custom rotation Lambda skeleton (Python)
    import boto3
    import json
    
    def lambda_handler(event, context):
        secret_arn = event['SecretId']
        token = event['ClientRequestToken']
        step = event['Step']
    
        client = boto3.client('secretsmanager')
    
        if step == "createSecret":
            # Generate new credentials and store as AWSPENDING
            current = client.get_secret_value(SecretId=secret_arn, VersionStage="AWSCURRENT")
            secret_dict = json.loads(current['SecretString'])
            secret_dict['api_key'] = generate_new_api_key()
            client.put_secret_value(
                SecretId=secret_arn,
                ClientRequestToken=token,
                SecretString=json.dumps(secret_dict),
                VersionStages=['AWSPENDING']
            )
        elif step == "setSecret":
            # Update the external service with the new key
            pending = client.get_secret_value(SecretId=secret_arn, VersionId=token, VersionStage="AWSPENDING")
            update_external_service(json.loads(pending['SecretString']))
        elif step == "testSecret":
            # Validate the new credentials work
            pending = client.get_secret_value(SecretId=secret_arn, VersionId=token, VersionStage="AWSPENDING")
            test_connection(json.loads(pending['SecretString']))
        elif step == "finishSecret":
            # Promote AWSPENDING to AWSCURRENT
            metadata = client.describe_secret(SecretId=secret_arn)
            for version, stages in metadata['VersionIdsToStages'].items():
                if 'AWSCURRENT' in stages and version != token:
                    client.update_secret_version_stage(
                        SecretId=secret_arn, VersionStage='AWSCURRENT',
                        MoveToVersionId=token, RemoveFromVersionId=version
                    )
                    break

    Best practice: The rotation Lambda must have network access to the target service. If the service is inside a VPC, deploy the Lambda in the same VPC with appropriate security group rules. Grant the Lambda execution role only secretsmanager:GetSecretValue, secretsmanager:PutSecretValue, secretsmanager:UpdateSecretVersionStage, and secretsmanager:DescribeSecret on the specific secret ARN.

    4. Use Customer-Managed KMS Keys for Secret Encryption

    Every secret stored in Secrets Manager is encrypted at rest. By default, Secrets Manager uses the AWS-managed key (aws/secretsmanager). While this provides encryption, it does not give you control over key policies, rotation schedules, or cross-account access. Customer-managed KMS keys provide granular control.

    Benefits of Customer-Managed Keys

    • Key policy control: Define exactly which principals can encrypt, decrypt, and administer the key.
    • Automatic key rotation: Enable annual automatic rotation of the KMS key material.
    • Cross-account access: Grant decrypt permissions to specific roles in other accounts via the key policy.
    • Audit trail: Every Decrypt and GenerateDataKey call appears in CloudTrail, showing exactly who accessed which secret.
    # Create a customer-managed KMS key for secrets
    aws kms create-key \
      --description "Secrets Manager encryption key" \
      --key-usage ENCRYPT_DECRYPT \
      --origin AWS_KMS \
      --tags '[{"TagKey":"Purpose","TagValue":"SecretsManager"}]'
    
    # Create a secret encrypted with the customer-managed key
    aws secretsmanager create-secret \
      --name "prod/payments/stripe-key" \
      --kms-key-id "arn:aws:kms:us-east-1:123456789012:key/mrk-EXAMPLE" \
      --secret-string '{"api_key":"sk_live_EXAMPLE"}'
    
    # Update an existing secret to use a customer-managed key
    aws secretsmanager update-secret \
      --secret-id "prod/myapp/database" \
      --kms-key-id "arn:aws:kms:us-east-1:123456789012:key/mrk-EXAMPLE"

    Best practice: For multi-region secrets, use KMS multi-Region keys (prefix mrk-) so that replicas can be decrypted with the corresponding key in each Region. If the origin secret uses a customer-managed key, all replicas must also use a customer-managed key -- you cannot mix AWS-managed and customer-managed keys across replicas.

    5. Attach Resource Policies to Restrict and Control Access

    Resource policies on secrets provide a second layer of access control beyond IAM identity policies. They are essential for cross-account access and for enforcing organizational guardrails that cannot be bypassed by any identity policy.

    Cross-Account Access

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowCrossAccountAccess",
          "Effect": "Allow",
          "Principal": {
            "AWS": "arn:aws:iam::987654321098:role/AppRole"
          },
          "Action": "secretsmanager:GetSecretValue",
          "Resource": "*"
        }
      ]
    }

    Deny Public or Unintended External Access

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "DenyExternalAccess",
          "Effect": "Deny",
          "Principal": "*",
          "Action": "secretsmanager:*",
          "Resource": "*",
          "Condition": {
            "StringNotEquals": {
              "aws:PrincipalOrgID": "o-EXAMPLE"
            }
          }
        }
      ]
    }
    # Attach a resource policy to a secret
    aws secretsmanager put-resource-policy \
      --secret-id "prod/myapp/database" \
      --resource-policy file://secret-resource-policy.json
    
    # Validate a resource policy before attaching
    aws secretsmanager validate-resource-policy \
      --resource-policy file://secret-resource-policy.json
    
    # View the current resource policy
    aws secretsmanager get-resource-policy \
      --secret-id "prod/myapp/database"

    Best practice: Always use validate-resource-policy before attaching. Secrets Manager will check for overly permissive access, including public access. Combine the aws:PrincipalOrgID condition with your organization ID to create a data perimeter that prevents any principal outside your organization from accessing secrets.

    6. Restrict Secret Retrieval to VPC Endpoints

    By default, calls to the Secrets Manager API traverse the public internet. A VPC interface endpoint (powered by AWS PrivateLink) ensures that all Secrets Manager API traffic stays within the AWS network, never crossing the public internet.

    # Create a VPC endpoint for Secrets Manager
    aws ec2 create-vpc-endpoint \
      --vpc-id vpc-0abc123def456 \
      --service-name com.amazonaws.us-east-1.secretsmanager \
      --vpc-endpoint-type Interface \
      --subnet-ids subnet-0aaa111 subnet-0bbb222 \
      --security-group-ids sg-0ccc333 \
      --private-dns-enabled

    Restrict Secrets to VPC Endpoint Only

    Apply a resource policy on each secret that denies access unless the request comes through the VPC endpoint:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "DenyAccessUnlessVPCEndpoint",
          "Effect": "Deny",
          "Principal": "*",
          "Action": "secretsmanager:GetSecretValue",
          "Resource": "*",
          "Condition": {
            "StringNotEquals": {
              "aws:sourceVpce": "vpce-0abc123def456"
            }
          }
        }
      ]
    }

    VPC Endpoint Policy

    Attach a custom endpoint policy to limit which secrets can be accessed through the endpoint:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowOnlyProdSecrets",
          "Effect": "Allow",
          "Principal": "*",
          "Action": [
            "secretsmanager:GetSecretValue",
            "secretsmanager:DescribeSecret"
          ],
          "Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/*"
        }
      ]
    }

    Best practice: Enable private DNS on the VPC endpoint so that the standard secretsmanager.us-east-1.amazonaws.com hostname resolves to the private endpoint IP. This means no application code changes are needed -- all SDK calls automatically route through the endpoint.

    7. Implement Least-Privilege IAM Policies with Tag-Based ABAC

    Secrets Manager supports fine-grained access control through both resource-level ARN permissions and attribute-based access control (ABAC) using tags. ABAC allows you to write a single IAM policy that scales automatically as new secrets are created, without updating the policy each time.

    Per-Secret Access Control

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowSpecificSecretAccess",
          "Effect": "Allow",
          "Action": [
            "secretsmanager:GetSecretValue",
            "secretsmanager:DescribeSecret"
          ],
          "Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/myapp/*"
        }
      ]
    }

    Tag-Based ABAC Policy

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "AllowAccessByTeamTag",
          "Effect": "Allow",
          "Action": [
            "secretsmanager:GetSecretValue",
            "secretsmanager:DescribeSecret"
          ],
          "Resource": "*",
          "Condition": {
            "StringEquals": {
              "secretsmanager:ResourceTag/Team": "${aws:PrincipalTag/Team}"
            }
          }
        }
      ]
    }
    # Tag a secret for ABAC
    aws secretsmanager tag-resource \
      --secret-id "prod/payments/stripe-key" \
      --tags '[{"Key":"Team","Value":"payments"},{"Key":"Environment","Value":"production"}]'
    
    # Deny deletion of secrets to all except security admins
    # (Apply as an SCP or IAM boundary)
    aws iam create-policy \
      --policy-name DenySecretDeletion \
      --policy-document '{
        "Version": "2012-10-17",
        "Statement": [{
          "Sid": "DenyDeleteSecret",
          "Effect": "Deny",
          "Action": [
            "secretsmanager:DeleteSecret",
            "secretsmanager:RemoveRegionsFromReplication"
          ],
          "Resource": "*",
          "Condition": {
            "StringNotLike": {
              "aws:PrincipalARN": "arn:aws:iam::*:role/SecurityAdmin"
            }
          }
        }]
      }'

    Best practice: Use a hierarchical naming convention like environment/application/secret-type (e.g., prod/payments/stripe-key). This enables wildcard ARN matching in IAM policies and makes ABAC tag-based policies more intuitive. Never grant secretsmanager:* on Resource: *.

    8. Enable Multi-Region Secret Replication for Disaster Recovery

    Multi-region secrets provide automatic replication of secret values to multiple AWS Regions. Replica secrets are read-only copies that stay in sync with the primary. This is essential for disaster recovery, regional failover, and reducing cross-region latency.

    # Replicate a secret to additional Regions
    aws secretsmanager replicate-secret-to-regions \
      --secret-id "prod/myapp/database" \
      --add-replica-regions '[
        {"Region":"eu-west-1","KmsKeyId":"arn:aws:kms:eu-west-1:123456789012:key/mrk-EXAMPLE"},
        {"Region":"ap-southeast-1","KmsKeyId":"arn:aws:kms:ap-southeast-1:123456789012:key/mrk-EXAMPLE"}
      ]'
    
    # Check replication status
    aws secretsmanager describe-secret \
      --secret-id "prod/myapp/database" \
      --query "ReplicationStatus"
    
    # Remove a replica Region
    aws secretsmanager remove-regions-from-replication \
      --secret-id "prod/myapp/database" \
      --remove-replica-regions '["ap-southeast-1"]'
    
    # Promote a replica to standalone (during regional failover)
    # This is done from the replica Region
    aws secretsmanager stop-replication-to-replica \
      --secret-id "arn:aws:secretsmanager:eu-west-1:123456789012:secret:prod/myapp/database-AbCdEf"

    Key Considerations

    • Rotation propagation: When rotation occurs on the primary secret, the new value automatically propagates to all replicas. You do not need to configure rotation on replicas.
    • KMS key consistency: If the primary uses a customer-managed key, all replicas must also use customer-managed keys. Use multi-Region KMS keys (mrk- prefix) for seamless cross-region encryption.
    • Failover: Use stop-replication-to-replica to promote a replica to a standalone secret during a regional outage. After recovery, you must manually re-establish replication.
    • Naming: Replica secrets share the same name as the primary, making application failover seamless -- just point the SDK to the new Region.

    9. Use the Batch Retrieval API to Reduce API Calls and Improve Performance

    The BatchGetSecretValue API allows you to retrieve up to 20 secrets in a single API call. This reduces latency, simplifies application code, and lowers the risk of hitting Secrets Manager service quotas (default 10,000 GetSecretValue requests per second per Region).

    # Retrieve multiple secrets in a single call (by name)
    aws secretsmanager batch-get-secret-value \
      --secret-id-list '["prod/myapp/database","prod/myapp/redis","prod/myapp/stripe-key"]'
    
    # Retrieve secrets by filter (e.g., all secrets with a specific tag)
    aws secretsmanager batch-get-secret-value \
      --filters '[{"Key":"tag-key","Values":["Environment"]},{"Key":"tag-value","Values":["production"]}]'

    Caching Strategy

    Combine batch retrieval with the AWS Secrets Manager caching libraries to minimize API calls further:

    • Python: aws-secretsmanager-caching library with configurable TTL (default 3600 seconds).
    • Java: aws-secretsmanager-jdbc for automatic JDBC connection string rotation.
    • Go / Node.js: Use the generic caching client or implement your own with a TTL-based cache.

    Best practice: IAM permissions for BatchGetSecretValue are evaluated per-secret. If a principal lacks access to one secret in the batch, Secrets Manager returns the accessible secrets and lists the inaccessible ones in the Errors field -- it does not fail the entire call. Ensure your IAM policies grant access to every secret your application needs.

    10. Monitor and Alert on Secret Access, Rotation Failures, and Anomalies

    Every Secrets Manager API call is logged in CloudTrail. Combined with CloudWatch alarms and EventBridge rules, you can detect unauthorized access, rotation failures, and anomalous retrieval patterns in real time.

    CloudTrail Events to Monitor

    • GetSecretValue -- track who is retrieving secrets and from which IP
    • PutSecretValue -- detect unauthorized secret modifications
    • DeleteSecret -- alert on secret deletion attempts
    • RotationFailed -- rotation Lambda errors that leave secrets in a broken state
    • RotationSucceeded -- confirm rotation is completing as expected

    EventBridge Rule for Rotation Failures

    # Create an EventBridge rule to alert on rotation failures
    aws events put-rule \
      --name "SecretsManagerRotationFailure" \
      --event-pattern '{
        "source": ["aws.secretsmanager"],
        "detail-type": ["AWS Service Event via CloudTrail"],
        "detail": {
          "eventName": ["RotationFailed"]
        }
      }'
    
    # Add an SNS target for the alert
    aws events put-targets \
      --rule "SecretsManagerRotationFailure" \
      --targets '[{
        "Id": "RotationFailureAlert",
        "Arn": "arn:aws:sns:us-east-1:123456789012:security-alerts"
      }]'

    CloudWatch Metric Filter for Unauthorized Access

    # Create a metric filter for AccessDeniedException on secrets
    aws logs put-metric-filter \
      --log-group-name "CloudTrail/DefaultLogGroup" \
      --filter-name "SecretsManagerAccessDenied" \
      --filter-pattern '{ ($.eventSource = "secretsmanager.amazonaws.com") && ($.errorCode = "AccessDeniedException") }' \
      --metric-transformations '[{
        "metricName": "SecretsManagerAccessDenied",
        "metricNamespace": "SecurityMetrics",
        "metricValue": "1"
      }]'
    
    # Create an alarm on the metric
    aws cloudwatch put-metric-alarm \
      --alarm-name "SecretsManagerUnauthorizedAccess" \
      --metric-name "SecretsManagerAccessDenied" \
      --namespace "SecurityMetrics" \
      --statistic Sum \
      --period 300 \
      --threshold 5 \
      --comparison-operator GreaterThanOrEqualToThreshold \
      --evaluation-periods 1 \
      --alarm-actions "arn:aws:sns:us-east-1:123456789012:security-alerts"

    Best practice: Use GuardDuty for anomaly detection on Secrets Manager usage patterns. GuardDuty can detect when a principal retrieves secrets it has never accessed before or retrieves secrets from an unusual geographic location.

    11. Understand Secret Versioning and Staging Labels for Safe Rotation

    Secrets Manager maintains multiple versions of each secret, tracked by staging labels. Understanding this versioning model is critical for debugging rotation issues and implementing safe rollback procedures.

    Staging Labels

    • AWSCURRENT: The active version that applications receive by default when calling GetSecretValue.
    • AWSPENDING: The new version being validated during rotation. Only exists while rotation is in progress.
    • AWSPREVIOUS: The formerly current version, retained as a rollback target. Automatically assigned when AWSCURRENT moves to a new version.
    # List all versions and their staging labels
    aws secretsmanager list-secret-version-ids \
      --secret-id "prod/myapp/database" \
      --query "Versions[*].{VersionId:VersionId,Stages:VersionStages}"
    
    # Retrieve the previous version (for rollback)
    aws secretsmanager get-secret-value \
      --secret-id "prod/myapp/database" \
      --version-stage "AWSPREVIOUS"
    
    # Manual rollback: move AWSCURRENT back to the previous version
    aws secretsmanager update-secret-version-stage \
      --secret-id "prod/myapp/database" \
      --version-stage "AWSCURRENT" \
      --move-to-version-id "previous-version-id" \
      --remove-from-version-id "current-version-id"

    Custom Staging Labels

    You can create custom staging labels for blue/green deployments or canary testing:

    # Add a custom staging label for canary testing
    aws secretsmanager update-secret-version-stage \
      --secret-id "prod/myapp/database" \
      --version-stage "CANARY" \
      --move-to-version-id "new-version-id"
    
    # Application code retrieves the canary version
    aws secretsmanager get-secret-value \
      --secret-id "prod/myapp/database" \
      --version-stage "CANARY"

    Best practice: If a rotation fails and leaves an AWSPENDING label behind, the next rotation attempt will fail. Monitor for stale AWSPENDING labels and remediate by either completing the rotation manually or removing the pending version.

    12. Enforce Continuous Compliance with Config Rules, Security Hub, and Automated Remediation

    Manual audits do not scale. Use AWS Config rules, Security Hub controls, and automated remediation to continuously verify that all secrets meet your organization's security standards.

    Security Hub Controls for Secrets Manager

    Control ID Description Severity
    [SecretsManager.1] Secrets should have automatic rotation enabled Medium
    [SecretsManager.2] Secrets with rotation enabled should rotate successfully Medium
    [SecretsManager.3] Remove unused secrets (not accessed in 90 days) Medium
    [SecretsManager.4] Secrets should be rotated within a specified number of days Medium
    # Enable Security Hub with the AWS Foundational Security Best Practices standard
    aws securityhub batch-enable-standards \
      --standards-subscription-requests '[{
        "StandardsArn": "arn:aws:securityhub:us-east-1::standards/aws-foundational-security-best-practices/v/1.0.0"
      }]'
    
    # Check Secrets Manager findings
    aws securityhub get-findings \
      --filters '{
        "GeneratorId": [{"Value": "aws-foundational-security-best-practices/v/1.0.0/SecretsManager", "Comparison": "PREFIX"}],
        "ComplianceStatus": [{"Value": "FAILED", "Comparison": "EQUALS"}]
      }' \
      --query "Findings[*].{Title:Title,SecretArn:Resources[0].Id,Status:Compliance.Status}"

    AWS Config Rules

    # Ensure all secrets have rotation enabled
    aws configservice put-config-rule --config-rule '{
      "ConfigRuleName": "secretsmanager-rotation-enabled-check",
      "Source": {
        "Owner": "AWS",
        "SourceIdentifier": "SECRETSMANAGER_ROTATION_ENABLED_CHECK"
      }
    }'
    
    # Ensure secrets are rotated within 90 days
    aws configservice put-config-rule --config-rule '{
      "ConfigRuleName": "secretsmanager-scheduled-rotation-success-check",
      "Source": {
        "Owner": "AWS",
        "SourceIdentifier": "SECRETSMANAGER_SCHEDULED_ROTATION_SUCCESS_CHECK"
      }
    }'
    
    # Ensure secrets use customer-managed KMS keys
    aws configservice put-config-rule --config-rule '{
      "ConfigRuleName": "secretsmanager-using-cmk",
      "Source": {
        "Owner": "AWS",
        "SourceIdentifier": "SECRETSMANAGER_USING_CMK"
      }
    }'

    Automated Remediation with Systems Manager

    # Create a remediation configuration to auto-enable rotation
    aws configservice put-remediation-configurations \
      --remediation-configurations '[{
        "ConfigRuleName": "secretsmanager-rotation-enabled-check",
        "TargetType": "SSM_DOCUMENT",
        "TargetId": "AWSConfigRemediation-EnableSecretRotation",
        "Parameters": {
          "AutomationAssumeRole": {"StaticValue": {"Values": ["arn:aws:iam::123456789012:role/ConfigRemediationRole"]}},
          "SecretId": {"ResourceValue": {"Value": "RESOURCE_ID"}},
          "RotationLambdaArn": {"StaticValue": {"Values": ["arn:aws:lambda:us-east-1:123456789012:function:DefaultRotation"]}},
          "RotationInterval": {"StaticValue": {"Values": ["30"]}}
        },
        "Automatic": true,
        "MaximumAutomaticAttempts": 3,
        "RetryAttemptSeconds": 60
      }]'

    Best practice: Deploy Config rules and Security Hub standards across all accounts via AWS Organizations. Use delegated administrator mode in Security Hub to aggregate findings centrally. Set up automated remediation for [SecretsManager.1] and [SecretsManager.3] to enforce rotation and clean up unused secrets automatically.


    Common Misconfigurations

    Misconfiguration Risk Detection
    Secrets without rotation enabled Static credentials with unlimited exploitation window Security Hub: [SecretsManager.1]
    Rotation configured but failing silently Credentials expire or become stale without detection Security Hub: [SecretsManager.2]
    Secrets encrypted with AWS-managed key only No control over key policy, no cross-account decrypt control Config rule: secretsmanager-using-cmk
    No resource policy (relying solely on IAM) No defense-in-depth; overly broad IAM policies can expose secrets Manual audit: get-resource-policy
    Secrets retrieved over public internet (no VPC endpoint) API traffic exposed to network-level interception VPC endpoint audit: describe-vpc-endpoints
    Unused secrets not cleaned up Orphaned credentials increase attack surface Security Hub: [SecretsManager.3]
    Hardcoded secrets in source code or env vars Credential leakage via Git history, logs, or process listings CodeGuru Reviewer, git-secrets, truffleHog

    Quick Reference Checklist

    # Practice Priority
    1Never hardcode secrets -- migrate to Secrets ManagerCritical
    2Enforce automatic rotation for native integrationsCritical
    3Write custom rotation Lambdas for non-native secretsHigh
    4Use customer-managed KMS keysHigh
    5Attach resource policies to every secretHigh
    6Restrict retrieval to VPC endpointsHigh
    7Implement least-privilege IAM with ABACCritical
    8Enable multi-region replicationMedium
    9Use batch retrieval API with cachingMedium
    10Monitor and alert on access and rotation failuresCritical
    11Understand versioning and staging labelsMedium
    12Enforce continuous compliance with Config and Security HubHigh

    Related Resources

    Go Deeper: The State of AWS Security 2026

    This article is just the start. Get the full picture with our free whitepaper - 8 chapters covering IAM, S3, VPC, monitoring, agentic AI security, compliance, and a prioritized action plan with 50+ CLI commands.

    Secrets ManagerCredential ManagementSecret RotationKMSResource PolicyVPC EndpointMulti-RegionABACCloudTrailSecurity Hub