View a markdown version of this page

Contoh Amazon SNS menggunakan skrip AWS CLI Bash - AWS Command Line Interface

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

Contoh Amazon SNS menggunakan skrip AWS CLI Bash

Contoh kode berikut menunjukkan cara melakukan tindakan dan menerapkan skenario umum dengan menggunakan skrip AWS Command Line Interface with Bash dengan Amazon SNS.

Skenario adalah contoh kode yang menunjukkan kepada Anda bagaimana menyelesaikan tugas tertentu dengan memanggil beberapa fungsi dalam layanan atau dikombinasikan dengan yang lain Layanan AWS.

Setiap contoh menyertakan tautan ke kode sumber lengkap, di mana Anda dapat menemukan instruksi tentang cara mengatur dan menjalankan kode dalam konteks.

Skenario

Contoh kode berikut ini menunjukkan cara untuk melakukan:

  • Membuat topik Amazon SNS

  • Berlangganan titik akhir email ke topik

  • Verifikasi langganan Anda

  • Publikasikan pesan ke topik

  • Pembersihan sumber daya

AWS CLI dengan skrip Bash
catatan

Ada lebih banyak tentang GitHub. Temukan contoh lengkapnya dan pelajari cara mengatur dan menjalankan di repositori tutorial pengembang Sample.

