📑 Table of Contents

Enterprise organizations increasingly operate across multiple cloud providers. Managing identities separately in each cloud creates complexity, security gaps, and operational overhead. This lab teaches you to implement unified identity federation where a single identity source (Azure AD/Entra ID) provides seamless, secure access to AWS, GCP, and CI/CD systems—all without long-lived credentials.

🎯 Lab Overview & Multi-Cloud IAM Strategy

The goal of multi-cloud identity federation is simple: one identity, many clouds, zero long-lived credentials. Users authenticate once to a central IdP and can access resources across all cloud providers. Workloads use federated identities instead of stored secrets.

Cloud Provider IAM Comparison

AWS IAM

IAM Users/Roles, Identity Center, STS, OIDC Federation

Azure/Entra ID

Users/Groups, Service Principals, Managed Identity, App Registrations

GCP IAM

Google Accounts, Service Accounts, Workload Identity Federation

📖 Federation Patterns

PatternDescriptionUse Case
User FederationIdP → AWS/GCP Console SSOHuman users accessing cloud consoles
Workload IdentityCI/CD → Cloud without secretsGitHub Actions, GitLab, Jenkins deploying to cloud
Service-to-ServiceCloud A workload → Cloud B APIAWS Lambda calling GCP API
Cross-AccountAccount A → Account B in same cloudCentralized operations across accounts

▼ MULTI-CLOUD IDENTITY ARCHITECTURE ▼

Entra ID

Central IdP

SAML/OIDC

Federation

AWS IAM

Identity Center

GCP IAM

Workload Identity

Common Use Cases

🔐 Unified SSO for Humans

Employees sign in once via Entra ID and access AWS, Azure, and GCP consoles.

SAMLOIDCSSO
🤖 CI/CD Multi-Cloud Deploy

GitHub Actions deploys to AWS, Azure, and GCP using federated identity—no stored secrets.

OIDCWorkload Identity
🔄 Cross-Cloud Data Pipeline

AWS Lambda processes data and writes to GCP BigQuery using federated credentials.

STSWorkload Identity
📊 Unified Audit Trail

All cloud access logs centralized for compliance and security monitoring.

CloudTrailAzure MonitorCloud Audit

🔷 Module 1: Entra ID as Central Identity Provider

Module 1: Configure Entra ID for Multi-Cloud Federation

Set up Entra ID as the single source of truth for identities.

⏱️ 45-60 minutes🎯 4 steps
1

Create Groups for Cloud Access

Azure Portal
Navigate to: Entra ID → Groups → New group Create cloud access groups: 1. Cloud-AWS-Admins - Type: Security - Description: Full admin access to AWS accounts 2. Cloud-AWS-Developers - Type: Security - Description: Developer access to AWS dev/staging 3. Cloud-GCP-Admins - Type: Security - Description: Full admin access to GCP projects 4. Cloud-GCP-Developers - Type: Security - Description: Developer access to GCP dev projects 5. Cloud-MultiCloud-Admins - Type: Security - Description: Admin access to ALL cloud providers Add appropriate users to each group.
2

Configure Group Claims

Azure Portal
Navigate to: Entra ID → Enterprise applications → [Your App] → Single sign-on → Attributes & Claims Configure group claims: → Add a group claim Group claim settings: - Groups assigned to the application - Source attribute: Group ID (for AWS) or Display Name (for readability) - Customize the name: "groups" or per-protocol default Advanced options: - Emit groups as role claims: Yes (for AWS SAML) - Group filter: Limit to groups starting with "Cloud-" This ensures SAML assertions and OIDC tokens include the user's group memberships for authorization.
3

Create App Registration for OIDC

Azure Portal
Navigate to: Entra ID → App registrations → New registration App registration details: - Name: MultiCloud-Workload-Identity - Supported account types: Single tenant - Redirect URI: (leave blank for workload identity) → Register After creation: 1. Note the Application (client) ID 2. Note the Directory (tenant) ID Configure federated credentials: → Certificates & secrets → Federated credentials → Add credential This is used for workload identity federation from GitHub Actions and other CI/CD systems.
4

Get OIDC Metadata

