Storage & Data Security

Encryption at Rest and in Transit

4 min read

Encryption is non-negotiable in cloud security. Every major compliance framework requires it, and modern cloud providers make it nearly effortless—yet many organizations still get it wrong.

Encryption at Rest

AWS S3 Encryption Options

Option Key Management Use Case
SSE-S3 AWS-managed (free) Default, baseline protection
SSE-KMS Customer-managed in KMS Audit trail, key rotation
SSE-C Customer-provided Strict key control requirements
Client-side Customer-managed End-to-end encryption

Enabling default encryption:

# Enable default SSE-KMS encryption on bucket
aws s3api put-bucket-encryption --bucket my-bucket \
    --server-side-encryption-configuration '{
        "Rules": [{
            "ApplyServerSideEncryptionByDefault": {
                "SSEAlgorithm": "aws:kms",
                "KMSMasterKeyID": "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"
            },
            "BucketKeyEnabled": true
        }]
    }'

KMS key policy for S3:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowS3Service",
      "Effect": "Allow",
      "Principal": {
        "Service": "s3.amazonaws.com"
      },
      "Action": [
        "kms:Decrypt",
        "kms:GenerateDataKey"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "kms:CallerAccount": "123456789012"
        }
      }
    }
  ]
}

Azure Encryption Options

Option Key Management Use Case
Microsoft-managed Azure-managed Default
Customer-managed key (CMK) Azure Key Vault Compliance requirements
Double encryption Infrastructure + service High security

Configure CMK encryption:

# Create Key Vault and key
az keyvault create --name myKeyVault --resource-group myRG --location eastus
az keyvault key create --vault-name myKeyVault --name storageKey --protection software

# Configure storage account with CMK
az storage account update \
    --name mystorageaccount \
    --resource-group myRG \
    --encryption-key-name storageKey \
    --encryption-key-vault "https://myKeyVault.vault.azure.net/" \
    --encryption-key-source Microsoft.Keyvault

GCP Encryption Options

Option Key Management Use Case
Google-managed Google-managed Default
Customer-managed (CMEK) Cloud KMS Compliance
Customer-supplied (CSEK) Customer holds keys Strict control

Configure CMEK for Cloud Storage:

# Create key ring and key
gcloud kms keyrings create my-keyring --location=global
gcloud kms keys create my-key \
    --location=global \
    --keyring=my-keyring \
    --purpose=encryption

# Create bucket with CMEK
gcloud storage buckets create gs://my-encrypted-bucket \
    --default-encryption-key=projects/my-project/locations/global/keyRings/my-keyring/cryptoKeys/my-key

Encryption in Transit

TLS Requirements

All modern cloud services enforce TLS, but you must ensure clients respect it:

AWS S3 - Enforce HTTPS only:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "DenyHTTP",
    "Effect": "Deny",
    "Principal": "*",
    "Action": "s3:*",
    "Resource": [
      "arn:aws:s3:::my-bucket",
      "arn:aws:s3:::my-bucket/*"
    ],
    "Condition": {
      "Bool": {
        "aws:SecureTransport": "false"
      }
    }
  }]
}

Azure - Require secure transfer:

az storage account update \
    --name mystorageaccount \
    --resource-group myRG \
    --https-only true \
    --min-tls-version TLS1_2

GCP - TLS is always enforced for Cloud Storage.

Avoid traversing the public internet entirely:

AWS VPC Endpoint:

# Terraform - S3 VPC Gateway Endpoint
resource "aws_vpc_endpoint" "s3" {
  vpc_id       = aws_vpc.main.id
  service_name = "com.amazonaws.us-east-1.s3"

  route_table_ids = [
    aws_route_table.private.id
  ]

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = "*"
      Action    = "s3:*"
      Resource  = ["arn:aws:s3:::my-bucket/*"]
    }]
  })
}

Azure Private Endpoint:

az network private-endpoint create \
    --name myStoragePrivateEndpoint \
    --resource-group myRG \
    --vnet-name myVNet \
    --subnet mySubnet \
    --private-connection-resource-id "/subscriptions/.../storageAccounts/mystorageaccount" \
    --group-id blob \
    --connection-name myConnection

Key Management Best Practices

Key Rotation

Provider Default Rotation Recommendation
AWS KMS Automatic (yearly) Enable automatic rotation
Azure Key Vault Manual by default Configure auto-rotation
GCP Cloud KMS Manual Schedule rotation

AWS KMS automatic rotation:

aws kms enable-key-rotation --key-id 12345678-1234-1234-1234-123456789012

Key Access Auditing

# AWS - View KMS key usage in CloudTrail
aws cloudtrail lookup-events \
    --lookup-attributes AttributeKey=ResourceType,AttributeValue=AWS::KMS::Key

# Azure - Key Vault diagnostics
az monitor diagnostic-settings create \
    --name KeyVaultDiagnostics \
    --resource "/subscriptions/.../vaults/myKeyVault" \
    --logs '[{"category": "AuditEvent", "enabled": true}]'

Encryption Decision Matrix

Scenario At Rest In Transit Key Management
General data SSE-S3/Default HTTPS Provider-managed
PII/PHI SSE-KMS/CMK HTTPS + VPC Customer-managed
Financial data SSE-KMS/CMK Private Link Customer-managed + HSM
Top secret Client-side Private Link Customer-supplied

Next, we'll explore access policy patterns and how to prevent accidental public exposure. :::

Quiz

Module 3: Storage & Data Security

Take Quiz