Cloud Security Best Practices
Cloud security isn't a separate discipline bolted on after architecture — it's woven into every decision you've made in the preceding lessons. This lesson synthesizes the security principles that apply across providers and walks through the controls that actually prevent breaches versus the ones that just generate compliance paperwork.
Cloud Security Architecture -- Defense in Depth
Attack Chain 1: Leaked Credentials
Public Repo
Key leaked
IAM
Authenticate
Permissions
Enumerate
Admin Role
Escalate
S3
Access data
Internet
Exfiltrate
Hardened: Same Attack, Defense in Depth
IAM Roles Anywhere
Federated creds
Least Privilege
Scoped role
VPC Endpoint
Egress filtered
Attack Chain 2: SSRF + Metadata (Capital One Pattern)
Web App
SSRF vuln
IMDSv2
169.254.169.254
Instance Creds
Token stolen
IMDSv2
v2 / Token required
GuardDuty
Continuous monitoring
SCP
Org-wide guardrails
Each control independently breaks the chain. Together they are defense in depth.
Shared Responsibility Revisited
Every provider publishes a shared responsibility model, and every breach happens in the customer's half. The provider secures the infrastructure — physical datacenters, hypervisors, the network fabric. You secure everything you put on top: configurations, identities, data, and application code. Misunderstanding this boundary is the root cause of most cloud incidents.
The line shifts depending on the service tier. With EC2/GCE/Azure VMs, you own the OS, patching, and everything above. With managed services like RDS or Cloud SQL, the provider handles patching but you own access control and encryption configuration. With serverless (Lambda, Cloud Functions), the provider owns nearly everything — but you still own IAM policies and application logic.
Identity Is the Perimeter
The network perimeter is gone. Identity is how you control access in cloud, and getting it wrong is the most common path to a breach.
Least privilege, always. No *:* policies, no Admin roles on service accounts. Start with zero permissions and add only what's needed. Review permissions quarterly and revoke what's unused. AWS IAM Access Analyzer, GCP IAM Recommender, and Azure Advisor all flag over-permissive roles.
No long-lived keys. Access keys in environment variables, config files, or (worst) committed to git are the number one cause of cloud breaches. Use IAM roles for EC2, workload identity for GKE, managed identities for Azure VMs. For CI/CD, use OIDC federation — GitHub Actions, GitLab, and all major CI systems support it. There should be zero access keys in your organization that aren't on an active deprecation plan.
Workload identity federation lets external identities (CI runners, on-prem services, other clouds) assume roles without storing credentials. AWS STS AssumeRoleWithWebIdentity, GCP Workload Identity Federation, Azure federated credentials. This is how modern CI/CD authenticates to cloud.
SCPs and Organization Policies are preventive guardrails. AWS Service Control Policies can deny actions across an entire organization — deny root user access, deny creating resources outside approved regions, deny disabling CloudTrail. GCP Organization Policies do the same. Azure Policy provides deny-by-default governance. These are your seatbelts.
MFA on root accounts is mandatory. Full stop. Every provider root/owner account should have hardware MFA keys, and the credentials should be locked in a safe, not in someone's password manager.
Network Hardening
Private subnets by default. Your databases, application servers, and internal services should never have public IPs. Use NAT gateways for outbound internet access from private subnets, and load balancers as the only public-facing entry point.
No 0.0.0.0/0 ingress. Every security group and firewall rule allowing traffic from anywhere is a ticking clock. Audit these regularly. SSH/RDP access should go through bastion hosts, Session Manager (AWS), IAP tunnels (GCP), or Azure Bastion — never directly exposed.
Private endpoints (AWS PrivateLink, GCP Private Service Connect, Azure Private Link) keep traffic to managed services on the provider's backbone network rather than traversing the internet. Use them for S3, databases, and any service that offers them.
Egress filtering is the neglected half of network security. Know what your workloads should be talking to and block everything else. A compromised instance that can reach the internet freely can exfiltrate data and download attack tools.
Data Protection
Encryption at rest is table stakes — enable it by default on every storage service. All three providers offer this with provider-managed keys at no extra cost. Use customer-managed keys (CMKs) through KMS/Cloud KMS/Azure Key Vault when you need key rotation control, cross-account access policies, or compliance requirements mandate it.
Encryption in transit means TLS everywhere. Between services, between your app and the database, between availability zones. Managed services handle this automatically; for your own services, enforce it.
No public buckets. S3 Block Public Access should be enabled at the account level. GCP's uniform bucket-level access eliminates object-level ACL confusion. Azure Storage accounts should have public access disabled by default. The number of breaches caused by public buckets is staggering and entirely preventable.
Secrets belong in a secrets manager — AWS Secrets Manager, GCP Secret Manager, Azure Key Vault. Not in environment variables, not in config files, not in CI/CD variables. Rotate secrets automatically. Database passwords, API keys, certificates — all of them.
Compute Security
Immutable infrastructure means you never patch a running server — you build a new image and replace it. This eliminates configuration drift and ensures every instance is in a known state. If you're SSHing into production to fix things, your deployment pipeline is broken.
IMDSv2 on AWS is critical. The instance metadata service (IMDS) is how EC2 instances get their IAM credentials. IMDSv1 is vulnerable to SSRF attacks — an attacker who can make your application issue HTTP requests can steal your instance's IAM credentials. The Capital One breach used exactly this vector. IMDSv2 requires a session token, which mitigates SSRF. Enforce it account-wide.
AWS Implementation
AWS security building blocks: IAM for identity, Security Groups and NACLs for network, KMS for encryption keys, CloudTrail for API audit logging (enable it in every region), GuardDuty for threat detection (ML-based anomaly detection on CloudTrail, VPC Flow Logs, and DNS), Security Hub for aggregating findings, Config for resource compliance rules, Organizations + SCPs for governance.
GCP Implementation
GCP equivalents: IAM with organization/folder/project hierarchy, VPC Firewall Rules (and hierarchical firewall policies), Cloud KMS for keys, Cloud Audit Logs for API logging, Security Command Center (SCC) for threat detection and vulnerability scanning, Organization Policies for preventive guardrails, BeyondCorp Enterprise for zero-trust access. GCP's VPC Service Controls create security perimeters around services to prevent data exfiltration.
Azure Implementation
Azure security stack: Entra ID (formerly Azure AD) for identity (deeply integrated with M365), NSGs and Azure Firewall for network, Azure Key Vault for keys and secrets, Activity Logs and Diagnostic Logs for auditing, Microsoft Defender for Cloud for threat detection, posture management, and compliance scoring, Azure Policy for governance. Conditional Access policies in Entra ID are powerful for context-based access control.
Side-by-Side Comparison
| Aspect | AWS | GCP | Azure |
|---|---|---|---|
| Threat detection | GuardDuty | Security Command Center | Defender for Cloud |
| Audit logging | CloudTrail | Cloud Audit Logs | Activity Logs |
| Key management | KMS | Cloud KMS | Key Vault |
| Secrets management | Secrets Manager | Secret Manager | Key Vault (secrets) |
| Policy guardrails | SCPs | Organization Policies | Azure Policy |
| Workload identity | IAM Roles + OIDC | Workload Identity Federation | Managed Identities + Federated Credentials |
| Zero-trust access | Session Manager / Verified Access | BeyondCorp / IAP | Azure Bastion / Conditional Access |
Prevention Over Detection
Detection is important but insufficient. By the time GuardDuty alerts you to anomalous API calls, the damage may be done. Prevention means policy-as-code: OPA/Gatekeeper, Sentinel, Checkov, tfsec scanning your IaC in CI before anything deploys. CSPM (Cloud Security Posture Management) continuously checks your configuration against benchmarks. IaC scanning in CI catches misconfigurations before they reach production.
The breach patterns that keep repeating: a public S3 bucket exposing customer data, an access key leaked in a git commit, an over-permissive IAM role allowing lateral movement, an SSRF vulnerability hitting the metadata service to steal credentials. Every one of these is preventable with the controls above.
Key Takeaways
- Identity is the perimeter — eliminate long-lived keys, use workload identity federation, enforce least privilege, and require MFA on all root/owner accounts
- Private by default: private subnets, no public IPs on workloads, private endpoints for managed services, egress filtering
- Encrypt everything (at rest and in transit), keep secrets in a secrets manager with rotation, and never allow public storage buckets
- Prevention beats detection: scan IaC in CI, enforce SCPs/org policies, and use CSPM to catch misconfigurations before they reach production
- The same breach patterns repeat endlessly (public buckets, leaked keys, SSRF to metadata) — all are preventable with standard controls
- IMDSv2 on AWS, immutable infrastructure everywhere, and no SSH into production
Next, we'll look at defining all of this infrastructure as version-controlled code.
Enjoyed this breakdown?
Get new lessons in your inbox.