Book a CallContact Us
Back to all posts
June 1, 2026

Decentralized IAM and Multi-Cloud Security: Building Zero Trust at Scale

AWS-US-EASTGCP-EU-WESTDECENTRALIZEDOIDC / IAMTRUST ENGINE

Decentralized IAM and Multi-Cloud Security: Building Zero Trust at Scale

The era of the castle-and-moat security model is over. When your infrastructure spans AWS, GCP, Azure, and on-premise environments, there is no perimeter. In this reality, Decentralized IAM and Multi-Cloud Security isn't just an architectural pattern-it is the only viable defense against lateral movement and sophisticated supply chain attacks. The identity of the requester, whether human or machine, is the new boundary.

Most organizations fail at this. They attempt to shoehorn legacy centralized identity providers (IdPs) into dynamic, multi-cloud Kubernetes clusters, resulting in brittle integrations, excessive permissions, and single points of failure. In this post, we dissect the problem, propose an opinionated architecture, and show you exactly how to implement it without compromising developer velocity.

The Problem: The Hub-and-Spoke Identity Trap

When companies first adopt a multi-cloud strategy, they typically route all authentication and authorization through a single centralized directory (e.g., Active Directory or a single Okta instance). This creates the Hub-and-Spoke Identity Trap.

Every service in AWS trying to access a database in GCP must authenticate against the central hub. This design introduces three critical flaws:

  1. Latency: A microservice architecture making hundreds of internal API calls per second cannot afford the round-trip latency to a central IdP.
  2. Availability: If the central IdP goes down, the entire multi-cloud infrastructure halts.
  3. Blast Radius: A compromised central directory grants the attacker keys to the entire kingdom, across all clouds.

You need identities to be verified locally, but managed globally.

Why Decentralized IAM and Multi-Cloud Security is Hard

Decentralizing identity means distributing trust, and distributing trust requires cryptographic proof that is continuously validated. When you have a workload in AWS EKS that needs to read an object in a Google Cloud Storage bucket, how does GCP know it can trust the AWS pod?

The naive approach is long-lived static credentials (e.g., AWS Access Keys or GCP Service Account JSON files) stored in Vault or Kubernetes Secrets. This is a massive anti-pattern. Static credentials leak, they are rarely rotated, and they break the core tenet of Zero Trust: ephemeral, scoped access.

The challenge is establishing workload identity federation across disparate trust domains. You must map an identity in Domain A (AWS OIDC provider) to a role in Domain B (GCP IAM) without exchanging long-lived secrets.

The Opinionated Architecture: Workload Identity Federation

We advocate for an architecture where each environment acts as its own Identity Provider (IdP) for the workloads it hosts. These local IdPs then federate trust with other cloud environments using OpenID Connect (OIDC).

Our reference architecture uses:

  • Kubernetes (EKS v1.30): Hosting the workloads.
  • AWS IAM OIDC Provider: The local IdP for EKS.
  • GCP Workload Identity Federation: Trusting the AWS OIDC provider.
  • SPIFFE/SPIRE (v1.8.0): For internal service-to-service mTLS and identity issuance.

Instead of passing secrets, the workload requests a short-lived token from its local environment. That token is cryptographically signed by the local IdP. The target environment (GCP) verifies the signature, maps the OIDC claim to a local IAM role, and grants temporary access.

Implementation: AWS EKS to GCP BigQuery

Let's look at a concrete implementation. We have a data ingestion service running in an AWS EKS cluster that needs to write to a GCP BigQuery dataset.

1. Configure the AWS EKS OIDC Provider

First, ensure your EKS cluster has an IAM OIDC provider associated with it. This allows Kubernetes service accounts to assume IAM roles, but more importantly, it gives us an issuer URL that GCP can trust.

# Terraform v1.8.0
# AWS Provider v5.40.0

data "tls_certificate" "eks" {
  url = aws_eks_cluster.main.identity[0].oidc[0].issuer
}

resource "aws_iam_openid_connect_provider" "eks" {
  client_id_list  = ["sts.amazonaws.com"]
  thumbprint_list = [data.tls_certificate.eks.certificates[0].sha1_fingerprint]
  url             = aws_eks_cluster.main.identity[0].oidc[0].issuer
}

2. Create the GCP Workload Identity Pool

In GCP, we create a Workload Identity Pool and a Provider. The Provider points to the AWS EKS OIDC issuer URL. We map the sub claim (which contains the Kubernetes namespace and service account name) to a Google IAM subject.

# GCP Provider v5.20.0

resource "google_iam_workload_identity_pool" "aws_pool" {
  workload_identity_pool_id = "aws-eks-pool"
  display_name              = "AWS EKS Trust Pool"
  description               = "Identity pool for EKS workloads"
}

