Skip to content
AWS aws security 6 min read

Encryption at Rest & in Transit

Encryption is how you keep data unreadable to anyone who isn’t supposed to see it. In AWS there are two completely separate jobs to do: protect data while it sits on disk (encryption “at rest”), and protect data while it travels over a network (encryption “in transit”). They solve different problems, and doing one does not do the other. This page explains both, where each applies, and the most common trap teams fall into.

At rest vs in transit — what each one actually protects

Encryption at rest scrambles data while it is stored — on an S3 (Simple Storage Service, AWS’s object storage) bucket, an EBS (Elastic Block Store, the virtual hard disks attached to servers) volume, or an RDS (Relational Database Service, managed databases) instance. If someone walks off with the physical disk, or gains raw access to the storage layer, the bytes are useless without the key.

Encryption in transit scrambles data while it moves across a network, using TLS (Transport Layer Security, the protocol behind HTTPS). It stops anyone “on the wire” — a compromised network device, a sniffing attacker — from reading or tampering with the data as it flows between your app and an AWS service, or between your users and your app.

Most at-rest encryption in AWS is backed by KMS (Key Management Service, AWS’s managed key vault). KMS holds the master keys, controls who can use them through IAM (Identity and Access Management) policies, and logs every use in CloudTrail.

ConcernEncryption at restEncryption in transit
Protects againstStolen disks, raw storage access, backups leakingNetwork eavesdropping, man-in-the-middle attacks
MechanismKMS-backed AES-256 on the storage layerTLS 1.2 / 1.3 on the connection
Where you turn it onS3 buckets, EBS volumes, RDS, DynamoDB, EFSService endpoints (HTTPS), load balancers, DB connections
Default in 2026?Often yes (S3, new EBS, many RDS engines)Endpoints support it; you must enforce/require it

The number one gotcha: “We’re encrypted” usually means only one of these. Turning on S3 or EBS encryption protects the stored bytes but does NOTHING for data moving over the network — you still need TLS. And TLS protects the connection but leaves nothing protecting the data once it lands on disk. You need BOTH for end-to-end protection.

Encryption at rest

When to use it

Always, for anything holding real data. It is cheap, usually free or near-free, and frequently required by compliance frameworks like HIPAA, PCI DSS, and SOC 2. There is rarely a reason NOT to enable it — the main exception is throwaway scratch storage where the data is genuinely worthless.

S3 — encrypted by default

Since 2023, all new S3 objects are encrypted at rest automatically using SSE-S3 (server-side encryption with S3-managed keys). You can upgrade a bucket to SSE-KMS so you control the key and get CloudTrail logging of key usage.

Console steps:

  1. Open the S3 console and click your bucket.
  2. Go to the Properties tab.
  3. Under Default encryption, click Edit.
  4. Choose Server-side encryption with AWS Key Management Service keys (SSE-KMS).
  5. Pick a KMS key (AWS-managed or one of yours), then Save changes.

CLI:

aws s3api put-bucket-encryption \
  --bucket my-app-prod-data \
  --server-side-encryption-configuration '{
    "Rules": [{
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "aws:kms",
        "KMSMasterKeyID": "arn:aws:kms:us-east-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"
      },
      "BucketKeyEnabled": true
    }]
  }'

Output:

(no output on success; exit code 0)

Cost note: BucketKeyEnabled: true is important. It cuts KMS API calls dramatically by caching a bucket-level key, which can reduce KMS request charges (about $0.03 per 10,000 requests) by 99% on high-traffic buckets.

EBS and RDS — must be set at creation

This is the second big gotcha. For EBS volumes and most RDS instances, encryption must be enabled when you create the resource. You cannot simply flip a switch on an existing unencrypted volume or database.

To retrofit encryption you do the “snapshot dance”: take a snapshot, copy that snapshot with encryption enabled, then create a new volume or DB from the encrypted copy and cut over.

Encrypt an existing EBS volume (CLI):

# 1. Snapshot the unencrypted volume
aws ec2 create-snapshot --volume-id vol-0a1b2c3d4e5f --description "pre-encryption"

# 2. Copy the snapshot WITH encryption (this is the step that adds encryption)
aws ec2 copy-snapshot \
  --source-region us-east-1 \
  --source-snapshot-id snap-0a1b2c3d4e5f \
  --encrypted \
  --kms-key-id alias/aws/ebs \
  --description "encrypted copy"

