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

OptionKey ManagementUse Case
SSE-S3AWS-managed (free)Default, baseline protection
SSE-KMSCustomer-managed in KMSAudit trail, key rotation
SSE-CCustomer-providedStrict key control requirements
Client-sideCustomer-managedEnd-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

OptionKey ManagementUse Case
Microsoft-managedAzure-managedDefault
Customer-managed key (CMK)Azure Key VaultCompliance requirements
Double encryptionInfrastructure + serviceHigh 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

OptionKey ManagementUse Case
Google-managedGoogle-managedDefault
Customer-managed (CMEK)Cloud KMSCompliance
Customer-supplied (CSEK)Customer holds keysStrict 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

ProviderDefault RotationRecommendation
AWS KMSAutomatic (yearly)Enable automatic rotation
Azure Key VaultManual by defaultConfigure auto-rotation
GCP Cloud KMSManualSchedule 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

ScenarioAt RestIn TransitKey Management
General dataSSE-S3/DefaultHTTPSProvider-managed
PII/PHISSE-KMS/CMKHTTPS + VPCCustomer-managed
Financial dataSSE-KMS/CMKPrivate LinkCustomer-managed + HSM
Top secretClient-sidePrivate LinkCustomer-supplied

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

Quick check: how does this lesson land for you?

Quiz

Module 3: Storage & Data Security

Take Quiz
FREE WEEKLY NEWSLETTER

Stay on the Nerd Track

One email per week — courses, deep dives, tools, and AI experiments.

No spam. Unsubscribe anytime.