AWS storage services - S3, EBS, EFS, Glacier, lifecycle policies, encryption, and data transfer
Scope: AWS storage - S3 buckets, EBS volumes, EFS file systems, Glacier archival, lifecycle policies, encryption Lines: ~300 Last Updated: 2025-10-25 Format Version: 1.0 (Atomic)
Activate this skill when:
S3 storage classes:
import boto3
s3 = boto3.client('s3')
def create_bucket(bucket_name, region='us-east-1'):
"""Create S3 bucket with versioning and encryption"""
# Create bucket
if region == 'us-east-1':
s3.create_bucket(Bucket=bucket_name)
else:
s3.create_bucket(
Bucket=bucket_name,
CreateBucketConfiguration={'LocationConstraint': region}
)
# Enable versioning
s3.put_bucket_versioning(
Bucket=bucket_name,
VersioningConfiguration={'Status': 'Enabled'}
)
# Enable default encryption
s3.put_bucket_encryption(
Bucket=bucket_name,
ServerSideEncryptionConfiguration={
'Rules': [
{
'ApplyServerSideEncryptionByDefault': {
'SSEAlgorithm': 'AES256'
},
'BucketKeyEnabled': True
}
]
}
)
# Block public access
s3.put_public_access_block(
Bucket=bucket_name,
PublicAccessBlockConfiguration={
'BlockPublicAcls': True,
'IgnorePublicAcls': True,
'BlockPublicPolicy': True,
'RestrictPublicBuckets': True
}
)
print(f"Created bucket: {bucket_name}")
def upload_object(bucket, key, file_path, storage_class='STANDARD'):
"""Upload file to S3 with storage class"""
s3.upload_file(
file_path,
bucket,
key,
ExtraArgs={
'StorageClass': storage_class,
'ServerSideEncryption': 'AES256',
'Metadata': {
'uploaded-by': 'automation',
'environment': 'production'
}
}
)
print(f"Uploaded {key} to {bucket} ({storage_class})")
EBS volume types:
import boto3
ec2 = boto3.client('ec2')
def create_and_attach_volume(instance_id, size_gb=100, volume_type='gp3'):
"""Create EBS volume and attach to instance"""
# Get instance AZ
response = ec2.describe_instances(InstanceIds=[instance_id])
az = response['Reservations'][0]['Instances'][0]['Placement']['AvailabilityZone']
# Create volume
volume_response = ec2.create_volume(
AvailabilityZone=az,
Size=size_gb,
VolumeType=volume_type,
Iops=3000 if volume_type == 'gp3' else None, # gp3 baseline
Throughput=125 if volume_type == 'gp3' else None, # MB/s
Encrypted=True,
TagSpecifications=[
{
'ResourceType': 'volume',
'Tags': [
{'Key': 'Name', 'Value': f'data-volume-{instance_id}'},
{'Key': 'ManagedBy', 'Value': 'automation'}
]
}
]
)
volume_id = volume_response['VolumeId']
print(f"Created volume: {volume_id}")
# Wait for volume to be available
waiter = ec2.get_waiter('volume_available')
waiter.wait(VolumeIds=[volume_id])
# Attach volume
ec2.attach_volume(
Device='/dev/sdf',
InstanceId=instance_id,
VolumeId=volume_id
)
print(f"Attached {volume_id} to {instance_id}")
return volume_id
def create_snapshot(volume_id, description):
"""Create EBS snapshot for backup"""
response = ec2.create_snapshot(
VolumeId=volume_id,
Description=description,
TagSpecifications=[
{
'ResourceType': 'snapshot',
'Tags': [
{'Key': 'BackupType', 'Value': 'automated'},
{'Key': 'CreatedBy', 'Value': 'backup-lambda'}
]
}
]
)
snapshot_id = response['SnapshotId']
print(f"Creating snapshot: {snapshot_id}")
return snapshot_id
EFS use cases:
import boto3
efs = boto3.client('efs')
def create_efs_file_system():
"""Create EFS file system with mount targets"""
# Create file system
response = efs.create_file_system(
PerformanceMode='generalPurpose', # or 'maxIO'
ThroughputMode='bursting', # or 'provisioned'
Encrypted=True,
Tags=[
{'Key': 'Name', 'Value': 'shared-storage'},
{'Key': 'Environment', 'Value': 'production'}
]
)
fs_id = response['FileSystemId']
print(f"Created EFS: {fs_id}")
# Wait for file system to be available
waiter = efs.get_waiter('file_system_available')
waiter.wait(FileSystemId=fs_id)
# Create mount targets in each subnet (AZ)
subnets = ['subnet-abc123', 'subnet-def456']
security_group = 'sg-0123456789abcdef0'
for subnet in subnets:
efs.create_mount_target(
FileSystemId=fs_id,
SubnetId=subnet,
SecurityGroups=[security_group]
)
print(f"Created mount targets for {fs_id}")
return fs_id
# Mount EFS on EC2 instance (user data script)
EFS_MOUNT_SCRIPT = """#!/bin/bash
# Install EFS utilities
yum install -y amazon-efs-utils
# Create mount point
mkdir -p /mnt/efs
# Mount EFS
mount -t efs -o tls {fs_id}:/ /mnt/efs
# Add to fstab for persistence
echo "{fs_id}:/ /mnt/efs efs defaults,_netdev,tls 0 0" >> /etc/fstab
"""
When to use: Automatic transition to cheaper storage classes
def configure_lifecycle_policy(bucket_name):
"""Configure S3 lifecycle transitions and expiration"""
s3.put_bucket_lifecycle_configuration(
Bucket=bucket_name,
LifecycleConfiguration={
'Rules': [
{
'Id': 'archive-old-logs',
'Status': 'Enabled',
'Filter': {'Prefix': 'logs/'},
'Transitions': [
{
'Days': 30,
'StorageClass': 'STANDARD_IA'
},
{
'Days': 90,
'StorageClass': 'GLACIER_FLEXIBLE_RETRIEVAL'
},
{
'Days': 365,
'StorageClass': 'DEEP_ARCHIVE'
}
],
'Expiration': {
'Days': 2555 # 7 years
}
},
{
'Id': 'cleanup-temp-files',
'Status': 'Enabled',
'Filter': {'Prefix': 'temp/'},
'Expiration': {
'Days': 7
},
'AbortIncompleteMultipartUpload': {
'DaysAfterInitiation': 1
}
},
{
'Id': 'intelligent-tiering',
'Status': 'Enabled',
'Filter': {'Prefix': 'data/'},
'Transitions': [
{
'Days': 0,
'StorageClass': 'INTELLIGENT_TIERING'
}
]
}
]
}
)
print(f"Configured lifecycle policy for {bucket_name}")
Benefits:
Use case: Trigger Lambda on file upload
def configure_s3_notifications(bucket_name, lambda_arn):
"""Configure S3 to trigger Lambda on object creation"""
# Grant S3 permission to invoke Lambda
lambda_client = boto3.client('lambda')
lambda_client.add_permission(
FunctionName=lambda_arn.split(':')[-1],
StatementId='s3-invoke-permission',
Action='lambda:InvokeFunction',
Principal='s3.amazonaws.com',
SourceArn=f'arn:aws:s3:::{bucket_name}'
)
# Configure notification
s3.put_bucket_notification_configuration(
Bucket=bucket_name,
NotificationConfiguration={
'LambdaFunctionConfigurations': [
{
'LambdaFunctionArn': lambda_arn,
'Events': ['s3:ObjectCreated:*'],
'Filter': {
'Key': {
'FilterRules': [
{'Name': 'prefix', 'Value': 'uploads/'},
{'Name': 'suffix', 'Value': '.jpg'}
]
}
}
}
]
}
)
print(f"Configured S3 notifications for {bucket_name}")
Use case: Temporary access to private objects
from botocore.exceptions import ClientError
def generate_presigned_url(bucket, key, expiration=3600):
"""Generate presigned URL for temporary access"""
try:
url = s3.generate_presigned_url(
'get_object',
Params={
'Bucket': bucket,
'Key': key
},
ExpiresIn=expiration # Seconds
)
return url
except ClientError as e:
print(f"Error generating URL: {e}")
return None
def generate_presigned_upload_url(bucket, key, expiration=3600):
"""Generate presigned URL for upload"""
url = s3.generate_presigned_url(
'put_object',
Params={
'Bucket': bucket,
'Key': key,
'ContentType': 'image/jpeg'
},
ExpiresIn=expiration,
HttpMethod='PUT'
)
return url
# Usage
download_url = generate_presigned_url('my-bucket', 'private/file.pdf', 300)
upload_url = generate_presigned_upload_url('my-bucket', 'uploads/new.jpg', 600)
Use case: Fast uploads from distant locations
# Enable Transfer Acceleration
aws s3api put-bucket-accelerate-configuration \
--bucket my-bucket \
--accelerate-configuration Status=Enabled
def upload_with_acceleration(bucket, key, file_path):
"""Upload using S3 Transfer Acceleration endpoint"""
# Create client with accelerate endpoint
s3_accelerate = boto3.client(
's3',
config=boto3.session.Config(
s3={'use_accelerate_endpoint': True}
)
)
# Upload file
s3_accelerate.upload_file(file_path, bucket, key)
print(f"Uploaded {key} using Transfer Acceleration")
Use case: Automated backup strategy
from datetime import datetime, timedelta
def backup_ebs_volumes(tag_key='Backup', tag_value='true'):
"""Create snapshots of tagged volumes"""
# Find volumes with backup tag
response = ec2.describe_volumes(
Filters=[
{'Name': f'tag:{tag_key}', 'Values': [tag_value]}
]
)
for volume in response['Volumes']:
volume_id = volume['VolumeId']
# Create snapshot
snapshot = ec2.create_snapshot(
VolumeId=volume_id,
Description=f'Automated backup {datetime.utcnow().isoformat()}',
TagSpecifications=[
{
'ResourceType': 'snapshot',
'Tags': [
{'Key': 'BackupDate', 'Value': datetime.utcnow().strftime('%Y-%m-%d')},
{'Key': 'VolumeId', 'Value': volume_id}
]
}
]
)
print(f"Created snapshot {snapshot['SnapshotId']} for {volume_id}")
def cleanup_old_snapshots(retention_days=30):
"""Delete snapshots older than retention period"""
cutoff_date = datetime.utcnow() - timedelta(days=retention_days)
# Find old snapshots
response = ec2.describe_snapshots(OwnerIds=['self'])
for snapshot in response['Snapshots']:
start_time = snapshot['StartTime'].replace(tzinfo=None)
if start_time < cutoff_date:
snapshot_id = snapshot['SnapshotId']
print(f"Deleting old snapshot: {snapshot_id}")
try:
ec2.delete_snapshot(SnapshotId=snapshot_id)
except ClientError as e:
print(f"Failed to delete {snapshot_id}: {e}")
| Use Case | Service | Type | Access Pattern | |----------|---------|------|----------------| | Objects, files, backups | S3 | Object | API/HTTP | | Block storage for EC2 | EBS | Block | Attached volume | | Shared file system | EFS | File | NFS mount | | Long-term archive | Glacier | Object | Rare retrieval |
Storage Class | Cost | Retrieval | Use Case
---------------------------|-----------|--------------|------------------
S3 Standard | $0.023 | Free | Active data
S3 Intelligent-Tiering | $0.023+ | Free | Unknown pattern
S3 Standard-IA | $0.0125 | $0.01/GB | Infrequent access
S3 Glacier Instant | $0.004 | $0.03/GB | Archive (instant)
S3 Glacier Flexible | $0.0036 | $0.01/GB | Archive (mins)
S3 Deep Archive | $0.00099 | $0.02/GB | Long-term (hours)
✅ DO: Enable versioning for critical data
✅ DO: Enable default encryption on all buckets
✅ DO: Use lifecycle policies to reduce costs
✅ DO: Block public access unless explicitly needed
✅ DO: Use presigned URLs for temporary access
✅ DO: Encrypt EBS volumes (especially production)
❌ DON'T: Make buckets public without justification
❌ DON'T: Store sensitive data without encryption
❌ DON'T: Use S3 Standard for infrequent access data
❌ DON'T: Forget to clean up old snapshots
❌ DON'T: Attach EBS volumes across AZs (not possible)
# ❌ NEVER: Create public bucket without justification
s3.create_bucket(Bucket='my-bucket')
s3.put_bucket_acl(Bucket='my-bucket', ACL='public-read')
# All objects publicly accessible!
# ✅ CORRECT: Block public access by default
s3.put_public_access_block(
Bucket='my-bucket',
PublicAccessBlockConfiguration={
'BlockPublicAcls': True,
'IgnorePublicAcls': True,
'BlockPublicPolicy': True,
'RestrictPublicBuckets': True
}
)
# Use presigned URLs for temporary access
❌ Public buckets: Data breaches, compliance violations, security incidents
✅ Correct approach: Block public access, use presigned URLs or CloudFront
# ❌ Don't use S3 Standard for all data
s3.upload_file('archive.zip', 'my-bucket', 'data/archive.zip')
# Paying $0.023/GB for rarely accessed data
# ✅ Correct: Use appropriate storage class
s3.upload_file(
'archive.zip',
'my-bucket',
'data/archive.zip',
ExtraArgs={'StorageClass': 'GLACIER_FLEXIBLE_RETRIEVAL'}
)
# Paying $0.0036/GB for archival data
❌ Wrong storage class: Overpaying for storage based on access patterns
✅ Better: Match storage class to access frequency, use lifecycle policies
aws-lambda-functions.md - Process S3 events with Lambdaaws-ec2-compute.md - Attach EBS volumes to EC2 instancesaws-databases.md - Storage for database backupsaws-networking.md - S3 access through VPC endpointsaws-iam-security.md - S3 bucket policies and IAM permissionsLast Updated: 2025-10-25 Format Version: 1.0 (Atomic)