Azure Portal
# Entra ID OIDC Discovery URLs TENANT_ID="your-tenant-id" # OpenID Configuration https://login.microsoftonline.com/${TENANT_ID}/v2.0/.well-known/openid-configuration # JWKS URI (for token validation) https://login.microsoftonline.com/${TENANT_ID}/discovery/v2.0/keys # Issuer URL https://login.microsoftonline.com/${TENANT_ID}/v2.0 # These URLs are used when configuring AWS and GCP # to trust Entra ID as an identity provider.

☁️ Module 2: AWS Federation with Entra ID

Module 2: Configure AWS to Trust Entra ID

Enable SSO from Entra ID to AWS using SAML and IAM Identity Center.

⏱️ 60-90 minutes🎯 5 steps
5

Option A: IAM Identity Center with Entra ID

AWS Console
Navigate to: IAM Identity Center → Settings → Identity source → Actions → Change identity source → Select: External identity provider Download metadata: - AWS SSO SAML metadata file - Or copy: AWS SSO ACS URL, AWS SSO Issuer URL In Entra ID: → Enterprise applications → New application → Search: "AWS IAM Identity Center" → Add and configure: Basic SAML Configuration: - Identifier: [AWS SSO Issuer URL] - Reply URL: [AWS SSO ACS URL] User Attributes & Claims: - Configure group claim - Map user attributes (email, name) Download: Federation Metadata XML Back in AWS: → Upload IdP metadata file → Enable automatic provisioning (SCIM) → Copy SCIM endpoint and token to Entra ID
6

Option B: Direct SAML Federation to IAM

AWS CLI
# Download Entra ID federation metadata # From: Entra ID → Enterprise apps → [App] → SAML → Federation Metadata XML # Create SAML identity provider in AWS aws iam create-saml-provider \ --saml-metadata-document file://azure-federation-metadata.xml \ --name EntraID-Federation # Note the provider ARN SAML_PROVIDER_ARN="arn:aws:iam::123456789012:saml-provider/EntraID-Federation" # Create IAM role for federated users cat > trust-policy.json << EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "${SAML_PROVIDER_ARN}" }, "Action": "sts:AssumeRoleWithSAML", "Condition": { "StringEquals": { "SAML:aud": "https://signin.aws.amazon.com/saml" } } } ] } EOF aws iam create-role \ --role-name EntraID-Admin-Role \ --assume-role-policy-document file://trust-policy.json aws iam attach-role-policy \ --role-name EntraID-Admin-Role \ --policy-arn arn:aws:iam::aws:policy/AdministratorAccess
7

Configure SCIM Provisioning

Azure Portal
Navigate to: Entra ID → Enterprise applications → AWS IAM Identity Center → Provisioning → Get started Provisioning Mode: Automatic Admin Credentials: - Tenant URL: [SCIM endpoint from AWS] - Secret Token: [SCIM token from AWS] → Test Connection → Save Mappings: → Provision Azure Active Directory Users → Provision Azure Active Directory Groups Enable: - Provision Users: Yes - Provision Groups: Yes Start provisioning: - Initial cycle syncs all assigned users/groups - Subsequent changes sync within 40 minutes Benefits: - Users created in Entra ID appear in AWS automatically - Group memberships sync for RBAC - Disabled users are disabled in AWS
8

Create Permission Sets for Entra Groups

AWS Console
Navigate to: IAM Identity Center → Permission sets Create permission sets matching your Entra ID groups: 1. AdminAccess (for Cloud-AWS-Admins) - AWS managed: AdministratorAccess - Session duration: 4 hours 2. DeveloperAccess (for Cloud-AWS-Developers) - Custom policy: EC2, S3, Lambda, RDS access - Session duration: 8 hours 3. ReadOnlyAccess (for auditors) - AWS managed: ViewOnlyAccess - Session duration: 8 hours Assign to accounts: → AWS accounts → Select account → Assign users or groups → Select synced Entra group → Select permission set
9

Test SSO from Entra ID to AWS

Azure Portal
Testing SSO: Option 1: From Entra ID → Enterprise applications → AWS IAM Identity Center → Single sign-on → Test → Select user → Test sign-on Option 2: From My Apps Portal → myapps.microsoft.com → Click AWS IAM Identity Center tile → Should redirect to AWS SSO portal Option 3: Direct to AWS SSO Portal → https://your-sso-portal.awsapps.com/start → Click "Sign in with your corporate ID" → Redirected to Entra ID for authentication → After MFA, returned to AWS portal Verify: - User sees correct AWS accounts - Correct permission sets are available - Can successfully access AWS Console

