AWS Security ChangesHomeSearch

AWS code-library medium security documentation change

Service: code-library · 2026-05-01 · Security-related medium

File: code-library/latest/ug/sts_example_secrets_manager_GettingStarted_073_section.md

Summary

Enhanced security practices in Secrets Manager tutorial: added secure random generation, least-privilege policies, secret rotation recommendations, improved error handling, and automated cleanup.

Security assessment

Changes include replacing insecure random ID generation with Python's secrets module, implementing least-privilege resource policies with version stage conditions, adding secret rotation recommendations, blocking public access, and using ARN-specific permissions instead of wildcards. These directly address potential security weaknesses in secret management.

Diff

diff --git a/code-library/latest/ug/sts_example_secrets_manager_GettingStarted_073_section.md b/code-library/latest/ug/sts_example_secrets_manager_GettingStarted_073_section.md
index 458a3c7a5..32a89e86d 100644
--- a//code-library/latest/ug/sts_example_secrets_manager_GettingStarted_073_section.md
+++ b//code-library/latest/ug/sts_example_secrets_manager_GettingStarted_073_section.md
@@ -42,0 +43,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    set -euo pipefail
+    
@@ -55 +57 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        if echo "$output" | grep -i "error" > /dev/null; then
+        if echo "$output" | grep -qi "error"; then
@@ -63 +65 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Function to generate a random identifier
+    # Function to generate a random identifier using secure method
@@ -65 +67 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        echo "sm$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 8 | head -n 1)"
+        python3 -c "import secrets; print('sm' + secrets.token_hex(4))"
@@ -68 +70 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Function to clean up resources
+    # Function to safely clean up resources
@@ -75 +77 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        if [ -n "$SECRET_NAME" ]; then
+        if [ -n "${SECRET_NAME:-}" ]; then
@@ -79 +81 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        if [ -n "$RUNTIME_ROLE_NAME" ]; then
+        if [ -n "${RUNTIME_ROLE_NAME:-}" ]; then
@@ -83 +85 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        if [ -n "$ADMIN_ROLE_NAME" ]; then
+        if [ -n "${ADMIN_ROLE_NAME:-}" ]; then
@@ -91,5 +93 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        echo "Do you want to clean up all created resources? (y/n): "
-        read -r CLEANUP_CHOICE
-        
-        if [[ "$CLEANUP_CHOICE" =~ ^[Yy]$ ]]; then
-            echo "Cleaning up resources..."
+        echo "Cleaning up all created resources..."
@@ -98 +96 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-            if [ -n "$SECRET_NAME" ]; then
+        if [ -n "${SECRET_NAME:-}" ]; then
@@ -100 +98 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-                aws secretsmanager delete-secret --secret-id "$SECRET_NAME" --force-delete-without-recovery
+            aws secretsmanager delete-secret --secret-id "$SECRET_NAME" --force-delete-without-recovery 2>/dev/null || true
@@ -104 +102,5 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-            if [ -n "$RUNTIME_ROLE_NAME" ]; then
+        if [ -n "${RUNTIME_ROLE_NAME:-}" ]; then
+            echo "Deleting inline policies from runtime role: $RUNTIME_ROLE_NAME"
+            for policy in $(aws iam list-role-policies --role-name "$RUNTIME_ROLE_NAME" --query 'PolicyNames[]' --output text 2>/dev/null || true); do
+                aws iam delete-role-policy --role-name "$RUNTIME_ROLE_NAME" --policy-name "$policy" 2>/dev/null || true
+            done
@@ -106 +108 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-                aws iam delete-role --role-name "$RUNTIME_ROLE_NAME"
+            aws iam delete-role --role-name "$RUNTIME_ROLE_NAME" 2>/dev/null || true
@@ -110 +112 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-            if [ -n "$ADMIN_ROLE_NAME" ]; then
+        if [ -n "${ADMIN_ROLE_NAME:-}" ]; then
@@ -112 +114,5 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-                aws iam detach-role-policy --role-name "$ADMIN_ROLE_NAME" --policy-arn "arn:aws:iam::aws:policy/SecretsManagerReadWrite"
+            aws iam detach-role-policy --role-name "$ADMIN_ROLE_NAME" --policy-arn "arn:aws:iam::aws:policy/SecretsManagerReadWrite" 2>/dev/null || true
+            
+            for policy in $(aws iam list-role-policies --role-name "$ADMIN_ROLE_NAME" --query 'PolicyNames[]' --output text 2>/dev/null || true); do
+                aws iam delete-role-policy --role-name "$ADMIN_ROLE_NAME" --policy-name "$policy" 2>/dev/null || true
+            done
@@ -115 +121 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-                aws iam delete-role --role-name "$ADMIN_ROLE_NAME"
+            aws iam delete-role --role-name "$ADMIN_ROLE_NAME" 2>/dev/null || true
@@ -119,3 +124,0 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        else
-            echo "Resources will not be deleted."
-        fi
@@ -125 +128 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    trap 'echo "Script interrupted. Running cleanup..."; cleanup_resources' INT TERM
+    trap 'echo "Script interrupted. Running cleanup..."; cleanup_resources' INT TERM EXIT
@@ -141,5 +144,3 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Create the SecretsManagerAdmin role
-    echo "Creating admin role: $ADMIN_ROLE_NAME"
-    ADMIN_ROLE_OUTPUT=$(aws iam create-role \
-        --role-name "$ADMIN_ROLE_NAME" \
-        --assume-role-policy-document '{
+    # Create assume role policy document
+    ASSUME_ROLE_POLICY=$(cat <<'EOF'
+    {
@@ -156 +157,9 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        }')
+    }
+    EOF
+    )
+    
+    # Create the SecretsManagerAdmin role
+    echo "Creating admin role: $ADMIN_ROLE_NAME"
+    ADMIN_ROLE_OUTPUT=$(aws iam create-role \
+        --role-name "$ADMIN_ROLE_NAME" \
+        --assume-role-policy-document "$ASSUME_ROLE_POLICY" 2>&1)
@@ -165 +174 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --policy-arn "arn:aws:iam::aws:policy/SecretsManagerReadWrite")
+        --policy-arn "arn:aws:iam::aws:policy/SecretsManagerReadWrite" 2>&1)
@@ -168 +177 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    echo "$ATTACH_POLICY_OUTPUT"
+    echo "Policy attached successfully"
@@ -174,12 +183 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --assume-role-policy-document '{
-            "Version":"2012-10-17",
-            "Statement": [
-                {
-                    "Effect": "Allow",
-                    "Principal": {
-                        "Service": "ec2.amazonaws.com"
-                    },
-                    "Action": "sts:AssumeRole"
-                }
-            ]
-        }')
+        --assume-role-policy-document "$ASSUME_ROLE_POLICY" 2>&1)
@@ -196,0 +195,8 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    # Generate secure secret value using environment variable or secure method
+    # WARNING: In production, use secure methods to inject secrets (AWS CodeBuild, parameter store, etc.)
+    if [ -z "${TUTORIAL_SECRET_VALUE:-}" ]; then
+        SECRET_VALUE=$(python3 -c "import json; print(json.dumps({'ClientID':'my_client_id','ClientSecret':__import__('secrets').token_urlsafe(32)}))")
+    else
+        SECRET_VALUE="$TUTORIAL_SECRET_VALUE"
+    fi
+    
@@ -200 +206,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --secret-string '{"ClientID":"my_client_id","ClientSecret":"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"}')
+        --secret-string "$SECRET_VALUE" \
+        --add-replica-regions 'Region=us-east-1' 2>&1)
@@ -207,3 +214,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    ACCOUNT_ID_OUTPUT=$(aws sts get-caller-identity --query "Account" --output text)
-    check_error "$ACCOUNT_ID_OUTPUT" "get-caller-identity"
-    ACCOUNT_ID=$ACCOUNT_ID_OUTPUT
+    ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text 2>&1)
+    check_error "$ACCOUNT_ID" "get-caller-identity"
@@ -212 +218,9 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Add resource policy to the secret
+    # Get secret ARN for precise resource policy
+    echo "Getting secret ARN..."
+    SECRET_ARN=$(aws secretsmanager describe-secret \
+        --secret-id "$SECRET_NAME" \
+        --query 'ARN' \
+        --output text 2>&1)
+    check_error "$SECRET_ARN" "describe-secret"
+    
+    # Add resource policy to the secret with least privilege
@@ -218,0 +233 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+                "Sid": "AllowRuntimeRoleReadSecret",
@@ -224 +239,6 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-                "Resource": "*"
+                "Resource": "$SECRET_ARN",
+                "Condition": {
+                    "StringEquals": {
+                        "secretsmanager:VersionStage": "AWSCURRENT"
+                    }
+                }
@@ -234 +254 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --block-public-policy)
+        --block-public-policy 2>&1)
@@ -237 +257,7 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    echo "$PUT_POLICY_OUTPUT"
+    echo "Resource policy added successfully"
+    
+    # Enable rotation policy recommendation
+    echo "Enabling secret metadata tags for rotation tracking..."
+    aws secretsmanager tag-resource \
+        --secret-id "$SECRET_NAME" \
+        --tags Key=Purpose,Value=Tutorial Key=AutoRotation,Value=Recommended 2>/dev/null || true
@@ -242 +268 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --secret-id "$SECRET_NAME")
+        --secret-id "$SECRET_NAME" 2>&1)
@@ -246 +272 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    echo "$GET_SECRET_OUTPUT" | grep -v "SecretString"
+    echo "$GET_SECRET_OUTPUT" | jq '{ARN: .ARN, Name: .Name, LastUpdatedDate: .LastUpdatedDate, VersionIdsToStages: .VersionIdsToStages}' 2>/dev/null || echo "Secret metadata retrieved (jq not available)"
@@ -249,0 +276,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    UPDATE_SECRET_VALUE=$(python3 -c "import json; print(json.dumps({'ClientID':'my_new_client_id','ClientSecret':__import__('secrets').token_urlsafe(32)}))")
+    
@@ -252 +280 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --secret-string '{"ClientID":"my_new_client_id","ClientSecret":"bPxRfiCYEXAMPLEKEY/wJalrXUtnFEMI/K7MDENG"}')
+        --secret-string "$UPDATE_SECRET_VALUE" 2>&1)
@@ -255 +283 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    echo "$UPDATE_SECRET_OUTPUT"
+    echo "Secret updated successfully"
@@ -260 +288 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --secret-id "$SECRET_NAME")
+        --secret-id "$SECRET_NAME" 2>&1)
@@ -264 +292,14 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    echo "$VERIFY_SECRET_OUTPUT" | grep -v "SecretString"
+    echo "$VERIFY_SECRET_OUTPUT" | jq '{ARN: .ARN, Name: .Name, LastUpdatedDate: .LastUpdatedDate, VersionIdsToStages: .VersionIdsToStages}' 2>/dev/null || echo "Secret metadata retrieved (jq not available)"
+    
+    # Step 6: Display rotation recommendations
+    echo ""
+    echo "Rotation Configuration Recommendations:"
+    echo "========================================"
+    DESCRIBE_OUTPUT=$(aws secretsmanager describe-secret --secret-id "$SECRET_NAME" 2>&1)
+    if echo "$DESCRIBE_OUTPUT" | grep -q "RotationRules"; then
+        echo "Current rotation configuration:"
+        echo "$DESCRIBE_OUTPUT" | jq '.RotationRules' 2>/dev/null || echo "Rotation rules available"
+    else
+        echo "No automatic rotation configured. Consider enabling rotation with:"
+        echo "aws secretsmanager rotate-secret --secret-id $SECRET_NAME --rotation-lambda-arn arn:aws:lambda:REGION:ACCOUNT:function:FUNCTION_NAME --rotation-rules AutomaticallyAfterDays=30"
+    fi
@@ -272,2 +313,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    echo "2. Created a secret in AWS Secrets Manager"
-    echo "3. Added a resource policy to control access to the secret"