resource "google_iam_workload_identity_pool_provider" "aws_provider" {
  workload_identity_pool_id          = google_iam_workload_identity_pool.aws_pool.workload_identity_pool_id
  workload_identity_pool_provider_id = "aws-eks-provider"
  display_name                       = "AWS EKS OIDC Provider"
  
  attribute_mapping = {
    "google.subject" = "assertion.sub"
    "attribute.namespace" = "assertion['kubernetes.io']['namespace']"
  }
  
  oidc {
    issuer_uri = aws_eks_cluster.main.identity[0].oidc[0].issuer
  }
}

3. Bind the GCP Service Account

Now we create a GCP Service Account that has permissions to write to BigQuery, and we allow the specific Kubernetes Service Account (via the Identity Pool) to impersonate it.

resource "google_service_account" "bq_writer" {
  account_id   = "bq-writer-sa"
  display_name = "BigQuery Writer Service Account"
}

resource "google_project_iam_member" "bq_data_editor" {
  project = var.project_id
  role    = "roles/bigquery.dataEditor"
  member  = "serviceAccount:${google_service_account.bq_writer.email}"
}

resource "google_service_account_iam_member" "workload_identity_user" {
  service_account_id = google_service_account.bq_writer.name
  role               = "roles/iam.workloadIdentityUser"
  
  # The member string matches the Google subject mapping from the provider
  # format: principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT
  member = "principal://iam.googleapis.com/${google_iam_workload_identity_pool.aws_pool.name}/subject/system:serviceaccount:data-ingest:bq-writer"
}

4. The Application Code

The application running in EKS uses the Google Cloud SDK. The SDK automatically detects the projected service account token provided by EKS, uses it to authenticate against the GCP Workload Identity Pool, and retrieves a short-lived access token for the bq-writer-sa. No static keys are required.

# Kubernetes Service Account and Pod definition
apiVersion: v1
kind: ServiceAccount
metadata:
  name: bq-writer
  namespace: data-ingest
  annotations:
    # Optional: If you also need AWS permissions
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/bq-writer-role

---
apiVersion: v1
kind: Pod
metadata:
  name: bq-writer-app
  namespace: data-ingest
spec:
  serviceAccountName: bq-writer
  containers:
  - name: app
    image: my-registry/bq-writer:v1.2.0
    env:
    # Tell Google SDK where to find the credential configuration
    - name: GOOGLE_APPLICATION_CREDENTIALS
      value: /var/run/secrets/google/credentials.json
    volumeMounts:
    - name: google-cloud-key
      mountPath: /var/run/secrets/google
    - name: k8s-token
      mountPath: /var/run/secrets/tokens
  volumes:
  - name: google-cloud-key
    configMap:
      name: workload-identity-config
  - name: k8s-token
    projected:
      sources:
      - serviceAccountToken:
          path: oidc-token
          expirationSeconds: 3600
          audience: sts.amazonaws.com # Or your GCP audience

Pitfalls to Avoid

Implementing this architecture is not without its risks. Here are the common failure modes we observe when teams adopt decentralized IAM:

1. Broad Claim Mapping

When configuring the Workload Identity Provider attribute mapping, do not map broad claims. If you map "google.subject" = "assertion.aud", you are allowing any workload in the EKS cluster to impersonate the GCP service account. Always map down to the specific sub (subject) which includes the namespace and service account name (system:serviceaccount:namespace:sa-name).

2. Ignoring Token Expiration

Projected service account tokens in Kubernetes expire. Your application must be capable of dynamically reloading credentials. Most modern SDKs handle this automatically, but custom authentication logic often caches tokens indefinitely, leading to hard-to-debug failures when the token expires after an hour.

3. Neglecting Audit Logs

Decentralization obscures visibility. You must aggregate audit logs from AWS CloudTrail, GCP Cloud Logging, and your Kubernetes API server into a central SIEM. If a workload identity is compromised, you need to trace its actions across cloud boundaries. Ensure you correlate the sub claim from the OIDC token with the resulting API calls in the target environment.

The Outcome: Security as an Enabler

Moving to a federated, decentralized IAM architecture fundamentally changes the security posture of an engineering organization.

By eliminating static credentials, you eradicate the primary vector for supply chain attacks. When a developer needs a new service to access a cross-cloud resource, they don't request a key from the security team. They write a Terraform module to establish the trust relationship and define the policy.

Security becomes code. Trust becomes ephemeral. The infrastructure becomes resilient. This is the only path forward for serious engineering teams operating at scale.

Loading...

Read Next

The AI Engineer Shortage and How to Outsource Smartly

The AI engineer shortage is crippling ambitious roadmaps. Here is exactly how to outsource smartly, ...

Read article

Why Your Automation ROI is Flawed (And How to Fix It)

If you think time saved equals money earned, your automation ROI calculation is broken. Learn how to...

Read article
Chat with us