🌐 Module 3: GCP Federation with Entra ID

Module 3: Configure GCP Workforce Identity Federation

Enable SSO from Entra ID to GCP using Workforce Identity Federation.

⏱️ 60-90 minutes🎯 5 steps
10

Create Workforce Identity Pool

gcloud CLI
# Set organization ID ORG_ID=$(gcloud organizations list --format="value(ID)" | head -1) # Create workforce identity pool gcloud iam workforce-pools create azure-ad-pool \ --organization=$ORG_ID \ --location="global" \ --display-name="Azure AD Workforce Pool" \ --description="Federation with Entra ID for employees" # Get pool resource name POOL_NAME="locations/global/workforcePools/azure-ad-pool"
11

Add Entra ID as OIDC Provider

gcloud CLI
# Variables from Entra ID TENANT_ID="your-tenant-id" CLIENT_ID="your-app-client-id" # Create OIDC provider gcloud iam workforce-pools providers create-oidc azure-ad \ --workforce-pool="azure-ad-pool" \ --location="global" \ --display-name="Azure AD" \ --description="Entra ID OIDC Provider" \ --issuer-uri="https://login.microsoftonline.com/${TENANT_ID}/v2.0" \ --client-id="${CLIENT_ID}" \ --attribute-mapping="google.subject=assertion.sub,google.display_name=assertion.name,google.groups=assertion.groups" \ --web-sso-response-type="id-token" \ --web-sso-assertion-claims-behavior="only-id-token-claims" # Provider name for IAM bindings PROVIDER_NAME="locations/global/workforcePools/azure-ad-pool/providers/azure-ad"
12

Grant IAM Permissions to Federated Users

gcloud CLI
PROJECT_ID=$(gcloud config get-value project) # Grant access to specific Entra ID group # Format: principalSet://iam.googleapis.com/POOL/attribute.KEY/VALUE ADMIN_GROUP_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" # Entra group Object ID # Grant project owner to admin group gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="principalSet://iam.googleapis.com/${POOL_NAME}/attribute.groups/${ADMIN_GROUP_ID}" \ --role="roles/owner" # Grant viewer to all federated users gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="principalSet://iam.googleapis.com/${POOL_NAME}/*" \ --role="roles/viewer" # Grant specific role to individual user gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="principal://iam.googleapis.com/${POOL_NAME}/subject/user-object-id" \ --role="roles/storage.admin"
13

Configure Console Access

GCP Console
Navigate to: IAM & Admin → Workforce Identity Federation → Select your pool → Providers → azure-ad Configure Console Access: → Enable "Allow Google Cloud console access" Console URL will be: https://console.cloud.google.com/iam-admin/workforce-identity-pools/locations/global/workforcePools/azure-ad-pool/providers/azure-ad?project=PROJECT_ID Or use: https://cloud.google.com/workforce Users can: 1. Go to workforce identity URL 2. Select "Azure AD" provider 3. Authenticate via Entra ID 4. Access GCP Console with federated identity
14

Configure gcloud CLI for Workforce Identity

gcloud CLI
# Create configuration file for workforce identity cat > workforce-config.json << EOF { "type": "external_account", "audience": "//iam.googleapis.com/${POOL_NAME}/providers/azure-ad", "subject_token_type": "urn:ietf:params:oauth:token-type:id_token", "token_url": "https://sts.googleapis.com/v1/token", "credential_source": { "file": "/path/to/azure-token.txt", "format": { "type": "text" } } } EOF # Login with workforce identity gcloud auth login --cred-file=workforce-config.json # Or use browser-based login gcloud auth login --workforce-pool-provider="${PROVIDER_NAME}" # Verify identity gcloud auth list

🐙 Module 4: GitHub Actions to Multi-Cloud

Module 4: Keyless CI/CD Deployments to AWS, Azure, and GCP

Configure GitHub Actions to deploy to all clouds using OIDC federation.

⏱️ 60-90 minutes🎯 4 steps
15

Configure AWS for GitHub OIDC

