Skip to content

Add workload identity authentication enhancement proposal - #45

Draft
Marcusk19 wants to merge 6 commits into
quay:mainfrom
Marcusk19:feat/workload-identity-authentication
Draft

Add workload identity authentication enhancement proposal#45
Marcusk19 wants to merge 6 commits into
quay:mainfrom
Marcusk19:feat/workload-identity-authentication

Conversation

@Marcusk19

@Marcusk19 Marcusk19 commented Aug 11, 2026

Copy link
Copy Markdown

Summary

  • Add an enhancement proposal for workload identity authentication for the Quay Management API.
  • Document the Kubernetes-to-Quay trust boundary, TokenReview validation, token issuance, compatibility, rollout, and security considerations.
  • Compare SubjectAccessReview (SAR) with an explicit administrator-controlled identity-to-Quay mapping.
  • Identify the Kubernetes CRD and standalone configuration questions for the explicit mapping approach.

References


## 7. Compatibility and rollout

- Additive feature, gated by FEATURE_KUBERNETES_SA_BOOTSTRAP and off by default.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JIRA (PROJQUAY-11090) requires the output to be "a standard OAuth Bearer token" with enforced scopes. This section says "reuse existing organization token CRUD" but doesn't specify the actual mechanism:

  1. Does the SA present its JWT to the existing org token endpoint and receive a scoped OAuth token back? If so, what request parameters does it pass (org, scope)?
  2. Or does SA authentication itself produce an identity (e.g., a robot account) that then uses the existing token CRUD APIs separately?

The initial implementation chose option 2 — SA JWT maps to a robot account directly, with no scoped OAuth token issuance. This means the SA gets full robot permissions rather than a scoped token, which doesn't match the JIRA's acceptance criteria or the spec's own §1 ("obtain scoped Quay Management API OAuth tokens").

Recommendation: specify the request/response contract. At minimum: what endpoint does the workload call, what does it send (JWT + requested scope), and what does it receive (scoped OAuth token with expiry)?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. The intended flow is ServiceAccount JWT + target organization + requested scopes into the existing organization token issuance path, returning a standard scoped Quay OAuth bearer token with expiration. The direct robot-identity approach was rejected because it gives the workload the robot’s standing permissions rather than a separately scoped token.


- Which authorization mapping model should be adopted?
- Is SubjectAccessReview required in addition to TokenReview, and what exact decision does it provide?
- Where should trust and mapping configuration live, and how is it managed by the Quay Operator?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bullet identifies audience requirements as needed but doesn't define them. The initial implementation sets verify_aud: False, disabling audience validation entirely. This means any valid SA JWT from the cluster authenticates to Quay regardless of its intended audience — a token minted for Vault, ArgoCD, or any other service would also work against Quay.

Recommendation: define a required audience value (e.g., SERVER_HOSTNAME or a dedicated audience like quay-management-api). The workload would request a projected token with that audience:

volumes:
  - name: quay-token
    projected:
      sources:
        - serviceAccountToken:
            audience: quay.example.com

Quay rejects tokens without the expected aud claim. This is how IRSA, GCP Workload Identity, and Vault K8s auth all work — audience binding is the primary defense against token reuse across services.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. TokenReview is the primary validation path, with Quay requesting validation for its expected audience; missing or mismatched audiences are rejected. Audience validation is part of establishing a Quay-intended identity, separate from the still-open authorization choice between an administrator-provided mapping and SAR.

- Authenticate eligible Kubernetes ServiceAccounts to Quay.
- Issue standard Quay OAuth tokens with enforced scopes and normal expiration/revocation behavior.
- Preserve existing human, non-Kubernetes, and programmatic-bootstrap flows.
- Provide auditable success and failure outcomes.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the test plan going to be? how are we going to verify this feature is ready for production?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question, I hadn't fully fleshed out that yet but I've added a section on testing so we have an idea of what the e2e behavior should be

- Namespace and ServiceAccount identity (including audience/issuer constraints where required).
- The Quay subject to use, such as a robot account or service identity.
- The permitted Quay organizations, repositories, operations, or Management API scopes.
- Lifecycle, ownership, audit, and revocation behavior.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So to be clear, a Quay admin will define the mapping between a k8s SA to an existing robot account?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems to be the way it's heading, at least in my head right now, the responsibility for the mapping should fall on the quay admin and we just provide the tools for it to happen

**Concerns:** Kubernetes verbs/resources do not map naturally to Quay repository, organization, and
**Management API** scopes; it adds another Kubernetes API dependency and call; and it makes Quay
permissions indirect and harder to audit. **SAR** is appropriate only if the product deliberately
defines Kubernetes RBAC as the source of truth for Quay access.

@bcaton85 bcaton85 Aug 13, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The permissions models not lining up properly is a fairly large issue. It's going to be challenging to match RBAC permissions to our existing auth model. It's going to be confusing as the user as well. It also adds yet another source of truth for authentication model instead of reusing what we have now.

@Marcusk19
Marcusk19 marked this pull request as draft August 13, 2026 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants