Security

Cloud IAM Best Practices: Least Privilege Across AWS, Azure, and GCP

Cross-cloud IAM patterns for AWS, Azure, and GCP — least privilege, identity federation, service account hygiene, and just-in-time access.

March 9, 20266 min readShipSafer Team

Cloud IAM Best Practices: Least Privilege Across AWS, Azure, and GCP

Identity is the new perimeter. In cloud environments, a misconfigured IAM role is frequently the single step between an attacker who has compromised one service and an attacker who has compromised your entire infrastructure. The 2020 Capital One breach, the 2022 Uber breach, and numerous S3 data exposures trace back to IAM misconfiguration — overly permissive roles, long-lived credentials, and lack of monitoring.

This guide covers IAM best practices with concrete implementation guidance across AWS, Azure, and GCP.

The Principle of Least Privilege

Every identity — human or machine — should have exactly the permissions required to perform its function, and no more. In practice, this means:

  • Grant specific actions, not broad wildcards (s3:GetObject not s3:*)
  • Scope to specific resources, not all resources (arn:aws:s3:::my-bucket/* not *)
  • Set conditions where possible (source IP, MFA required, time-based)
  • Review and revoke unused permissions regularly

The challenge is that least privilege is easy to state and hard to achieve. Developers often request broad permissions during development and never narrow them. "Just use admin for now" becomes permanent.

AWS IAM Analyzer identifies resource policies that grant public or cross-account access and IAM roles with unused permissions:

# Create an analyzer for your account
aws accessanalyzer create-analyzer \
  --analyzer-name account-analyzer \
  --type ACCOUNT

# List findings
aws accessanalyzer list-findings \
  --analyzer-name account-analyzer \
  --filter '{"status":{"eq":["ACTIVE"]}}'

GCP IAM Recommender surfaces roles that have been granted but not used in the past 90 days:

gcloud recommender recommendations list \
  --recommender=google.iam.policy.Recommender \
  --location=global \
  --resource-type=cloudresourcemanager.googleapis.com/Project \
  --project=my-project

Azure Access Reviews (Entra ID) enable periodic recertification of role assignments, where managers confirm whether each user still needs their access.

Service Account and Workload Identity Hygiene

Machine identities (service accounts, managed identities, workload identity) are the most common source of excessive privilege because they are often provisioned once and never reviewed.

Never use default service accounts:

  • AWS: The EC2 default instance role has minimal permissions but is often overridden with broad policies.
  • GCP: The default Compute Engine service account has the overly broad "Editor" role — remove it.
  • Azure: Managed Identities have no permissions by default (good), but role assignments accumulate.

Use workload identity federation to allow cloud workloads to authenticate without long-lived credentials:

AWS — OIDC with GitHub Actions:

# GitHub Actions workflow
permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-deploy-role
          aws-region: us-east-1

No AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY stored in GitHub secrets. The OIDC token from GitHub is exchanged for a short-lived AWS role session.

GCP — Workload Identity Federation:

# Create workload identity pool for GitHub Actions
gcloud iam workload-identity-pools create "github-pool" \
  --project=my-project \
  --location="global"

# Bind to GitHub repository
gcloud iam service-accounts add-iam-policy-binding \
  "my-sa@my-project.iam.gserviceaccount.com" \
  --member="principalSet://iam.googleapis.com/projects/123/locations/global/workloadIdentityPools/github-pool/attribute.repository/my-org/my-repo" \
  --role="roles/iam.workloadIdentityUser"

Azure — Managed Identity for Azure resources:

resource vm 'Microsoft.Compute/virtualMachines@2023-09-01' = {
  identity: {
    type: 'SystemAssigned'  // Azure creates and manages this identity
  }
}

// Grant role
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(vm.id, storageAccount.id, 'Storage Blob Data Reader')
  properties: {
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')
    principalId: vm.identity.principalId
    principalType: 'ServicePrincipal'
  }
}

Identity Federation and SSO

Federated identity allows users to authenticate once to your corporate identity provider (IdP) and access cloud resources without separate cloud accounts.

Benefits:

  • Single point for provisioning and deprovisioning — disable an employee in Okta/Entra and their cloud access is immediately revoked
  • Consistent MFA enforcement across all cloud accounts
  • Centralized audit trail

AWS SSO (IAM Identity Center):

Okta/Entra ID → AWS IAM Identity Center → AWS accounts
                         ↓
                  Permission Sets (like roles)
                  mapped to groups in IdP

Set up SAML/OIDC federation between your IdP and IAM Identity Center. Map IdP groups to AWS permission sets. Users authenticate via SSO and get temporary credentials via the AWS CLI:

aws configure sso
aws sso login --profile dev

GCP — Workforce Identity Federation:

gcloud iam workforce-pools create "corporate-pool" \
  --organization=123456789 \
  --location="global" \
  --description="Corporate SAML federation"

Azure uses Entra ID natively. Users sign in with their Entra ID credentials across all Azure services. External guest users can be B2B invited.

Just-in-Time (JIT) Access

JIT access means privileged access is temporary — granted on request, for a limited time, for a specific purpose, and automatically revoked.

This dramatically reduces the blast radius of a compromised account. If a developer's laptop is stolen, the attacker does not inherit weeks of unrevoked admin access.

AWS — Temporary privilege elevation with STS:

# Assume a privileged role for a 1-hour session
aws sts assume-role \
  --role-arn arn:aws:iam::123456789012:role/ProductionAdmin \
  --role-session-name "incident-investigation-2026-03-09" \
  --duration-seconds 3600

# Use the temporary credentials
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...

Teleport provides JIT access management across AWS, GCP, Azure, Kubernetes, and databases. It records all sessions, requires approval workflows for privileged access, and auto-expires sessions:

# Teleport access request
kind: access_request
spec:
  user: alice
  roles: ["production-admin"]
  reason: "Investigating P1 incident #1234"
  reviewers: ["bob", "charlie"]  # Requires approval from these users

Azure PIM (Privileged Identity Management) provides JIT activation for Entra ID roles and Azure resource roles, with configurable approval workflows and time limits.

Cross-Cloud IAM Patterns

When operating in multiple clouds, consistency matters.

Shared governance model:

  1. Central identity provider (Okta, Entra ID) as the source of truth for human identities
  2. Federated access from IdP to each cloud via SAML or OIDC
  3. Workload identity federation for machine-to-machine across clouds
  4. Common tagging taxonomy so cloud resources are attributable to teams and services
  5. Unified audit trail — ship IAM audit logs from all clouds to a central SIEM

Permission boundary patterns:

Use permission boundaries (AWS) and VPC Service Controls (GCP) to create guardrails that limit the maximum permissions any identity can ever have, even if a role is misconfigured.

// AWS Permission Boundary — no IAM or billing access, ever
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["ec2:*", "s3:*", "rds:*", "logs:*"],
      "Resource": "*"
    },
    {
      "Effect": "Deny",
      "Action": ["iam:*", "organizations:*", "billing:*"],
      "Resource": "*"
    }
  ]
}

IAM audit cadence:

  • Continuously: Alert on new admin role grants, cross-account trust relationships, and public resource policies
  • Weekly: Review IAM Analyzer findings
  • Quarterly: Full access review — who has what, is it still needed?
  • Annually: Penetration test specifically targeting IAM privilege escalation paths

IAM hygiene is not a one-time project. In active environments, permissions drift constantly as new services are added, developers request access, and infrastructure evolves. The organizations that maintain least privilege do so through automated enforcement and regular review — not through one-off cleanup.

Check Your Security Score — Free

See exactly how your domain scores on DMARC, TLS, HTTP headers, and 25+ other automated security checks in under 60 seconds.