AWS CLI
# Create OIDC provider for GitHub aws iam create-open-id-connect-provider \ --url "https://token.actions.githubusercontent.com" \ --client-id-list "sts.amazonaws.com" \ --thumbprint-list "6938fd4d98bab03faadb97b34396831e3780aea1" # Create trust policy for specific repo GITHUB_ORG="your-org" GITHUB_REPO="your-repo" cat > github-trust-policy.json << EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" }, "StringLike": { "token.actions.githubusercontent.com:sub": "repo:${GITHUB_ORG}/${GITHUB_REPO}:*" } } } ] } EOF aws iam create-role \ --role-name GitHub-Actions-AWS-Deploy \ --assume-role-policy-document file://github-trust-policy.json aws iam attach-role-policy \ --role-name GitHub-Actions-AWS-Deploy \ --policy-arn arn:aws:iam::aws:policy/PowerUserAccess
16

Configure Azure for GitHub OIDC

Azure CLI
# Create app registration az ad app create --display-name "GitHub-Actions-Deploy" APP_ID=$(az ad app list --display-name "GitHub-Actions-Deploy" --query "[0].appId" -o tsv) # Create service principal az ad sp create --id $APP_ID SP_OBJECT_ID=$(az ad sp show --id $APP_ID --query "id" -o tsv) # Add federated credential for GitHub GITHUB_ORG="your-org" GITHUB_REPO="your-repo" az ad app federated-credential create \ --id $APP_ID \ --parameters '{ "name": "github-main-branch", "issuer": "https://token.actions.githubusercontent.com", "subject": "repo:'"${GITHUB_ORG}/${GITHUB_REPO}"':ref:refs/heads/main", "audiences": ["api://AzureADTokenExchange"] }' # Grant Azure permissions SUBSCRIPTION_ID=$(az account show --query id -o tsv) az role assignment create \ --assignee $SP_OBJECT_ID \ --role "Contributor" \ --scope "/subscriptions/${SUBSCRIPTION_ID}"
17

Configure GCP for GitHub OIDC

gcloud CLI
PROJECT_ID=$(gcloud config get-value project) PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)") # Create workload identity pool gcloud iam workload-identity-pools create "github-pool" \ --location="global" \ --display-name="GitHub Actions Pool" # Add GitHub as OIDC provider gcloud iam workload-identity-pools providers create-oidc "github" \ --location="global" \ --workload-identity-pool="github-pool" \ --display-name="GitHub" \ --issuer-uri="https://token.actions.githubusercontent.com" \ --attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository" # Create service account gcloud iam service-accounts create github-actions-deploy \ --display-name="GitHub Actions Deploy" GCP_SA="github-actions-deploy@${PROJECT_ID}.iam.gserviceaccount.com" # Grant SA permissions gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:$GCP_SA" \ --role="roles/storage.admin" # Allow GitHub repo to impersonate SA GITHUB_ORG="your-org" GITHUB_REPO="your-repo" gcloud iam service-accounts add-iam-policy-binding $GCP_SA \ --role="roles/iam.workloadIdentityUser" \ --member="principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/github-pool/attribute.repository/${GITHUB_ORG}/${GITHUB_REPO}"
18

GitHub Actions Multi-Cloud Workflow

GitHub
# .github/workflows/multi-cloud-deploy.yml name: Multi-Cloud Deploy on: push: branches: [main] permissions: id-token: write contents: read jobs: deploy-aws: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::123456789012:role/GitHub-Actions-AWS-Deploy aws-region: us-east-1 - name: Deploy to AWS run: | aws s3 cp ./dist s3://my-bucket/ --recursive deploy-azure: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Azure Login uses: azure/login@v1 with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - name: Deploy to Azure run: | az storage blob upload-batch -d container -s ./dist deploy-gcp: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Authenticate to GCP uses: google-github-actions/auth@v2 with: workload_identity_provider: 'projects/123456/locations/global/workloadIdentityPools/github-pool/providers/github' service_account: 'github-actions-deploy@project-id.iam.gserviceaccount.com' - name: Deploy to GCP run: | gcloud storage cp ./dist/* gs://my-bucket/

🔄 Module 5: Cross-Cloud Service-to-Service

Module 5: Workloads Calling Across Cloud Providers

Enable AWS workloads to access GCP APIs and vice versa.

⏱️ 45-60 minutes🎯 3 steps
19

