Skip to content

Support Azure Workload Identity (WIF) in image stream registry env vars#442

Open
kaovilai wants to merge 1 commit into
openshift:oadp-devfrom
kaovilai:azure-wif-registry
Open

Support Azure Workload Identity (WIF) in image stream registry env vars#442
kaovilai wants to merge 1 commit into
openshift:oadp-devfrom
kaovilai:azure-wif-registry

Conversation

@kaovilai

Copy link
Copy Markdown
Member

Note

Responses generated with Claude

Fixes #439 (linked Jira: OADP-6675)

Problem

getAzureRegistryEnvVars() always referenced oadp-<bsl>-azure-registry-secret for REGISTRY_STORAGE_AZURE_ACCOUNTKEY and the SPN env vars. On Azure Workload Identity (WIF/STS) clusters the OADP operator never creates that secret (no long-lived credentials to extract), so image stream backup failed with:

secrets "oadp-<bsl>-azure-registry-secret" not found

Fix

  • WIF detection (isAzureWorkloadIdentity): read the BSL credential secret (bsl.spec.credential, or OADP default cloud-credentials-azure/cloud). WIF when it contains no long-lived credentials (AZURE_STORAGE_ACCOUNT_ACCESS_KEY, AZURE_CLIENT_SECRET) and has AZURE_FEDERATED_TOKEN_FILE, or AZURE_CLIENT_ID + AZURE_TENANT_ID (format written by the operator's stsflow.CreateOrUpdateSTSAzureSecret). If the secret cannot be read, fall back to the previous long-lived behavior.
  • WIF mode env vars: only REGISTRY_STORAGE=azure, REGISTRY_STORAGE_AZURE_CONTAINER, REGISTRY_STORAGE_AZURE_ACCOUNTNAME. With no accountkey and no credentials.type=client_secret parameter, newAzureClient() in the openshift/docker-distribution v3 azure driver falls through to azidentity.NewDefaultAzureCredential, which authenticates via WorkloadIdentityCredential using AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_FEDERATED_TOKEN_FILE from the Velero pod environment. The registry runs in-process (udistribution) inside the Velero pod, so the pod environment is exactly the process environment azidentity reads.
  • Refactored getBslSecretPath into a shared getBslSecretKeySelector; added parseAzureCredentialsConfig env-file parser.

Changes required in other repos

None for OADP 1.5+:

Repo Status
openshift/oadp-operator (oadp-1.5+, oadp-dev) ReconcileAzureWorkloadIdentitySecret creates azure-workload-identity-env secret (AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_FEDERATED_TOKEN_FILE=/var/run/secrets/openshift/serviceaccount/token) and injects it into the Velero deployment via envFrom; bound-sa-token projected volume always mounted at /var/run/secrets/openshift/serviceaccount. OADP ≤ 1.4 operator lacks this wiring and would need it for this fix to work there.
openshift/docker-distribution (v3, pinned via go.mod replace) ✅ no change; DefaultAzureCredential fallthrough already present
migtools/udistribution ✅ no change; only consumes REGISTRY_* env strings for registry config, azidentity reads AZURE_* from process env

Credential type limitations

  • WIF requires the BSL to reference the STS-flow credential secret (e.g. cloud-credentials-azure/azurekey). Unreadable credential secret → long-lived path assumed.
  • Storage account key auth unchanged.
  • SPN (client secret) BSLs keep the existing REGISTRY_STORAGE_AZURE_SPN_* wiring, but those env var names parse into storage.azure.spn.client.id etc., which do not map to the distribution/v3 azure driver's credentials.{type,clientid,tenantid,secret} parameters — registry SPN auth was and remains non-functional. Account key and WIF are the working auth modes for the in-process registry.
  • The WIF identity must be able to generate user delegation keys on the storage account (e.g. Storage Blob Data Contributor), since the token-credential path signs blob URLs with user delegation SAS.

Testing

  • make test — all packages pass.
  • New Test_getAzureRegistryEnvVars_WorkloadIdentity (envtest): WIF secret → 3 env vars only; storage-account-key secret, SPN secret, missing secret → unchanged long-lived env vars.
  • New Test_parseAzureCredentialsConfig unit tests (operator azurekey format, quotes/CRLF/comments/sections, empty data).

🤖 Generated with Claude Code

Fixes openshift#439 (OADP-6675)

getAzureRegistryEnvVars() always referenced the
oadp-<bsl>-azure-registry-secret for REGISTRY_STORAGE_AZURE_ACCOUNTKEY and
the SPN env vars. On Azure WIF/STS clusters the OADP operator never creates
that secret (there are no long-lived credentials to extract), so image
stream backup failed with:
    secrets "oadp-<bsl>-azure-registry-secret" not found

Detect WIF by reading the BSL credential secret (bsl.Spec.Credential, or
the OADP default cloud-credentials-azure/cloud) and checking that it
contains no long-lived credentials (AZURE_STORAGE_ACCOUNT_ACCESS_KEY,
AZURE_CLIENT_SECRET) and does contain AZURE_FEDERATED_TOKEN_FILE, or
AZURE_CLIENT_ID plus AZURE_TENANT_ID (the format written by the operator's
stsflow.CreateOrUpdateSTSAzureSecret). If the secret cannot be read, fall
back to the previous long-lived behavior.

In WIF mode only REGISTRY_STORAGE, REGISTRY_STORAGE_AZURE_CONTAINER and
REGISTRY_STORAGE_AZURE_ACCOUNTNAME are set. With no accountkey and no
credentials.type=client_secret parameter, newAzureClient() in the
openshift/docker-distribution v3 azure storage driver falls through to
azidentity.NewDefaultAzureCredential, which authenticates via
WorkloadIdentityCredential using AZURE_CLIENT_ID, AZURE_TENANT_ID and
AZURE_FEDERATED_TOKEN_FILE from the Velero pod environment. The registry
runs in-process (udistribution) inside the Velero pod, so the pod
environment is the process environment azidentity reads.

Changes required in other repos: none for OADP 1.5+.
- openshift/oadp-operator (oadp-1.5 and oadp-dev already implement this):
  ReconcileAzureWorkloadIdentitySecret creates the
  azure-workload-identity-env secret (AZURE_CLIENT_ID, AZURE_TENANT_ID,
  AZURE_FEDERATED_TOKEN_FILE=/var/run/secrets/openshift/serviceaccount/token)
  and injects it into the Velero deployment via envFrom; the bound-sa-token
  projected volume is always mounted at
  /var/run/secrets/openshift/serviceaccount. Operator versions without that
  wiring (OADP <= 1.4) would additionally need it for this fix to work.
- openshift/docker-distribution (v3, pinned via go.mod replace): no change;
  the azure driver DefaultAzureCredential fallthrough already exists.
- migtools/udistribution: no change; it only consumes REGISTRY_* env
  strings for registry config, while azidentity reads AZURE_* from the
  process environment.

Credential type limitations:
- WIF requires the BSL to reference the STS-flow credential secret
  (e.g. cloud-credentials-azure/azurekey). If the BSL credential cannot be
  read, the long-lived path is assumed.
- Storage account key auth is unchanged (REGISTRY_STORAGE_AZURE_ACCOUNTKEY
  from the registry secret).
- SPN (client secret) BSLs keep the existing REGISTRY_STORAGE_AZURE_SPN_*
  wiring, but those env var names parse into storage.azure.spn.client.id
  etc., which do not map to the distribution/v3 azure driver's
  credentials.{type,clientid,tenantid,secret} parameters, so registry SPN
  auth was and remains non-functional; account key and WIF are the working
  auth modes for the in-process registry.
- The WIF identity must be authorized to generate user delegation keys on
  the storage account (e.g. Storage Blob Data Contributor), since the
  token-credential path signs blob URLs with user delegation SAS.

Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Caution

Review failed

An error occurred during the review process. Please try again later.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@openshift-ci

openshift-ci Bot commented Jul 15, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: kaovilai

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 15, 2026
@kaovilai

Copy link
Copy Markdown
Member Author

/hold for testing in far future

@openshift-ci openshift-ci Bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jul 15, 2026
@openshift-ci

openshift-ci Bot commented Jul 15, 2026

Copy link
Copy Markdown

@kaovilai: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Image stream backup: Azure Workload Identity (WIF) not supported in registry env var wiring

1 participant