Frontend Labs
⋯

Part 2 — Cloud security foundations

The cloud moved the most important security control from the network to identity. This Part is about the identity plane, the guardrails around it, the network that remains, and the data underneath — with AWS as the primary worked example and GCP/Azure equivalents noted throughout.

Chapter 5 — The cloud security model and the identity plane

In one sentence

In the cloud, "who can call which API on which resource" — the IAM policy graph — is the primary security boundary, and most cloud breaches are a walk through that graph, not a memory-corruption exploit.

Where we are

You know network segmentation, TLS, and app security. In the cloud those still matter, but the provider runs the hypervisor, the network fabric, and the managed services. What you configure is: identities, their permissions, resource policies, network rules, encryption settings, and logging. The attack surface that's uniquely yours is misconfiguration of those, and the currency of attack is credentials and API calls.

How it works

The shared responsibility model (know exactly where the line is):

   PROVIDER secures ("security OF the cloud"):
     physical DCs, hardware, hypervisor, the global network backbone,
     managed-service internals (RDS engine host, S3 storage layer, the
     Lambda sandbox).

   YOU secure ("security IN the cloud"):
     IAM (identities, policies, roles, federation),
     resource configuration (bucket policies, SG rules, KMS key policies,
       public/private settings, versioning),
     OS + app on anything you run (EC2, containers, functions' code),
     network design (VPC, subnets, routing, endpoints),
     data (classification, encryption choices, retention),
     detection & response for your account activity.

   The line MOVES by service model:
     IaaS (EC2)      you patch the OS.
     PaaS (RDS)      provider patches the engine; you patch nothing, but you
                     configure access, encryption, network, backups.
     FaaS (Lambda)   provider runs everything; you own the code, its deps,
                     its IAM role, and its triggers.
     SaaS            you own configuration and data governance only.

The identity plane. Every cloud action is an authenticated, authorised, logged API call. The pieces:

   PRINCIPALS
     - human users (federated from your IdP -- ideally NO long-lived IAM
       users; use SSO -> temporary role sessions)
     - workload identities: an EC2 instance profile, an EKS pod role (IRSA),
       a Lambda execution role, a GCP service account, an Azure managed
       identity
     - external principals: another account, a partner, a SaaS integration
       (cross-account role assumption -- a common breach vector)

   CREDENTIALS
     - long-lived: IAM access keys, service-account key files -> the thing
       that leaks (G1 Ch 49). Aim to have ~none.
     - temporary: STS session tokens (AssumeRole), OIDC-federated tokens,
       instance metadata creds -> short TTL, the goal state.

   PERMISSIONS
     - identity-based policies (attached to the principal)
     - resource-based policies (attached to the resource: bucket policy,
       KMS key policy, role trust policy)
     - guardrails: SCPs (org-wide caps), permission boundaries (per-principal
       cap), session policies (per-session cap)

   EVERY call is evaluated against ALL of these, and LOGGED (CloudTrail /
   Cloud Audit Logs / Azure Activity Log). The log is your primary
   detection data source (Ch 54).

Provider mapping:

Concept AWS GCP Azure
Identity service IAM + IAM Identity Center Cloud IAM Entra ID + Azure RBAC
Workload identity Instance profile / IRSA / Pod Identity Service account + Workload Identity Managed identity
Org guardrail SCP (Organizations) Org Policy + IAM deny policies Azure Policy + Management Groups
Per-principal cap Permissions boundary (no direct equiv; use deny policies) (no direct equiv)
Audit log CloudTrail Cloud Audit Logs Activity Log + Entra logs
Native CSPM/threat Security Hub / GuardDuty Security Command Center Defender for Cloud
Metadata endpoint 169.254.169.254 (IMDSv2) metadata.google.internal 169.254.169.254 (Metadata:true)

Worked example

Trace one S3 read, end to end, so the plane is concrete.

   `exports-worker` (a pod in EKS) calls s3:GetObject on
   arn:aws:s3:::ss-exports/tenant-42/invoice-2026-08.pdf

   1. The pod has a projected ServiceAccount token (audience sts.amazonaws
      .com) mounted by the EKS Pod Identity webhook.
   2. The AWS SDK calls sts:AssumeRoleWithWebIdentity, presenting that
      token. STS checks the role's TRUST POLICY: does it trust the cluster
      OIDC provider AND this exact ServiceAccount (sub =
      system:serviceaccount:core:exports-worker)? Yes -> returns a
      15-min-to-1-hour session credential for role `exports-worker-role`.
   3. The SDK calls s3:GetObject with that session credential.
   4. AWS evaluates:
        - SCP on the account: does it allow s3:GetObject? (org guardrail)
        - Identity policy on `exports-worker-role`: Allow s3:GetObject on
          arn:aws:s3:::ss-exports/*  ? yes
        - Permission boundary on the role, if any: allows it? yes
        - Bucket policy on ss-exports: no explicit Deny for this principal?
          correct -- and it may not even need an Allow (same-account
          identity policy suffices)
        - Is the object encrypted with a KMS key? then also: does the role
          have kms:Decrypt on that key, AND does the KEY POLICY allow the
          role? BOTH must pass.
        - Any explicit Deny anywhere (SCP, boundary, bucket policy, VPC
          endpoint policy)? -> if yes, DENIED regardless of Allows.
      All pass -> object returned.
   5. CloudTrail (S3 data events enabled on this bucket) logs: principal,
      role session name, source IP (the pod's NAT IP or a VPC endpoint),
      the object key, whether it was a VPC-endpoint call, the KMS key used.

   Attack surface visible here: the OIDC trust condition (too loose -> any
   pod assumes the role), the identity policy resource (`ss-exports/*` vs
   `ss-exports/tenant-42/*`), the KMS key policy, and whether data events
   are even logged.

Real-world scenario: the shared-responsibility gap, at scale

   In 2017, security researchers at UpGuard found a publicly-accessible
   Amazon S3 bucket, owned by a THIRD-PARTY TELECOM VENDOR (NICE Systems)
   working for Verizon, containing roughly 14 million Verizon customer
   records (names, addresses, account PINs, and in some cases account
   details usable for account takeover). The bucket had NO access
   restriction at all -- anyone with the URL could download it.
   This is the shared-responsibility model (this chapter's opening
   framing) failing at the SEAM between two organisations: Verizon's own
   infrastructure was not directly at fault, but the VENDOR's resource
   configuration -- squarely "security IN the cloud," the customer's
   (here, the vendor-as-customer's) job, never the provider's -- was
   simply never set. Nobody on either side owned the question "is this
   specific bucket's access configuration actually correct," which is
   exactly why Part 2 Ch 7's guardrails (a org-wide policy denying
   public buckets, enforced automatically, not requested politely) exist
   -- and why this responsibility boundary needs to be explicit in every
   vendor/third-party relationship, not just your own accounts.

Practice (40 min)

  1. In your sandbox account, run aws sts get-caller-identity and aws iam get-account-authorization-details (or the read-only enumerate-iam tool). Read your own principal's effective permissions.
  2. Enable CloudTrail (an org trail if you have an org; else an account trail) to an S3 bucket with log file validation on. Do the same for one bucket's data events.
  3. Make one s3:GetObject call; find the event in CloudTrail; identify every field an investigator would use (principal, sourceIPAddress, userAgent, sessionContext, vpcEndpointId).
  4. Draw the shared-responsibility line for three services you use (one IaaS, one PaaS, one FaaS) — write exactly what you must configure for each.
  5. Do the equivalent identity-service exploration in GCP or Azure if you use them (gcloud projects get-iam-policy, az role assignment list).

Common mistakes

  • Thinking network-first. In the cloud, a security group is a control but IAM is the control. A locked-down VPC with an over-permissioned role is wide open via the API.
  • Long-lived IAM users and access keys. These are the leak vector. Federate humans via SSO; give workloads role-based short-lived creds.
  • Not knowing where the responsibility line is. "RDS is managed so it's secure" — you still own its network exposure, encryption, IAM auth, backups, and parameter group.
  • CloudTrail not enabled for data events. Management events alone won't show you object-level reads/writes — the exfiltration itself.
  • Assuming one Allow is enough. KMS-encrypted objects need the key policy and the IAM policy. Cross-account needs both sides.

Check yourself

  1. State the shared-responsibility split and how it shifts from IaaS to FaaS.
  2. Name the three categories of principal and give a workload-identity example for AWS, GCP, and Azure.
  3. In AWS policy evaluation, what always wins, and what must be true for an action to be allowed?
  4. Why is CloudTrail data events (not just management events) important for detection?
  5. For a KMS-encrypted S3 object, which policies must both allow the read?

(Answers: Appendix G.)

Further reading

  • Docs: AWS "IAM policy evaluation logic"; GCP "IAM overview" and "policy evaluation"; Azure "How Azure RBAC determines access".
  • Book: AWS Security, Dylan Shields; Practical Cloud Security (2nd ed.), Chris Dotson — the best vendor-neutral treatment.
  • Site: cloudsecdocs.com; the AWS "Well-Architected" Security Pillar; hackingthe.cloud (offensive) and wiz.io/academy (defensive explainers).
  • Talk: "The Attacker's Guide to AWS" and Scott Piper's (summitroute) cloud security posts; flaws.cloud walkthroughs.

Generated from real-life-security-guide-v1.md · 8 Oct 2026 16:36