- Foundation — accounts, identity & guardrailsPublished
- Network & Perimeter — segmentation & private connectivityPublished
- 3Data & Secrets — encryption, KMS & storageYou're reading this
- Detection & Response — logging, CSPM & threat detectionComing Oct 2026
- Govern & Comply — policy-as-code & continuous complianceComing Nov 2026
Cloud Security Program · Part 3 — Data & Secrets: Encryption, Key Management & Storage Hardening
The third deep-dive: encrypt data at rest and in transit, run a disciplined key hierarchy, get secrets out of code, and stop public data exposure across AWS, GCP and Azure.
This is Part 3 of the Cloud Security Program — the data phase, and it only earns its keep because Parts 1 and 2 already exist. Part 1 built the ground: an account/organization hierarchy that isolates blast radius, one governed identity for humans and machines, and org-wide preventative guardrails a well-meaning engineer cannot click past. Part 2 wrapped a network around that: segmentation so a breached workload cannot roam, private connectivity so traffic to your managed services never touches the public internet, default-deny egress so a foothold becomes a dead end, and a hardened, filtered edge in front of everything the world can see. This part turns from the container to the contents — the data itself. Encryption at rest and in transit so intercepted or exfiltrated bytes are useless; a key hierarchy with rotation and separation of duties so the keys are governed as carefully as the data; secrets pulled out of code and environment variables into a managed store, reachable only through workload identity; and storage hardened so it cannot leak to the open internet — still the single most common cause of cloud breaches. None of this replaces the perimeter from Part 2; it assumes it. The private endpoints and guardrails you built are precisely what keep the keys and secrets in this phase reachable only from inside.
As before, the structure is a three-column comparison — AWS, GCP, Azure side by side — because these are the same four controls wearing three different badges. Learn the concept once; apply it three times. And where Part 1's guardrails matter, we call them out: the SCPs / Organization Policies / Azure Policy you inherited are exactly how you make these data baselines non-optional rather than a convention teams remember.
Scope of this phase
Every part of this program is scope-bounded so you know exactly when you are done and are not tempted to boil the ocean.
- In scope: encryption at rest and in transit (default encryption everywhere, customer-managed keys where they buy you something, TLS on every hop); key management (a key hierarchy with rotation, separation of duties, HSM-backed keys, and External Key Management / BYOK for residency and regulatory needs, with key access tied back to the least-privilege identity from Part 1); secrets management (a managed secrets store, rotation, dynamic secrets, access via workload identity rather than static keys); and storage hardening (blocking public access org-wide, plus data classification and residency).
- Explicitly out of scope (later parts): the detection, CSPM and incident-response use of the key-usage and data-access logs you enable here (Part 4); and continuous compliance, drift and framework mapping (Part 5). You will generate key-access and audit telemetry in this phase; you consume it later.
- Definition of done: the exit checklist at the end of this part. When every box is ticked across all three clouds, you are ready for Part 4 — and not before.
Data & secrets, across three clouds
| Building block | AWS | GCP | Azure |
|---|---|---|---|
| Encryption at rest | SSE-KMS · EBS/S3 encryption | Default encryption + CMEK | Storage Service Encryption + disk encryption |
| Key management (KMS) | AWS KMS + CloudHSM | Cloud KMS + Cloud HSM + Cloud EKM | Key Vault + Managed HSM |
| Secrets management | Secrets Manager + Parameter Store | Secret Manager | Key Vault (secrets) |
| Storage public-access | S3 Block Public Access | Public access prevention + uniform access | Disable public access + network rules |
Same four controls on every cloud — encrypt at rest, own your keys, vault your secrets, and block public storage access.
The four building blocks — encryption, key management, secrets, storage hardening — reinforce each other but can be worked in parallel by a small team. Take them one at a time.
Building block 1 — Encryption at rest & in transit
Start from the good news: on all three clouds, data at rest is encrypted by default, with keys the provider manages for you. You cannot create an unencrypted S3 bucket, a plaintext Cloud Storage object, or an unencrypted Azure Storage account — the platform encrypts every block transparently. So the question is never "is it encrypted?" but "who controls the key, and is the transit path encrypted too?"
| Concept | AWS | GCP | Azure |
|---|---|---|---|
| Default at-rest encryption | SSE (S3, EBS, RDS) — always on | Google-managed encryption — always on | Storage Service Encryption / disk encryption — always on |
| Provider-managed key | AWS-owned / AWS-managed KMS key | Google-managed key | Microsoft-managed key |
| Customer-managed key | SSE-KMS with a customer-managed CMK | CMEK (Cloud KMS key) | Customer-managed key in Key Vault / Managed HSM |
| In transit | TLS to endpoints; aws:SecureTransport policy | TLS by default; in-transit encryption on backbone | TLS; "secure transfer required" on Storage |
The meaningful decision is default (provider-managed) versus customer-managed keys (CMK/CMEK). Provider-managed keys are fine for a great deal of low-sensitivity data: they are free, automatic, and rotate without you. You reach for customer-managed keys when you need something the provider key cannot give you: the ability to define exactly who can use the key (a key policy separate from the data-resource policy), an audit trail of every encrypt/decrypt call, control over rotation, and — the big one for regulated workloads — the ability to revoke access to all data at once by disabling a single key (crypto-shredding). If a compliance regime, a customer contract, or a data-residency rule requires you to hold the keys, CMK/CMEK is how. A sensible default: provider-managed for everything, customer-managed for the datasets carrying regulated or high-value data.
Encryption in transit is the other half and is easy to under-do. Default at-rest encryption does nothing for a credential sniffed off an unencrypted internal hop. Require TLS everywhere — not just at the edge (Part 2) but between services, to your databases, and to object storage — and enforce it: an S3 bucket policy that denies any request where aws:SecureTransport is false, "secure transfer required" on Azure Storage, and TLS-only connections to managed databases. This is also where Part 1 pays off: a preventative guardrail can require customer-managed keys on tagged resources and deny the creation of any storage that permits unencrypted transport, so the baseline is enforced by the platform rather than remembered by a reviewer.
Building block 2 — Key management
Once you commit to customer-managed keys, the keys themselves become an asset that needs governance — arguably more than the data, because a key protects thousands of objects. Every cloud gives you a managed KMS with the same shape: a hierarchy in which a hardware-protected root key never leaves the service and is used only to wrap the data keys that actually encrypt your bytes (envelope encryption). You rarely touch a data key directly; you govern the root.
| Concept | AWS | GCP | Azure |
|---|---|---|---|
| Managed KMS | AWS KMS | Cloud KMS | Azure Key Vault |
| HSM-backed keys | KMS custom key store + CloudHSM | Cloud HSM (FIPS 140-2 L3) | Key Vault Managed HSM |
| Automatic key rotation | Yearly rotation on CMKs | Rotation period per key | Rotation policy on keys |
| External / BYOK | External Key Store (XKS) / imported keys | Cloud EKM (external key manager) | BYOK import / Managed HSM |
| Envelope encryption | Data keys wrapped by CMK | DEK wrapped by KEK | Keys wrap storage/disk keys |
Four disciplines make key management real rather than nominal. Rotation: turn on automatic rotation so key material is replaced on a schedule without re-encrypting data (the key hierarchy makes this cheap). Separation of duties: the people who administer a key must not be the same as those who use it to decrypt, and neither should overlap with the owners of the data — you express this through the key policy and IAM, tying it directly to the least-privilege identity model from Part 1. A key policy is where you make "only this workload's role may decrypt, only these two humans may administer, nobody may delete without MFA and a waiting period" concrete:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AppRoleMayUseKeyForDecryptOnly",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:role/prod-app" },
"Action": ["kms:Decrypt", "kms:GenerateDataKey"],
"Resource": "*"
},
{
"Sid": "KeyAdminsManageNotUse",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:role/kms-admins" },
"Action": ["kms:Create*", "kms:Enable*", "kms:Put*", "kms:ScheduleKeyDeletion", "kms:Revoke*"],
"Resource": "*"
}
]
}HSM-backed keys raise the assurance level: for the most sensitive keys, back them with a FIPS-validated hardware security module — CloudHSM behind a KMS custom key store, GCP Cloud HSM, or Azure Managed HSM — so key material provably never exists in software. External key management / BYOK goes furthest and matters when a regulator or a data-residency requirement says the cloud provider must not be able to access your key material unilaterally: AWS External Key Store, GCP Cloud EKM, and Azure BYOK/Managed HSM let the key live in an external key manager (or your own HSM) so that the provider must call out to a system you control for every decrypt — you can cut off access, and therefore all data access, from outside the cloud entirely. Reserve it for the workloads that genuinely need it; it adds real operational weight.
Building block 3 — Secrets management
Encryption and key management protect data at rest; secrets management protects the credentials that unlock everything else. The failure mode is depressingly common and independent of cloud: a database password in a config file, an API token in an environment variable, a private key committed to Git. The fix is a two-parter — get secrets out of code and into a managed store, and change how workloads authenticate so they fetch secrets using their identity rather than holding a static key of their own.
| Concept | AWS | GCP | Azure |
|---|---|---|---|
| Secrets store | Secrets Manager | Secret Manager | Key Vault (secrets) |
| Config / parameters | SSM Parameter Store | Secret Manager | Key Vault / App Configuration |
| Automatic rotation | Built-in (Lambda rotators) | Rotation schedules + notifications | Rotation via Event Grid / functions |
| Dynamic / short-lived creds | RDS/IAM auth, STS | IAM DB auth, short-lived tokens | Entra managed identity, DB tokens |
| Access without static keys | IAM role / instance profile | Workload Identity / service account | Managed identity |
The target state: no long-lived secret ever lives in a repo, an image, or an environment variable. Application secrets — third-party API keys, signing keys, database passwords you cannot avoid — live in the managed secrets store, encrypted with a CMK from building block 2, and are fetched at runtime by a workload that authenticates with its own cloud identity: an IAM role on AWS, Workload Identity on GCP, a managed identity on Azure. That identity, not a static access key, is what grants access to the secret. The result is that there is no bootstrap secret to steal — the machine's identity is conferred by the platform. A minimal retrieval via workload identity, with no static credential anywhere in sight:
import boto3
# No access keys in code or env: the SDK uses the instance/task IAM role
# (the workload's own identity). KMS-decrypt happens server-side, gated by
# the secret's resource policy AND the caller's least-privilege role.
sm = boto3.client("secretsmanager")
db_password = sm.get_secret_value(SecretId="prod/db/password")["SecretString"]Two upgrades pay off quickly. Rotation: enable automatic rotation so a leaked secret has a short useful life; all three stores support scheduled rotation, and for supported databases the store can rotate the credential end to end. Dynamic secrets: better still, prefer credentials that never need storing — IAM database authentication (AWS/GCP) and Entra-based database tokens (Azure) issue short-lived, on-demand credentials tied to the workload's identity, so there is no standing password to rotate or leak at all. This is the same principle as Part 1's move away from static keys, applied to data-tier access. If your organization already runs the DevSecOps program, this is the cloud-side counterpart to its secrets baseline: the CI/CD pipeline injects nothing more than the workload identity, and the workload resolves its own secrets at runtime.
Building block 4 — Storage hardening
Everything above assumes the data is behind a boundary at all. The most common cloud breach is duller than any of it: a storage bucket or blob container set to public, indexed and scraped. Encryption does not help when you have handed out read access to the world. So the final building block is blunt — make public data exposure structurally impossible, then classify what you hold so you know where to spend the effort.
| Concept | AWS | GCP | Azure |
|---|---|---|---|
| Block public access | S3 Block Public Access (account + bucket) | Public Access Prevention (org policy) | Disable "allow blob public access" |
| Uniform access model | Bucket policies / disable ACLs | Uniform bucket-level access | Azure RBAC data-plane, disable anonymous |
| Network restriction | Bucket policy + VPC endpoint (Part 2) | VPC Service Controls (Part 2) | Storage firewall + Private Endpoint (Part 2) |
| Classification / discovery | Macie | Sensitive Data Protection (DLP) | Microsoft Purview |
The single highest-value action here is to block public access at the organization level, not per bucket, so no individual team can re-enable it by accident. On AWS, enable S3 Block Public Access at the account level and disable bucket ACLs so access is governed by policy alone; on GCP, enforce Public Access Prevention as an Organization Policy and turn on uniform bucket-level access so per-object ACLs cannot silently expose data; on Azure, disable "allow blob public access" on storage accounts and require Azure RBAC on the data plane. Each of these is exactly the kind of thing Part 1's guardrail engine should enforce so it cannot be undone:
{
"BlockPublicAcls": true,
"IgnorePublicAcls": true,
"BlockPublicPolicy": true,
"RestrictPublicBuckets": true
}Set this at the account level and enforced org-wide via an SCP, no bucket in the account can be made public — a public-read policy is simply ignored — which removes the entire class of "someone flipped a bucket to public" incidents in one move.
Layer on the network restrictions from Part 2 (VPC endpoints, VPC Service Controls, storage firewalls with Private Endpoints) so the data is not merely non-public but reachable only from inside your perimeter. Then close the loop with data classification: you cannot protect what you have not inventoried. Run the provider's discovery service — Macie (AWS), Sensitive Data Protection / DLP (GCP), Microsoft Purview (Azure) — to find where regulated data (PII, cardholder data, health records) actually lives, tag it, and use those tags to drive the earlier decisions: which datasets get customer-managed keys, which need HSM-backed or external keys, and which carry residency constraints that dictate the regions and key-management model you are allowed to use. Classification is what turns a blanket policy into a proportionate one.
Definition of done — Data & Secrets exit checklist
You are ready for Part 4 when every one of these is true, in each cloud you run:
- Encryption at rest: default encryption confirmed on all storage, disks and managed databases; customer-managed keys (CMK/CMEK) applied to every dataset carrying regulated or high-value data, with a documented rule for when default keys suffice.
- Encryption in transit: TLS enforced on every hop — edge, service-to-service, to databases and object storage — with policy that denies unencrypted transport (
aws:SecureTransportfalse, Azure "secure transfer required", TLS-only DB connections). - Key management: a governed key hierarchy with automatic rotation on; separation of duties between key admins, key users and data owners expressed in key policy + IAM and tied to Part 1's identities; HSM-backed keys for the most sensitive material; External Key Management / BYOK (XKS / Cloud EKM / Managed HSM) evaluated for residency- or regulator-driven workloads; key deletion guarded (waiting period, MFA).
- Secrets management: no long-lived secret in any repo, image or environment variable; secrets in the managed store encrypted with a CMK; workloads fetch them via workload identity (IAM role / Workload Identity / managed identity), never a static key; automatic rotation enabled; dynamic / IAM-based database credentials used where supported.
- Storage hardening: public access blocked org-wide via Part 1's guardrails (S3 Block Public Access / Public Access Prevention / disabled blob public access); uniform access model in force (ACLs disabled / uniform bucket-level access / RBAC data plane); storage reachable only from inside the perimeter using Part 2's private connectivity.
- Classification & residency: sensitive data discovered and tagged via Macie / Sensitive Data Protection / Purview; classification driving key choice and residency; residency constraints mapped to allowed regions and key-management model.
Tick every box and the data is protected in depth — encrypted, key-governed, secret-free in code, and impossible to expose publicly. Skip one — the one bucket still ACL-public, the database password still in an env var, the CMK whose admins can also decrypt — and it becomes the exact asset a later incident walks off with.
What's next
Part 4 — Detection & Response turns from prevention to what happens when something slips past it. With accounts, identity and guardrails (Part 1), a contained network (Part 2), and encrypted, key-governed, non-public data (Part 3) all in place, we design the visibility layer: centralized logging across all three clouds, the CSPM and threat-detection services (GuardDuty / Security Command Center / Microsoft Defender for Cloud) that consume the flow logs, firewall drops, key-usage records and data-access trails you have been generating throughout this program, and the incident-response runbooks that turn an alert into a contained, evidenced response. The key-access and secret-retrieval logs you switched on here are among the highest-signal detections in the whole estate — anomalous decrypt volume or an out-of-pattern secret fetch is often the first sign of compromise. It ships next month.
Standing up the data layer is also where a platform earns its keep a second time: ISMShed captures your encryption coverage, key-management posture, secrets hygiene and public-access controls as continuous, framework-mapped audit evidence across ISO 27001, ENS, NIS2, DORA, SOC 2 and GDPR — so the data-protection controls this phase produces become your compliance story rather than a spreadsheet you rebuild before every audit. And if you would like experienced hands to design the encryption model, key hierarchy and secrets baseline across your own AWS, GCP and Azure estate, Axelia's cloud-security and GRC consultants run the program alongside you. Protect the data now, and the detection work in Part 4 has something worth defending.
