View a markdown version of this page

Working with Amazon EBS encryption, snapshots, and volume initialization - AWS SDK Code Examples

There are more AWS SDK examples available in the AWS Doc SDK Examples GitHub repo.

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)"