AWS Lambda to GCP (via Workload Identity Federation)

gcloud CLI
# Scenario: AWS Lambda needs to write to GCP BigQuery # 1. Create workload identity pool for AWS gcloud iam workload-identity-pools create "aws-pool" \ --location="global" \ --display-name="AWS Workload Pool" # 2. Add AWS as identity provider AWS_ACCOUNT_ID="123456789012" gcloud iam workload-identity-pools providers create-aws "aws-provider" \ --location="global" \ --workload-identity-pool="aws-pool" \ --account-id="${AWS_ACCOUNT_ID}" \ --attribute-mapping="google.subject=assertion.arn" # 3. Create GCP service account gcloud iam service-accounts create aws-lambda-bigquery \ --display-name="AWS Lambda BigQuery Access" GCP_SA="aws-lambda-bigquery@${PROJECT_ID}.iam.gserviceaccount.com" # 4. Grant BigQuery permissions gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:$GCP_SA" \ --role="roles/bigquery.dataEditor" # 5. Allow specific Lambda role to impersonate LAMBDA_ROLE_ARN="arn:aws:iam::${AWS_ACCOUNT_ID}:role/my-lambda-role" gcloud iam service-accounts add-iam-policy-binding $GCP_SA \ --role="roles/iam.workloadIdentityUser" \ --member="principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/aws-pool/subject/${LAMBDA_ROLE_ARN}"
20

Lambda Code to Call GCP

Python
# Lambda function code (Python) import json from google.cloud import bigquery from google.auth import identity_pool def lambda_handler(event, context): # Create credentials using workload identity federation credentials = identity_pool.Credentials.from_info({ "type": "external_account", "audience": "//iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/aws-pool/providers/aws-provider", "subject_token_type": "urn:ietf:params:aws:token-type:aws4_request", "service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/aws-lambda-bigquery@PROJECT_ID.iam.gserviceaccount.com:generateAccessToken", "token_url": "https://sts.googleapis.com/v1/token", "credential_source": { "environment_id": "aws1", "regional_cred_verification_url": "https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15" } }) # Use credentials with BigQuery client client = bigquery.Client( project="your-gcp-project", credentials=credentials ) # Insert data to BigQuery table_id = "your-gcp-project.dataset.table" rows_to_insert = [{"column1": "value1", "column2": "value2"}] errors = client.insert_rows_json(table_id, rows_to_insert) return {"statusCode": 200, "body": json.dumps("Success!")}
21

GCP Cloud Run to AWS (via STS)

AWS CLI
# Scenario: GCP Cloud Run needs to read from AWS S3 # 1. Create OIDC provider for GCP in AWS PROJECT_NUMBER="your-gcp-project-number" aws iam create-open-id-connect-provider \ --url "https://accounts.google.com" \ --client-id-list "${PROJECT_NUMBER}" \ --thumbprint-list "08745487e891c19e3078c1f2a07e452950ef36f6" # 2. Create IAM role for GCP service account GCP_SA_EMAIL="cloud-run-sa@your-gcp-project.iam.gserviceaccount.com" GCP_SA_UNIQUE_ID="123456789012345678901" cat > gcp-trust-policy.json << EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::AWS_ACCOUNT:oidc-provider/accounts.google.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "accounts.google.com:sub": "${GCP_SA_UNIQUE_ID}" } } } ] } EOF aws iam create-role \ --role-name GCP-CloudRun-S3-Access \ --assume-role-policy-document file://gcp-trust-policy.json aws iam attach-role-policy \ --role-name GCP-CloudRun-S3-Access \ --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess

📋 Module 6: Unified Access Governance

Module 6: Centralize Access Reviews and Governance

Implement unified governance across all cloud providers.

⏱️ 30-45 minutes🎯 3 steps
22

Entra ID Governance for Cloud Access

Azure Portal
Create Access Packages for Multi-Cloud: Navigate to: Entra ID → Identity Governance → Access packages Package 1: "Multi-Cloud Admin Access" Resources: - Cloud-AWS-Admins group - Cloud-GCP-Admins group - Cloud-Azure-Admins group (if using Azure) Policies: - Request: Users can request - Approval: Require manager + Cloud Security team - Lifecycle: 90-day expiration, quarterly review - Access reviews: Every 90 days Package 2: "Cloud Developer Access" Resources: - Cloud-AWS-Developers group - Cloud-GCP-Developers group Policies: - Request: Users can request - Approval: Manager approval - Lifecycle: 180-day expiration Benefits: - Single request for multi-cloud access - Unified approval workflow - Automatic expiration and review
23

