

# Amazon SNS examples using AWS CLI with Bash script
<a name="bash_sns_code_examples"></a>

The following code examples show you how to perform actions and implement common scenarios by using the AWS Command Line Interface with Bash script with Amazon SNS.

*Scenarios* are code examples that show you how to accomplish specific tasks by calling multiple functions within a service or combined with other AWS services.

Each example includes a link to the complete source code, where you can find instructions on how to set up and run the code in context.

**Topics**
+ [Scenarios](#scenarios)

## Scenarios
<a name="scenarios"></a>

### Create an Amazon SNS topic and publish messages
<a name="sns_GettingStarted_048_bash_topic"></a>

The following code example shows how to:
+ Create an Amazon SNS topic
+ Subscribe an email endpoint to the topic
+ Verify your subscription
+ Publish a message to the topic
+ Clean up resources

**AWS CLI with Bash script**  
 There's more on GitHub. Find the complete example and learn how to set up and run in the [Sample developer tutorials](https://github.com/aws-samples/sample-developer-tutorials/tree/main/tuts/048-amazon-simple-notification-service-gs) repository. 

```
#!/bin/bash

# Amazon SNS Getting Started Script
# This script demonstrates how to create an SNS topic, subscribe to it, publish a message,
# and clean up resources.

# Set up logging
LOG_FILE="sns-tutorial.log"
exec > >(tee -a "$LOG_FILE") 2>&1

echo "Starting Amazon SNS Getting Started Tutorial..."
echo "$(date)"
echo "=============================================="

# Function to handle errors
handle_error() {
    echo "ERROR: $1"
    echo "Attempting to clean up resources..."
    cleanup_resources
    exit 1
}

# Function to clean up resources
cleanup_resources() {
    if [ -n "$SUBSCRIPTION_ARN" ] && [ "$SUBSCRIPTION_ARN" != "pending confirmation" ]; then
        echo "Deleting subscription: $SUBSCRIPTION_ARN"
        aws sns unsubscribe --subscription-arn "$SUBSCRIPTION_ARN"
    fi
    
    if [ -n "$TOPIC_ARN" ]; then
        echo "Deleting topic: $TOPIC_ARN"
        aws sns delete-topic --topic-arn "$TOPIC_ARN"
    fi
}

# Generate a random topic name suffix
RANDOM_SUFFIX=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 8 | head -n 1)
TOPIC_NAME="my-topic-${RANDOM_SUFFIX}"

# Step 1: Create an SNS topic
echo "Creating SNS topic: $TOPIC_NAME"
TOPIC_RESULT=$(aws sns create-topic --name "$TOPIC_NAME")

# Check for errors
if echo "$TOPIC_RESULT" | grep -i "error" > /dev/null; then
    handle_error "Failed to create SNS topic: $TOPIC_RESULT"
fi

# Extract the topic ARN
TOPIC_ARN=$(echo "$TOPIC_RESULT" | grep -o '"TopicArn": "[^"]*' | cut -d'"' -f4)

if [ -z "$TOPIC_ARN" ]; then
    handle_error "Failed to extract topic ARN from result: $TOPIC_RESULT"
fi

echo "Successfully created topic with ARN: $TOPIC_ARN"

# Step 2: Subscribe to the topic
echo ""
echo "=============================================="
echo "EMAIL SUBSCRIPTION"
echo "=============================================="
echo "Please enter your email address to subscribe to the topic:"
read -r EMAIL_ADDRESS

echo "Subscribing email: $EMAIL_ADDRESS to topic"
SUBSCRIPTION_RESULT=$(aws sns subscribe \
    --topic-arn "$TOPIC_ARN" \
    --protocol email \
    --notification-endpoint "$EMAIL_ADDRESS")

# Check for errors
if echo "$SUBSCRIPTION_RESULT" | grep -i "error" > /dev/null; then
    handle_error "Failed to create subscription: $SUBSCRIPTION_RESULT"
fi

# Extract the subscription ARN (will be "pending confirmation")
SUBSCRIPTION_ARN=$(echo "$SUBSCRIPTION_RESULT" | grep -o '"SubscriptionArn": "[^"]*' | cut -d'"' -f4)

echo "Subscription created: $SUBSCRIPTION_ARN"
echo "A confirmation email has been sent to $EMAIL_ADDRESS"
echo "Please check your email and confirm the subscription."
echo ""
echo "Waiting for you to confirm the subscription..."
echo "Press Enter after you have confirmed the subscription to continue:"
read -r

# Step 3: List subscriptions to verify
echo "Listing subscriptions for topic: $TOPIC_ARN"
SUBSCRIPTIONS=$(aws sns list-subscriptions-by-topic --topic-arn "$TOPIC_ARN")

# Check for errors
if echo "$SUBSCRIPTIONS" | grep -i "error" > /dev/null; then
    handle_error "Failed to list subscriptions: $SUBSCRIPTIONS"
fi

echo "Current subscriptions:"
echo "$SUBSCRIPTIONS"

# Get the confirmed subscription ARN
SUBSCRIPTION_ARN=$(echo "$SUBSCRIPTIONS" | grep -o '"SubscriptionArn": "[^"]*' | grep -v "pending confirmation" | head -1 | cut -d'"' -f4)

if [ -z "$SUBSCRIPTION_ARN" ] || [ "$SUBSCRIPTION_ARN" == "pending confirmation" ]; then
    echo "Warning: No confirmed subscription found. You may not have confirmed the subscription yet."
    echo "The script will continue, but you may not receive the test message."
fi

# Step 4: Publish a message to the topic
echo ""
echo "Publishing a test message to the topic"
MESSAGE="Hello from Amazon SNS! This is a test message sent at $(date)."
PUBLISH_RESULT=$(aws sns publish \
    --topic-arn "$TOPIC_ARN" \
    --message "$MESSAGE")

# Check for errors
if echo "$PUBLISH_RESULT" | grep -i "error" > /dev/null; then
    handle_error "Failed to publish message: $PUBLISH_RESULT"
fi

MESSAGE_ID=$(echo "$PUBLISH_RESULT" | grep -o '"MessageId": "[^"]*' | cut -d'"' -f4)
echo "Message published successfully with ID: $MESSAGE_ID"
echo "Check your email for the message."

# Pause to allow the user to check their email
echo ""
echo "Pausing for 10 seconds to allow message delivery..."
sleep 10

# Step 5: Clean up resources
echo ""
echo "=============================================="
echo "CLEANUP CONFIRMATION"
echo "=============================================="
echo "Resources created:"
echo "- SNS Topic: $TOPIC_ARN"
echo "- Subscription: $SUBSCRIPTION_ARN"
echo ""
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..."
    cleanup_resources
    echo "Cleanup completed successfully."
else
    echo "Skipping cleanup. Resources will remain in your AWS account."
    echo "To clean up later, use the following commands:"
    echo "aws sns unsubscribe --subscription-arn $SUBSCRIPTION_ARN"
    echo "aws sns delete-topic --topic-arn $TOPIC_ARN"
fi

echo ""
echo "Tutorial completed successfully!"
echo "$(date)"
echo "=============================================="
```
+ For API details, see the following topics in *AWS CLI Command Reference*.
  + [CreateTopic](https://docs.aws.amazon.com/goto/aws-cli/sns-2010-03-31/CreateTopic)
  + [DeleteTopic](https://docs.aws.amazon.com/goto/aws-cli/sns-2010-03-31/DeleteTopic)
  + [ListSubscriptionsByTopic](https://docs.aws.amazon.com/goto/aws-cli/sns-2010-03-31/ListSubscriptionsByTopic)
  + [Publish](https://docs.aws.amazon.com/goto/aws-cli/sns-2010-03-31/Publish)
  + [Subscribe](https://docs.aws.amazon.com/goto/aws-cli/sns-2010-03-31/Subscribe)
  + [Unsubscribe](https://docs.aws.amazon.com/goto/aws-cli/sns-2010-03-31/Unsubscribe)

### Getting Started with IoT Device Defender
<a name="iot_GettingStarted_079_bash_topic"></a>

The following code example shows how to:
+ Create Required IAM Roles
+ Enable IoT Device Defender Audit Checks
+ Run an On-Demand Audit
+ Create a Mitigation Action
+ Apply Mitigation Actions to Findings
+ Set Up SNS Notifications (Optional)
+ Enable IoT Logging

**AWS CLI with Bash script**  
 There's more on GitHub. Find the complete example and learn how to set up and run in the [Sample developer tutorials](https://github.com/aws-samples/sample-developer-tutorials/tree/main/tuts/079-aws-iot-device-defender-gs) repository. 

```
#!/bin/bash

# AWS IoT Device Defender Getting Started Script
# This script demonstrates how to use AWS IoT Device Defender to enable audit checks,
# view audit results, create mitigation actions, and apply them to findings.

# Set up logging
LOG_FILE="iot-device-defender-script-$(date +%Y%m%d%H%M%S).log"
exec > >(tee -a "$LOG_FILE") 2>&1

echo "==================================================="
echo "AWS IoT Device Defender Getting Started Script"
echo "==================================================="
echo "Starting script execution at $(date)"
echo ""

# Function to check for errors in command output
check_error() {
    if echo "$1" | grep -i "An error occurred\|Exception\|Failed\|usage: aws" > /dev/null; then
        echo "ERROR: Command failed with the following output:"
        echo "$1"
        return 1
    fi
    return 0
}

# Function to create IAM roles
create_iam_role() {
    local ROLE_NAME=$1
    local TRUST_POLICY=$2
    local MANAGED_POLICY=$3
    
    echo "Creating IAM role: $ROLE_NAME"
    
    # Check if role already exists
    ROLE_EXISTS=$(aws iam get-role --role-name "$ROLE_NAME" 2>&1 || echo "NOT_EXISTS")
    
    if echo "$ROLE_EXISTS" | grep -i "NoSuchEntity" > /dev/null; then
        # Create the role with trust policy
        ROLE_RESULT=$(aws iam create-role \
            --role-name "$ROLE_NAME" \
            --assume-role-policy-document "$TRUST_POLICY" 2>&1)
        
        if ! check_error "$ROLE_RESULT"; then
            echo "Failed to create role $ROLE_NAME"
            return 1
        fi
        
        # For IoT logging role, create an inline policy instead of using a managed policy
        if [[ "$ROLE_NAME" == "AWSIoTLoggingRole" ]]; then
            LOGGING_POLICY='{
                "Version":"2012-10-17",		 	 	 
                "Statement": [
                    {
                        "Effect": "Allow",
                        "Action": [
                            "logs:CreateLogGroup",
                            "logs:CreateLogStream",
                            "logs:PutLogEvents",
                            "logs:PutMetricFilter",
                            "logs:PutRetentionPolicy",
                            "logs:GetLogEvents",
                            "logs:DescribeLogStreams"
                        ],
                        "Resource": [
                            "arn:aws:logs:*:*:*"
                        ]
                    }
                ]
            }'
            
            POLICY_RESULT=$(aws iam put-role-policy \
                --role-name "$ROLE_NAME" \
                --policy-name "${ROLE_NAME}Policy" \
                --policy-document "$LOGGING_POLICY" 2>&1)
                
            if ! check_error "$POLICY_RESULT"; then
                echo "Failed to attach inline policy to role $ROLE_NAME"
                return 1
            fi
        elif [[ "$ROLE_NAME" == "IoTMitigationActionErrorLoggingRole" ]]; then
            MITIGATION_POLICY='{
                "Version":"2012-10-17",		 	 	 
                "Statement": [
                    {
                        "Effect": "Allow",
                        "Action": [
                            "iot:UpdateCACertificate",
                            "iot:UpdateCertificate",
                            "iot:SetV2LoggingOptions",
                            "iot:SetLoggingOptions",
                            "iot:AddThingToThingGroup",
                            "iot:PublishToTopic"
                        ],
                        "Resource": "*"
                    },
                    {
                        "Effect": "Allow",
                        "Action": "iam:PassRole",
                        "Resource": "*",
                        "Condition": {
                            "StringEquals": {
                                "iam:PassedToService": "iot.amazonaws.com"
                            }
                        }
                    }
                ]
            }'
            
            POLICY_RESULT=$(aws iam put-role-policy \
                --role-name "$ROLE_NAME" \
                --policy-name "${ROLE_NAME}Policy" \
                --policy-document "$MITIGATION_POLICY" 2>&1)
                
            if ! check_error "$POLICY_RESULT"; then
                echo "Failed to attach inline policy to role $ROLE_NAME"
                return 1
            fi
        else
            # Attach managed policy to role if provided
            if [ -n "$MANAGED_POLICY" ]; then
                ATTACH_RESULT=$(aws iam attach-role-policy \
                    --role-name "$ROLE_NAME" \
                    --policy-arn "$MANAGED_POLICY" 2>&1)
                
                if ! check_error "$ATTACH_RESULT"; then
                    echo "Failed to attach policy to role $ROLE_NAME"
                    return 1
                fi
            fi
        fi
        
        echo "Role $ROLE_NAME created successfully"
    else
        echo "Role $ROLE_NAME already exists, skipping creation"
    fi
    
    # Get the role ARN
    ROLE_ARN=$(aws iam get-role --role-name "$ROLE_NAME" --query 'Role.Arn' --output text)
    echo "Role ARN: $ROLE_ARN"
    return 0
}

# Array to store created resources for cleanup
declare -a CREATED_RESOURCES

# Step 1: Create IAM roles needed for the tutorial
echo "==================================================="
echo "Step 1: Creating required IAM roles"
echo "==================================================="

# Create IoT Device Defender Audit role
IOT_DEFENDER_AUDIT_TRUST_POLICY='{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "iot.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}'

create_iam_role "AWSIoTDeviceDefenderAuditRole" "$IOT_DEFENDER_AUDIT_TRUST_POLICY" "arn:aws:iam::aws:policy/service-role/AWSIoTDeviceDefenderAudit"
AUDIT_ROLE_ARN=$ROLE_ARN
CREATED_RESOURCES+=("IAM Role: AWSIoTDeviceDefenderAuditRole")

# Create IoT Logging role
IOT_LOGGING_TRUST_POLICY='{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "iot.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}'

create_iam_role "AWSIoTLoggingRole" "$IOT_LOGGING_TRUST_POLICY" ""
LOGGING_ROLE_ARN=$ROLE_ARN
CREATED_RESOURCES+=("IAM Role: AWSIoTLoggingRole")

# Create IoT Mitigation Action role
IOT_MITIGATION_TRUST_POLICY='{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "iot.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}'

create_iam_role "IoTMitigationActionErrorLoggingRole" "$IOT_MITIGATION_TRUST_POLICY" ""
MITIGATION_ROLE_ARN=$ROLE_ARN
CREATED_RESOURCES+=("IAM Role: IoTMitigationActionErrorLoggingRole")

# Step 2: Enable audit checks
echo ""
echo "==================================================="
echo "Step 2: Enabling AWS IoT Device Defender audit checks"
echo "==================================================="

# Get current audit configuration
echo "Getting current audit configuration..."
CURRENT_CONFIG=$(aws iot describe-account-audit-configuration)
echo "$CURRENT_CONFIG"

# Enable specific audit checks
echo "Enabling audit checks..."
UPDATE_RESULT=$(aws iot update-account-audit-configuration \
  --role-arn "$AUDIT_ROLE_ARN" \
  --audit-check-configurations '{"LOGGING_DISABLED_CHECK":{"enabled":true}}')

if ! check_error "$UPDATE_RESULT"; then
    echo "Failed to update audit configuration"
    exit 1
fi

echo "Audit checks enabled successfully"

# Step 3: Run an on-demand audit
echo ""
echo "==================================================="
echo "Step 3: Running an on-demand audit"
echo "==================================================="

echo "Starting on-demand audit task..."
AUDIT_TASK_RESULT=$(aws iot start-on-demand-audit-task \
  --target-check-names LOGGING_DISABLED_CHECK)

if ! check_error "$AUDIT_TASK_RESULT"; then
    echo "Failed to start on-demand audit task"
    exit 1
fi

TASK_ID=$(echo "$AUDIT_TASK_RESULT" | grep -o '"taskId": "[^"]*' | cut -d'"' -f4)
echo "Audit task started with ID: $TASK_ID"
CREATED_RESOURCES+=("Audit Task: $TASK_ID")

# Wait for the audit task to complete
echo "Waiting for audit task to complete (this may take a few minutes)..."
TASK_STATUS="IN_PROGRESS"
while [ "$TASK_STATUS" != "COMPLETED" ]; do
    sleep 10
    TASK_DETAILS=$(aws iot describe-audit-task --task-id "$TASK_ID")
    TASK_STATUS=$(echo "$TASK_DETAILS" | grep -o '"taskStatus": "[^"]*' | cut -d'"' -f4)
    echo "Current task status: $TASK_STATUS"
    
    if [ "$TASK_STATUS" == "FAILED" ]; then
        echo "Audit task failed"
        exit 1
    fi
done

echo "Audit task completed successfully"

# Get audit findings
echo "Getting audit findings..."
FINDINGS=$(aws iot list-audit-findings \
  --task-id "$TASK_ID")

echo "Audit findings:"
echo "$FINDINGS"

# Check if we have any non-compliant findings
if echo "$FINDINGS" | grep -q '"findingId"'; then
    FINDING_ID=$(echo "$FINDINGS" | grep -o '"findingId": "[^"]*' | head -1 | cut -d'"' -f4)
    echo "Found non-compliant finding with ID: $FINDING_ID"
    HAS_FINDINGS=true
else
    echo "No non-compliant findings detected"
    HAS_FINDINGS=false
fi

# Step 4: Create a mitigation action
echo ""
echo "==================================================="
echo "Step 4: Creating a mitigation action"
echo "==================================================="

# Check if mitigation action already exists
MITIGATION_EXISTS=$(aws iot list-mitigation-actions --action-name "EnableErrorLoggingAction" 2>&1)
if echo "$MITIGATION_EXISTS" | grep -q "EnableErrorLoggingAction"; then
    echo "Mitigation action 'EnableErrorLoggingAction' already exists, deleting it first..."
    aws iot delete-mitigation-action --action-name "EnableErrorLoggingAction"
    # Wait a moment for deletion to complete
    sleep 5
fi

echo "Creating mitigation action to enable AWS IoT logging..."
MITIGATION_RESULT=$(aws iot create-mitigation-action \
  --action-name "EnableErrorLoggingAction" \
  --role-arn "$MITIGATION_ROLE_ARN" \
  --action-params "{\"enableIoTLoggingParams\":{\"roleArnForLogging\":\"$LOGGING_ROLE_ARN\",\"logLevel\":\"ERROR\"}}")

echo "$MITIGATION_RESULT"
if ! check_error "$MITIGATION_RESULT"; then
    echo "Failed to create mitigation action"
    exit 1
fi

echo "Mitigation action created successfully"
CREATED_RESOURCES+=("Mitigation Action: EnableErrorLoggingAction")

# Step 5: Apply mitigation action to findings (if any)
if [ "$HAS_FINDINGS" = true ]; then
    echo ""
    echo "==================================================="
    echo "Step 5: Applying mitigation action to findings"
    echo "==================================================="

    MITIGATION_TASK_ID="MitigationTask-$(date +%s)"
    echo "Starting mitigation actions task with ID: $MITIGATION_TASK_ID"
    
    MITIGATION_TASK_RESULT=$(aws iot start-audit-mitigation-actions-task \
      --task-id "$MITIGATION_TASK_ID" \
      --target "{\"findingIds\":[\"$FINDING_ID\"]}" \
      --audit-check-to-actions-mapping "{\"LOGGING_DISABLED_CHECK\":[\"EnableErrorLoggingAction\"]}")

    if ! check_error "$MITIGATION_TASK_RESULT"; then
        echo "Failed to start mitigation actions task"
        exit 1
    fi

    echo "Mitigation actions task started successfully"
    CREATED_RESOURCES+=("Mitigation Task: $MITIGATION_TASK_ID")
    
    # Wait for the mitigation task to complete
    echo "Waiting for mitigation task to complete..."
    sleep 10
    
    # Use a more reliable date format for the API call
    START_TIME=$(date -u -d 'today' '+%Y-%m-%dT%H:%M:%S.000Z')
    END_TIME=$(date -u '+%Y-%m-%dT%H:%M:%S.000Z')
    
    MITIGATION_TASKS=$(aws iot list-audit-mitigation-actions-tasks \
      --start-time "$START_TIME" \
      --end-time "$END_TIME" 2>&1)
    
    if check_error "$MITIGATION_TASKS"; then
        echo "Mitigation tasks:"
        echo "$MITIGATION_TASKS"
    else
        echo "Could not retrieve mitigation task status, but task was started successfully"
    fi
else
    echo ""
    echo "==================================================="
    echo "Step 5: Skipping mitigation action application (no findings)"
    echo "==================================================="
fi

# Step 6: Set up SNS notifications (optional)
echo ""
echo "==================================================="
echo "Step 6: Setting up SNS notifications"
echo "==================================================="

# Check if SNS topic already exists
SNS_TOPICS=$(aws sns list-topics)
if echo "$SNS_TOPICS" | grep -q "IoTDDNotifications"; then
    echo "SNS topic 'IoTDDNotifications' already exists, using existing topic..."
    TOPIC_ARN=$(echo "$SNS_TOPICS" | grep -o '"TopicArn": "[^"]*IoTDDNotifications' | cut -d'"' -f4)
else
    echo "Creating SNS topic for notifications..."
    SNS_RESULT=$(aws sns create-topic --name "IoTDDNotifications")

    if ! check_error "$SNS_RESULT"; then
        echo "Failed to create SNS topic"
        exit 1
    fi

    TOPIC_ARN=$(echo "$SNS_RESULT" | grep -o '"TopicArn": "[^"]*' | cut -d'"' -f4)
    echo "SNS topic created with ARN: $TOPIC_ARN"
    CREATED_RESOURCES+=("SNS Topic: IoTDDNotifications")
fi

echo "Updating audit configuration to enable SNS notifications..."
SNS_UPDATE_RESULT=$(aws iot update-account-audit-configuration \
  --audit-notification-target-configurations "{\"SNS\":{\"targetArn\":\"$TOPIC_ARN\",\"roleArn\":\"$AUDIT_ROLE_ARN\",\"enabled\":true}}")

if ! check_error "$SNS_UPDATE_RESULT"; then
    echo "Failed to update audit configuration for SNS notifications"
    exit 1
fi

echo "SNS notifications enabled successfully"

# Step 7: Enable AWS IoT logging
echo ""
echo "==================================================="
echo "Step 7: Enabling AWS IoT logging"
echo "==================================================="

echo "Setting up AWS IoT logging options..."

# Create the logging options payload
LOGGING_OPTIONS_PAYLOAD="{\"roleArn\":\"$LOGGING_ROLE_ARN\",\"logLevel\":\"ERROR\"}"

LOGGING_RESULT=$(aws iot set-v2-logging-options \
  --role-arn "$LOGGING_ROLE_ARN" \
  --default-log-level "ERROR" 2>&1)

if ! check_error "$LOGGING_RESULT"; then
    echo "Failed to set up AWS IoT v2 logging, trying v1 logging..."
    
    # Try the older set-logging-options command with proper payload format
    LOGGING_RESULT_V1=$(aws iot set-logging-options \
      --logging-options-payload "$LOGGING_OPTIONS_PAYLOAD" 2>&1)
    
    if ! check_error "$LOGGING_RESULT_V1"; then
        echo "Failed to set up AWS IoT logging with both v1 and v2 methods"
        echo "V2 result: $LOGGING_RESULT"
        echo "V1 result: $LOGGING_RESULT_V1"
        exit 1
    else
        echo "AWS IoT v1 logging enabled successfully"
    fi
else
    echo "AWS IoT v2 logging enabled successfully"
fi

# Verify logging is enabled
echo "Verifying logging configuration..."
LOGGING_CONFIG=$(aws iot get-v2-logging-options 2>&1)
if check_error "$LOGGING_CONFIG"; then
    echo "V2 Logging configuration:"
    echo "$LOGGING_CONFIG"
else
    echo "Checking v1 logging configuration..."
    LOGGING_CONFIG_V1=$(aws iot get-logging-options 2>&1)
    if check_error "$LOGGING_CONFIG_V1"; then
        echo "V1 Logging configuration:"
        echo "$LOGGING_CONFIG_V1"
    else
        echo "Could not retrieve logging configuration"
    fi
fi

# Script completed successfully
echo ""
echo "==================================================="
echo "AWS IoT Device Defender setup completed successfully!"
echo "==================================================="
echo "The following resources were created:"
for resource in "${CREATED_RESOURCES[@]}"; do
    echo "- $resource"
done
echo ""

# Ask if user wants to clean up resources
echo "==========================================="
echo "CLEANUP CONFIRMATION"
echo "==========================================="
echo "Do you want to clean up all created resources? (y/n): "
read -r CLEANUP_CHOICE

if [[ $CLEANUP_CHOICE =~ ^[Yy]$ ]]; then
    echo "Starting cleanup process..."
    
    # Disable AWS IoT logging
    echo "Disabling AWS IoT logging..."
    
    # Try to disable v2 logging first
    DISABLE_V2_RESULT=$(aws iot set-v2-logging-options \
      --default-log-level "DISABLED" 2>&1)
    
    if ! check_error "$DISABLE_V2_RESULT"; then
        echo "Failed to disable v2 logging, trying v1..."
        # Try v1 logging disable
        DISABLE_V1_RESULT=$(aws iot set-logging-options \
          --logging-options-payload "{\"logLevel\":\"DISABLED\"}" 2>&1)
        
        if ! check_error "$DISABLE_V1_RESULT"; then
            echo "Warning: Could not disable logging through either v1 or v2 methods"
        else
            echo "V1 logging disabled successfully"
        fi
    else
        echo "V2 logging disabled successfully"
    fi
    
    # Delete mitigation action
    echo "Deleting mitigation action..."
    aws iot delete-mitigation-action --action-name "EnableErrorLoggingAction"
    
    # Reset audit configuration
    echo "Resetting IoT Device Defender audit configuration..."
    aws iot update-account-audit-configuration \
      --audit-check-configurations '{"LOGGING_DISABLED_CHECK":{"enabled":false}}' 2>&1 | grep -qi "error" && echo "Warning: Failed to disable audit check"
    aws iot delete-account-audit-configuration --delete-scheduled-audits 2>&1 | grep -qi "error" && echo "Warning: Failed to delete audit configuration"
    
    # Delete SNS topic
    echo "Deleting SNS topic..."
    aws sns delete-topic --topic-arn "$TOPIC_ARN"
    
    # Detach policies from roles and delete roles (in reverse order)
    echo "Cleaning up IAM roles..."
    
    # Check if policies exist before trying to delete them
    ROLE_POLICIES=$(aws iam list-role-policies --role-name "IoTMitigationActionErrorLoggingRole" 2>&1)
    if ! echo "$ROLE_POLICIES" | grep -q "NoSuchEntity"; then
        if echo "$ROLE_POLICIES" | grep -q "IoTMitigationActionErrorLoggingRolePolicy"; then
            aws iam delete-role-policy \
                --role-name "IoTMitigationActionErrorLoggingRole" \
                --policy-name "IoTMitigationActionErrorLoggingRolePolicy"
        fi
    fi
    aws iam delete-role --role-name "IoTMitigationActionErrorLoggingRole"
    
    ROLE_POLICIES=$(aws iam list-role-policies --role-name "AWSIoTLoggingRole" 2>&1)
    if ! echo "$ROLE_POLICIES" | grep -q "NoSuchEntity"; then
        if echo "$ROLE_POLICIES" | grep -q "AWSIoTLoggingRolePolicy"; then
            aws iam delete-role-policy \
                --role-name "AWSIoTLoggingRole" \
                --policy-name "AWSIoTLoggingRolePolicy"
        fi
    fi
    aws iam delete-role --role-name "AWSIoTLoggingRole"
    
    aws iam detach-role-policy \
        --role-name "AWSIoTDeviceDefenderAuditRole" \
        --policy-arn "arn:aws:iam::aws:policy/service-role/AWSIoTDeviceDefenderAudit"
    aws iam delete-role --role-name "AWSIoTDeviceDefenderAuditRole"
    
    echo "Cleanup completed successfully"
else
    echo "Skipping cleanup. Resources will remain in your AWS account."
fi

echo ""
echo "Script execution completed at $(date)"
echo "Log file: $LOG_FILE"
```
+ For API details, see the following topics in *AWS CLI Command Reference*.
  + [AttachRolePolicy](https://docs.aws.amazon.com/goto/aws-cli/iam-2010-05-08/AttachRolePolicy)
  + [CreateMitigationAction](https://docs.aws.amazon.com/goto/aws-cli/iot-2015-05-28/CreateMitigationAction)
  + [CreateRole](https://docs.aws.amazon.com/goto/aws-cli/iam-2010-05-08/CreateRole)
  + [CreateTopic](https://docs.aws.amazon.com/goto/aws-cli/sns-2010-03-31/CreateTopic)
  + [DeleteAccountAuditConfiguration](https://docs.aws.amazon.com/goto/aws-cli/iot-2015-05-28/DeleteAccountAuditConfiguration)
  + [DeleteMitigationAction](https://docs.aws.amazon.com/goto/aws-cli/iot-2015-05-28/DeleteMitigationAction)
  + [DeleteRole](https://docs.aws.amazon.com/goto/aws-cli/iam-2010-05-08/DeleteRole)
  + [DeleteRolePolicy](https://docs.aws.amazon.com/goto/aws-cli/iam-2010-05-08/DeleteRolePolicy)
  + [DeleteTopic](https://docs.aws.amazon.com/goto/aws-cli/sns-2010-03-31/DeleteTopic)
  + [DescribeAccountAuditConfiguration](https://docs.aws.amazon.com/goto/aws-cli/iot-2015-05-28/DescribeAccountAuditConfiguration)
  + [DescribeAuditTask](https://docs.aws.amazon.com/goto/aws-cli/iot-2015-05-28/DescribeAuditTask)
  + [DetachRolePolicy](https://docs.aws.amazon.com/goto/aws-cli/iam-2010-05-08/DetachRolePolicy)
  + [GetLoggingOptions](https://docs.aws.amazon.com/goto/aws-cli/iot-2015-05-28/GetLoggingOptions)
  + [GetRole](https://docs.aws.amazon.com/goto/aws-cli/iam-2010-05-08/GetRole)
  + [GetV2LoggingOptions](https://docs.aws.amazon.com/goto/aws-cli/iot-2015-05-28/GetV2LoggingOptions)
  + [ListAuditFindings](https://docs.aws.amazon.com/goto/aws-cli/iot-2015-05-28/ListAuditFindings)
  + [ListAuditMitigationActionsTasks](https://docs.aws.amazon.com/goto/aws-cli/iot-2015-05-28/ListAuditMitigationActionsTasks)
  + [ListMitigationActions](https://docs.aws.amazon.com/goto/aws-cli/iot-2015-05-28/ListMitigationActions)
  + [ListRolePolicies](https://docs.aws.amazon.com/goto/aws-cli/iam-2010-05-08/ListRolePolicies)
  + [ListTopics](https://docs.aws.amazon.com/goto/aws-cli/sns-2010-03-31/ListTopics)
  + [PutRolePolicy](https://docs.aws.amazon.com/goto/aws-cli/iam-2010-05-08/PutRolePolicy)
  + [SetLoggingOptions](https://docs.aws.amazon.com/goto/aws-cli/iot-2015-05-28/SetLoggingOptions)
  + [SetV2LoggingOptions](https://docs.aws.amazon.com/goto/aws-cli/iot-2015-05-28/SetV2LoggingOptions)
  + [StartAuditMitigationActionsTask](https://docs.aws.amazon.com/goto/aws-cli/iot-2015-05-28/StartAuditMitigationActionsTask)
  + [StartOnDemandAuditTask](https://docs.aws.amazon.com/goto/aws-cli/iot-2015-05-28/StartOnDemandAuditTask)
  + [UpdateAccountAuditConfiguration](https://docs.aws.amazon.com/goto/aws-cli/iot-2015-05-28/UpdateAccountAuditConfiguration)

### Getting started with Config
<a name="config_service_GettingStarted_053_bash_topic"></a>

The following code example shows how to:
+ Create an Amazon S3 bucket
+ Create an Amazon SNS topic
+ Create an IAM role for Config
+ Set up the Config configuration recorder
+ Set up the Config delivery channel
+ Start the configuration recorder
+ Verify the Config setup

**AWS CLI with Bash script**  
 There's more on GitHub. Find the complete example and learn how to set up and run in the [Sample developer tutorials](https://github.com/aws-samples/sample-developer-tutorials/tree/main/tuts/053-aws-config-gs) repository. 

```
#!/bin/bash

# AWS Config Setup Script (v2)
# This script sets up AWS Config with the AWS CLI

# Error handling
set -e
LOGFILE="aws-config-setup-v2.log"
touch $LOGFILE
exec > >(tee -a $LOGFILE)
exec 2>&1

# Function to handle errors
handle_error() {
    echo "ERROR: An error occurred at line $1"
    echo "Attempting to clean up resources..."
    cleanup_resources
    exit 1
}

# Set trap for error handling
trap 'handle_error $LINENO' ERR

# Function to generate random identifier
generate_random_id() {
    echo $(openssl rand -hex 6)
}

# Function to check if command was successful
check_command() {
    if echo "$1" | grep -i "error" > /dev/null; then
        echo "ERROR: $1"
        return 1
    fi
    return 0
}

# Function to clean up resources
cleanup_resources() {
    if [ -n "$CONFIG_RECORDER_NAME" ]; then
        echo "Stopping configuration recorder..."
        aws configservice stop-configuration-recorder --configuration-recorder-name "$CONFIG_RECORDER_NAME" 2>/dev/null || true
    fi
    
    # Check if we created a new delivery channel before trying to delete it
    if [ -n "$DELIVERY_CHANNEL_NAME" ] && [ "$CREATED_NEW_DELIVERY_CHANNEL" = "true" ]; then
        echo "Deleting delivery channel..."
        aws configservice delete-delivery-channel --delivery-channel-name "$DELIVERY_CHANNEL_NAME" 2>/dev/null || true
    fi
    
    if [ -n "$CONFIG_RECORDER_NAME" ] && [ "$CREATED_NEW_CONFIG_RECORDER" = "true" ]; then
        echo "Deleting configuration recorder..."
        aws configservice delete-configuration-recorder --configuration-recorder-name "$CONFIG_RECORDER_NAME" 2>/dev/null || true
    fi
    
    if [ -n "$ROLE_NAME" ]; then
        if [ -n "$POLICY_NAME" ]; then
            echo "Detaching custom policy from role..."
            aws iam delete-role-policy --role-name "$ROLE_NAME" --policy-name "$POLICY_NAME" 2>/dev/null || true
        fi
        
        if [ -n "$MANAGED_POLICY_ARN" ]; then
            echo "Detaching managed policy from role..."
            aws iam detach-role-policy --role-name "$ROLE_NAME" --policy-arn "$MANAGED_POLICY_ARN" 2>/dev/null || true
        fi
        
        echo "Deleting IAM role..."
        aws iam delete-role --role-name "$ROLE_NAME" 2>/dev/null || true
    fi
    
    if [ -n "$SNS_TOPIC_ARN" ]; then
        echo "Deleting SNS topic..."
        aws sns delete-topic --topic-arn "$SNS_TOPIC_ARN" 2>/dev/null || true
    fi
    
    if [ -n "$S3_BUCKET_NAME" ]; then
        echo "Emptying S3 bucket..."
        aws s3 rm "s3://$S3_BUCKET_NAME" --recursive 2>/dev/null || true
        
        echo "Deleting S3 bucket..."
        aws s3api delete-bucket --bucket "$S3_BUCKET_NAME" 2>/dev/null || true
    fi
}

# Function to display created resources
display_resources() {
    echo ""
    echo "==========================================="
    echo "CREATED RESOURCES"
    echo "==========================================="
    echo "S3 Bucket: $S3_BUCKET_NAME"
    echo "SNS Topic ARN: $SNS_TOPIC_ARN"
    echo "IAM Role: $ROLE_NAME"
    if [ "$CREATED_NEW_CONFIG_RECORDER" = "true" ]; then
        echo "Configuration Recorder: $CONFIG_RECORDER_NAME (newly created)"
    else
        echo "Configuration Recorder: $CONFIG_RECORDER_NAME (existing)"
    fi
    if [ "$CREATED_NEW_DELIVERY_CHANNEL" = "true" ]; then
        echo "Delivery Channel: $DELIVERY_CHANNEL_NAME (newly created)"
    else
        echo "Delivery Channel: $DELIVERY_CHANNEL_NAME (existing)"
    fi
    echo "==========================================="
}

# Get AWS account ID
echo "Getting AWS account ID..."
ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
if [ -z "$ACCOUNT_ID" ]; then
    echo "ERROR: Failed to get AWS account ID"
    exit 1
fi
echo "AWS Account ID: $ACCOUNT_ID"

# Generate random identifier for resources
RANDOM_ID=$(generate_random_id)
echo "Generated random identifier: $RANDOM_ID"

# Step 1: Create an S3 bucket
S3_BUCKET_NAME="configservice-${RANDOM_ID}"
echo "Creating S3 bucket: $S3_BUCKET_NAME"

# Get the current region
AWS_REGION=$(aws configure get region)
if [ -z "$AWS_REGION" ]; then
    AWS_REGION="us-east-1"  # Default to us-east-1 if no region is configured
fi
echo "Using AWS Region: $AWS_REGION"

# Create bucket with appropriate command based on region
if [ "$AWS_REGION" = "us-east-1" ]; then
    BUCKET_RESULT=$(aws s3api create-bucket --bucket "$S3_BUCKET_NAME")
else
    BUCKET_RESULT=$(aws s3api create-bucket --bucket "$S3_BUCKET_NAME" --create-bucket-configuration LocationConstraint="$AWS_REGION")
fi
check_command "$BUCKET_RESULT"
echo "S3 bucket created: $S3_BUCKET_NAME"

# Block public access for the bucket
aws s3api put-public-access-block \
    --bucket "$S3_BUCKET_NAME" \
    --public-access-block-configuration "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
echo "Public access blocked for bucket"

# Step 2: Create an SNS topic
TOPIC_NAME="config-topic-${RANDOM_ID}"
echo "Creating SNS topic: $TOPIC_NAME"
SNS_RESULT=$(aws sns create-topic --name "$TOPIC_NAME")
check_command "$SNS_RESULT"
SNS_TOPIC_ARN=$(echo "$SNS_RESULT" | grep -o 'arn:aws:sns:[^"]*')
echo "SNS topic created: $SNS_TOPIC_ARN"

# Step 3: Create an IAM role for AWS Config
ROLE_NAME="config-role-${RANDOM_ID}"
POLICY_NAME="config-delivery-permissions"
MANAGED_POLICY_ARN="arn:aws:iam::aws:policy/service-role/AWS_ConfigRole"

echo "Creating trust policy document..."
cat > config-trust-policy.json << EOF
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "config.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

echo "Creating IAM role: $ROLE_NAME"
ROLE_RESULT=$(aws iam create-role --role-name "$ROLE_NAME" --assume-role-policy-document file://config-trust-policy.json)
check_command "$ROLE_RESULT"
ROLE_ARN=$(echo "$ROLE_RESULT" | grep -o 'arn:aws:iam::[^"]*' | head -1)
echo "IAM role created: $ROLE_ARN"

echo "Attaching AWS managed policy to role..."
ATTACH_RESULT=$(aws iam attach-role-policy --role-name "$ROLE_NAME" --policy-arn "$MANAGED_POLICY_ARN")
check_command "$ATTACH_RESULT"
echo "AWS managed policy attached"

echo "Creating custom policy document for S3 and SNS access..."
cat > config-delivery-permissions.json << EOF
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::${S3_BUCKET_NAME}/AWSLogs/${ACCOUNT_ID}/*",
      "Condition": {
        "StringLike": {
          "s3:x-amz-acl": "bucket-owner-full-control"
        }
      }
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetBucketAcl"
      ],
      "Resource": "arn:aws:s3:::${S3_BUCKET_NAME}"
    },
    {
      "Effect": "Allow",
      "Action": [
        "sns:Publish"
      ],
      "Resource": "${SNS_TOPIC_ARN}"
    }
  ]
}
EOF

echo "Attaching custom policy to role..."
POLICY_RESULT=$(aws iam put-role-policy --role-name "$ROLE_NAME" --policy-name "$POLICY_NAME" --policy-document file://config-delivery-permissions.json)
check_command "$POLICY_RESULT"
echo "Custom policy attached"

# Wait for IAM role to propagate
echo "Waiting for IAM role to propagate (15 seconds)..."
sleep 15

# Step 4: Check if configuration recorder already exists
CONFIG_RECORDER_NAME="default"
CREATED_NEW_CONFIG_RECORDER="false"

echo "Checking for existing configuration recorder..."
EXISTING_RECORDERS=$(aws configservice describe-configuration-recorders 2>/dev/null || echo "")
if echo "$EXISTING_RECORDERS" | grep -q "name"; then
    echo "Configuration recorder already exists. Will update it."
    # Get the name of the existing recorder
    CONFIG_RECORDER_NAME=$(echo "$EXISTING_RECORDERS" | grep -o '"name": "[^"]*"' | head -1 | cut -d'"' -f4)
    echo "Using existing configuration recorder: $CONFIG_RECORDER_NAME"
else
    echo "No existing configuration recorder found. Will create a new one."
    CREATED_NEW_CONFIG_RECORDER="true"
fi

echo "Creating configuration recorder configuration..."
cat > configurationRecorder.json << EOF
{
  "name": "${CONFIG_RECORDER_NAME}",
  "roleARN": "${ROLE_ARN}",
  "recordingMode": {
    "recordingFrequency": "CONTINUOUS"
  }
}
EOF

echo "Creating recording group configuration..."
cat > recordingGroup.json << EOF
{
  "allSupported": true,
  "includeGlobalResourceTypes": true
}
EOF

echo "Setting up configuration recorder..."
RECORDER_RESULT=$(aws configservice put-configuration-recorder --configuration-recorder file://configurationRecorder.json --recording-group file://recordingGroup.json)
check_command "$RECORDER_RESULT"
echo "Configuration recorder set up"

# Step 5: Check if delivery channel already exists
DELIVERY_CHANNEL_NAME="default"
CREATED_NEW_DELIVERY_CHANNEL="false"

echo "Checking for existing delivery channel..."
EXISTING_CHANNELS=$(aws configservice describe-delivery-channels 2>/dev/null || echo "")
if echo "$EXISTING_CHANNELS" | grep -q "name"; then
    echo "Delivery channel already exists."
    # Get the name of the existing channel
    DELIVERY_CHANNEL_NAME=$(echo "$EXISTING_CHANNELS" | grep -o '"name": "[^"]*"' | head -1 | cut -d'"' -f4)
    echo "Using existing delivery channel: $DELIVERY_CHANNEL_NAME"
    
    # Update the existing delivery channel
    echo "Creating delivery channel configuration for update..."
    cat > deliveryChannel.json << EOF
{
  "name": "${DELIVERY_CHANNEL_NAME}",
  "s3BucketName": "${S3_BUCKET_NAME}",
  "snsTopicARN": "${SNS_TOPIC_ARN}",
  "configSnapshotDeliveryProperties": {
    "deliveryFrequency": "Six_Hours"
  }
}
EOF

    echo "Updating delivery channel..."
    CHANNEL_RESULT=$(aws configservice put-delivery-channel --delivery-channel file://deliveryChannel.json)
    check_command "$CHANNEL_RESULT"
    echo "Delivery channel updated"
else
    echo "No existing delivery channel found. Will create a new one."
    CREATED_NEW_DELIVERY_CHANNEL="true"
    
    echo "Creating delivery channel configuration..."
    cat > deliveryChannel.json << EOF
{
  "name": "${DELIVERY_CHANNEL_NAME}",
  "s3BucketName": "${S3_BUCKET_NAME}",
  "snsTopicARN": "${SNS_TOPIC_ARN}",
  "configSnapshotDeliveryProperties": {
    "deliveryFrequency": "Six_Hours"
  }
}
EOF

    echo "Creating delivery channel..."
    CHANNEL_RESULT=$(aws configservice put-delivery-channel --delivery-channel file://deliveryChannel.json)
    check_command "$CHANNEL_RESULT"
    echo "Delivery channel created"
fi

# Step 6: Start the configuration recorder
echo "Checking configuration recorder status..."
RECORDER_STATUS=$(aws configservice describe-configuration-recorder-status 2>/dev/null || echo "")
if echo "$RECORDER_STATUS" | grep -q '"recording": true'; then
    echo "Configuration recorder is already running."
else
    echo "Starting configuration recorder..."
    START_RESULT=$(aws configservice start-configuration-recorder --configuration-recorder-name "$CONFIG_RECORDER_NAME")
    check_command "$START_RESULT"
    echo "Configuration recorder started"
fi

# Step 7: Verify the AWS Config setup
echo "Verifying delivery channel..."
VERIFY_CHANNEL=$(aws configservice describe-delivery-channels)
check_command "$VERIFY_CHANNEL"
echo "$VERIFY_CHANNEL"

echo "Verifying configuration recorder..."
VERIFY_RECORDER=$(aws configservice describe-configuration-recorders)
check_command "$VERIFY_RECORDER"
echo "$VERIFY_RECORDER"

echo "Verifying configuration recorder status..."
VERIFY_STATUS=$(aws configservice describe-configuration-recorder-status)
check_command "$VERIFY_STATUS"
echo "$VERIFY_STATUS"

# Display created resources
display_resources

# Ask if user wants to clean up resources
echo ""
echo "==========================================="
echo "CLEANUP CONFIRMATION"
echo "==========================================="
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..."
    cleanup_resources
    echo "Cleanup completed."
else
    echo "Resources will not be cleaned up. You can manually clean them up later."
fi

echo "Script completed successfully!"
```
+ For API details, see the following topics in *AWS CLI Command Reference*.
  + [AttachRolePolicy](https://docs.aws.amazon.com/goto/aws-cli/iam-2010-05-08/AttachRolePolicy)
  + [CreateBucket](https://docs.aws.amazon.com/goto/aws-cli/s3-2006-03-01/CreateBucket)
  + [CreateRole](https://docs.aws.amazon.com/goto/aws-cli/iam-2010-05-08/CreateRole)
  + [CreateTopic](https://docs.aws.amazon.com/goto/aws-cli/sns-2010-03-31/CreateTopic)
  + [DeleteBucket](https://docs.aws.amazon.com/goto/aws-cli/s3-2006-03-01/DeleteBucket)
  + [DeleteConfigurationRecorder](https://docs.aws.amazon.com/goto/aws-cli/config-2014-11-12/DeleteConfigurationRecorder)
  + [DeleteDeliveryChannel](https://docs.aws.amazon.com/goto/aws-cli/config-2014-11-12/DeleteDeliveryChannel)
  + [DeleteRole](https://docs.aws.amazon.com/goto/aws-cli/iam-2010-05-08/DeleteRole)
  + [DeleteRolePolicy](https://docs.aws.amazon.com/goto/aws-cli/iam-2010-05-08/DeleteRolePolicy)
  + [DeleteTopic](https://docs.aws.amazon.com/goto/aws-cli/sns-2010-03-31/DeleteTopic)
  + [DescribeConfigurationRecorderStatus](https://docs.aws.amazon.com/goto/aws-cli/config-2014-11-12/DescribeConfigurationRecorderStatus)
  + [DescribeConfigurationRecorders](https://docs.aws.amazon.com/goto/aws-cli/config-2014-11-12/DescribeConfigurationRecorders)
  + [DescribeDeliveryChannels](https://docs.aws.amazon.com/goto/aws-cli/config-2014-11-12/DescribeDeliveryChannels)
  + [DetachRolePolicy](https://docs.aws.amazon.com/goto/aws-cli/iam-2010-05-08/DetachRolePolicy)
  + [GetCallerIdentity](https://docs.aws.amazon.com/goto/aws-cli/sts-2011-06-15/GetCallerIdentity)
  + [PutConfigurationRecorder](https://docs.aws.amazon.com/goto/aws-cli/config-2014-11-12/PutConfigurationRecorder)
  + [PutDeliveryChannel](https://docs.aws.amazon.com/goto/aws-cli/config-2014-11-12/PutDeliveryChannel)
  + [PutPublicAccessBlock](https://docs.aws.amazon.com/goto/aws-cli/s3-2006-03-01/PutPublicAccessBlock)
  + [PutRolePolicy](https://docs.aws.amazon.com/goto/aws-cli/iam-2010-05-08/PutRolePolicy)
  + [Rm](https://docs.aws.amazon.com/goto/aws-cli/s3-2006-03-01/Rm)
  + [StartConfigurationRecorder](https://docs.aws.amazon.com/goto/aws-cli/config-2014-11-12/StartConfigurationRecorder)
  + [StopConfigurationRecorder](https://docs.aws.amazon.com/goto/aws-cli/config-2014-11-12/StopConfigurationRecorder)