2026-07: Secure Workload Identity for Single-Operator Multitenancy
Context
ASO supports single-operator multitenancy via a three-level credential hierarchy:
- Global credentials (via the
aso-controller-settingssecret in the operator namespace) - Per-namespace credentials (via a fixed
aso-credentialsecret in the resource’s namespace) - Per-resource credentials (via the
serviceoperator.azure.com/credential-fromannotation)
When using Workload Identity for
authentication, each credential secret contains only AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID, and AZURE_CLIENT_ID.
The operator then uses its own projected ServiceAccount token
(system:serviceaccount:azureserviceoperator-system:azureserviceoperator-default) to perform an OAuth2 token exchange
with Azure AD, presenting the AZURE_CLIENT_ID from the secret. This works because the Managed Identity has a
FederatedIdentityCredential registered for the ASO controller’s ServiceAccount subject.
The Security Problem
Unlike service principal and certificate authentication modes, none of the values in a Workload Identity credential
secret (AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID, AZURE_CLIENT_ID) are truly secret. They are GUIDs that can be discovered through:
- The Azure portal or CLI (e.g.
az identity show) - Azure Resource Graph queries
- Reading secrets in other namespaces if the user has RBAC access to do so
- Social engineering or documentation leaks
Because all namespaces share the same ServiceAccount token for the Azure token exchange, a user who can create ASO
resources in any namespace can forge a credential secret referencing any Managed Identity that has a
FederatedIdentityCredential configured for the ASO ServiceAccount. This is a privilege escalation vulnerability:
a tenant in namespace team-a can create a secret with team-b’s AZURE_CLIENT_ID and use team-b’s Azure identity
to manage Azure resources.
This has been raised as a security concern by multiple users (#4810, #4807).
The only current mitigation is deploying ASO in multi-operator multitenancy mode, where each namespace has its own ASO pod and ServiceAccount. This provides true isolation because each pod’s Service Account token can only be exchanged for the Managed Identity it is federated with. However, multi-operator multitenancy is significantly harder to administer (multiple CRD installs, webhook routing, independent upgrades) and does not scale well.
Requirements
- Namespace-level credential isolation: It must not be possible for a tenant in one namespace to use a Managed Identity that has been authorized for a different namespace, even if they know the Client ID.
- Privileged authorization: The binding between a namespace and an Azure identity must be authorized by a user with appropriate privileges (cluster admin or similar), not merely by possession of credential values.
- Self-service bootstrapping: Teams that have already created a Managed Identity with appropriate
FederatedIdentityCredentials should be able to bootstrap their namespace without requiring write access to the
azureserviceoperator-systemnamespace. - Backward compatibility: The existing credential hierarchy and secret format should continue to work for users who don’t need the hardened mode. This should be opt-in (at least, for now).
- Workload Identity focus: While the solution should be designed with extensibility in mind, the primary target is Workload Identity, as client secret and client certificate authentication modes have genuinely secret credential values that provide their own authorization factor.
- Single operator: The solution must work within the single-operator multitenancy model (one ASO pod for the whole cluster).
- Manageable complexity: The solution should be simpler to administer than multi-operator multitenancy — that is the entire motivation for single-operator mode.
Options
Option 1: ServiceAccount Impersonation (Per-Namespace ServiceAccounts for Azure Auth Only)
The ASO controller impersonates a namespace-scoped ServiceAccount to obtain a token for Azure AD token exchange, instead of using its own ServiceAccount token directly.
Setup (admin actions):
- Cluster admin installs ASO and configures new ASO configuration
AZURE_WORKLOAD_IDENTITY_AUTH_MODE=strict(in the globalaso-controller-settingssecret). - Cluster admin creates a
ServiceAccountin each tenant namespace (e.g.,aso-team-ain namespaceteam-a). - Cluster admin creates a
FederatedIdentityCredentialin Azure forteam-a’s Managed Identity with subjectsystem:serviceaccount:team-a:aso-team-a. - Cluster admin creates an RBAC
Role/RoleBindingorClusterRole/ClusterRoleBindinggranting ASO’s controller ServiceAccount permission to create tokens for (serviceaccounts/token) the per-namespace Service Account. - The credential secret in
team-areferences the Client ID ofteam-a’s Managed Identity as before.
Auth flow:
- User creates an ASO resource in namespace
team-a. - ASO reads the credential secret from
team-a, which includes the Client ID and the Service Account name (aso-team-a). - ASO uses the TokenRequest API to mint a short-lived token for
ServiceAccount team-a/aso-team-awith audienceapi://AzureADTokenExchange. The token’s subject issystem:serviceaccount:team-a:aso-team-a. - ASO exchanges this token with Azure AD for an access token, presenting the Client ID from the secret.
- Azure AD validates that the FederatedIdentityCredential on the Managed Identity matches the token’s subject —
since the FIC is scoped to
team-a’s Service Account, other namespaces cannot use this identity even if they know the Client ID.
Implementation details:
- ASO would use the Kubernetes TokenRequest API
to create a short-lived token for the target namespace’s Service Account with the
api://AzureADTokenExchangeaudience. It would cache this token and manage refreshing it as-needed. - The controller needs
serviceaccounts/token: createpermission for the well-known Service Account name. With the fixed-name convention, this is a singleClusterRole/ClusterRoleBindingscoped viaresourceNames: ["aso-workload"], shipped as part of the ASO Helm chart. - In the configurable variant (not chosen), a new field in the credential secret would indicate the Service Account name. With the fixed-name convention chosen in this design, no credential secret changes are needed.
Variant: Fixed vs. configurable Service Account name
There are two sub-variants for how the Service Account name is determined:
- Configurable (per-secret): The credential secret includes a field (
AZURE_WORKLOAD_IDENTITY_SERVICE_ACCOUNT) specifying which Service Account to use. This is the most flexible — different credentials in the same namespace could use different SAs. - Fixed convention: ASO uses a well-known Service Account name (e.g.,
aso-workload) in every namespace. No configuration is needed — if the Service Account exists and the RBAC grant is in place, ASO uses it automatically.
The fixed-name approach is simpler to administer and requires no changes to the credential secret format. The configurable variant could be offered as a future extension if there’s demand.
- When this mode is enabled, if ASO encounters a namespace without the designated Service Account or without the RBAC grant, it refuses to authenticate and sets a clear error condition on the resource.
- Note that the per-namespace Service Account only needs to exist and be tokenizable; it doesn’t need any Kubernetes RBAC permissions itself.
- Both namespace-scoped credentials and per-resource credentials within that namespace would use the same Service Account for token exchange. Since Kubernetes RBAC is also namespace-scoped, there is no hard security boundary between these two levels within the same namespace — the isolation boundary is the namespace itself.
- The TokenRequest API call adds a small amount of latency to Azure authentication. However, the Service Account token can be requested with a configurable expiration (e.g., 1 hour) and cached, so the extra API call only occurs on initial auth and periodic refresh — not on every Azure API call.
Pros:
- Uses native Kubernetes primitives (ServiceAccount, TokenRequest API, RBAC) — no new CRDs.
- RBAC for
serviceAccounts/tokenon the main ASO service account can be scoped to specific Service Account names usingresourceNames, if desired. - The authorization gate is the FederatedIdentityCredential in Azure (which requires Azure-level permissions to create) and the RBAC grant allowing ASO to mint tokens for the per-namespace Service Account (which requires cluster-admin). Without both, ASO can’t authenticate in that namespace. Since each serviceAccount must have a FederatedIdentityCredential bound to a unique subject (including that Service Account name + namespace), stealing a Client ID is useless since each Client ID only works for the Service Account it is bound to.
- Credential secrets retain their existing format — no changes needed.
- Minimal change to ASO’s Kubernetes RBAC model and controller architecture.
- Supports self-service bootstrapping: once the ClusterRole is installed with ASO, teams can create the Service Account in their
own namespace and the FIC in Azure without needing write access to
azureserviceoperator-system.
Cons:
- Requires the
AZURE_WORKLOAD_IDENTITY_AUTH_MODEfeature to be enabled (at least initially), it is not the default. If not enabled, the security benefit is lost. - Requires cluster admin to create a ServiceAccount and RBAC binding per namespace — this is the “cost” of security, but it’s the same cost External Secrets Operator imposes (see Appendix: External Secrets Operator) and is significantly less than multi-operator multitenancy.
- Only addresses Workload Identity. Client secret/certificate auth modes don’t benefit (though they don’t need to, as their credentials are genuinely secret).
- Does not provide Kubernetes-level audit trail showing which Service Account performed which operations in which namespace.
- Each namespace requires its own FederatedIdentityCredential on the Managed Identity. Azure limits the number of FICs per identity (currently 20), so using the same identity across many namespaces will hit this limit. Users needing the same identity in more than 20 namespaces would need to create duplicate Managed Identities with the same role assignments, or use the AKS Identity Bindings feature.
Option 2: ServiceAccount Impersonation for Both Azure Auth AND Kubernetes Operations
This option extends Option 1 by also impersonating the per-namespace Service Account for all Kubernetes operations in that namespace: reading secrets, watching ASO resources, writing status, creating output secrets/configmaps — in addition to Azure token exchange.
Pros:
- All the pros of Option 1.
- Full isolation: each namespace’s operations are performed under that namespace’s Service Account identity.
- Kubernetes audit logs clearly attribute operations to the per-namespace SA.
Cons:
- See option 1’s cons as well.
- Significantly more complex to implement. The ASO controller currently uses a single informer/cache for all namespaces. Impersonating different SAs for different namespaces would require per-namespace clients or impersonation headers on every API call.
- Each per-namespace Service Account would need its own RBAC grants for the ASO resource types, secrets, configmaps, and events in its namespace. This is a large amount of RBAC to administer.
- Performance implications: per-namespace informer caches or impersonation on every call adds both CPU and memory overhead. While the actual resources being monitored would be the same as today, the overhead would be running the informer cache infrastructure N times (1x per namespace) rather than once, like we do today.
- Closer to multi-operator multitenancy in management complexity, undermining the simplicity benefit of single-operator mode.
- Does not meaningfully reduce the blast radius of an ASO pod compromise compared to Option 1. In both cases, the ASO controller’s own Service Account retains broad cluster-wide Kubernetes permissions — and in Option 2 it also has RBAC to mint tokens for every managed namespace’s SA, so compromising the ASO pod grants equivalent access either way.
- Fundamentally changes ASO’s controller architecture in ways that are difficult to make backward-compatible.
Option 3: Admin-Controlled Credential CRD (ASO-Managed SecretStore Equivalent)
Introduce a new namespaced CRD (e.g., ASOCredential or CredentialBinding) that only cluster admins can create,
replacing the use of Secrets as the credential mechanism for Workload Identity. This is conceptually similar to
the approach used by the External Secrets Operator (see Appendix: External Secrets Operator
for a detailed comparison).
Setup:
- Cluster admin creates an
ASOCredentialCR in each tenant namespace specifying the Client ID, Tenant ID, and Subscription ID. - ASO watches
ASOCredentialresources and uses them instead of (or in addition to) credential secrets. - RBAC for
ASOCredentialresources is restricted to cluster admins. - Optionally, ASO is configured with
AZURE_DISALLOW_WORKLOAD_IDENTITY_SECRETS=true(in the globalaso-controller-settingssecret) that causes it to reject credential secrets containing Workload Identity configuration, ensuringASOCredentialCRDs are the only accepted path for Workload Identity.
Pros:
- Clear admin-controlled authorization boundary (CRD RBAC, not Secret RBAC).
- Auditable — CRD resources are visible via
kubectl get asocredentials. - Does not require per-namespace ServiceAccounts or RBAC for token creation.
- With secrets disabled for Workload Identity, the shared Service Account token is not exploitable — users have no way to get ASO to perform a token exchange with an unauthorized Client ID.
- Does not consume FederatedIdentityCredentials per namespace (avoids the 20 FIC-per-identity Azure limit).
- Does not require write access to
azureserviceoperator-systemfor per-namespace setup, but does require a cluster admin to create theASOCredentialresource.
Cons:
- Adds a new CRD to ASO’s already large CRD footprint.
- Requires a parallel credential resolution path alongside the existing Secret-based system. CRD cannot be used for
ServicePrincipal or Certificate based auth because those actually contain secret data and so must be stored in a
Kubernetes secret.
- The CRD could theoretically hold ServicePrincipal or Certificate credentials too, but Kubernetes
Secretresources benefit from encryption at rest (viaEncryptionConfiguration), audit log redaction, and other special handling that CRD specs do not receive by default.
- The CRD could theoretically hold ServicePrincipal or Certificate credentials too, but Kubernetes
- ASO already has a working Secret-based system and users using it for Workload Identity, making migration awkward.
Option 4: Namespace Label/Annotation Allowlist
The ASO operator configuration includes an allowlist mapping Client IDs to allowed namespaces. The operator rejects credential secrets whose Client ID is not explicitly allowed for the secret’s namespace.
Setup:
- Cluster admin configures ASO (via Helm values, global ConfigMap, or operator flags) with a mapping:
client-id-x → [namespace-a, namespace-b]. - When ASO reads a credential secret, it checks the Client ID against the allowlist for that namespace.
- If the Client ID is not allowed, reconciliation fails with a clear error.
Pros:
- No new CRDs or ServiceAccounts required.
- Centralized configuration — admin manages one allowlist.
- Simple conceptual model.
Cons:
- Centralized configuration does not scale: every namespace/identity change requires updating the operator config and potentially restarting the operator.
- Awkward to manage in GitOps workflows where namespace and identity provisioning are decentralized.
- If the allowlist is not enforced (i.e., made optional or left unconfigured), the security benefit is lost — same
as Option 3 without
AZURE_DISALLOW_WORKLOAD_IDENTITY_SECRETSor option 1/2 withoutAZURE_WORKLOAD_IDENTITY_AUTH_MODE. - Does not support self-service bootstrapping: every namespace/identity change requires an admin to update the
allowlist in
aso-controller-settings(in theazureserviceoperator-systemnamespace).
Option 5: Admission Webhook Validation
Deploy an admission webhook (built into ASO or external via OPA/Kyverno) that validates credential secrets on creation/update, rejecting secrets with unauthorized Client IDs.
Pros:
- Can be implemented with existing tools (Kyverno, OPA Gatekeeper) without ASO changes.
- Preventive — blocks unauthorized secrets before they’re created.
Cons:
- External policy engines are an additional dependency and management burden.
- Built-in webhook would need the same allowlist configuration as Option 4.
- Users could potentially work around the webhook (e.g., creating the secret before the webhook is deployed,
or if the webhook is unavailable due to
failurePolicy: Ignore). - Not a defense-in-depth solution — it’s a gate at one point, not a fundamental architectural fix.
- Policy management is typically centralized (cluster-scoped policies or operator namespace), limiting self-service bootstrapping by teams.
Decision
We choose Option 1: ServiceAccount Impersonation (Service Account for Azure token exchange only), using the
fixed convention variant: ASO uses a well-known ServiceAccount name (aso-workload) in every namespace. This option will be
disabled by default and configured via the new AZURE_WORKLOAD_IDENTITY_AUTH_MODE setting in aso-controller-settings.
This setting accepts two values:
relaxed(default): ASO uses its own Service Account token for all Workload Identity token exchanges, matching current behavior.strict: ASO requires a per-namespaceaso-workloadServiceAccount for namespace-scoped and per-resource Workload Identity credentials. The global credential (aso-controller-settings) continues to use ASO’s own SA token, since it is managed by cluster admins who are already trusted.
This option provides the strongest security guarantee: the FederatedIdentityCredential is bound to a per-namespace ServiceAccount subject, so possessing a Client ID alone is insufficient to use an identity. The real authorization boundary is twofold:
- Kubernetes side (necessary but not the security boundary): The team must be able to create a ServiceAccount and a credential Secret in their namespace. These are common namespace-admin permissions. The ClusterRole shipped with ASO pre-authorizes token creation for the well-known Service Account name, so no per-namespace cluster-admin approval is needed.
- Azure side (the real security boundary): The team must have Azure-level permissions to create a FederatedIdentityCredential on the Managed Identity, binding it to the namespace’s Service Account subject. Without this, the token exchange will fail — even if the Kubernetes resources exist. This is the authorization gate that prevents unauthorized use of an identity.
Together these mean the Kubernetes setup is a prerequisite, but the actual trust decision is made in Azure: only users who can configure a FIC for a given Managed Identity can authorize a namespace to use it. It is worth noting that users can configure ASO to do this for them, see Using ASO to create its own credentials.
Using a fixed Service Account name means no changes to the credential secret format are needed. The credential secret continues
to contain only AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID, and AZURE_CLIENT_ID as before. It also means that
a ClusterRole/ClusterRoleBinding can be automatically included at ASO install time enabling impersonation of specifically
those accounts, which makes management easy.
Proposed Configuration
When AZURE_WORKLOAD_IDENTITY_AUTH_MODE=strict is set in the global aso-controller-settings secret,
ASO requires a ServiceAccount named aso-workload to exist in each namespace where namespace-scoped or per-resource
Workload Identity credentials are used. The global credential continues to use ASO’s own Service Account token.
The credential secret format is unchanged from the current format.
When this mode is enabled:
- ASO looks for a ServiceAccount named
aso-workloadin the resource’s namespace. - ASO uses the TokenRequest API to mint a short-lived token for that Service Account with audience
api://AzureADTokenExchange. - ASO uses this token (instead of its own projected Service Account token) for the OAuth2 token exchange with Azure AD.
- The FederatedIdentityCredential on the Managed Identity must have subject
system:serviceaccount:<namespace>:aso-workload(not the ASO controller’s SA).
When AZURE_WORKLOAD_IDENTITY_AUTH_MODE is not set or is relaxed, ASO falls back to the current
behavior (using its own Service Account token for all namespaces), maintaining backward compatibility.
Admin Setup Workflow
The RBAC grant for token creation can be done once at the cluster level using the fixed Service Account name. ASO ships this
ClusterRole/ClusterRoleBinding as part of its Helm chart when the feature is enabled:
# Shipped with ASO (Helm chart) — grants ASO permission to create tokens
# for any Service Account named "aso-workload" in any namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: aso-token-creator
rules:
- apiGroups: [""]
resources: ["serviceaccounts/token"]
resourceNames: ["aso-workload"]
verbs: ["create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: aso-token-creator
subjects:
- kind: ServiceAccount
name: azureserviceoperator-default
namespace: azureserviceoperator-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: aso-token-creator
Per-namespace setup:
# 1. Create the well-known ServiceAccount in the tenant namespace
kubectl create serviceaccount aso-workload -n team-a
# 2. Create the FederatedIdentityCredential in Azure for team-a's Managed Identity
# This can also be done using ASO itself, see:
# https://azure.github.io/azure-service-operator/guide/authentication/#using-aso-to-create-its-own-credentials
az identity federated-credential create \
--name team-a-aso \
--identity-name team-a-identity \
--resource-group rg-identities \
--issuer "${AKS_OIDC_ISSUER}" \
--subject "system:serviceaccount:team-a:aso-workload" \
--audience "api://AzureADTokenExchange"
# 3. Create the credential secret (format unchanged)
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: aso-credential
namespace: team-a
stringData:
AZURE_SUBSCRIPTION_ID: "${SUBSCRIPTION_ID}"
AZURE_TENANT_ID: "${TENANT_ID}"
AZURE_CLIENT_ID: "${TEAM_A_CLIENT_ID}"
EOF
Because the ClusterRole uses resourceNames: ["aso-workload"], ASO can only create tokens for SAs with that
exact name — it cannot mint tokens for arbitrary ServiceAccounts.
FAQ
Q: Does this work with the global credential (aso-controller-settings)?
A: The global credential always uses ASO’s own Service Account token, even in strict mode. The global credential is managed by
cluster admins who are already trusted, so per-namespace Service Account impersonation is unnecessary. strict mode only applies
to namespace-scoped and per-resource Workload Identity credentials.
Q: What about ServicePrincipal (client secret/certificate) credentials?
A: These authentication modes already use genuinely secret credential values (the client secret or certificate private key) as the authorization factor. A user who doesn’t know the client secret cannot forge a credential. The ServiceAccount impersonation feature is specific to Workload Identity where the credential values are all non-secret.
Q: What happens if the ServiceAccount doesn’t exist or ASO doesn’t have permission to create tokens for it?
A: ASO will fail the reconciliation with a clear error condition on the resource, indicating that the ServiceAccount is missing or the RBAC is not configured. This is the same behavior as other credential resolution failures today.
Q: In strict mode, can a tenant’s resources still fall back to the global credential?
A: Yes. If a namespace has no namespace-scoped or per-resource credential, ASO will still fall back to the global
credential (if configured), which uses the ASO controller’s own Service Account token. This means tenant resources could be
managed using the global identity. Whether this is acceptable depends on the admin’s intent — some admins
intentionally configure a global credential as a shared default, while security-conscious admins may want to prevent
this entirely. Disabling or restricting the global credential fallback is a separate concern that could be addressed
by a future configuration option (e.g., requiring every namespace to have an explicit credential), but it is
orthogonal to this design and does not affect the per-namespace isolation guarantees that strict mode provides.
Today, if admins do not want to allow fallback to the global credential, just do not supply global credential details.
Status
Proposed.
Consequences
- When
AZURE_WORKLOAD_IDENTITY_AUTH_MODE=strict, cluster admins (or teams with appropriate permissions) will need to create a ServiceAccount per tenant namespace. This is additional setup compared to today but significantly less than multi-operator multitenancy. Inrelaxedmode (the default), no changes are needed. - Users who don’t use Workload Identity or don’t need cross-tenant isolation are unaffected.
- Documentation for the credential scope guide and Workload Identity setup will need updates.
- The
AZURE_WORKLOAD_IDENTITY_AUTH_MODE=strictsetting provides a cluster-wide enforcement mechanism for security-conscious organizations.
Experience Report
TBC
References
- #4810: Improve single-operator multitenancy credential management for Workload Identity
- #4807: What is the best practice for multi-tenancy when using workload identity?
- #3645: Support for Namespace scoped RoleAssignments that mitigate privilege escalation risks
- ADR-2022-09: Support For Multiple Credentials Under Global Operator
- External Secrets Operator — Multi Tenancy Guide
- External Secrets Operator — Security Best Practices
- Kubernetes TokenRequest API
- Azure Workload Identity Overview
Appendix: External Secrets Operator (ESO)
The External Secrets Operator (ESO) faces a similar challenge: a cluster-wide controller that needs to authenticate to external APIs on behalf of different tenants. ESO’s approach provides useful contrast for this design.
How External Secrets Operator Works
ESO introduces dedicated CRDs to model the authentication boundary:
SecretStore(namespaced): Defines how to access an external secret provider, including auth credentials. ASecretStoreis scoped to a single namespace and cannot reference resources across namespaces.ClusterSecretStore(cluster-scoped): A cluster-wide store that can be referenced from any namespace, with optionalnamespaceSelectorconditions to restrict which namespaces may use it.ExternalSecret(namespaced): References aSecretStoreorClusterSecretStoreand declares what to fetch.
For service-account-based auth (e.g. Vault Kubernetes auth), ESO requests a token for a serviceAccountRef defined
in the SecretStore. ESO’s RBAC includes serviceaccounts/token: create permission, which can be scoped per-SA
using resourceNames constraints for hardening.
External Secrets Operator’s Multitenancy Models
ESO documents three multitenancy models:
- Shared
ClusterSecretStore: A single CSS withnamespaceSelectorconditions. Simple but coarse-grained. - Managed
SecretStoreper Namespace: Cluster admins create namespacedSecretStoreresources with per-namespace credentials/roles. Access is governed by the external API’s own role system. - ESO as a Service: Tenants manage their own
SecretStoreandExternalSecretresources autonomously.
Comparison with ASO’s Situation
| Aspect | ESO | ASO (current) |
|---|---|---|
| Auth configuration | Dedicated CRD (SecretStore) created by admin |
Kubernetes Secret creatable by any user with secret-create RBAC |
| Namespace isolation | SecretStore enforces namespace boundary by design |
Secret is namespace-scoped but contents are not secret |
| Admin control point | CRD creation requires explicit RBAC grant | Secret creation is a common permission many users already have |
| Service Account token exchange | ESO requests tokens for per-store SAs (serviceAccountRef) |
ASO uses its own single Service Account for all namespaces |
| Audit trail | SecretStore is a visible, auditable API resource |
Opaque secret contents are not easily auditable |
The key architectural difference is that ESO uses a dedicated CRD as the admin-controlled authorization boundary, while ASO uses Kubernetes Secrets. Since Secrets are a general-purpose resource that many users have permission to create, they do not serve as an effective authorization gate for Workload Identity where the credential values themselves are not secret.