Cross-Cloud Access Reviews

Azure Portal
Create unified access review: Navigate to: Entra ID → Identity Governance → Access reviews → New access review Review scope: - Select: Groups + Applications - Groups: Cloud-AWS-Admins, Cloud-GCP-Admins Review settings: - Reviewers: Group owners - Duration: 7 days - Recurrence: Quarterly - Auto-apply results: Yes - If reviewer doesn't respond: Remove access Advanced settings: - Show recommendations: Yes (based on sign-in activity) - Require reason for approval: Yes This reviews access across AWS AND GCP from one place!
24

PIM for Multi-Cloud Admin

Azure Portal
Configure PIM for cloud admin groups: Navigate to: Entra ID → Privileged Identity Management → Groups → Add groups Add groups: - Cloud-AWS-Admins - Cloud-GCP-Admins - Cloud-MultiCloud-Admins Configure settings for each: → Settings → Edit Activation: - Maximum duration: 4 hours - Require MFA: Yes - Require justification: Yes - Require approval: Yes - Approvers: Cloud Security Team Assignment: - Require MFA on active assignment: Yes - Require justification: Yes Now users must: 1. Request activation in PIM 2. Provide justification 3. Get approval (if required) 4. Complete MFA 5. Access granted for limited time 6. Automatic deactivation

📊 Module 7: Centralized Audit & Monitoring

Module 7: Aggregate Logs from All Cloud Providers

Create unified audit trail for compliance and security monitoring.

⏱️ 30-45 minutes🎯 3 steps
25

Export AWS CloudTrail to Central SIEM

AWS CLI
# Organization trail exports to S3 aws cloudtrail create-trail \ --name org-audit-trail \ --s3-bucket-name central-audit-logs \ --is-organization-trail \ --is-multi-region-trail \ --include-global-service-events # Enable trail aws cloudtrail start-logging --name org-audit-trail # Export to CloudWatch Logs for real-time aws cloudtrail update-trail \ --name org-audit-trail \ --cloud-watch-logs-log-group-arn arn:aws:logs:us-east-1:123456789012:log-group:cloudtrail-logs \ --cloud-watch-logs-role-arn arn:aws:iam::123456789012:role/cloudtrail-cloudwatch-role # For SIEM integration (Splunk, Sentinel): # - S3 → Lambda → SIEM # - S3 → EventBridge → SIEM # - CloudWatch Logs → Subscription Filter → SIEM
26

Export GCP Audit Logs

gcloud CLI
# Create log sink for organization gcloud logging sinks create audit-to-bigquery \ --organization=$ORG_ID \ --log-filter='logName:"cloudaudit.googleapis.com"' \ --destination=bigquery.googleapis.com/projects/audit-project/datasets/audit_logs # Or sink to Cloud Storage gcloud logging sinks create audit-to-gcs \ --organization=$ORG_ID \ --log-filter='logName:"cloudaudit.googleapis.com"' \ --destination=storage.googleapis.com/central-audit-logs # Or sink to Pub/Sub for SIEM gcloud logging sinks create audit-to-pubsub \ --organization=$ORG_ID \ --log-filter='logName:"cloudaudit.googleapis.com"' \ --destination=pubsub.googleapis.com/projects/audit-project/topics/audit-logs # Grant sink service account access to destination SINK_SA=$(gcloud logging sinks describe audit-to-bigquery \ --organization=$ORG_ID --format="value(writerIdentity)") # Grant BigQuery Data Editor to $SINK_SA
27

Centralize in Azure Sentinel

Azure Portal
Azure Sentinel as Central SIEM: Navigate to: Microsoft Sentinel → Data connectors Connect AWS: → Amazon Web Services → Configure CloudTrail S3 bucket → Or use AWS → EventBridge → Azure Event Hub Connect GCP: → Google Cloud Platform → Configure Pub/Sub subscription → Or use GCS → Azure Storage sync Connect Entra ID (native): → Azure Active Directory → Enable: Sign-in logs, Audit logs, Provisioning logs Create Analytics Rules: 1. Multi-cloud admin access from unusual location 2. Failed authentication across clouds 3. Privileged access without PIM activation 4. Cross-cloud lateral movement detection Workbooks: - Multi-Cloud IAM Dashboard - Federation Health Monitor - Cross-Cloud Access Patterns

