Skip to content

PROJQUAY-5850: feat(operator): standardized STS configuration via OLM and CCO#40

Open
quay-devel wants to merge 4 commits intoquay:mainfrom
quay-devel:feat/projquay-5850-sts-olm-cco-support
Open

PROJQUAY-5850: feat(operator): standardized STS configuration via OLM and CCO#40
quay-devel wants to merge 4 commits intoquay:mainfrom
quay-devel:feat/projquay-5850-sts-olm-cco-support

Conversation

@quay-devel
Copy link
Copy Markdown

Summary

Design proposal for integrating the Quay operator with the standardized OpenShift STS configuration flow using OLM and the Cloud Credential Operator (CCO) CredentialRequest API (OCPSTRAT-171 / OCPSTRAT-6).

The enhancement enables Quay on STS-enabled OpenShift clusters (ROSA, OSD) to authenticate to AWS object storage using short-lived STS credentials instead of static IAM keys, by delegating credential management to CCO.

What's included

  • enhancements/sts-olm-cco-support.md — new enhancement proposal covering:
    • Motivation: ROSA/OSD security requirements, strategic alignment with OCPSTRAT-6
    • Opt-in design via quay-operator/aws-sts-role-arn annotation on QuayRegistry
    • CredentialRequest CR lifecycle (creation, watching, deletion)
    • Changes to controllers/quay/features.go and pkg/kustomize/secrets.go for STS credential injection
    • CSV annotation (token-auth-aws: "true") and new RBAC rules for CCO APIs
    • Cluster capability detection (platform type, OIDC issuer presence)
    • Graceful fallback when annotation absent; Degraded condition when CCO fails to reconcile
    • RHEL-based deployment guidance (AWS_ROLE_ARN / Web Identity Token file)
    • Test plan (unit, integration, E2E kuttl on ROSA), upgrade/downgrade strategy

Related

  • Jira: PROJQUAY-5850
  • Platform strategy: OCPSTRAT-171, OCPSTRAT-6
  • Related: PROJQUAY-7729 (GCP WIF for GCS)

🤖 Generated with Claude Code

Design proposal for integrating the Quay operator with OpenShift's
Cloud Credential Operator (CCO) CredentialRequest flow, enabling
STS-based (short-lived) AWS credentials in place of static keys.
Targets ROSA and OSD customers who require IAM-role-only policies.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread enhancements/sts-olm-cco-support.md Outdated
Comment on lines +4 to +5
- "@dmesser"
- "@doconnor"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Authors are not accurate

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.

Fixed — removed the Jira reporter/assignee handles which were not necessarily the document authors. Set to TBD pending the correct GitHub handles from the team.

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.

Fixed — removed the Jira reporter/assignee handles which were not necessarily the document authors. Set to TBD pending the correct GitHub handles from the team.

quay-devel and others added 2 commits April 17, 2026 21:33
… (PROJQUAY-5850)

- Replace open questions with concrete resolved answers for all four items
- Fix credential flow: CCO writes a web-identity credentials file (role_arn +
  web_identity_token_file), not static keys; operator mounts this into Quay
  pods via AWS_SHARED_CREDENTIALS_FILE, avoiding any rotation reconcile loop
- Fix CredentialRequest spec: add stsIAMRoleARN field (available OCP 4.14+),
  correct serviceAccountNames to quay-app (not operator SA), add ownerRef
- Expand cluster detection: check CCO credentialsMode, OIDC issuer presence,
  and CredentialRequest CRD availability - not just platform type
- Add full IAM permission analysis derived from static analysis of
  storage/cloud.py boto3 call sites (GetObject, PutObject, DeleteObject,
  HeadObject, ListBucket, HeadBucket, GetBucketLocation, AbortMultipartUpload,
  ListBucketMultipartUploads, GetBucketCors, PutBucketCors, multipart actions)
  with example policy document and trust policy template
- Add dedicated section on unmanaged ObjectStorage: explain why the operator
  cannot create a scoped CredentialRequest without the bucket name, and
  document three user-facing alternatives (IRSA SA annotation, STSS3Storage,
  AWS_ROLE_ARN env var via override)
- Expand RHEL guidance: document all three options (EC2 instance profile,
  STSS3Storage cross-account assume-role, manual web identity token)