#!/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 -euo pipefail # Set up logging with secure file permissions LOG_FILE="sns-tutorial.log" touch "$LOG_FILE" chmod 600 "$LOG_FILE" 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" >&2 echo "Attempting to clean up resources..." cleanup_resources exit 1 } # Function to clean up resources cleanup_resources() { local exit_code=$? if [ -n "${SUBSCRIPTION_ARN:-}" ] && [ "$SUBSCRIPTION_ARN" != "pending confirmation" ] && [ "$SUBSCRIPTION_ARN" != "PendingConfirmation" ]; then echo "Deleting subscription: $SUBSCRIPTION_ARN" if ! aws sns unsubscribe --subscription-arn "$SUBSCRIPTION_ARN" --region "$AWS_REGION" 2>/dev/null; then echo "Warning: Failed to delete subscription" >&2 fi fi if [ -n "${TOPIC_ARN:-}" ]; then echo "Deleting topic: $TOPIC_ARN" if ! aws sns delete-topic --topic-arn "$TOPIC_ARN" --region "$AWS_REGION" 2>/dev/null; then echo "Warning: Failed to delete topic" >&2 fi fi return $exit_code } # Validate AWS region AWS_REGION="${AWS_REGION:-us-east-1}" if [[ ! "$AWS_REGION" =~ ^[a-z]{2}-[a-z]+-[0-9]{1}$ ]]; then handle_error "Invalid AWS region format: $AWS_REGION" fi # Set trap to cleanup on exit trap cleanup_resources EXIT # Verify AWS CLI is installed and configured if ! command -v aws &> /dev/null; then handle_error "AWS CLI is not installed or not in PATH" fi if ! command -v jq &> /dev/null; then handle_error "jq is not installed or not in PATH" fi if ! aws sts get-caller-identity --region "$AWS_REGION" &> /dev/null; then handle_error "AWS credentials are not configured or invalid" fi # Generate a random topic name suffix using secure method RANDOM_SUFFIX=$(openssl rand -hex 4) TOPIC_NAME="my-topic-${RANDOM_SUFFIX}" # Validate topic name length (max 256 characters) if [ ${#TOPIC_NAME} -gt 256 ]; then handle_error "Topic name exceeds maximum length of 256 characters" fi # Step 1: Create an SNS topic echo "Creating SNS topic: $TOPIC_NAME" TOPIC_RESULT=$(aws sns create-topic \ --name "$TOPIC_NAME" \ --region "$AWS_REGION" \ --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-simple-notification-service-gs \ --output json) || handle_error "Failed to create SNS topic" # Extract the topic ARN using jq for reliable parsing TOPIC_ARN=$(echo "$TOPIC_RESULT" | jq -r '.TopicArn // empty') || handle_error "Failed to parse topic result" if [ -z "$TOPIC_ARN" ]; then handle_error "Failed to extract topic ARN from result: $TOPIC_RESULT" fi # Validate ARN format if [[ ! "$TOPIC_ARN" =~ ^arn:aws:sns:[a-z0-9-]+:[0-9]{12}:[a-zA-Z0-9_-]+$ ]]; then handle_error "Invalid SNS topic ARN format: $TOPIC_ARN" fi echo "Successfully created topic with ARN: $TOPIC_ARN" # Step 2: Subscribe to the topic using Email-JSON protocol to reduce costs echo "" echo "==============================================" echo "EMAIL SUBSCRIPTION" echo "==============================================" EMAIL_ADDRESS="test-${RANDOM_SUFFIX}@example.com" # Validate email format (basic validation) if [[ ! "$EMAIL_ADDRESS" =~ ^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then handle_error "Invalid email format: $EMAIL_ADDRESS" fi echo "Subscribing email: $EMAIL_ADDRESS to topic using Email-JSON protocol" SUBSCRIPTION_RESULT=$(aws sns subscribe \ --topic-arn "$TOPIC_ARN" \ --protocol email-json \ --notification-endpoint "$EMAIL_ADDRESS" \ --region "$AWS_REGION" \ --output json) || handle_error "Failed to create subscription" # Extract the subscription ARN using jq SUBSCRIPTION_ARN=$(echo "$SUBSCRIPTION_RESULT" | jq -r '.SubscriptionArn // empty') || handle_error "Failed to parse subscription result" echo "Subscription created: $SUBSCRIPTION_ARN" echo "A confirmation email has been sent to $EMAIL_ADDRESS" echo "" # Tag the subscription if [ "$SUBSCRIPTION_ARN" != "PendingConfirmation" ] && [ "$SUBSCRIPTION_ARN" != "pending confirmation" ]; then aws sns tag-resource \ --resource-arn "$SUBSCRIPTION_ARN" \ --tags Key=project,Value=doc-smith Key=tutorial,Value=amazon-simple-notification-service-gs \ --region "$AWS_REGION" 2>/dev/null || echo "Warning: Failed to tag subscription" fi # Step 3: List subscriptions to verify echo "Listing subscriptions for topic: $TOPIC_ARN" SUBSCRIPTIONS=$(aws sns list-subscriptions-by-topic --topic-arn "$TOPIC_ARN" --region "$AWS_REGION" --output json) || handle_error "Failed to list subscriptions" echo "Current subscriptions:" echo "$SUBSCRIPTIONS" | jq '.' # Get the confirmed subscription ARN with optimized jq query and improved error handling CONFIRMED_SUBSCRIPTION=$(echo "$SUBSCRIPTIONS" | jq -r '.Subscriptions[]? | select(.SubscriptionArn != "PendingConfirmation") | .SubscriptionArn' 2>/dev/null | head -n 1) if [ -n "$CONFIRMED_SUBSCRIPTION" ]; then SUBSCRIPTION_ARN="$CONFIRMED_SUBSCRIPTION" else 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)." # Validate message length (max 256 KB for SNS) if [ ${#MESSAGE} -gt 262144 ]; then handle_error "Message exceeds maximum size of 256 KB" fi PUBLISH_RESULT=$(aws sns publish \ --topic-arn "$TOPIC_ARN" \ --message "$MESSAGE" \ --region "$AWS_REGION" \ --output json) || handle_error "Failed to publish message" MESSAGE_ID=$(echo "$PUBLISH_RESULT" | jq -r '.MessageId // empty') || handle_error "Failed to parse publish result" if [ -z "$MESSAGE_ID" ]; then handle_error "No message ID returned from publish operation" fi # Validate message ID format (UUID v4) if [[ ! "$MESSAGE_ID" =~ ^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$ ]]; then handle_error "Unexpected message ID format: $MESSAGE_ID" fi 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 3 seconds to allow message delivery..." sleep 3 # Step 5: Clean up resources echo "" echo "==============================================" echo "CLEANUP CONFIRMATION" echo "==============================================" echo "Resources created:" echo "- SNS Topic: $TOPIC_ARN" echo "- Subscription: ${SUBSCRIPTION_ARN:-N/A}" echo "" echo "Cleaning up resources to avoid unnecessary charges..." echo "" echo "Tutorial completed successfully!" echo "$(date)" echo "=============================================="

