Skip to content

feat(pod-identity): add Argo Rollouts IAM role for AMP query (IRSA, #42) - #831

Open
allamand wants to merge 8 commits into
release/v0.3.0-rc3from
fix/argo-rollouts-pod-identity
Open

feat(pod-identity): add Argo Rollouts IAM role for AMP query (IRSA, #42)#831
allamand wants to merge 8 commits into
release/v0.3.0-rc3from
fix/argo-rollouts-pod-identity

Conversation

@allamand

@allamand allamand commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Problem

The Argo Rollouts controller needs to query Amazon Managed Prometheus (AMP) to run the metrics analysis gate in Phase 30.5. The SA annotation in gitops/addons/registry/gitops.yaml already points to arn:aws:iam::<account>:role/<clusterName>-argo-rollouts, but that role was never created and the OIDC provider was never registered.

Root cause: IRSA required, Pod Identity won't work

prometheus/common/sigv4 v0.1.0 (used by Argo Rollouts for AMP SigV4 auth) uses aws-sdk-go v1.38.35 which supports AWS_WEB_IDENTITY_TOKEN_FILE (IRSA) but not AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE (Pod Identity token file).

Upstream tracking: argoproj/argo-rollouts#4536
Upstream fix PR (migrate to aws-sdk-go-v2): argoproj/argo-rollouts#5010

Complete fix (all 5 pieces)

1. IAM Role + Policy (ack-pod-identity chart)

New argo-rollouts identity with skipPIA: true and AMP query policy. skipPIA prevents creating a PodIdentityAssociation (which would trigger Pod Identity injection instead of IRSA).

2. IRSA trust policy in role.yaml (new)

When skipPIA: true AND aws.oidcIssuer is set, the role gets an IRSA trust policy (sts:AssumeRoleWithWebIdentity with OIDC condition) instead of the default Pod Identity trust (pods.eks.amazonaws.com).

3. oidcIssuer injected into chart values (core.yaml)

The ack_pod_identities ApplicationSet now injects aws.oidcIssuer from the cluster secret annotation eks_oidc_issuer (written by the EksCluster RGD at cluster-creation time).

4. OIDC provider registration at bootstrap (kind-kro-ack Taskfile)

New task spokes:register-oidc-providers — discovers spoke clusters from fleet/members, reads each cluster's OIDC issuer, and registers it as an IAM OpenID Connect provider if not already present. This is the missing piece: EKS creates the OIDC endpoint automatically but does NOT register the provider in IAM, which is required for IRSA to work.

Called from workshop/Taskfile.yaml after wait-for-spokes (clusters are ACTIVE at that point), only when PROVIDER=kind-kro-ack.

5. Mirror in crossplane-pod-identity (drift test requirement)

Same skipPIA flag and oidcIssuer support mirrored to the Crossplane chart.

Files changed

File Change
ack-pod-identity/values.yaml argo-rollouts identity: skipPIA: true, AMP policy
ack-pod-identity/templates/role.yaml IRSA trust when skipPIA=true + oidcIssuer set
ack-pod-identity/templates/pod-identity-association.yaml Skip PIA when skipPIA: true
crossplane-pod-identity/values.yaml Mirror
crossplane-pod-identity/templates/pod-identity-association.yaml Mirror
overlays/environments/dev/pod-identities/values.yaml Enable on dev spokes
overlays/environments/prod/pod-identities/values.yaml Enable on prod spokes
gitops/addons/registry/core.yaml Inject aws.oidcIssuer from cluster secret
cluster-providers/kind-kro-ack/Taskfile.yaml New task spokes:register-oidc-providers
workshop/Taskfile.yaml Call OIDC registration after wait-for-spokes

Future state

Once argoproj/argo-rollouts#5010 is merged and released (aws-sdk-go-v2, Pod Identity support):

  • Remove skipPIA: true → use Pod Identity normally
  • Remove spokes:register-oidc-providers call from workshop Taskfile
  • The OIDC provider registration becomes optional

Validation

Tested on kro-c1 (586794472760), spoke cluster peeks-spoke-dev:

  1. OIDC provider registered manually (simulates the new bootstrap task) ✅
  2. ACK creates IAM Role with IRSA trust policy ✅
  3. No PodIdentityAssociation (skipPIA) → IRSA injection via AWS_WEB_IDENTITY_TOKEN_FILE
  4. Manual AnalysisRun: phase=Successful, value=[1,1,1...]

Fixes Issue #42 in platform-engineering-on-eks tracker.

…sters

Adds an `argo-rollouts` identity entry to both pod-identity charts (ack and
crossplane mirrors) and enables it in the dev and prod spoke overlays.

## Problem (Issue #42)

The Argo Rollouts controller needs to query Amazon Managed Prometheus (AMP)
to run the `metrics` analysis gate in Phase 30.5 (Metrics Driven Decisions).
The `AnalysisTemplate` uses Prometheus `sigv4` auth — the controller signs
requests with AWS SigV4 credentials from the default AWS credential chain.

The SA annotation in `gitops/addons/registry/gitops.yaml` already points to
`<clusterName>-argo-rollouts` but that role was never created by any chart,
so the Pod Identity Agent had nothing to inject → SigV4 calls failed.

## Fix

- Adds `argo-rollouts` identity (disabled by default) to both chart mirrors
  with an inline `ArgoRolloutsAMPQueryPolicy` (aps:QueryMetrics and read-only
  APS actions). Role name pattern follows the charts' convention:
  `<aws.clusterName>-argo-rollouts` (matches the gitops.yaml SA annotation).
- Enables the identity in the `dev` and `prod` spoke environment overlays
  (spoke clusters are where Argo Rollouts runs; hub/control-plane excluded).
- Chart comment explains the Pod Identity flow — no OIDC/IRSA required; the
  AWS SDK v1 default chain picks up `AWS_CONTAINER_CREDENTIALS_FULL_URI` that
  the Pod Identity Agent injects once the PIA exists.

## Validation plan

Apply to kro-c1 live (peeks-spoke-dev) and verify:
1. ACK creates IAM Role `peeks-spoke-dev-argo-rollouts` and PIA
2. Argo Rollouts pod restarts → `AWS_CONTAINER_CREDENTIALS_FULL_URI` present
3. Phase 30.5 metrics AnalysisRun succeeds (SigV4 AMP query returns > 0)

Fixes #42 (platform-engineering-on-eks issue tracker)
@allamand

allamand commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Live test results + Root cause analysis

✅ What works

  • ACK creates IAM Role peeks-spoke-dev-argo-rollouts + PodIdentityAssociation ✅
  • Pod restart → AWS_CONTAINER_CREDENTIALS_FULL_URI=http://169.254.170.23/v1/credentials injected ✅
  • AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE=/var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token present ✅

❌ What doesn't work yet (upstream bug)

prometheus/common/sigv4 v0.1.0 (used by Argo Rollouts all versions including v1.10) depends on aws-sdk-go v1.38.35 (April 2021). This version only supports AWS_CONTAINER_AUTHORIZATION_TOKEN (env var with token value) — it does not support AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE (path to token file, introduced in SDK v1.44+).

EKS Pod Identity injects the file path variant, not the env var. So the SDK v1.38.35 credential chain fails with NoCredentialProviders.

NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors

Fix options

Option A (upstream fix) — Update prometheus/common/sigv4 to use a newer aws-sdk-go version that reads the token from the file. Needs a PR to https://github.com/prometheus/common and then updating argo-rollouts to use the newer version.

Option B (Helm workaround) — Add an initContainer or sidecar to copy the token file content into AWS_CONTAINER_AUTHORIZATION_TOKEN env var. Can be done via the Helm chart extraEnv + extraVolumes.

Option C (use IRSA annotation instead of PIA) — The SA already has the IRSA annotation (eks.amazonaws.com/role-arn). If the OIDC provider for the spoke cluster is registered, IRSA injects a WEBIDENTITY_TOKEN_FILE which aws-sdk-go v1.38+ does support. We created the OIDC provider manually (kro-c1) and it worked in the previous test run where IRSA was used.

Recommendation

This PR is still valuable — it creates the IAM Role + PIA correctly. But a companion change is needed to make the credentials actually work:

  • Either implement Option B (Helm values override to expose token as env var)
  • Or implement Option C (OIDC provider + IRSA trust policy, relying on the existing SA annotation)

Option C is the path of least resistance given the SA annotation already uses IRSA format.

@allamand

allamand commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

✅ Live test VALIDATED on kro-c1

Summary

After resolving two additional issues, the metrics gate works end-to-end:

AnalysisRun result:

phase=Successful  value=[1,1,1,1,1,1,1,1,0,1...]
✅ AMP SigV4 via IRSA FULLY VALIDATED!

Issue 1 — Pod Identity vs IRSA (aws-sdk-go v1 incompatibility)

prometheus/common/sigv4 v0.1.0 uses aws-sdk-go v1.38.35 which does not support AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE. EKS Pod Identity injects the token as a file path; the old SDK only handles AWS_CONTAINER_AUTHORIZATION_TOKEN (token value as env var).

Fix: Remove the PodIdentityAssociation for argo-rollouts. The SA already has the eks.amazonaws.com/role-arn IRSA annotation — with the OIDC provider registered and PIA absent, EKS injects AWS_WEB_IDENTITY_TOKEN_FILE instead, which the SDK v1.38 does support.

PR action: This chart creates the IAM role via ACK and a PodIdentityAssociation. The PIA needs to be removed from the ACK template — we want IRSA injection, not Pod Identity injection. Update pod-identity-association.yaml to skip creating the PIA for argo-rollouts (or add a skipPIA flag).

Issue 2 — AMP URL must NOT include /api/v1/query (Bug #38 extension)

The ExternalSecret amp-workspace-secrets-rust-microservice-dev syncs from peeks/platform/amp and the amp-workspace value was set to the full query URL:
https://aps-workspaces.../api/v1/query

The Prometheus client appends /api/v1/query to the address, producing:
https://aps-workspaces.../api/v1/query/api/v1/queryHTTP 404

Fix: Store only the workspace base URL:
https://aps-workspaces.us-west-2.amazonaws.com/workspaces/${ws-id}

This needs to be fixed in the bootstrap process that creates peeks/platform/amp in Secrets Manager.

Next steps for this PR

  1. Modify ack-pod-identity/templates/pod-identity-association.yaml to support a skipPIA flag (or remove PIA for argo-rollouts)
  2. Document that the OIDC provider must be pre-registered for spoke clusters
  3. Update issues tracker with Bug Fixing Guest from Teams for backstage templates #38 extension (URL format)

…ead of Pod Identity

Adds a `skipPIA: true` opt-out field to the pod-identity charts. When set,
the PodIdentityAssociation CR is not created (only IAM Role + Policy are).

This is required for Argo Rollouts because:
- The SA annotation `eks.amazonaws.com/role-arn` uses the IRSA mechanism
- `prometheus/common/sigv4 v0.1.0` (used by Argo Rollouts for AMP SigV4 auth)
  depends on `aws-sdk-go v1.38.35` which supports `AWS_WEB_IDENTITY_TOKEN_FILE`
  (IRSA) but NOT `AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE` (Pod Identity)
- Creating a PIA would inject Pod Identity tokens which the old SDK cannot read,
  causing `NoCredentialProviders` errors

With `skipPIA: true` + OIDC provider registered + IRSA trust policy on the role,
the pod gets `AWS_WEB_IDENTITY_TOKEN_FILE` injected → SigV4 AMP queries work.

Validated live on kro-c1 (peeks-spoke-dev): AnalysisRun Successful with
`value=[1,1,1,1,...]` — AMP queries returning real metrics.

Note: Also revealed a second bug (AMP URL format) — the `peeks/platform/amp`
Secrets Manager secret must store the workspace base URL WITHOUT the
`/api/v1/query` suffix. The Prometheus client appends it automatically.
Correct: `https://aps-workspaces.us-west-2.amazonaws.com/workspaces/${ws-id}`
Wrong:   `https://...workspaces/${ws-id}/api/v1/query` → 404 on every query
… not Pod Identity

Clarify that argo-rollouts uses IRSA (not Pod Identity) because
prometheus/common/sigv4 v0.1.0 only supports AWS_WEB_IDENTITY_TOKEN_FILE.
References argoproj/argo-rollouts#5010 for the upstream fix.
@allamand allamand changed the title feat(pod-identity): add Argo Rollouts AMP query identity to spoke clusters (#42) feat(pod-identity): add Argo Rollouts IAM role for AMP query (IRSA, #42) Sep 1, 2026
…true

When an identity has skipPIA=true (no PodIdentityAssociation created), the
IAM role needs an IRSA trust policy instead of a Pod Identity trust policy.

Changes:
- role.yaml: conditionally generates IRSA trust (sts:AssumeRoleWithWebIdentity
  with OIDC condition) when skipPIA=true AND aws.oidcIssuer is set, otherwise
  falls back to Pod Identity trust (pods.eks.amazonaws.com)
- core.yaml: injects aws.oidcIssuer from cluster secret annotation
  eks_oidc_issuer into the ack_pod_identities chart values

This completes the argo-rollouts fix: the role now has the correct trust
policy for IRSA injection (AWS_WEB_IDENTITY_TOKEN_FILE) which is required
because prometheus/common/sigv4 v0.1.0 does not support Pod Identity.

Note: aws.oidcIssuer requires the OIDC provider to be registered in IAM.
On EKS, this is done automatically since EKS 1.25 at cluster creation time.
The EksCluster RGD writes eks_oidc_issuer to the cluster secret.
Temporary workaround for argoproj/argo-rollouts#4536:
Argo Rollouts' SigV4 provider (prometheus/common/sigv4 v0.1.0 / aws-sdk-go
v1.38) supports IRSA but not Pod Identity. IRSA requires the EKS OIDC issuer
to be registered as an IAM OpenID Connect provider — EKS creates the endpoint
automatically but does NOT register it in IAM.

Changes:
- cluster-providers/kind-kro-ack/Taskfile.yaml: new task
  'spokes:register-oidc-providers' — discovers spoke clusters from fleet/members,
  reads each cluster's OIDC issuer, and creates the IAM OIDC provider if missing.
  Idempotent (skips if already registered). Only runs on kind-kro-ack.
- workshop/Taskfile.yaml: call the new task after wait-for-spokes (spokes are
  ACTIVE at that point) but only when PROVIDER=kind-kro-ack.
- gitops/addons/registry/core.yaml: inject aws.oidcIssuer from the cluster
  secret annotation into ack-pod-identity chart values (used by role.yaml
  to build the IRSA trust policy for skipPIA identities).

Together with PR #831 (argo-rollouts IAM role + skipPIA IRSA trust policy),
this makes the OIDC provider available so the role's trust policy can be
satisfied and IRSA injection (`AWS_WEB_IDENTITY_TOKEN_FILE`) works.

This workaround will be removed once argoproj/argo-rollouts#5010 is merged.
…ke scrapers

The initial seed-observability runs in the background during hub install,
before spoke clusters (peeks-spoke-dev/prod) exist. The spoke scraper loop
finds no clusters → spoke_dev_cluster_arn/subnet/sg annotations are empty in
the hub Secrets Manager secret → ESO propagates empty values to the ArgoCD
cluster secret → observability-aws chart generates no spoke Crossplane Scrapers.

Fix: re-run seed-observability after wait-for-spokes (spokes are ACTIVE at that
point) so spoke cluster ARN/SG/subnets are correctly seeded into SM and the
observability-aws chart generates spoke scrapers on the next sync.

Verified: Team 10 (ADIDAS PEEKS, fresh WS account) confirms the bug — only
peeks-peeks-hub scraper present, no peeks-spoke-dev scraper. Phase 30.5
metrics gate fails because Rust application metrics (team-rust namespace) are
not in AMP.
…y seed

The seed-observability task used hardcoded 'spoke-dev'/'spoke-prod' cluster
names when calling 'aws eks describe-cluster'. The actual cluster names are
'<prefix>-spoke-dev' / '<prefix>-spoke-prod' (e.g. 'peeks-spoke-dev').

This caused:
  WARN: Cluster spoke-dev not found in us-west-2. Scraper skipped.
  WARN: Cluster spoke-prod not found in us-west-2. Scraper skipped.

So the spoke_dev_cluster_arn/subnet/sg annotations were never written to the
hub Secrets Manager secret → observability-aws chart generated no spoke
Crossplane Scrapers → Phase 30.5 metrics gate always fails (no spoke metrics
in AMP).

The peeks-observability-seed.timer runs every 20min and kept overwriting any
manually-set annotations with empty values.

Fix: replace 'spoke-dev spoke-prod' with
'{{.RESOURCE_PREFIX}}-spoke-dev {{.RESOURCE_PREFIX}}-spoke-prod' in both
kind-kro-ack and kind-crossplane Taskfiles.

Verified on Team 10 (ADIDAS PEEKS, account 795798215864): log showed
exactly the WARN message above on every timer run.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant