Cloud IAM security: securing AWS, Azure and GCP properly
Cloud Identity and Access Management Security: AWS IAM (Least Privilege, Permission Boundaries, Service Control Policies, IAM Access Analyzer), Azure RBAC + Entra ID (Custom Roles, Conditional Access, Managed Identities), GCP IAM (Workload Identity Federation, Organization Policies), Service Account Security, Cloud-native Secret Management (AWS Secrets Manager, Azure Key Vault, GCP Secret Manager), Cross-Cloud Identity Federation and CSPM Integration.
Table of Contents (5 sections)
Cloud IAM is different from on-premises IAM: everything runs via APIs, permissions are more granular, and a single misconfigured service account can lead to a complete cloud compromise.
AWS IAM: Implementing Least Privilege
AWS IAM Best Practices:
Secure the Root Account:
→ Root Account: ONLY for initial account setup
→ Afterward: Enable MFA + Delete access keys
→ Root: Never use for daily work!
→ AWS Organizations: Isolate the root account
Principle of Least Privilege:
# WRONG: Policy too broad
{
"Effect": "Allow",
"Action": "*", # Everything allowed!
"Resource": "*"
}
# CORRECT: minimal permissions
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-specific-bucket/*",
"Condition": {
"StringEquals": {
"aws:RequestedRegion": "eu-central-1" # Frankfurt only!
}
}
}
IAM Access Analyzer:
# Finds resources that are publicly or cross-account accessible
aws accessanalyzer create-analyzer \
--analyzer-name "company-analyzer" \
--type ACCOUNT
# Reports: Which S3 buckets, SQS queues, and KMS keys are too exposed?
aws accessanalyzer list-findings --analyzer-arn arn:aws:access-analyzer:...
Permission Boundaries:
# Delegated administration: What is the maximum scope of permissions an admin can grant?
# An admin cannot grant permissions that they do not have themselves!
aws iam create-policy --policy-name DevTeamBoundary \
--policy-document file://dev-boundary.json
aws iam put-user-permissions-boundary \
--user-name developer1 \
--permissions-boundary arn:aws:iam::ACCOUNT:policy/DevTeamBoundary
Service Control Policies (AWS Organizations):
# SCP: Guardrails for the entire OU/account
# Prevents certain actions across the entire organization
{
"Effect": "Deny",
"Action": [
"ec2:*", # No EC2 in unauthorized regions
"s3:CreateBucket"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": ["eu-central-1", "eu-west-1"]
}
}
}
AWS: Service Accounts and Roles
EC2 Instance Roles vs. Access Keys:
WRONG: Access Keys in EC2 Instance:
→ Hardcoded in code → Risk if code is leaked
→ In .env file → Risk if server is compromised
→ Stored in S3 → Risk if bucket is exposed
NEVER store access keys in EC2/Lambda/Containers!
CORRECT: IAM Instance Profile:
# EC2 instance: Assign IAM role
# Instance automatically accesses credentials (IMDS)
# No hardcoding of keys required!
# In code:
import boto3
s3 = boto3.client('s3') # Automatically uses Instance Role credentials!
# Lambda: automatic Execution Role
# ECS/Fargate: Task Role
# Kubernetes (EKS): IRSA (IAM Roles for Service Accounts)
Enforce IMDS v2 (Security!):
# IMDSv1: without tokens (vulnerable to SSRF!)
# IMDSv2: token-based (SSRF-resistant)
aws ec2 modify-instance-metadata-options \
--instance-id i-1234567890abcdef0 \
--http-tokens required # Enforce IMDSv2!
--http-put-response-hop-limit 1 # Hop limit: no container escape!
AWS Secrets Manager:
# Securely store database passwords and API keys:
aws secretsmanager create-secret \
--name "prod/db/password" \
--secret-string "$(cat /dev/urandom | tr -dc A-Za-z0-9 | head -c32)"
# Automatic rotation:
aws secretsmanager rotate-secret \
--secret-id "prod/db/password" \
--rotation-lambda-arn arn:aws:lambda:...
# In code (no hardcoding!):
import boto3
client = boto3.client('secretsmanager')
secret = client.get_secret_value(SecretId='prod/db/password')
Azure RBAC and Entra ID
Azure Identity Best Practices:
Azure RBAC Basic Principles:
→ Scope: Management Group > Subscription > Resource Group > Resource
→ The narrower the scope, the better!
→ Use custom roles if built-in roles are too broad
# WRONG: Owner at the subscription level
# CORRECT: Contributor only for a specific resource group
az role assignment create \
--assignee user@company.com \
--role "Storage Blob Data Contributor" \
--scope "/subscriptions/SUB-ID/resourceGroups/rg-data/providers/Microsoft.Storage/storageAccounts/myaccount"
Managed Identities (no secret management required!):
# System-assigned: 1:1 bound to a resource
# User-assigned: multiple resources can share
# Example: App Service accesses Key Vault:
az webapp identity assign --name myapp --resource-group myrg
# Key Vault Policy:
az keyvault set-policy \
--name mykeyvault \
--object-id $(az webapp identity show --name myapp --query principalId -o tsv) \
--secret-permissions get list
# In code: no password/key required!
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
credential = DefaultAzureCredential() # Automatically uses Managed Identity!
client = SecretClient(vault_url="https://mykeyvault.vault.azure.net", credential=credential)
Azure AD Conditional Access:
# Zero-Trust: every access is context-based
Example policy: "Admin access only from compliant devices":
→ Users: all Global Admins
→ Apps: all Cloud Apps
→ Conditions: Device platforms = all
→ Grant: Require compliant device
+ Require MFA
+ Require Hybrid Azure AD joined
→ Session: Sign-in Frequency = 1h
GCP IAM and Workload Identity
Google Cloud IAM:
Basic principles:
→ Google Accounts for people
→ Service Accounts for applications (never used manually!)
→ Workload Identity Federation: external identities without keys
Service Account Best Practices:
# WRONG: Download and save the Service Account JSON key
# RIGHT: Workload Identity (no key required!)
# Create a service account:
gcloud iam service-accounts create webapp-sa \
--description "Web App Service Account" \
--display-name "webapp-sa"
# Minimal permissions:
gcloud projects add-iam-policy-binding PROJECT_ID \
--member "serviceAccount:webapp-sa@PROJECT_ID.iam.gserviceaccount.com" \
--role "roles/storage.objectViewer" \ # Read-only!
--condition "title=bucket-condition,expression=resource.name.startsWith('projects/_/buckets/my-bucket')"
Workload Identity Federation (OpenID Connect):
# External service (GitHub Actions, Kubernetes) without a key!
# GitHub Actions → GCP access:
# Register GitHub OIDC provider:
gcloud iam workload-identity-pools create "github-pool" \
--location="global"
gcloud iam workload-identity-pools providers create-oidc "github-provider" \
--location="global" \
--workload-identity-pool="github-pool" \
--issuer-uri="https://token.actions.githubusercontent.com" \
--attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository"
# In GitHub Action:
# id-token: write permission -> no GCP key required!
- uses: google-github-actions/auth@v2
with:
workload_identity_provider: "projects/123/locations/global/workloadIdentityPools/github-pool/providers/github-provider"
service_account: "webapp-sa@PROJECT.iam.gserviceaccount.com"
Organization Policies:
# Constraints for the entire GCP organization
gcloud org-policies set-policy \
--project=PROJECT_ID constraints/compute.requireOsLogin \
--value=ENFORCE # OS login required for all VMs
gcloud org-policies set-policy \
--project=PROJECT_ID constraints/iam.disableServiceAccountKeyCreation \
--value=ENFORCE # No service account keys!
CSPM: Cloud Security Posture Management
Automatic misconfiguration detection:
What CSPM checks:
→ Are S3 buckets publicly accessible?
→ Is MFA enforced for the root account?
→ Unused IAM roles + access keys
→ Unencrypted databases/storage
→ Logging (CloudTrail, Activity Log) enabled?
→ Network configuration: Security groups too open?
CSPM tools:
AWS Security Hub:
→ Built into AWS, free (findings: $0.001/entry)
→ Aggregates: GuardDuty, Inspector, Macie, Config
→ CIS AWS Benchmark automatically checked
Microsoft Defender for Cloud:
→ Built into Azure
→ Secure Score: 0–100 (Target: >80)
→ Recommendations with specific fixes
Wiz / Orca Security (commercial):
→ Multi-cloud (AWS + Azure + GCP + K8s)
→ Attack Path Analysis: how far can an attacker get?
→ Very powerful, but expensive
Checkov + Terraform (preventive):
→ IaC scanning before deployment
→ Find misconfigurations before deployment
→ See above: DevSecOps integration Questions about this topic?
Our experts advise you free of charge and without obligation.
About the Author
Geschäftsführender Gesellschafter der AWARE7 GmbH mit langjähriger Expertise in Informationssicherheit, Penetrationstesting und IT-Risikomanagement. Absolvent des Masterstudiengangs Internet-Sicherheit an der Westfälischen Hochschule (if(is), Prof. Norbert Pohlmann). Bestseller-Autor im Wiley-VCH Verlag und Lehrbeauftragter der ASW-Akademie. Einschätzungen zu Cybersecurity und digitaler Souveränität erschienen u.a. in Welt am Sonntag, WDR, Deutschlandfunk und Handelsblatt.
10 Publikationen
- Einsatz von elektronischer Verschlüsselung - Hemmnisse für die Wirtschaft (2018)
- Kompass IT-Verschlüsselung - Orientierungshilfen für KMU (2018)
- IT Security Day 2025 - Live Hacking: KI in der Cybersicherheit (2025)
- Live Hacking - Credential Stuffing: Finanzrisiken jenseits Ransomware (2025)
- Keynote: Live Hacking Show - Ein Blick in die Welt der Cyberkriminalität (2025)
- Analyse von Angriffsflächen bei Shared-Hosting-Anbietern (2024)
- Gänsehaut garantiert: Die schaurigsten Funde aus dem Leben eines Pentesters (2022)
- IT Security Zertifizierungen — CISSP, T.I.S.P. & Co (Live-Webinar) (2023)
- Sicherheitsforum Online-Banking — Live Hacking (2021)
- Nipster im Netz und das Ende der Kreidezeit (2017)