Contoh kode berikut ini menunjukkan cara untuk melakukan:

  • Buat Peran IAM yang Diperlukan

  • Aktifkan Pemeriksaan Audit Pembela Perangkat IoT

  • Jalankan Audit Sesuai Permintaan

  • Buat Aksi Mitigasi

  • Terapkan Tindakan Mitigasi pada Temuan

  • Mengatur Pemberitahuan SNS (Opsional)

  • Aktifkan Logging IoT

AWS CLI dengan skrip Bash
catatan

Ada lebih banyak tentang GitHub. Temukan contoh lengkapnya dan pelajari cara mengatur dan menjalankan di repositori tutorial pengembang Sample.

#!/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 -euo pipefail # 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 -iE "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 safely extract JSON values using jq extract_json_value() { local json="$1" local key="$2" echo "$json" | jq -r ".${key} // empty" 2>/dev/null || echo "" } # Function to validate JSON validate_json() { local json="$1" echo "$json" | jq empty 2>/dev/null } # Function to check AWS CLI availability check_aws_cli() { if ! command -v aws &> /dev/null; then echo "ERROR: AWS CLI is not installed or not in PATH" return 1 fi if ! command -v jq &> /dev/null; then echo "ERROR: jq is not installed or not in PATH" return 1 fi return 0 } # Function to get AWS account ID get_account_id() { local account_id account_id=$(aws sts get-caller-identity --query 'Account' --output text 2>/dev/null) || true if [ -z "$account_id" ]; then echo "ERROR: Could not retrieve AWS account ID" return 1 fi echo "$account_id" return 0 } # Function to create IAM roles with retry logic create_iam_role() { local ROLE_NAME=$1 local TRUST_POLICY=$2 local MANAGED_POLICY=$3 local RETRY_COUNT=0 local MAX_RETRIES=3 echo "Creating IAM role: $ROLE_NAME" # Validate trust policy JSON if ! validate_json "$TRUST_POLICY"; then echo "ERROR: Invalid trust policy JSON for role $ROLE_NAME" return 1 fi # Check if role already exists if aws iam get-role --role-name "$ROLE_NAME" >/dev/null 2>&1; then echo "Role $ROLE_NAME already exists, skipping creation" ROLE_ARN=$(aws iam get-role --role-name "$ROLE_NAME" --query 'Role.Arn' --output text 2>/dev/null) || true if [ -z "$ROLE_ARN" ]; then echo "ERROR: Could not retrieve ARN for existing role $ROLE_NAME" return 1 fi echo "Role ARN: $ROLE_ARN" return 0 fi # Create the role with trust policy and retry logic while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do ROLE_RESULT=$(aws iam create-role \ --role-name "$ROLE_NAME" \ --assume-role-policy-document "$TRUST_POLICY" 2>&1) || true if check_error "$ROLE_RESULT"; then break fi RETRY_COUNT=$((RETRY_COUNT + 1)) if [ $RETRY_COUNT -lt $MAX_RETRIES ]; then echo "Retrying role creation (attempt $((RETRY_COUNT + 1))/$MAX_RETRIES)..." sleep $((RETRY_COUNT * 2)) fi done if ! check_error "$ROLE_RESULT"; then echo "Failed to create role $ROLE_NAME after $MAX_RETRIES attempts" return 1 fi aws iam tag-role --role-name "$ROLE_NAME" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-iot-device-defender-gs 2>&1 || true # For IoT logging role, create an inline policy instead of using a managed policy if [[ "$ROLE_NAME" == "AWSIoTLoggingRole" ]]; then local LOGGING_POLICY LOGGING_POLICY=$(cat <<'EOF' { "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:*:*:*" } ] } EOF ) if ! validate_json "$LOGGING_POLICY"; then echo "ERROR: Invalid logging policy JSON" return 1 fi POLICY_RESULT=$(aws iam put-role-policy \ --role-name "$ROLE_NAME" \ --policy-name "${ROLE_NAME}Policy" \ --policy-document "$LOGGING_POLICY" 2>&1) || true if ! check_error "$POLICY_RESULT"; then echo "Failed to attach inline policy to role $ROLE_NAME" return 1 fi elif [[ "$ROLE_NAME" == "IoTMitigationActionErrorLoggingRole" ]]; then local MITIGATION_POLICY MITIGATION_POLICY=$(cat <<'EOF' { "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iot:UpdateCACertificate", "iot:UpdateCertificate", "iot:SetV2LoggingOptions", "iot:SetLoggingOptions", "iot:AddThingToThingGroup" ], "Resource": "arn:aws:iot:*:*:*" }, { "Effect": "Allow", "Action": "iam:PassRole", "Resource": "*", "Condition": { "StringEquals": { "iam:PassedToService": "iot.amazonaws.com" } } } ] } EOF ) if ! validate_json "$MITIGATION_POLICY"; then echo "ERROR: Invalid mitigation policy JSON" return 1 fi POLICY_RESULT=$(aws iam put-role-policy \ --role-name "$ROLE_NAME" \ --policy-name "${ROLE_NAME}Policy" \ --policy-document "$MITIGATION_POLICY" 2>&1) || true 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) || true 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" # Get the role ARN with error handling ROLE_ARN=$(aws iam get-role --role-name "$ROLE_NAME" --query 'Role.Arn' --output text 2>/dev/null) || true if [ -z "$ROLE_ARN" ]; then echo "ERROR: Could not retrieve ARN for newly created role $ROLE_NAME" return 1 fi echo "Role ARN: $ROLE_ARN" return 0 } # Array to store created resources for cleanup declare -a CREATED_RESOURCES # Validate prerequisites echo "Validating prerequisites..." if ! check_aws_cli; then echo "ERROR: Prerequisites not met" exit 1 fi ACCOUNT_ID=$(get_account_id) || exit 1 echo "AWS Account ID: $ACCOUNT_ID" echo "" # 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=$(cat <<'EOF' { "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "iot.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF ) if ! create_iam_role "AWSIoTDeviceDefenderAuditRole" "$IOT_DEFENDER_AUDIT_TRUST_POLICY" "arn:aws:iam::aws:policy/service-role/AWSIoTDeviceDefenderAudit"; then echo "ERROR: Failed to create audit role" exit 1 fi AUDIT_ROLE_ARN=$ROLE_ARN CREATED_RESOURCES+=("IAM Role: AWSIoTDeviceDefenderAuditRole") # Create IoT Logging role IOT_LOGGING_TRUST_POLICY=$(cat <<'EOF' { "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "iot.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF ) if ! create_iam_role "AWSIoTLoggingRole" "$IOT_LOGGING_TRUST_POLICY" ""; then echo "ERROR: Failed to create logging role" exit 1 fi LOGGING_ROLE_ARN=$ROLE_ARN CREATED_RESOURCES+=("IAM Role: AWSIoTLoggingRole") # Create IoT Mitigation Action role IOT_MITIGATION_TRUST_POLICY=$(cat <<'EOF' { "Version":"2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "iot.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } EOF ) if ! create_iam_role "IoTMitigationActionErrorLoggingRole" "$IOT_MITIGATION_TRUST_POLICY" ""; then echo "ERROR: Failed to create mitigation role" exit 1 fi MITIGATION_ROLE_ARN=$ROLE_ARN CREATED_RESOURCES+=("IAM Role: IoTMitigationActionErrorLoggingRole") # Wait for IAM role propagation echo "Waiting for IAM role propagation..." sleep 5 # 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 --output json 2>&1) || true if validate_json "$CURRENT_CONFIG"; then echo "$CURRENT_CONFIG" | jq '.' 2>/dev/null || echo "Could not parse current configuration" fi # Enable specific audit checks with proper JSON escaping echo "Enabling audit checks..." AUDIT_CONFIG='{"LOGGING_DISABLED_CHECK":{"enabled":true}}' if ! validate_json "$AUDIT_CONFIG"; then echo "ERROR: Invalid audit configuration JSON" exit 1 fi UPDATE_RESULT=$(aws iot update-account-audit-configuration \ --role-arn "$AUDIT_ROLE_ARN" \ --audit-check-configurations "$AUDIT_CONFIG" 2>&1) || 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 --output json 2>&1) || true if ! check_error "$AUDIT_TASK_RESULT"; then echo "Failed to start on-demand audit task" exit 1 fi TASK_ID=$(extract_json_value "$AUDIT_TASK_RESULT" "taskId") if [ -z "$TASK_ID" ]; then echo "ERROR: Could not extract task ID from response" exit 1 fi echo "Audit task started with ID: $TASK_ID" CREATED_RESOURCES+=("Audit Task: $TASK_ID") # Tag the audit task via IoT service aws iot tag-resource --resource-arn "arn:aws:iot:$(aws configure get region):${ACCOUNT_ID}:audittask/${TASK_ID}" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-iot-device-defender-gs 2>&1 || true # Wait for the audit task to complete echo "Waiting for audit task to complete (this may take a few minutes)..." TASK_STATUS="IN_PROGRESS" TIMEOUT=0 MAX_TIMEOUT=600 POLL_INTERVAL=15 while [ "$TASK_STATUS" != "COMPLETED" ]; do if [ $TIMEOUT -ge $MAX_TIMEOUT ]; then echo "WARNING: Audit task did not complete within ${MAX_TIMEOUT} seconds, continuing..." break fi sleep "$POLL_INTERVAL" TIMEOUT=$((TIMEOUT + POLL_INTERVAL)) TASK_DETAILS=$(aws iot describe-audit-task --task-id "$TASK_ID" --output json 2>&1) || true if validate_json "$TASK_DETAILS"; then TASK_STATUS=$(extract_json_value "$TASK_DETAILS" "taskStatus") echo "Current task status: $TASK_STATUS (elapsed: ${TIMEOUT}s)" if [ "$TASK_STATUS" = "FAILED" ]; then echo "WARNING: Audit task failed, continuing with script..." FAILURE_REASON=$(extract_json_value "$TASK_DETAILS" "taskStatistics.failedChecksNotApplicable") if [ -n "$FAILURE_REASON" ]; then echo "Reason: $FAILURE_REASON" fi break fi else echo "WARNING: Could not parse task details, retrying..." fi done echo "Audit task processing completed" # Get audit findings (non-blocking) echo "Getting audit findings..." FINDINGS=$(aws iot list-audit-findings \ --task-id "$TASK_ID" --output json 2>&1) || true if validate_json "$FINDINGS"; then FINDING_COUNT=$(echo "$FINDINGS" | jq '.findings | length' 2>/dev/null || echo "0") echo "Audit findings count: $FINDING_COUNT" if [ "$FINDING_COUNT" -gt 0 ]; then echo "Sample finding:" echo "$FINDINGS" | jq '.findings[0]' 2>/dev/null || echo "Could not parse finding" fi else echo "WARNING: Could not parse audit findings response" FINDINGS='{"findings":[]}' fi # Check if we have any non-compliant findings FINDING_ID=$(extract_json_value "$FINDINGS" "findings[0].findingId") if [ -n "$FINDING_ID" ]; then 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 and delete it if aws iot describe-mitigation-action --action-name "EnableErrorLoggingAction" >/dev/null 2>&1; then echo "Mitigation action 'EnableErrorLoggingAction' already exists, deleting it first..." aws iot delete-mitigation-action --action-name "EnableErrorLoggingAction" 2>&1 || true sleep 2 fi echo "Creating mitigation action to enable AWS IoT logging..." # Build mitigation action parameters JSON MITIGATION_PARAMS=$(cat <<EOF { "enableIoTLoggingParams": { "roleArnForLogging": "$LOGGING_ROLE_ARN", "logLevel": "ERROR" } } EOF ) if ! validate_json "$MITIGATION_PARAMS"; then echo "ERROR: Invalid mitigation parameters JSON" exit 1 fi MITIGATION_RESULT=$(aws iot create-mitigation-action \ --action-name "EnableErrorLoggingAction" \ --role-arn "$MITIGATION_ROLE_ARN" \ --action-params "$MITIGATION_PARAMS" --output json 2>&1) || true if ! check_error "$MITIGATION_RESULT"; then echo "Failed to create mitigation action" exit 1 fi if validate_json "$MITIGATION_RESULT"; then echo "Mitigation action created successfully" MITIGATION_ACTION_ARN=$(extract_json_value "$MITIGATION_RESULT" "actionArn") if [ -n "$MITIGATION_ACTION_ARN" ]; then echo "Mitigation Action ARN: $MITIGATION_ACTION_ARN" aws iot tag-resource --resource-arn "$MITIGATION_ACTION_ARN" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-iot-device-defender-gs 2>&1 || true fi else echo "WARNING: Could not validate mitigation action response, but action may have been created" fi 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" # Build target JSON TARGET_JSON=$(cat <<EOF { "findingIds": ["$FINDING_ID"] } EOF ) if ! validate_json "$TARGET_JSON"; then echo "ERROR: Invalid target JSON" exit 1 fi # Build audit check to actions mapping JSON AUDIT_CHECK_MAPPING=$(cat <<EOF { "LOGGING_DISABLED_CHECK": ["EnableErrorLoggingAction"] } EOF ) if ! validate_json "$AUDIT_CHECK_MAPPING"; then echo "ERROR: Invalid audit check mapping JSON" exit 1 fi MITIGATION_TASK_RESULT=$(aws iot start-audit-mitigation-actions-task \ --task-id "$MITIGATION_TASK_ID" \ --target "$TARGET_JSON" \ --audit-check-to-actions-mapping "$AUDIT_CHECK_MAPPING" --output json 2>&1) || true if ! check_error "$MITIGATION_TASK_RESULT"; then echo "WARNING: Failed to start mitigation actions task, continuing..." else echo "Mitigation actions task started successfully" CREATED_RESOURCES+=("Mitigation Task: $MITIGATION_TASK_ID") 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 --output json 2>&1) || true TOPIC_ARN="" if validate_json "$SNS_TOPICS"; then TOPIC_ARN=$(echo "$SNS_TOPICS" | jq -r '.Topics[] | select(.TopicArn | contains("IoTDDNotifications")) | .TopicArn' 2>/dev/null | head -1 || echo "") fi if [ -n "$TOPIC_ARN" ]; then echo "SNS topic 'IoTDDNotifications' already exists, using existing topic..." echo "Topic ARN: $TOPIC_ARN" else echo "Creating SNS topic for notifications..." SNS_RESULT=$(aws sns create-topic --name "IoTDDNotifications" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-iot-device-defender-gs --output json 2>&1) || true if ! check_error "$SNS_RESULT"; then echo "WARNING: Failed to create SNS topic, continuing..." SNS_RESULT="" else TOPIC_ARN=$(extract_json_value "$SNS_RESULT" "TopicArn") if [ -n "$TOPIC_ARN" ]; then echo "SNS topic created with ARN: $TOPIC_ARN" CREATED_RESOURCES+=("SNS Topic: IoTDDNotifications") fi fi fi if [ -n "$TOPIC_ARN" ]; then echo "Updating audit configuration to enable SNS notifications..." # Build SNS notification configuration JSON SNS_CONFIG=$(cat <<EOF { "SNS": { "targetArn": "$TOPIC_ARN", "roleArn": "$AUDIT_ROLE_ARN", "enabled": true } } EOF ) if ! validate_json "$SNS_CONFIG"; then echo "ERROR: Invalid SNS configuration JSON" exit 1 fi SNS_UPDATE_RESULT=$(aws iot update-account-audit-configuration \ --audit-notification-target-configurations "$SNS_CONFIG" 2>&1) || true if ! check_error "$SNS_UPDATE_RESULT"; then echo "WARNING: Failed to update audit configuration for SNS notifications" else echo "SNS notifications enabled successfully" fi else echo "Skipping SNS configuration due to topic creation failure" fi # Step 7: Enable AWS IoT logging echo "" echo "===================================================" echo "Step 7: Enabling AWS IoT logging" echo "===================================================" echo "Setting up AWS IoT logging options..." LOGGING_RESULT=$(aws iot set-v2-logging-options \ --role-arn "$LOGGING_ROLE_ARN" \ --default-log-level "ERROR" 2>&1) || true if ! check_error "$LOGGING_RESULT"; then echo "V2 logging setup failed, trying v1 logging..." V1_LOGGING_CONFIG=$(cat <<EOF { "roleArn": "$LOGGING_ROLE_ARN", "logLevel": "ERROR" } EOF ) if ! validate_json "$V1_LOGGING_CONFIG"; then echo "ERROR: Invalid v1 logging configuration JSON" exit 1 fi LOGGING_RESULT_V1=$(aws iot set-logging-options \ --logging-options-payload "$V1_LOGGING_CONFIG" 2>&1) || true if ! check_error "$LOGGING_RESULT_V1"; then echo "WARNING: Failed to set up AWS IoT logging with both v1 and v2 methods, continuing..." 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 --output json 2>&1) || true if [ -n "$LOGGING_CONFIG" ] && ! check_error "$LOGGING_CONFIG" && validate_json "$LOGGING_CONFIG"; then echo "Logging configuration verified" echo "$LOGGING_CONFIG" | jq '.' 2>/dev/null || echo "Configuration retrieved but could not display details" else echo "Could not verify logging configuration, but setup completed" 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[@]+"${CREATED_RESOURCES[@]}"}"; do echo "- $resource" done echo "" # Cleanup phase echo "===========================================" echo "CLEANUP" echo "===========================================" echo "Starting automatic cleanup of resources..." echo "Waiting 10 seconds before cleanup to allow resource stabilization..." sleep 10 # Disable AWS IoT logging echo "Disabling AWS IoT logging..." DISABLE_V2_RESULT=$(aws iot set-v2-logging-options \ --default-log-level "DISABLED" 2>&1) || true if check_error "$DISABLE_V2_RESULT"; then echo "V2 logging disabled successfully" else echo "Attempting v1 logging disable..." V1_DISABLE_CONFIG=$(cat <<'EOF' { "logLevel": "DISABLED" } EOF ) DISABLE_V1_RESULT=$(aws iot set-logging-options \ --logging-options-payload "$V1_DISABLE_CONFIG" 2>&1) || true if check_error "$DISABLE_V1_RESULT"; then echo "V1 logging disabled successfully" else echo "WARNING: Could not disable logging" fi fi # Delete mitigation action echo "Deleting mitigation action..." aws iot delete-mitigation-action --action-name "EnableErrorLoggingAction" 2>&1 || true # Reset audit configuration echo "Resetting IoT Device Defender audit configuration..." RESET_AUDIT_CONFIG='{"LOGGING_DISABLED_CHECK":{"enabled":false}}' aws iot update-account-audit-configuration \ --audit-check-configurations "$RESET_AUDIT_CONFIG" 2>&1 || true # Delete SNS topic echo "Deleting SNS topic..." if [ -n "${TOPIC_ARN:-}" ] && [ "$TOPIC_ARN" != "null" ]; then aws sns delete-topic --topic-arn "$TOPIC_ARN" 2>&1 || true fi # Clean up IAM roles with improved error handling echo "Cleaning up IAM roles..." cleanup_role() { local role_name=$1 echo "Cleaning up role: $role_name" if aws iam get-role --role-name "$role_name" >/dev/null 2>&1; then ROLE_POLICIES=$(aws iam list-role-policies --role-name "$role_name" --output json 2>&1 || echo '{"PolicyNames":[]}') if validate_json "$ROLE_POLICIES"; then while IFS= read -r policy_name; do if [ -n "$policy_name" ] && [ "$policy_name" != "null" ]; then echo " Deleting inline policy: $policy_name" aws iam delete-role-policy \ --role-name "$role_name" \ --policy-name "$policy_name" 2>&1 || true fi done < <(echo "$ROLE_POLICIES" | jq -r '.PolicyNames[]' 2>/dev/null || echo "") fi ATTACHED_POLICIES=$(aws iam list-attached-role-policies --role-name "$role_name" --output json 2>&1 || echo '{"AttachedPolicies":[]}') if validate_json "$ATTACHED_POLICIES"; then while IFS= read -r policy_arn; do if [ -n "$policy_arn" ] && [ "$policy_arn" != "null" ]; then echo " Detaching managed policy: $policy_arn" aws iam detach-role-policy \ --role-name "$role_name" \ --policy-arn "$policy_arn" 2>&1 || true fi done < <(echo "$ATTACHED_POLICIES" | jq -r '.AttachedPolicies[].PolicyArn' 2>/dev/null || echo "") fi echo " Deleting role: $role_name" aws iam delete-role --role-name "$role_name" 2>&1 || true else echo " Role $role_name does not exist or already deleted" fi } cleanup_role "AWSIoTDeviceDefenderAuditRole" cleanup_role "AWSIoTLoggingRole" cleanup_role "IoTMitigationActionErrorLoggingRole" echo "Cleanup completed successfully" echo "" echo "Script execution completed at $(date)" echo "Log file: $LOG_FILE"