🏗️ Module 8: Terraform Multi-Cloud IAM

Module 8: Infrastructure as Code for Multi-Cloud Identity

Manage cross-cloud IAM configuration with Terraform.

⏱️ 45-60 minutes🎯 3 steps
28

Terraform Provider Setup

Terraform
# providers.tf terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } azuread = { source = "hashicorp/azuread" version = "~> 2.0" } google = { source = "hashicorp/google" version = "~> 5.0" } } } provider "aws" { region = "us-east-1" } provider "azuread" { tenant_id = var.azure_tenant_id } provider "google" { project = var.gcp_project_id region = "us-central1" }
29

Terraform AWS OIDC Federation

Terraform
# aws-federation.tf # OIDC Provider for GitHub Actions resource "aws_iam_openid_connect_provider" "github" { url = "https://token.actions.githubusercontent.com" client_id_list = ["sts.amazonaws.com"] thumbprint_list = ["6938fd4d98bab03faadb97b34396831e3780aea1"] } # Role for GitHub Actions resource "aws_iam_role" "github_actions" { name = "GitHub-Actions-Deploy" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Principal = { Federated = aws_iam_openid_connect_provider.github.arn } Action = "sts:AssumeRoleWithWebIdentity" Condition = { StringLike = { "token.actions.githubusercontent.com:sub" = "repo:${var.github_org}/${var.github_repo}:*" } StringEquals = { "token.actions.githubusercontent.com:aud" = "sts.amazonaws.com" } } } ] }) } resource "aws_iam_role_policy_attachment" "github_actions" { role = aws_iam_role.github_actions.name policy_arn = "arn:aws:iam::aws:policy/PowerUserAccess" }
30

Terraform GCP Workload Identity

Terraform
# gcp-federation.tf # Workload Identity Pool resource "google_iam_workload_identity_pool" "github" { workload_identity_pool_id = "github-pool" display_name = "GitHub Actions Pool" } # OIDC Provider resource "google_iam_workload_identity_pool_provider" "github" { workload_identity_pool_id = google_iam_workload_identity_pool.github.workload_identity_pool_id workload_identity_pool_provider_id = "github" display_name = "GitHub" oidc { issuer_uri = "https://token.actions.githubusercontent.com" } attribute_mapping = { "google.subject" = "assertion.sub" "attribute.repository" = "assertion.repository" } } # Service Account resource "google_service_account" "github_actions" { account_id = "github-actions-deploy" display_name = "GitHub Actions Deploy" } # IAM binding resource "google_project_iam_member" "github_storage" { project = var.gcp_project_id role = "roles/storage.admin" member = "serviceAccount:${google_service_account.github_actions.email}" } # Workload Identity binding resource "google_service_account_iam_binding" "github_workload_identity" { service_account_id = google_service_account.github_actions.name role = "roles/iam.workloadIdentityUser" members = [ "principalSet://iam.googleapis.com/${google_iam_workload_identity_pool.github.name}/attribute.repository/${var.github_org}/${var.github_repo}" ] }

🛡️ Security Best Practices

✅ Multi-Cloud Identity Best Practices

  • ✅ Use a single IdP (Entra ID/Okta) as the source of truth for human identities
  • ✅ Implement OIDC federation over SAML for modern workloads
  • ✅ Never store long-lived credentials—use workload identity federation
  • ✅ Enable MFA for all human access across all clouds
  • ✅ Use attribute-based conditions (repo, branch, environment) in trust policies
  • ✅ Implement unified access reviews via Entra ID Governance
  • ✅ Centralize audit logs in a single SIEM (Sentinel, Splunk, Chronicle)
  • ✅ Use PIM/JIT for privileged access across all providers
  • ✅ Define cloud access via groups, not individual users
  • ✅ Automate IAM with Terraform for consistency and auditability
  • ✅ Regular cross-cloud access reviews (quarterly minimum)
  • ✅ Monitor for cross-cloud lateral movement in SIEM