# 3. Create a new encrypted volume from the encrypted snapshot
aws ec2 create-volume \
  --availability-zone us-east-1a \
  --snapshot-id snap-0fedcba987654321

Output:

{
    "VolumeId": "vol-0fedcba987654321",
    "Encrypted": true,
    "KmsKeyId": "arn:aws:kms:us-east-1:111122223333:key/abcd1234-...",
    "State": "creating"
}

You then detach the old volume and attach the new encrypted one (this requires stopping the instance). For RDS, the equivalent is create-db-snapshotcopy-db-snapshot --kms-key-id ...restore-db-instance-from-db-snapshot, followed by repointing your app at the new endpoint.

Tip: Turn on EBS encryption by default for your whole account/region so you never create an unencrypted volume by accident: aws ec2 enable-ebs-encryption-by-default. This avoids the snapshot dance entirely going forward.

Encryption in transit

When to use it

For any traffic carrying credentials, personal data, or anything sensitive — which is almost everything. The exceptions are minimal (e.g. fully public, read-only content), and even there TLS prevents tampering, so enabling it is the safe default.

TLS for your application traffic

The most common place you configure this is on an ALB (Application Load Balancer). You attach a certificate from ACM (AWS Certificate Manager, which issues free TLS certificates) to an HTTPS listener.

Console steps:

  1. Open EC2 > Load Balancers and select your ALB.
  2. Go to Listeners and rules and click Add listener.
  3. Set Protocol to HTTPS and Port to 443.
  4. Under Default SSL/TLS certificate, choose a certificate from ACM.
  5. Pick a modern Security policy (e.g. ELBSecurityPolicy-TLS13-1-2-2021-06) and save.

CLI — create the HTTPS listener:

aws elbv2 create-listener \
  --load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:111122223333:loadbalancer/app/my-alb/0a1b2c3d \
  --protocol HTTPS --port 443 \
  --ssl-policy ELBSecurityPolicy-TLS13-1-2-2021-06 \
  --certificates CertificateArn=arn:aws:acm:us-east-1:111122223333:certificate/0a1b2c3d-4e5f \
  --default-actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:us-east-1:111122223333:targetgroup/web/0a1b2c3d

Output:

{
    "Listeners": [{
        "ListenerArn": "arn:aws:...:listener/app/my-alb/0a1b2c3d/9f8e7d6c",
        "Port": 443,
        "Protocol": "HTTPS",
        "SslPolicy": "ELBSecurityPolicy-TLS13-1-2-2021-06"
    }]
}

Enforcing TLS — not just offering it

Supporting HTTPS is not the same as requiring it. Force it explicitly:

  • Redirect HTTP to HTTPS on the ALB so plain port-80 traffic is bounced to 443.
  • Require TLS on S3 with a bucket policy that denies any request where aws:SecureTransport is false.
  • Require TLS to RDS by enforcing SSL connections (e.g. rds.force_ssl=1 in a parameter group for PostgreSQL).
# Terraform: deny non-TLS access to an S3 bucket
data "aws_iam_policy_document" "require_tls" {
  statement {
    effect    = "Deny"
    actions   = ["s3:*"]
    resources = ["arn:aws:s3:::my-app-prod-data", "arn:aws:s3:::my-app-prod-data/*"]
    principals {
      type        = "*"
      identifiers = ["*"]
    }
    condition {
      test     = "Bool"
      variable = "aws:SecureTransport"
      values   = ["false"]
    }
  }
}

Best Practices

  • Enable BOTH at rest and in transit — verify each independently rather than assuming one “covers” you.
  • Turn on EBS encryption by default account-wide so you never ship an unencrypted volume.
  • Plan RDS/EBS encryption at creation time; budget downtime for the snapshot-copy retrofit on anything already running.
  • Use customer-managed KMS keys (not just AWS-managed) when you need fine-grained access control and CloudTrail auditing of key usage.
  • Enable BucketKeyEnabled on S3 to slash KMS request costs on busy buckets.
  • Enforce TLS with explicit denies and redirects — don’t just leave HTTPS as an option alongside plaintext.
  • Use a modern TLS security policy (1.2 minimum, 1.3 where supported) and let ACM auto-renew your certificates.
Last updated June 15, 2026
Was this helpful?