Contoh kode berikut ini menunjukkan cara untuk melakukan:

  • Buat bucket Amazon S3.

  • Membuat topik Amazon SNS

  • Buat peran IAM untuk Config

  • Siapkan perekam konfigurasi Config

  • Siapkan saluran pengiriman Config

  • Mulai perekam konfigurasi

  • Verifikasi pengaturan Config

AWS CLI dengan skrip Bash
catatan

Ada lebih banyak tentang GitHub. Temukan contoh lengkapnya dan pelajari cara mengatur dan menjalankan di repositori tutorial pengembang Sample.

#!/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..." if [ "$BUCKET_IS_SHARED" = "false" ]; then aws s3api delete-bucket --bucket "$S3_BUCKET_NAME" 2>/dev/null || true fi 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 # Check for shared prereq bucket PREREQ_BUCKET=$(aws cloudformation describe-stacks --stack-name tutorial-prereqs-bucket \ --query 'Stacks[0].Outputs[?OutputKey==`BucketName`].OutputValue' --output text 2>/dev/null) if [ -n "$PREREQ_BUCKET" ] && [ "$PREREQ_BUCKET" != "None" ]; then S3_BUCKET_NAME="$PREREQ_BUCKET" BUCKET_IS_SHARED=true echo "Using shared bucket: $S3_BUCKET_NAME" else BUCKET_IS_SHARED=false S3_BUCKET_NAME="configservice-${RANDOM_ID}" echo "Creating S3 bucket: $S3_BUCKET_NAME" fi # 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 [ "$BUCKET_IS_SHARED" = "false" ]; then 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" aws s3api put-bucket-tagging --bucket "$S3_BUCKET_NAME" --tagging 'TagSet=[{Key=project,Value=doc-smith},{Key=tutorial,Value=aws-config-gs}]' echo "Tags applied to S3 bucket" else echo "Using shared bucket: $S3_BUCKET_NAME (skipping creation)" fi # 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" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-config-gs) 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" aws iam tag-role --role-name "$ROLE_NAME" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-config-gs echo "Tags applied to IAM role" 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" if [ "$CREATED_NEW_CONFIG_RECORDER" = "true" ]; then aws configservice tag-resource --resource-arn "arn:aws:config:${AWS_REGION}:${ACCOUNT_ID}:config-recorder/${CONFIG_RECORDER_NAME}" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-config-gs echo "Tags applied to configuration recorder" fi # 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" aws configservice tag-resource --resource-arn "arn:aws:config:${AWS_REGION}:${ACCOUNT_ID}:delivery-channel/${DELIVERY_CHANNEL_NAME}" --tags Key=project,Value=doc-smith Key=tutorial,Value=aws-config-gs echo "Tags applied to delivery channel" 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): " CLEANUP_CHOICE='y' 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!"