PHI-Compliant S3: aws:SecureTransport + SSE-KMS for Encryption in Transit and at Rest

Ned
Ned Cloud Engineer
· Updated · 3 min read
PHI-Compliant S3: aws:SecureTransport + SSE-KMS for Encryption in Transit and at Rest

The Problem

A hospital needs to store patient records in S3. Compliance requires:

  • All PHI encrypted in transit
  • All PHI encrypted at rest
  • The compliance team must administer the encryption key

You need a solution that enforces both encryption boundaries and hands the compliance team full key control.

The Solution

Two layers:

  1. Bucket policy with aws:SecureTransport condition — rejects any request not using HTTPS/TLS (in transit)
  2. Default encryption using SSE-KMS with a customer-managed key — compliance team owns the key policy (at rest)

How It Works

Step 1: Bucket Policy That Blocks Non-HTTPS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "DenyInsecureTransport",
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:*",
    "Resource": [
      "arn:aws:s3:::phi-records",
      "arn:aws:s3:::phi-records/*"
    ],
    "Condition": {
      "Bool": { "aws:SecureTransport": "false" }
    }
  }]
}

Any request over HTTP (not HTTPS) evaluates aws:SecureTransport as false and gets denied. This is a hard block — even if IAM would allow the action, the bucket policy deny wins.

Step 2: Create the KMS Key Owned by Compliance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
aws kms create-key --description "PHI encryption key" \
  --policy '{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Sid": "AllowComplianceAdmin",
        "Effect": "Allow",
        "Principal": { "AWS": "arn:aws:iam::123456789012:role/ComplianceTeam" },
        "Action": ["kms:*"],
        "Resource": "*"
      },
      {
        "Sid": "AllowS3UseOfTheKey",
        "Effect": "Allow",
        "Principal": { "AWS": "arn:aws:iam::123456789012:role/PhiApp" },
        "Action": ["kms:Encrypt", "kms:Decrypt", "kms:GenerateDataKey*"],
        "Resource": "*"
      }
    ]
  }'

The compliance team can manage rotation, disable the key, or delete it. Application roles can only use it.

Step 3: Set SSE-KMS as Default Bucket Encryption

1
2
3
4
5
6
7
8
9
10
aws s3api put-bucket-encryption \
  --bucket phi-records \
  --server-side-encryption-configuration '{
    "Rules": [{
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "aws:kms",
        "KMSMasterKeyID": "alias/phi-encryption"
      }
    }]
  }'

Why Not the Alternatives?

ACM certificate on S3 — You cannot attach an ACM cert to an S3 bucket endpoint. S3 provides its own TLS certificates automatically.

aws:SecureTransport + SSE-S3 — SSE-S3 keys are fully AWS-managed. The compliance team cannot administer them. Fails the key administration requirement.

aws:SecureTransport + Macie — Macie is a discovery service, not an encryption service. It finds PII but doesn’t encrypt anything at rest.

Key Takeaways

  • aws:SecureTransport condition in a bucket policy enforces HTTPS for all requests
  • SSE-KMS with a customer-managed key lets you separate key administration from data usage
  • Split the KMS key policy: compliance team gets kms:*, applications get only kms:Encrypt/kms:Decrypt
  • S3 does not accept custom certificates — encryption in transit is enforced via bucket policy, not cert configuration
  • Always use Deny for security-critical bucket policies — deny statements are the last word in policy evaluation
Rating:
Share
Previous Private S3 Access with VPC Endpoints: No Internet, No NAT Gateway, No Public IP Next S3 Interface VPC Endpoint: Private Access With Fine-Grained IAM Role Restriction