- Scope enhancement to managed ObjectStorage only; unmanaged deferred

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove placeholder authors derived from Jira ticket reporter/assignee;
those are not necessarily the document authors. Set to TBD pending
correct GitHub handles from the team.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@jbpratt jbpratt left a comment

Choose a reason for hiding this comment

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

Hmm this doesn't make sense yet.. the operator doesn't manage the aws s3 bucket (unmanaged object store) so why should it manage the credentials and what should that look like?

… (PROJQUAY-5850)

Major corrections based on codebase research and OLM/CCO documentation:

- Scope to unmanaged ObjectStorage only. Managed = NooBaa/ODF OBC which
  produces internal credentials unrelated to AWS IAM. Customers who want
  real AWS S3 on ROSA must set ObjectStorage: managed: false.

- Fix role ARN input mechanism: use ROLEARN env var injected by OLM via
  Subscription spec.config.env (OCPSTRAT-171 standard), not a QuayRegistry
  annotation. OLM propagates ROLEARN to all operator-managed pods.

- Fix CredentialRequest target: serviceAccountNames: [quay-app] not the
  operator SA. The quay-app pods call S3, not the operator. The operator
  acts as a credential broker, creating the CredentialRequest on behalf of
  the application SA. serviceAccountNames is a required enforcement field
  in CCO 4.14+ (not just metadata).

- Fix credential flow: CCO produces a web-identity credentials file
  (role_arn + web_identity_token_file path), not static keys. Operator
  mounts this into quay-app pods as AWS_SHARED_CREDENTIALS_FILE. boto
  handles AssumeRoleWithWebIdentity transparently on each S3 call.

- Note that CredentialRequest must be created at runtime (OKD docs
  explicitly state bundled CredentialRequests are not supported).

- Drop statementEntries bucket scoping: operator does not know the bucket
  name for unmanaged storage; resource: '*' is used since CCO in STS mode
  does not create or enforce IAM policies (the actual policy is the
  customer's responsibility on the IAM role).

- Expand cluster detection to check CCO credentialsMode (skip STS if Mint
  or Passthrough), CRD availability, and OIDC issuer presence.

- Add warning behavior when ROLEARN is set but ObjectStorage is managed.

- Correct config.yaml section: for unmanaged storage the operator does not
  generate storage config at all (customer provides it). Operator only
  ensures AWS_SHARED_CREDENTIALS_FILE is set on quay-app pods.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
name: <quayregistry-name>-quay-app-aws
namespace: <quayregistry-namespace>
serviceAccountNames:
- quay-app
Copy link
Copy Markdown

@tlwu2013 tlwu2013 Apr 28, 2026

Choose a reason for hiding this comment

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

The cloudTokenPath is missing from the spec (w/o it, CCO cannot verify the operator's identity).

The guide ("How To Short-Lived Token Auth", step 3 for AWS) requires setting cloudTokenPath: /var/run/secrets/openshift/serviceaccount/token, so CCO knows where to find the operator pod's projected OIDC token when processing the CredentialRequest.
https://docs.google.com/document/d/1iFNpyycby_rOY1wUew-yl3uPWlE00krTgr9XHDZOTNo/edit?tab=t.0#heading=h.ugf6s9d5c2k2

  serviceAccountNames:
    - quay-app
  cloudTokenPath: /var/run/secrets/openshift/serviceaccount/token   # add this

### CSV Changes

```yaml
features.operators.openshift.io/token-auth-aws: "true" # changed from "false"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

If I read the guide correctly, it also mentions two additional CSV changes for the operator pod alongside the annotation:

  • A bound-sa-token projected volume mount so the operator itself has an OIDC token at /var/run/secrets/openshift/serviceaccount/token <--this is what cloudTokenPath in the CredentialRequest points to.

  • RBAC for config.openshift.io/infrastructures and operator.openshift.io/cloudcredentials.

This volume is needed for the operator pod's cloudTokenPath directory to exist. CCO cannot validate the CredentialRequest without it.

# Add to operator Deployment in CSV:
volumeMounts:
  - name: bound-sa-token
    mountPath: /var/run/secrets/openshift/serviceaccount
    readOnly: true
volumes:
  - name: bound-sa-token
    projected:
      sources:
        - serviceAccountToken:
            path: token
            audience: openshift

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants