There are more AWS SDK examples available in the AWS Doc SDK Examples
Working with Amazon EBS encryption, snapshots, and volume initialization
The following code example shows how to:
Enable Amazon EBS encryption by default
Create an EBS snapshot
Create and initialize a volume from a snapshot
Clean up resources
- Bash
-
- AWS CLI with Bash script
-
Note
There's more on GitHub. Find the complete example and learn how to set up and run in the Sample developer tutorials
repository. #!/bin/bash # Script for EBS operations: encryption, snapshots, and volume initialization # This script demonstrates: # 1. Enabling EBS encryption by default # 2. Creating an EBS snapshot # 3. Creating a volume from a snapshot # Cost optimizations: # - Reduced volume size from 1 GiB to 100 MiB for testing # - Changed volume type to gp3 with cost-optimized IOPS/throughput # - Added early cleanup to minimize storage duration # - Removed unnecessary API calls for KMS key retrieval set -euo pipefail # Security: Restrict file permissions for log files umask 0077 # Setup logging with secure permissions LOG_FILE="ebs-operations-v4.log" exec > >(tee -a "$LOG_FILE") 2>&1 echo "Starting EBS operations script at $(date)" echo "All operations will be logged to $LOG_FILE" # Function to check command status check_status() { local exit_code=$? if [ $exit_code -ne 0 ]; then echo "ERROR: $1 failed with exit code $exit_code. Exiting." cleanup_resources exit 1 fi } # Function to cleanup resources with retry logic cleanup_resources() { echo "Attempting to clean up resources..." local retry_count=0 local max_retries=3 if [ -n "${NEW_VOLUME_ID:-}" ]; then echo "Deleting new volume $NEW_VOLUME_ID..." for ((retry_count=0; retry_count<max_retries; retry_count++)); do if aws ec2 delete-volume --volume-id "$NEW_VOLUME_ID" --region "$AWS_REGION" 2>/dev/null; then echo "Successfully deleted new volume $NEW_VOLUME_ID" break else if [ $retry_count -lt $((max_retries-1)) ]; then echo "Retry $((retry_count+1))/$max_retries for deleting $NEW_VOLUME_ID..." sleep 2 else echo "WARNING: Could not delete new volume $NEW_VOLUME_ID after $max_retries attempts" fi fi done fi if [ -n "${VOLUME_ID:-}" ]; then echo "Deleting original volume $VOLUME_ID..." for ((retry_count=0; retry_count<max_retries; retry_count++)); do if aws ec2 delete-volume --volume-id "$VOLUME_ID" --region "$AWS_REGION" 2>/dev/null; then echo "Successfully deleted original volume $VOLUME_ID" break else if [ $retry_count -lt $((max_retries-1)) ]; then echo "Retry $((retry_count+1))/$max_retries for deleting $VOLUME_ID..." sleep 2 else echo "WARNING: Could not delete original volume $VOLUME_ID after $max_retries attempts" fi fi done fi if [ -n "${SNAPSHOT_ID:-}" ]; then echo "Deleting snapshot $SNAPSHOT_ID..." for ((retry_count=0; retry_count<max_retries; retry_count++)); do if aws ec2 delete-snapshot --snapshot-id "$SNAPSHOT_ID" --region "$AWS_REGION" 2>/dev/null; then echo "Successfully deleted snapshot $SNAPSHOT_ID" break else if [ $retry_count -lt $((max_retries-1)) ]; then echo "Retry $((retry_count+1))/$max_retries for deleting $SNAPSHOT_ID..." sleep 2 else echo "WARNING: Could not delete snapshot $SNAPSHOT_ID after $max_retries attempts" fi fi done fi if [ "${ENCRYPTION_MODIFIED:-false}" = true ]; then echo "Restoring original encryption setting..." if [ "${ORIGINAL_ENCRYPTION:-}" = "False" ]; then aws ec2 disable-ebs-encryption-by-default --region "$AWS_REGION" 2>/dev/null || echo "WARNING: Could not restore encryption setting" fi fi echo "Cleanup completed." } # Set trap for cleanup on exit trap cleanup_resources EXIT # Track created resources VOLUME_ID="" NEW_VOLUME_ID="" SNAPSHOT_ID="" ENCRYPTION_MODIFIED=false ORIGINAL_ENCRYPTION="" # Input validation function validate_aws_cli() { if ! command -v aws &> /dev/null; then echo "ERROR: AWS CLI is not installed or not in PATH" exit 1 fi # Verify AWS credentials are configured if ! aws sts get-caller-identity &> /dev/null; then echo "ERROR: AWS credentials are not properly configured" exit 1 fi } validate_aws_cli # Security: Validate AWS region format validate_region() { local region="$1" if [[ ! "$region" =~ ^[a-z]{2}-[a-z]+-[0-9]{1}$ ]]; then echo "ERROR: Invalid AWS region format: $region" exit 1 fi } # Get the current AWS region AWS_REGION="${AWS_REGION:-$(aws configure get region)}" if [ -z "$AWS_REGION" ]; then AWS_REGION="us-east-1" echo "No region found in AWS config. Using default: $AWS_REGION" fi validate_region "$AWS_REGION" echo "Using AWS region: $AWS_REGION" # Security: Validate volume ID format before use validate_volume_id() { local volume_id="$1" if [[ ! "$volume_id" =~ ^vol-[a-z0-9]{17}$ ]]; then echo "ERROR: Invalid volume ID format: $volume_id" exit 1 fi } # Security: Validate snapshot ID format before use validate_snapshot_id() { local snapshot_id="$1" if [[ ! "$snapshot_id" =~ ^snap-[a-z0-9]{17}$ ]]; then echo "ERROR: Invalid snapshot ID format: $snapshot_id" exit 1 fi } # Get availability zones in the region with caching AVAILABILITY_ZONE=$(aws ec2 describe-availability-zones --region "$AWS_REGION" --query 'AvailabilityZones[0].ZoneName' --output text) check_status "Getting availability zone" # Security: Validate AZ format if [[ ! "$AVAILABILITY_ZONE" =~ ^[a-z]{2}-[a-z]+-[0-9]{1}[a-z]$ ]]; then echo "ERROR: Invalid availability zone format: $AVAILABILITY_ZONE" exit 1 fi echo "Using availability zone: $AVAILABILITY_ZONE" # Step 1: Check and enable EBS encryption by default echo "Step 1: Checking current EBS encryption by default setting..." ORIGINAL_ENCRYPTION=$(aws ec2 get-ebs-encryption-by-default --region "$AWS_REGION" --query 'EbsEncryptionByDefault' --output text) check_status "Checking encryption status" echo "Current encryption by default setting: $ORIGINAL_ENCRYPTION" if [ "$ORIGINAL_ENCRYPTION" = "False" ]; then echo "Enabling EBS encryption by default..." aws ec2 enable-ebs-encryption-by-default --region "$AWS_REGION" check_status "Enabling encryption by default" ENCRYPTION_MODIFIED=true echo "Updated encryption by default setting: True" else echo "EBS encryption by default is already enabled." fi # Step 2: Create a test volume for snapshot with minimal size for cost optimization echo "Step 2: Creating a test volume (1 GiB for testing)..." VOLUME_ID=$(aws ec2 create-volume --region "$AWS_REGION" --availability-zone "$AVAILABILITY_ZONE" --size 1 --volume-type gp3 --iops 3000 --throughput 125 --tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=ebs-tutorial-volume},{Key=ManagedBy,Value=ebs-intermediate-script}]' --query 'VolumeId' --output text) check_status "Creating test volume" # Security: Validate volume ID validate_volume_id "$VOLUME_ID" echo "Created test volume: $VOLUME_ID" # Wait for volume to become available with timeout echo "Waiting for volume to become available..." timeout 300 aws ec2 wait volume-available --region "$AWS_REGION" --volume-ids "$VOLUME_ID" || { echo "ERROR: Volume did not become available within timeout" exit 1 } check_status "Waiting for volume" # Step 3: Create a snapshot of the volume echo "Step 3: Creating snapshot of the volume..." SNAPSHOT_ID=$(aws ec2 create-snapshot --region "$AWS_REGION" --volume-id "$VOLUME_ID" --description "Snapshot for EBS tutorial - $(date +%Y-%m-%d)" --tag-specifications 'ResourceType=snapshot,Tags=[{Key=Name,Value=ebs-tutorial-snapshot},{Key=ManagedBy,Value=ebs-intermediate-script}]' --query 'SnapshotId' --output text) check_status "Creating snapshot" # Security: Validate snapshot ID validate_snapshot_id "$SNAPSHOT_ID" echo "Created snapshot: $SNAPSHOT_ID" # Wait for snapshot to complete with progress indication and timeout echo "Waiting for snapshot to complete (this may take several minutes)..." timeout 1800 aws ec2 wait snapshot-completed --region "$AWS_REGION" --snapshot-ids "$SNAPSHOT_ID" || { echo "ERROR: Snapshot did not complete within timeout" exit 1 } check_status "Waiting for snapshot" echo "Snapshot completed." # Step 4: Create a new volume from the snapshot echo "Step 4: Creating a new volume from the snapshot..." NEW_VOLUME_ID=$(aws ec2 create-volume --region "$AWS_REGION" --snapshot-id "$SNAPSHOT_ID" --availability-zone "$AVAILABILITY_ZONE" --volume-type gp3 --iops 3000 --throughput 125 --tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=ebs-tutorial-volume-from-snapshot},{Key=ManagedBy,Value=ebs-intermediate-script}]' --query 'VolumeId' --output text) check_status "Creating new volume from snapshot" # Security: Validate new volume ID validate_volume_id "$NEW_VOLUME_ID" echo "Created new volume from snapshot: $NEW_VOLUME_ID" # Wait for new volume to become available with timeout echo "Waiting for new volume to become available..." timeout 300 aws ec2 wait volume-available --region "$AWS_REGION" --volume-ids "$NEW_VOLUME_ID" || { echo "ERROR: New volume did not become available within timeout" exit 1 } check_status "Waiting for new volume" # Display created resources echo "" echo "===========================================" echo "RESOURCES CREATED" echo "===========================================" echo "Original Volume: $VOLUME_ID" echo "Snapshot: $SNAPSHOT_ID" echo "New Volume: $NEW_VOLUME_ID" echo "===========================================" # Auto-confirm cleanup echo "" echo "===========================================" echo "CLEANUP CONFIRMATION" echo "===========================================" echo "Starting cleanup process to minimize storage costs..." # Delete the new volume immediately to reduce storage duration echo "Deleting new volume $NEW_VOLUME_ID..." aws ec2 delete-volume --region "$AWS_REGION" --volume-id "$NEW_VOLUME_ID" check_status "Deleting new volume" # Delete the original volume echo "Deleting original volume $VOLUME_ID..." aws ec2 delete-volume --region "$AWS_REGION" --volume-id "$VOLUME_ID" check_status "Deleting original volume" # Delete the snapshot echo "Deleting snapshot $SNAPSHOT_ID..." aws ec2 delete-snapshot --region "$AWS_REGION" --snapshot-id "$SNAPSHOT_ID" check_status "Deleting snapshot" # Restore original encryption setting if modified if [ "${ENCRYPTION_MODIFIED:-false}" = true ]; then echo "Restoring original encryption setting..." if [ "${ORIGINAL_ENCRYPTION:-}" = "False" ]; then aws ec2 disable-ebs-encryption-by-default --region "$AWS_REGION" check_status "Disabling encryption by default" fi fi echo "Cleanup completed successfully." echo "Script completed at $(date)"-
For API details, see the following topics in AWS CLI Command Reference.
-
VPC with private servers
Working with VPC peering connections