From 394da18f6c6d6d2a48ecdf0f3740d38956eeda40 Mon Sep 17 00:00:00 2001 From: Min Zhang Date: Fri, 15 May 2026 10:55:44 -0400 Subject: [PATCH 1/3] feat: integrate Tekton Chains with RHTAS keyless signing via SPIFFE Use direct TektonConfig resource with ServerSideApply (following sabre1041/spiffe-openshift pattern) instead of Job-based patching. Configures SPIFFE CSI volume, TUF cache, and env vars declaratively through the operator's options.deployments mechanism. Signed-off-by: Min Zhang --- charts/supply-chain/templates/_helpers.tpl | 6 +- charts/tekton-chains/Chart.yaml | 17 + charts/tekton-chains/templates/_helpers.tpl | 52 ++ .../templates/tektonconfig-chains.yaml | 64 ++ charts/tekton-chains/values.yaml | 42 + docs/SYNC-WAVE-INVENTORY.md | 9 + scripts/features/features.yaml | 6 +- scripts/features/quay.yaml | 5 + scripts/features/registry/option-1-quay.yaml | 4 +- scripts/features/tekton-chains.yaml | 11 + scripts/gen-feature-variants.md | 3 + values-hub.yaml | 775 +++++++----------- 12 files changed, 529 insertions(+), 465 deletions(-) create mode 100644 charts/tekton-chains/Chart.yaml create mode 100644 charts/tekton-chains/templates/_helpers.tpl create mode 100644 charts/tekton-chains/templates/tektonconfig-chains.yaml create mode 100644 charts/tekton-chains/values.yaml create mode 100644 scripts/features/tekton-chains.yaml diff --git a/charts/supply-chain/templates/_helpers.tpl b/charts/supply-chain/templates/_helpers.tpl index e3d23e02..156de036 100644 --- a/charts/supply-chain/templates/_helpers.tpl +++ b/charts/supply-chain/templates/_helpers.tpl @@ -93,7 +93,6 @@ Sigstore environment variables used in Pipeline Tasks value: $(params.ca-file) - name: COSIGN_YES value: "true" -{{- if eq .Values.rhtas.oidc.enabled true }} - name: OIDC_IDENTITY value: $(params.oidc-identity) - name: OIDC_ISSUER @@ -106,6 +105,7 @@ Sigstore environment variables used in Pipeline Tasks value: $(params.oidc-issuer) - name: SIGSTORE_OIDC_ISSUER value: $(params.oidc-issuer) +{{- if eq .Values.rhtas.oidc.enabled true }} - name: OIDC_CLIENT_ID value: $(params.rhtas-oidc-client-id) - name: COSIGN_OIDC_CLIENT_ID @@ -135,11 +135,11 @@ Sigstore params used in Pipeline Tasks value: $(params.tuf-url) - name: cli-server-url value: $(params.cli-server-url) -{{- if eq .Values.rhtas.oidc.enabled true }} - name: oidc-identity value: $(params.oidc-identity) - name: oidc-issuer value: $(params.oidc-issuer) +{{- if eq .Values.rhtas.oidc.enabled true }} - name: rhtas-oidc-client-id value: $(params.rhtas-oidc-client-id) {{- end }} @@ -164,13 +164,13 @@ Sigstore params descriptions used in Pipeline Tasks - description: Cosign CLI server URL name: cli-server-url type: string -{{- if eq .Values.rhtas.oidc.enabled true }} - description: OIDC identity in signatures name: oidc-identity type: string - description: OIDC issuer in signatures name: oidc-issuer type: string +{{- if eq .Values.rhtas.oidc.enabled true }} - description: RHTAS OIDC client ID name: rhtas-oidc-client-id type: string diff --git a/charts/tekton-chains/Chart.yaml b/charts/tekton-chains/Chart.yaml new file mode 100644 index 00000000..858878a5 --- /dev/null +++ b/charts/tekton-chains/Chart.yaml @@ -0,0 +1,17 @@ +apiVersion: v2 +name: tekton-chains +description: Tekton Chains configuration for OpenShift Pipelines supply chain security with RHTAS keyless signing +type: application +version: 0.1.0 +appVersion: "1.15.0" +keywords: + - tekton-chains + - supply-chain-security + - sigstore + - in-toto + - slsa + - zero-trust + - openshift-pipelines +maintainers: + - name: Zero Trust Validated Patterns Team + email: ztvp-arch-group@redhat.com diff --git a/charts/tekton-chains/templates/_helpers.tpl b/charts/tekton-chains/templates/_helpers.tpl new file mode 100644 index 00000000..52a669ab --- /dev/null +++ b/charts/tekton-chains/templates/_helpers.tpl @@ -0,0 +1,52 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "tekton-chains.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "tekton-chains.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "tekton-chains.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "tekton-chains.labels" -}} +helm.sh/chart: {{ include "tekton-chains.chart" . }} +{{ include "tekton-chains.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/part-of: tekton-chains +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "tekton-chains.selectorLabels" -}} +app.kubernetes.io/name: {{ include "tekton-chains.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/charts/tekton-chains/templates/tektonconfig-chains.yaml b/charts/tekton-chains/templates/tektonconfig-chains.yaml new file mode 100644 index 00000000..d69ca8e2 --- /dev/null +++ b/charts/tekton-chains/templates/tektonconfig-chains.yaml @@ -0,0 +1,64 @@ +{{- if .Values.chains.enabled }} +--- +apiVersion: operator.tekton.dev/v1alpha1 +kind: TektonConfig +metadata: + name: config + annotations: + argocd.argoproj.io/sync-wave: "47" + argocd.argoproj.io/sync-options: Delete=false,ServerSideApply=true,SkipDryRunOnMissingResource=true +spec: + chain: + artifacts.taskrun.format: {{ .Values.chains.artifacts.taskrun.format }} + artifacts.taskrun.storage: {{ .Values.chains.artifacts.taskrun.storage }} + artifacts.pipelinerun.format: {{ .Values.chains.artifacts.pipelinerun.format }} + artifacts.pipelinerun.storage: {{ .Values.chains.artifacts.pipelinerun.storage }} + {{- if .Values.chains.artifacts.pipelinerun.enableDeepInspection }} + artifacts.pipelinerun.enable-deep-inspection: "true" + {{- end }} + artifacts.oci.storage: {{ .Values.chains.artifacts.oci.storage }} + disabled: false + transparency.enabled: {{ .Values.chains.transparency.enabled | quote }} + transparency.url: https://rekor-server-trusted-artifact-signer.{{ .Values.global.hubClusterDomain }} + signers.x509.fulcio.enabled: {{ .Values.chains.signers.x509.fulcio.enabled }} + signers.x509.fulcio.address: https://fulcio-server-trusted-artifact-signer.{{ .Values.global.hubClusterDomain }} + signers.x509.fulcio.issuer: https://spire-spiffe-oidc-discovery-provider.{{ .Values.global.hubClusterDomain }} + signers.x509.fulcio.provider: {{ .Values.chains.signers.x509.fulcio.provider }} + {{- if .Values.chains.signers.x509.tuf.enabled }} + signers.x509.tuf.mirror.url: https://tuf-trusted-artifact-signer.{{ .Values.global.hubClusterDomain }} + {{- end }} + options: + disabled: false + deployments: + tekton-chains-controller: + spec: + template: + spec: + containers: + - name: tekton-chains-controller + env: + - name: SPIFFE_ENDPOINT_SOCKET + value: {{ .Values.chains.spiffe.socketMount }}/{{ .Values.chains.spiffe.socketFile }} + {{- if .Values.chains.signers.x509.tuf.enabled }} + - name: TUF_ROOT + value: {{ .Values.chains.tuf.mountPath }} + {{- end }} + resources: {} + volumeMounts: + - mountPath: {{ .Values.chains.spiffe.socketMount }} + name: spiffe-workload-api + {{- if .Values.chains.signers.x509.tuf.enabled }} + - mountPath: {{ .Values.chains.tuf.mountPath }} + name: {{ .Values.chains.tuf.name }} + {{- end }} + volumes: + - csi: + driver: csi.spiffe.io + readOnly: true + name: spiffe-workload-api + {{- if .Values.chains.signers.x509.tuf.enabled }} + - emptyDir: {} + name: {{ .Values.chains.tuf.name }} + {{- end }} + targetNamespace: openshift-pipelines +{{- end }} diff --git a/charts/tekton-chains/values.yaml b/charts/tekton-chains/values.yaml new file mode 100644 index 00000000..a6a09f4e --- /dev/null +++ b/charts/tekton-chains/values.yaml @@ -0,0 +1,42 @@ +# Tekton Chains Configuration for ZTVP +# Configures the TektonConfig CR to enable Tekton Chains with RHTAS keyless signing + +global: + hubClusterDomain: apps.example.com + +chains: + enabled: true + + artifacts: + taskrun: + format: in-toto + storage: oci + signer: x509 + pipelinerun: + format: in-toto + storage: oci + signer: x509 + enableDeepInspection: true + oci: + format: simplesigning + storage: oci + signer: x509 + + transparency: + enabled: true + + signers: + x509: + fulcio: + enabled: true + provider: spiffe + tuf: + enabled: true + + tuf: + name: tuf + mountPath: /tuf + + spiffe: + socketMount: /spiffe-workload-api + socketFile: spire-agent.sock diff --git a/docs/SYNC-WAVE-INVENTORY.md b/docs/SYNC-WAVE-INVENTORY.md index fa7a57c1..e2a47083 100644 --- a/docs/SYNC-WAVE-INVENTORY.md +++ b/docs/SYNC-WAVE-INVENTORY.md @@ -70,6 +70,8 @@ Every sync-wave in the repository, in order. **App** = hub-level Argo CD Applica | 46 | └ acs-central | chart | console-link | | 46 | └ acs-secured-cluster | chart | secured-cluster-cr | | 46 | └ rhtas-operator | chart | securesign | +| 47 | tekton-chains | **App** | Tekton Chains config (RHTAS keyless signing) | +| 47 | └ tekton-chains | chart | tektonconfig-chains (TektonConfig CR) | | 48 | supply-chain | **App** | | | 48+0 | └ supply-chain | chart | registry-image-namespace (Namespace, RBAC), pipeline-sa, tasks (incl. restart-qtodo), secrets (quay-pass, rhtpa-pass), quay-user, rhtas/rhtpa-config, pipeline-qtodo-restarter (Role+RoleBinding in qtodo ns) | | 48+1 | └ supply-chain | chart (hook) | enable-registry-default-route (Sync hook Job) | @@ -112,6 +114,7 @@ Every sync-wave in the repository, in order. **App** = hub-level Argo CD Applica | trusted-profile-analyzer | 10 | 41 | Chart resources (OBC, DB, etc.) | | acs-secured-cluster | 15 | 46 | — | | trusted-artifact-signer | 15 | 46 | Deploy after dependencies | +| tekton-chains | — | 47 | After RHTAS, before supply-chain (newly added) | | supply-chain | — | 48 | After RHTAS/ACS, before chart templates (newly added) | | acs-policies | 20 | 51 | After ACS Central + Secured Cluster | @@ -209,6 +212,12 @@ Charts marked **(external)** have been externalized to standalone repositories m | --- | ---: | ---: | | securesign.yaml | 15 | 46 | +### tekton-chains (`charts/tekton-chains/templates/`) — App wave: 47 + +| Resource | Old | Current | +| --- | ---: | ---: | +| tektonconfig-chains.yaml | — | 47 | + ### rhtpa-operator (`charts/rhtpa-operator/templates/`) — App wave: 41 | Resource | Old | Current | diff --git a/scripts/features/features.yaml b/scripts/features/features.yaml index ee35f2cf..49ca349a 100644 --- a/scripts/features/features.yaml +++ b/scripts/features/features.yaml @@ -22,9 +22,13 @@ features: description: "OpenShift Pipelines" depends_on: [] + tekton-chains: + description: "Tekton Chains with RHTAS keyless signing via SPIFFE" + depends_on: [pipelines, rhtas] + supply-chain: description: "Full secure supply chain pipeline" - depends_on: [pipelines, rhtas, rhtpa, storage] + depends_on: [tekton-chains, rhtpa, storage] registry_option_required: true org: ztvp image_name: qtodo diff --git a/scripts/features/quay.yaml b/scripts/features/quay.yaml index bdb44f15..83abd6e9 100644 --- a/scripts/features/quay.yaml +++ b/scripts/features/quay.yaml @@ -25,3 +25,8 @@ clusterGroup: chartVersion: 0.1.* annotations: argocd.argoproj.io/sync-wave: "41" + overrides: + - name: job.image + value: "registry.redhat.io/openshift4/ose-cli:latest" + - name: job.resources.limits.memory + value: "512Mi" diff --git a/scripts/features/registry/option-1-quay.yaml b/scripts/features/registry/option-1-quay.yaml index 5dc6b059..487be3a8 100644 --- a/scripts/features/registry/option-1-quay.yaml +++ b/scripts/features/registry/option-1-quay.yaml @@ -40,7 +40,9 @@ clusterGroup: argocd.argoproj.io/sync-wave: "41" overrides: - name: job.image - value: "registry.redhat.io/openshift4/ose-cli-rhel9:latest" + value: "registry.redhat.io/openshift4/ose-cli:latest" + - name: job.resources.limits.memory + value: "512Mi" merge_into_applications: supply-chain: diff --git a/scripts/features/tekton-chains.yaml b/scripts/features/tekton-chains.yaml new file mode 100644 index 00000000..f2e9cce4 --- /dev/null +++ b/scripts/features/tekton-chains.yaml @@ -0,0 +1,11 @@ +# Tekton Chains for supply chain security with RHTAS keyless signing +# Depends on: pipelines (OpenShift Pipelines operator), rhtas (RHTAS for Fulcio/Rekor/TUF) +# Applies TektonConfig with ServerSideApply to configure SPIFFE and TUF volumes +clusterGroup: + applications: + tekton-chains: + name: tekton-chains + project: hub + path: charts/tekton-chains + annotations: + argocd.argoproj.io/sync-wave: "47" diff --git a/scripts/gen-feature-variants.md b/scripts/gen-feature-variants.md index d084a79a..fe9235e9 100644 --- a/scripts/gen-feature-variants.md +++ b/scripts/gen-feature-variants.md @@ -48,6 +48,9 @@ python3 scripts/gen-feature-variants.py --features rhtpa # Enable multiple features python3 scripts/gen-feature-variants.py --features rhtpa,rhtas +# Enable Tekton Chains (auto-resolves: pipelines -> rhtas -> tekton-chains) +python3 scripts/gen-feature-variants.py --features tekton-chains + # Full supply chain: pick a registry option (1, 2, or 3) python3 scripts/gen-feature-variants.py --features supply-chain --registry-option 1 diff --git a/values-hub.yaml b/values-hub.yaml index e870fb8f..1707cc62 100644 --- a/values-hub.yaml +++ b/values-hub.yaml @@ -47,67 +47,70 @@ spire: # vaultPath: "secret/data/hub/infra/registry/registry-user" # passwordVaultKey: "registry-password" +global: + registry: + enabled: true + domain: "quay-registry-quay-quay-enterprise.apps.{{ .Values.global.clusterDomain }}" + # Placeholders auto-replaced by the generator (supply-chain defines org=ztvp, image_name=qtodo) + repository: ztvp/qtodo + user: quay-user + vaultPath: "secret/data/hub/infra/quay/quay-users" + passwordVaultKey: "quay-user-password" + clusterGroup: name: hub isHubCluster: true namespaces: - - open-cluster-management - - vault - - qtodo - - golang-external-secrets - - keycloak-system: - operatorGroup: true - targetNamespace: keycloak-system - - cert-manager - - cert-manager-operator: - operatorGroup: true - targetNamespace: cert-manager-operator - # Layer 1: Storage and Registry - # Required for RHTPA and QUAY (provides NooBaa object storage backend) - # - openshift-storage: - # operatorGroup: true - # targetNamespace: openshift-storage - # annotations: - # openshift.io/cluster-monitoring: "true" - # argocd.argoproj.io/sync-wave: "26" # Propagated to OperatorGroup by framework - # - quay-enterprise: - # annotations: - # argocd.argoproj.io/sync-wave: "32" # Create before NooBaa and all Quay components - # labels: - # openshift.io/cluster-monitoring: "true" - # RHTAS namespace (required when RHTAS application is enabled) - # COMMENTED OUT: Uncomment to enable RHTAS with SPIFFE signing - # - trusted-artifact-signer: - # annotations: - # argocd.argoproj.io/sync-wave: "32" # Auto-created by RHTAS operator - # labels: - # openshift.io/cluster-monitoring: "true" - # - rhtpa-operator: - # operatorGroup: true - # targetNamespace: rhtpa-operator - # annotations: - # argocd.argoproj.io/sync-wave: "26" # Create before operator subscription - # - trusted-profile-analyzer: - # annotations: - # argocd.argoproj.io/sync-wave: "32" # Create before RHTPA components - # labels: - # openshift.io/cluster-monitoring: "true" - - zero-trust-workload-identity-manager: - operatorGroup: true - targetNamespace: zero-trust-workload-identity-manager - - openshift-compliance: - operatorGroup: true - targetNamespace: openshift-compliance - annotations: - openshift.io/cluster-monitoring: "true" - # Secure Supply Chain: Uncomment to enable OpenShift Pipelines - # - openshift-pipelines - # - # Red Hat Advanced Cluster Security (RHACS/StackRox) - Uncomment to enable - - stackrox: - operatorGroup: true - labels: - openshift.io/cluster-monitoring: "true" + - open-cluster-management + - vault + - qtodo + - golang-external-secrets + - keycloak-system: + operatorGroup: true + targetNamespace: keycloak-system + - cert-manager + - cert-manager-operator: + operatorGroup: true + targetNamespace: cert-manager-operator + - zero-trust-workload-identity-manager: + operatorGroup: true + targetNamespace: zero-trust-workload-identity-manager + - openshift-compliance: + operatorGroup: true + targetNamespace: openshift-compliance + annotations: + openshift.io/cluster-monitoring: "true" + - stackrox: + operatorGroup: true + labels: + openshift.io/cluster-monitoring: "true" + - openshift-pipelines + - trusted-artifact-signer: + annotations: + argocd.argoproj.io/sync-wave: "32" + labels: + openshift.io/cluster-monitoring: "true" + - openshift-storage: + operatorGroup: true + targetNamespace: openshift-storage + annotations: + openshift.io/cluster-monitoring: "true" + argocd.argoproj.io/sync-wave: "26" + - rhtpa-operator: + operatorGroup: true + targetNamespace: rhtpa-operator + annotations: + argocd.argoproj.io/sync-wave: "26" + - trusted-profile-analyzer: + annotations: + argocd.argoproj.io/sync-wave: "32" + labels: + openshift.io/cluster-monitoring: "true" + - quay-enterprise: + annotations: + argocd.argoproj.io/sync-wave: "32" + labels: + openshift.io/cluster-monitoring: "true" subscriptions: acm: name: advanced-cluster-management @@ -119,10 +122,6 @@ clusterGroup: namespace: cert-manager-operator channel: stable-v1 catalogSource: redhat-marketplace - # Secure Supply Chain: Uncomment to enable OpenShift Pipelines - # openshift-pipelines: - # name: openshift-pipelines-operator-rh - # namespace: openshift-operators rhbk: name: rhbk-operator namespace: keycloak-system @@ -141,54 +140,46 @@ clusterGroup: config: nodeSelector: node-role.kubernetes.io/worker: "" - # - # ACS Operator Subscription (Uncomment to enable) rhacs-operator: name: rhacs-operator namespace: openshift-operators channel: stable source: redhat-operators - # - # Storage and Registry operator subscriptions - # Required for RHTPA and QUAY (provides NooBaa object storage backend) - # ODF provides object storage backend (NooBaa) for RHTPA and optionally Quay - # odf: - # name: odf-operator - # namespace: openshift-storage - # channel: stable-4.20 - # annotations: - # argocd.argoproj.io/sync-wave: "27" # Install after OperatorGroup (26) - # quay-operator: - # name: quay-operator - # namespace: openshift-operators - # channel: stable-3.15 - # annotations: - # argocd.argoproj.io/sync-wave: "28" # Install after ODF operator - # RHTAS operator subscription (required when RHTAS application is enabled) - # COMMENTED OUT: Uncomment to enable RHTAS with SPIFFE integration - # rhtas-operator: - # name: rhtas-operator - # namespace: openshift-operators - # channel: stable-v1.3 - # annotations: - # argocd.argoproj.io/sync-wave: "29" # Install after Quay operator, before applications - # catalogSource: redhat-operators - # RHTPA operator subscription - # Channel: stable-v1.1 provides latest 1.1.x patch updates - # Note: No direct upgrade path from 1.1.x to 2.x (requires fresh install) - # rhtpa-operator: - # name: rhtpa-operator - # namespace: rhtpa-operator # MUST use dedicated namespace (not openshift-operators) - # channel: stable-v1.1 # Use stable-v1.1 channel for 1.1.x updates - # catalogSource: redhat-operators - # annotations: - # argocd.argoproj.io/sync-wave: "27" # Install after OperatorGroup (26), before applications + openshift-pipelines: + name: openshift-pipelines-operator-rh + namespace: openshift-operators + rhtas-operator: + name: rhtas-operator + namespace: openshift-operators + channel: stable-v1.3 + annotations: + argocd.argoproj.io/sync-wave: "29" + catalogSource: redhat-operators + odf: + name: odf-operator + namespace: openshift-storage + channel: stable-4.20 + annotations: + argocd.argoproj.io/sync-wave: "27" + rhtpa-operator: + name: rhtpa-operator + namespace: rhtpa-operator + channel: stable-v1.1 + catalogSource: redhat-operators + annotations: + argocd.argoproj.io/sync-wave: "27" + quay-operator: + name: quay-operator + namespace: openshift-operators + channel: stable-3.15 + annotations: + argocd.argoproj.io/sync-wave: "28" projects: - - hub + - hub # Explicitly mention the cluster-state based overrides we plan to use for this pattern. # We can use self-referential variables because the chart calls the tpl function with these variables defined sharedValueFiles: - - '/overrides/values-{{ $.Values.global.clusterPlatform }}.yaml' + - '/overrides/values-{{ $.Values.global.clusterPlatform }}.yaml' # sharedValueFiles is a flexible mechanism that will add the listed valuefiles to every app defined in the # applications section. We intend this to supplement and possibly even replace previous "magic" mechanisms, though # we do not at present have a target date for removal. @@ -213,64 +204,33 @@ clusterGroup: path: charts/ztvp-certificates annotations: argocd.argoproj.io/sync-wave: "21" - # Ignore the ACM-replicated policy in local-cluster namespace - # ACM automatically creates policy replicas with name pattern: . ignoreDifferences: - - group: policy.open-cluster-management.io - kind: Policy - name: openshift-config.ztvp-certificates-distribution - namespace: local-cluster - jsonPointers: - - / - # Use extraValueFiles for complex nested structures like additionalCertificates - # The validated patterns framework only processes 'overrides' as --set parameters - # Edit /overrides/values-ztvp-certificates.yaml to configure: - # - Additional CA certificates (additionalCertificates array) - # - Automatic rollout restart for consuming applications + - group: policy.open-cluster-management.io + kind: Policy + name: openshift-config.ztvp-certificates-distribution + namespace: local-cluster + jsonPointers: + - / extraValueFiles: - - /overrides/values-ztvp-certificates.yaml - - '/overrides/values-ztvp-certificates-{{ $.Values.global.clusterPlatform }}.yaml' + - /overrides/values-ztvp-certificates.yaml + - '/overrides/values-ztvp-certificates-{{ $.Values.global.clusterPlatform }}.yaml' overrides: - # Disable Job TTL to prevent ArgoCD OutOfSync when Kubernetes deletes completed Jobs - # The initial Job runs once during first sync; CronJob handles ongoing extraction - - name: debug.keepFailedJobs - value: "true" - - # Enable verbose logging for troubleshooting (uncomment if needed) - # - name: debug.verbose - # value: "true" - - # Primary custom CA: Use secretRef to reference an existing Kubernetes secret containing CA certificates - # Uncomment to add a primary custom CA: - # Single cert: oc create secret generic custom-ca-bundle --from-file=ca.crt=/path/to/ca.crt -n openshift-config - # Multiple certs: cat corp-root.crt intermediate.crt partner.crt > combined-ca.crt && oc create secret generic custom-ca-bundle --from-file=ca.crt=combined-ca.crt -n openshift-config - # Disabled for now - using auto-detection only - # - name: customCA.secretRef.enabled - # value: "true" - - name: customCA.secretRef.name - value: custom-ca-bundle - - name: customCA.secretRef.namespace - value: openshift-config - - name: customCA.secretRef.key - value: ca.crt - - # Automatic rollout configuration (simple overrides work fine) - - name: rollout.enabled - value: "true" - - name: rollout.strategy - value: labeled - - # Node-level image pull trust for kubelet - # Required when pulling images from registries behind the cluster ingress - # (e.g. built-in Quay, embedded OpenShift registry). Patches image.config.openshift.io/cluster. - # Uncomment and set the registry hostname when enabling Option 1 (Quay) or Option 3 (embedded OpenShift). - # - name: imagePullTrust.enabled - # value: "true" - # - name: imagePullTrust.registries[0] - # value: default-route-openshift-image-registry.apps.{{ $.Values.global.clusterDomain }} - - # Note: additionalCertificates (complex nested array) temporarily disabled - # Need to find proper way to pass complex structures in Validated Patterns + - name: debug.keepFailedJobs + value: "true" + - name: customCA.secretRef.name + value: custom-ca-bundle + - name: customCA.secretRef.namespace + value: openshift-config + - name: customCA.secretRef.key + value: ca.crt + - name: rollout.enabled + value: "true" + - name: rollout.strategy + value: labeled + - name: imagePullTrust.enabled + value: "true" + - name: imagePullTrust.registries[0] + value: "quay-registry-quay-quay-enterprise.apps.{{ $.Values.global.clusterDomain }}" acm: name: acm namespace: open-cluster-management @@ -280,14 +240,13 @@ clusterGroup: annotations: argocd.argoproj.io/sync-wave: "5" ignoreDifferences: - - group: internal.open-cluster-management.io - kind: ManagedClusterInfo - jsonPointers: - - /spec/loggingCA - # We override the secret store because we are not provisioning clusters + - group: internal.open-cluster-management.io + kind: ManagedClusterInfo + jsonPointers: + - /spec/loggingCA overrides: - - name: global.secretStore.backend - value: none + - name: global.secretStore.backend + value: none acm-managed-clusters: name: acm-managed-clusters project: hub @@ -295,11 +254,11 @@ clusterGroup: annotations: argocd.argoproj.io/sync-wave: "10" ignoreDifferences: - - group: cluster.open-cluster-management.io - kind: ManagedCluster - jsonPointers: - - /metadata/labels/cloud - - /metadata/labels/vendor + - group: cluster.open-cluster-management.io + kind: ManagedCluster + jsonPointers: + - /metadata/labels/cloud + - /metadata/labels/vendor compliance-scanning: name: compliance-scanning namespace: openshift-compliance @@ -309,174 +268,59 @@ clusterGroup: chart: ocp-compliance-scanning chartVersion: 0.0.* overrides: - # Disable unused PVC - compliance operator creates its own PVCs per scan - # via rawResultStorage in scan-setting.yaml. The explicit PVC causes - # ArgoCD 'Progressing' status on storage with WaitForFirstConsumer mode. - - name: compliance.storage.enabled - value: "false" + - name: compliance.storage.enabled + value: "false" vault: name: vault namespace: vault project: hub chart: hashicorp-vault chartVersion: 0.1.* - extraValueFiles: - - /overrides/values-vault-network-policy.yaml annotations: argocd.argoproj.io/sync-wave: "25" - # Custom Vault policies for least-privilege access - # Each application gets access only to its specific secrets path - # - # TWO types of policies needed: - # 1. -k8s-secret - for Kubernetes auth (ClusterSecretStore/ExternalSecrets) - # 2. -jwt-secret - for JWT/SPIFFE auth (application workloads) - # - # NOTE: K8s auth policies are auto-created by Ansible from vaultPrefixes - # JWT auth policies below are manually defined for apps that need direct Vault access policies: - # ============================================================ - # JWT/SPIFFE Auth Policies (for application workloads) - # These are used by apps authenticating via SPIFFE JWT tokens - # Only define policies for apps that need direct Vault access - # K8s auth policies (-k8s-secret) are auto-created by Ansible - # ============================================================ - - name: apps-qtodo-jwt-secret - policy: | - path "secret/data/apps/qtodo/*" { - capabilities = ["read"] - } - - name: hub-infra-rhtpa-jwt-secret - policy: | - path "secret/data/hub/infra/rhtpa/*" { - capabilities = ["read"] - } - - name: hub-supply-chain-jwt-secret - policy: | - path "secret/data/hub/infra/quay/*" { - capabilities = ["read"] - } - path "secret/data/hub/infra/registry/*" { - capabilities = ["read", "create", "update"] - } - path "secret/data/hub/infra/rhtpa/rhtpa-oidc-cli" { - capabilities = ["read"] - } + - name: apps-qtodo-jwt-secret + policy: | + path "secret/data/apps/qtodo/*" { + capabilities = ["read"] + } + - name: hub-infra-rhtpa-jwt-secret + policy: | + path "secret/data/hub/infra/rhtpa/*" { + capabilities = ["read"] + } + - name: hub-supply-chain-jwt-secret + policy: | + path "secret/data/hub/infra/quay/*" { + capabilities = ["read"] + } + path "secret/data/hub/infra/registry/*" { + capabilities = ["read", "create", "update"] + } + path "secret/data/hub/infra/rhtpa/rhtpa-oidc-cli" { + capabilities = ["read"] + } jwt: enabled: true oidcDiscoveryUrl: https://spire-spiffe-oidc-discovery-provider.zero-trust-workload-identity-manager.svc.cluster.local oidcDiscoveryCa: /run/secrets/kubernetes.io/serviceaccount/service-ca.crt defaultRole: qtodo roles: - - name: qtodo - audience: https://keycloak.apps.{{ $.Values.global.clusterDomain }}/realms/ztvp - subject: spiffe://apps.{{ $.Values.global.clusterDomain }}/ns/qtodo/sa/qtodo - policies: - - apps-qtodo-jwt-secret - # RHTPA vault role - # - name: rhtpa - # audience: rhtpa - # subject: spiffe://apps.{{ $.Values.global.clusterDomain }}/ns/trusted-profile-analyzer/sa/rhtpa - # policies: - # - hub-infra-rhtpa-jwt-secret - # Supply chain vault role (for Tekton pipelines; enable with supply-chain app / Option 3 or BYO registry) - # - name: supply-chain - # audience: supply-chain - # subject: spiffe://apps.{{ $.Values.global.clusterDomain }}/ns/{{ $.Values.global.pattern }}-hub/sa/pipeline - # policies: - # - hub-supply-chain-jwt-secret - # Shared Object Storage Backend - # Required for RHTPA and QUAY (provides S3-compatible storage via NooBaa MCG) - # NooBaa MCG provides S3-compatible object storage for multiple applications - # noobaa-mcg: - # name: noobaa-mcg - # namespace: openshift-storage - # project: hub - # path: charts/noobaa-mcg - # annotations: - # argocd.argoproj.io/sync-wave: "36" # Deploy after core services - # Quay Container Registry (uses NooBaa for storage) - # quay-registry: - # name: quay-registry - # namespace: quay-enterprise - # project: hub - # chart: quay - # chartVersion: 0.1.* - # annotations: - # argocd.argoproj.io/sync-wave: "41" # Deploy after NooBaa storage backend - # RHTAS with SPIFFE Integration - # COMMENTED OUT: Uncomment to enable RHTAS with SPIFFE and Email issuers - # Depends on: Vault, SPIRE, Keycloak (for Email OIDC issuer if used) - # trusted-artifact-signer: - # name: trusted-artifact-signer - # namespace: trusted-artifact-signer - # project: hub - # path: charts/rhtas-operator - # annotations: - # argocd.argoproj.io/sync-wave: "46" # Deploy after dependencies - # overrides: - # # OIDC Issuer Configuration - Both can be enabled simultaneously - # # Enable SPIFFE issuer for workload identity - # - name: rhtas.zeroTrust.spire.enabled - # value: "true" - # - name: rhtas.zeroTrust.spire.trustDomain - # value: "apps.{{ $.Values.global.clusterDomain }}" - # - name: rhtas.zeroTrust.spire.issuer - # value: "https://spire-spiffe-oidc-discovery-provider.apps.{{ $.Values.global.clusterDomain }}" - # # Enable Keycloak issuer for user/email authentication - # - name: rhtas.zeroTrust.email.enabled - # value: "true" - # - name: rhtas.zeroTrust.email.issuer - # value: https://keycloak.apps.{{ $.Values.global.clusterDomain }}/realms/ztvp - # RHTPA (Red Hat Trusted Profile Analyzer) with SPIFFE Integration - # Depends on: NooBaa MCG (storage), Vault (secrets), SPIRE (identity), Keycloak (auth) - # trusted-profile-analyzer: - # name: trusted-profile-analyzer - # namespace: trusted-profile-analyzer - # project: hub - # path: charts/rhtpa-operator - # annotations: - # argocd.argoproj.io/sync-wave: "41" # Create chart resources (OBC, DB, etc.) - # # Note: The TrustedProfileAnalyzer CR is created by ACM Policy at wave 81 - # # to ensure the operator is fully ready (mitigates v1.1.0 initialization bug) - # # Ignore differences to prevent OutOfSync status - # ignoreDifferences: - # # Ignore Job status changes (completion, failure counts, conditions) - # # Jobs are created by hooks and their status changes don't require re-sync - # - group: batch - # kind: Job - # jsonPointers: - # - /status - # overrides: - # # Vault Integration - # # - name: rhtpa.zeroTrust.vault.url - # # value: https://vault.vault.svc.cluster.local:8200 - # # Keycloak URL is automatically constructed from global.localClusterDomain - # # TLS Configuration - Custom Ingress CA (for Azure/AWS/GCP with custom certs) - # # For standard OpenShift deployments, auto-detection works without overrides - # # For cloud platforms with custom ingress certs in non-standard locations: - # # - name: rhtpa.tls.ingressCA.customSource.enabled - # # value: "true" - # # - name: rhtpa.tls.ingressCA.customSource.secretName - # # value: "custom-ingress-cert" - # # - name: rhtpa.tls.ingressCA.customSource.secretNamespace - # # value: "openshift-ingress" - # # - name: rhtpa.tls.ingressCA.customSource.secretKey - # # value: "tls.crt" - # # Importer Configuration - # # Enable all 5 importers explicitly (chart defaults: cve and osv-github enabled) - # # Period defaults to 1d for all importers (configured in chart) - # # Default importers - # # - name: rhtpa.modules.createImporters.importers.cve.cve.disabled - # # value: "false" - # # - name: rhtpa.modules.createImporters.importers.osv-github.osv.disabled - # # value: "false" - # # Additional importers (disabled by default due to large datasets) - # # - name: rhtpa.modules.createImporters.importers.redhat-csaf.csaf.disabled - # # value: "false" - # # - name: rhtpa.modules.createImporters.importers.quay-redhat-user-workloads.quay.disabled - # # value: "false" - # # - name: rhtpa.modules.createImporters.importers.redhat-sboms.sbom.disabled - # # value: "false" + - name: qtodo + audience: https://keycloak.apps.{{ $.Values.global.clusterDomain }}/realms/ztvp + subject: spiffe://apps.{{ $.Values.global.clusterDomain }}/ns/qtodo/sa/qtodo + policies: + - apps-qtodo-jwt-secret + - name: rhtpa + audience: rhtpa + subject: "spiffe://apps.{{ $.Values.global.clusterDomain }}/ns/trusted-profile-analyzer/sa/rhtpa" + policies: + - hub-infra-rhtpa-jwt-secret + - name: supply-chain + audience: supply-chain + subject: "spiffe://apps.{{ $.Values.global.clusterDomain }}/ns/{{ $.Values.global.pattern }}-hub/sa/pipeline" + policies: + - hub-supply-chain-jwt-secret golang-external-secrets: name: golang-external-secrets namespace: golang-external-secrets @@ -493,13 +337,6 @@ clusterGroup: chartVersion: 0.0.* annotations: argocd.argoproj.io/sync-wave: "35" - # SPIFFE Identity Provider is enabled by default in the chart. - # Override issuer/jwksUrl only if auto-generated values from cluster domain are not suitable. - # overrides: - # - name: keycloak.spiffeIdentityProvider.config.config.issuer - # value: "spiffe://apps.example.com" - # - name: keycloak.spiffeIdentityProvider.config.config.jwksUrl - # value: "https://spire-spiffe-oidc-discovery-provider.apps.example.com/keys" rh-cert-manager: name: rh-cert-manager namespace: cert-manager-operator @@ -517,8 +354,8 @@ clusterGroup: annotations: argocd.argoproj.io/sync-wave: "30" overrides: - - name: spire.clusterName - value: hub + - name: spire.clusterName + value: hub qtodo: name: qtodo namespace: qtodo @@ -527,114 +364,57 @@ clusterGroup: annotations: argocd.argoproj.io/sync-wave: "38" ignoreDifferences: - - kind: ServiceAccount - jqPathExpressions: - - .imagePullSecrets[]|select(.name | contains("-dockercfg-")) + - kind: ServiceAccount + jqPathExpressions: + - .imagePullSecrets[]|select(.name | contains("-dockercfg-")) overrides: - - name: app.oidc.enabled - value: "true" - - name: app.spire.enabled - value: "true" - - name: app.vault.url - value: https://vault.vault.svc.cluster.local:8200 - - name: app.vault.role - value: qtodo - - name: app.vault.secretPath - value: secret/data/apps/qtodo/qtodo-db - # Secure Supply Chain: when global.registry.enabled=true the chart - # automatically derives the image from global.registry.domain/repository. - # No override needed here. - # Uncomment to seed the registry with the upstream qtodo image - # before the supply-chain pipeline runs (avoids ImagePullBackOff on first install) - # - name: app.seedImage.enabled - # value: "true" - # Secure Supply Chain - Uncomment to enable (required for Option 1, 2, or 3 registry flows in docs) - # supply-chain: - # name: supply-chain - # project: hub - # path: charts/supply-chain - # annotations: - # argocd.argoproj.io/sync-wave: "48" - # ignoreDifferences: - # - kind: ServiceAccount - # jqPathExpressions: - # - .imagePullSecrets[]|select(.name | contains("-dockercfg-")) - # overrides: - # # Registry credentials are inherited from global.registry. - # # Only set app-specific overrides below. - # # Built-in Quay: uncomment to enable the Quay user provisioner CronJob - # # - name: quay.enabled - # # value: "true" - # # Built-in Quay: self-signed certs require TLS verify off - # # - name: registry.tlsVerify - # # value: "false" - # # Embedded OpenShift (Option 3): create image namespace and grant push RBAC - # # - name: registry.embeddedOpenShift.ensureImageNamespaceRBAC - # # value: "true" - # # Embedded OpenShift (Option 3): periodically refresh pipeline SA token in Vault - # # - name: registry.embeddedOpenShift.tokenRefresher.enabled - # # value: "true" - # # Enable RHTAS signing - # # - name: rhtas.enabled - # # value: "true" - # # Enable RHTPA SBOM upload - # # - name: rhtpa.enabled - # # value: "true" - # # Uncomment to auto-trigger a pipeline run on every ArgoCD sync - # # - name: pipelinerun.enabled - # # value: "true" - # - # ACS Central Services + - name: app.oidc.enabled + value: "true" + - name: app.spire.enabled + value: "true" + - name: app.vault.url + value: https://vault.vault.svc.cluster.local:8200 + - name: app.vault.role + value: qtodo + - name: app.vault.secretPath + value: secret/data/apps/qtodo/qtodo-db acs-central: name: acs-central-services namespace: stackrox project: hub path: charts/acs-central overrides: - # Uncomment and set if you need a specific StorageClass: - # - name: central.persistence.storageClass - # value: gp3-csi # Example for AWS - - name: central.exposure.route.enabled - value: "true" - - name: central.exposure.route.reencrypt.host - value: "central.{{ $.Values.global.localClusterDomain }}" - - name: integration.keycloak.enabled - value: "true" - - name: integration.keycloak.realm - value: "ztvp" - - name: integration.keycloak.clientId - value: "acs-central" - # ACS to scan images stored in Quay (Uncomment to enable) - # - name: integration.quay.enabled - # value: "true" - # - name: integration.quay.url - # value: "quay-quay-enterprise.apps.{{ .Values.global.domain }}" + - name: central.exposure.route.enabled + value: "true" + - name: integration.keycloak.enabled + value: "true" + - name: integration.keycloak.realm + value: "ztvp" + - name: integration.keycloak.clientId + value: "acs-central" extraValueFiles: - - /values-global.yaml - - /values-{{ .Values.global.pattern }}-hub.yaml + - /values-global.yaml + - /values-{{ .Values.global.pattern }}-hub.yaml ignoreDifferences: - - group: platform.stackrox.io - kind: Central - jsonPointers: - - /spec/scanner/scannerComponent + - group: platform.stackrox.io + kind: Central + jsonPointers: + - /spec/scanner/scannerComponent annotations: argocd.argoproj.io/sync-wave: "41" - - # ACS Secured Cluster acs-secured-cluster: name: acs-secured-cluster namespace: stackrox project: hub path: charts/acs-secured-cluster overrides: - - name: clusterName - value: hub + - name: clusterName + value: hub extraValueFiles: - - /values-global.yaml - - /values-{{ .Values.global.pattern }}-hub.yaml + - /values-global.yaml + - /values-{{ .Values.global.pattern }}-hub.yaml annotations: argocd.argoproj.io/sync-wave: "46" - # ACS Policies acs-policies: name: acs-policies namespace: stackrox @@ -642,58 +422,133 @@ clusterGroup: path: charts/acs-policies annotations: argocd.argoproj.io/sync-wave: "51" + trusted-artifact-signer: + name: trusted-artifact-signer + namespace: trusted-artifact-signer + project: hub + path: charts/rhtas-operator + annotations: + argocd.argoproj.io/sync-wave: "46" + overrides: + - name: rhtas.zeroTrust.spire.enabled + value: "true" + - name: rhtas.zeroTrust.spire.trustDomain + value: "apps.{{ $.Values.global.clusterDomain }}" + - name: rhtas.zeroTrust.spire.issuer + value: "https://spire-spiffe-oidc-discovery-provider.apps.{{ $.Values.global.clusterDomain }}" + - name: rhtas.zeroTrust.email.enabled + value: "true" + - name: rhtas.zeroTrust.email.issuer + value: "https://keycloak.apps.{{ $.Values.global.clusterDomain }}/realms/ztvp" + tekton-chains: + name: tekton-chains + project: hub + path: charts/tekton-chains + annotations: + argocd.argoproj.io/sync-wave: "47" + noobaa-mcg: + name: noobaa-mcg + namespace: openshift-storage + project: hub + path: charts/noobaa-mcg + annotations: + argocd.argoproj.io/sync-wave: "36" + trusted-profile-analyzer: + name: trusted-profile-analyzer + namespace: trusted-profile-analyzer + project: hub + path: charts/rhtpa-operator + annotations: + argocd.argoproj.io/sync-wave: "41" + ignoreDifferences: + - group: batch + kind: Job + jsonPointers: + - /status + supply-chain: + name: supply-chain + project: hub + path: charts/supply-chain + annotations: + argocd.argoproj.io/sync-wave: "48" + ignoreDifferences: + - kind: ServiceAccount + jqPathExpressions: + - ".imagePullSecrets[]|select(.name | contains(\"-dockercfg-\"))" + overrides: + - name: quay.enabled + value: "true" + - name: registry.tlsVerify + value: "false" + - name: rhtas.enabled + value: "true" + - name: rhtpa.enabled + value: "true" + quay-registry: + name: quay-registry + namespace: quay-enterprise + project: hub + chart: quay + chartVersion: 0.1.* + annotations: + argocd.argoproj.io/sync-wave: "41" + overrides: + - name: job.image + value: "registry.redhat.io/openshift4/ose-cli:latest" + - name: job.resources.limits.memory + value: "512Mi" argoCD: resourceHealthChecks: - - check: | - local hs = {} - if obj.status ~= nil and obj.status.phase ~= nil then - if obj.status.phase == "Bound" then - hs.status = "Healthy" - hs.message = "PVC is bound" - elseif obj.status.phase == "Pending" then - hs.status = "Healthy" - hs.message = "PVC is pending" - elseif obj.status.phase == "Lost" then - hs.status = "Degraded" - hs.message = "PVC is lost" - else - hs.status = "Progressing" - hs.message = obj.status.phase - end + - check: | + local hs = {} + if obj.status ~= nil and obj.status.phase ~= nil then + if obj.status.phase == "Bound" then + hs.status = "Healthy" + hs.message = "PVC is bound" + elseif obj.status.phase == "Pending" then + hs.status = "Healthy" + hs.message = "PVC is pending" + elseif obj.status.phase == "Lost" then + hs.status = "Degraded" + hs.message = "PVC is lost" else hs.status = "Progressing" - hs.message = "Waiting for PVC status" + hs.message = obj.status.phase end - return hs - kind: PersistentVolumeClaim - - check: | - local hs = {} + else hs.status = "Progressing" - hs.message = "Waiting for status update." - if obj.status ~= nil then - if obj.status.conditions ~= nil then - for i, condition in ipairs(obj.status.conditions) do - if condition.type == "Done" and condition.status == "True" then - hs.status = "Healthy" - hs.message = condition.message - return hs - end - if condition.type == "Started" and condition.status == "True" then - hs.status = "Progressing" - hs.message = "Realm import is running" - return hs - end - if condition.type == "HasErrors" and condition.status == "True" then - hs.status = "Degraded" - hs.message = condition.message - return hs - end + hs.message = "Waiting for PVC status" + end + return hs + kind: PersistentVolumeClaim + - check: | + local hs = {} + hs.status = "Progressing" + hs.message = "Waiting for status update." + if obj.status ~= nil then + if obj.status.conditions ~= nil then + for i, condition in ipairs(obj.status.conditions) do + if condition.type == "Done" and condition.status == "True" then + hs.status = "Healthy" + hs.message = condition.message + return hs + end + if condition.type == "Started" and condition.status == "True" then + hs.status = "Progressing" + hs.message = "Realm import is running" + return hs + end + if condition.type == "HasErrors" and condition.status == "True" then + hs.status = "Degraded" + hs.message = condition.message + return hs end end end - return hs - group: k8s.keycloak.org - kind: KeycloakRealmImport + end + return hs + group: k8s.keycloak.org + kind: KeycloakRealmImport resourceExclusions: | - apiGroups: - internal.open-cluster-management.io From 34a797af7eef1a8e1257b87c0251da0ba3611fce Mon Sep 17 00:00:00 2001 From: Min Zhang Date: Fri, 15 May 2026 11:49:33 -0400 Subject: [PATCH 2/3] fix: add ClusterStaticEntry workaround for SPIRE ignoreNamespaces The ZTWIM operator hardcodes ignoreNamespaces: ["openshift-*"] in the spire-controller-manager config, which prevents SPIRE from issuing identities to pods in openshift-pipelines. Work around this by creating ClusterStaticEntry resources that register the tekton-chains-controller directly, bypassing the ignoreNamespaces filter. A PostSync Job dynamically discovers node UIDs to build the correct parentID for each SPIRE agent. Signed-off-by: Min Zhang --- .../templates/spire-static-entries.yaml | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 charts/tekton-chains/templates/spire-static-entries.yaml diff --git a/charts/tekton-chains/templates/spire-static-entries.yaml b/charts/tekton-chains/templates/spire-static-entries.yaml new file mode 100644 index 00000000..a6a19457 --- /dev/null +++ b/charts/tekton-chains/templates/spire-static-entries.yaml @@ -0,0 +1,143 @@ +{{- if and .Values.chains.enabled .Values.chains.signers.x509.fulcio.enabled }} +{{- if eq .Values.chains.signers.x509.fulcio.provider "spiffe" }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: tekton-chains-spire-config + namespace: {{ .Release.Namespace }} + annotations: + argocd.argoproj.io/sync-wave: "48" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: tekton-chains-spire-config + annotations: + argocd.argoproj.io/sync-wave: "48" +rules: +- apiGroups: [""] + resources: ["nodes"] + verbs: ["list"] +- apiGroups: ["spire.spiffe.io"] + resources: ["clusterstaticentries"] + verbs: ["get", "list", "create", "update", "patch", "delete"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: tekton-chains-spire-config + annotations: + argocd.argoproj.io/sync-wave: "48" +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: tekton-chains-spire-config +subjects: +- kind: ServiceAccount + name: tekton-chains-spire-config + namespace: {{ .Release.Namespace }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: tekton-chains-spire-entries + namespace: {{ .Release.Namespace }} + annotations: + argocd.argoproj.io/sync-wave: "48" + argocd.argoproj.io/hook: PostSync + argocd.argoproj.io/hook-delete-policy: BeforeHookCreation + labels: + {{- include "tekton-chains.labels" . | nindent 4 }} +spec: + backoffLimit: 5 + template: + metadata: + labels: + {{- include "tekton-chains.selectorLabels" . | nindent 8 }} + spec: + serviceAccountName: tekton-chains-spire-config + restartPolicy: Never + containers: + - name: create-entries + image: registry.redhat.io/openshift4/ose-cli-rhel9:latest + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + cpu: 200m + memory: 256Mi + command: ["/bin/bash", "-c"] + args: + - | + set -euo pipefail + + TRUST_DOMAIN=$(oc get configmap spire-controller-manager \ + -n zero-trust-workload-identity-manager \ + -o jsonpath='{.data.controller-manager-config\.yaml}' \ + | grep trustDomain | awk '{print $2}') + CLUSTER_NAME=$(oc get configmap spire-controller-manager \ + -n zero-trust-workload-identity-manager \ + -o jsonpath='{.data.controller-manager-config\.yaml}' \ + | grep 'clusterName:' | awk '{print $2}') + CLASS_NAME=$(oc get configmap spire-controller-manager \ + -n zero-trust-workload-identity-manager \ + -o jsonpath='{.data.controller-manager-config\.yaml}' \ + | grep 'className:' | head -1 | awk '{print $2}') + + echo "Trust domain: $TRUST_DOMAIN" + echo "Cluster name: $CLUSTER_NAME" + echo "Class name: $CLASS_NAME" + + NODES=$(oc get nodes -o jsonpath='{range .items[*]}{.metadata.name} {.metadata.uid}{"\n"}{end}') + echo "" + echo "Nodes:" + echo "$NODES" + + echo "$NODES" | while read -r NODE_NAME NODE_UID; do + [ -z "$NODE_NAME" ] && continue + ENTRY_NAME="tekton-chains-controller-${NODE_NAME}" + PARENT_ID="spiffe://${TRUST_DOMAIN}/spire/agent/k8s_psat/${CLUSTER_NAME}/${NODE_UID}" + SPIFFE_ID="spiffe://${TRUST_DOMAIN}/ns/openshift-pipelines/sa/tekton-chains-controller" + + echo "" + echo "Creating ClusterStaticEntry: $ENTRY_NAME" + echo " parentID: $PARENT_ID" + + oc apply -f - </dev/null || true) + for entry in $EXISTING; do + ENTRY_SHORT=$(echo "$entry" | sed 's|clusterstaticentry.spire.spiffe.io/||') + NODE_PART=$(echo "$ENTRY_SHORT" | sed 's|tekton-chains-controller-||') + if ! echo "$NODES" | grep -q "^${NODE_PART} "; then + echo "Removing stale entry: $ENTRY_SHORT" + oc delete "$entry" || true + fi + done + + echo "" + echo "Done. Current entries:" + oc get clusterstaticentries -l app.kubernetes.io/managed-by=tekton-chains-spire-config +{{- end }} +{{- end }} From 4f91b94d9b1b27c78dea473357ff0235116e2fc4 Mon Sep 17 00:00:00 2001 From: Min Zhang Date: Fri, 15 May 2026 16:00:45 -0400 Subject: [PATCH 3/3] fix: restore values-hub.yaml and update ose-cli to ose-cli-rhel9 Restore commented-out placeholders (quay overrides, tekton-chains block) that were lost during the test branch merge. Update ose-cli image references to ose-cli-rhel9 in values-hub.yaml and scripts/features/. Signed-off-by: Min Zhang --- scripts/features/quay.yaml | 2 +- scripts/features/registry/option-1-quay.yaml | 2 +- values-hub.yaml | 791 +++++++++++-------- 3 files changed, 478 insertions(+), 317 deletions(-) diff --git a/scripts/features/quay.yaml b/scripts/features/quay.yaml index 83abd6e9..bd29edf0 100644 --- a/scripts/features/quay.yaml +++ b/scripts/features/quay.yaml @@ -27,6 +27,6 @@ clusterGroup: argocd.argoproj.io/sync-wave: "41" overrides: - name: job.image - value: "registry.redhat.io/openshift4/ose-cli:latest" + value: "registry.redhat.io/openshift4/ose-cli-rhel9:latest" - name: job.resources.limits.memory value: "512Mi" diff --git a/scripts/features/registry/option-1-quay.yaml b/scripts/features/registry/option-1-quay.yaml index 487be3a8..8251b773 100644 --- a/scripts/features/registry/option-1-quay.yaml +++ b/scripts/features/registry/option-1-quay.yaml @@ -40,7 +40,7 @@ clusterGroup: argocd.argoproj.io/sync-wave: "41" overrides: - name: job.image - value: "registry.redhat.io/openshift4/ose-cli:latest" + value: "registry.redhat.io/openshift4/ose-cli-rhel9:latest" - name: job.resources.limits.memory value: "512Mi" diff --git a/values-hub.yaml b/values-hub.yaml index 1707cc62..a5dbd0e6 100644 --- a/values-hub.yaml +++ b/values-hub.yaml @@ -47,70 +47,67 @@ spire: # vaultPath: "secret/data/hub/infra/registry/registry-user" # passwordVaultKey: "registry-password" -global: - registry: - enabled: true - domain: "quay-registry-quay-quay-enterprise.apps.{{ .Values.global.clusterDomain }}" - # Placeholders auto-replaced by the generator (supply-chain defines org=ztvp, image_name=qtodo) - repository: ztvp/qtodo - user: quay-user - vaultPath: "secret/data/hub/infra/quay/quay-users" - passwordVaultKey: "quay-user-password" - clusterGroup: name: hub isHubCluster: true namespaces: - - open-cluster-management - - vault - - qtodo - - golang-external-secrets - - keycloak-system: - operatorGroup: true - targetNamespace: keycloak-system - - cert-manager - - cert-manager-operator: - operatorGroup: true - targetNamespace: cert-manager-operator - - zero-trust-workload-identity-manager: - operatorGroup: true - targetNamespace: zero-trust-workload-identity-manager - - openshift-compliance: - operatorGroup: true - targetNamespace: openshift-compliance - annotations: - openshift.io/cluster-monitoring: "true" - - stackrox: - operatorGroup: true - labels: - openshift.io/cluster-monitoring: "true" - - openshift-pipelines - - trusted-artifact-signer: - annotations: - argocd.argoproj.io/sync-wave: "32" - labels: - openshift.io/cluster-monitoring: "true" - - openshift-storage: - operatorGroup: true - targetNamespace: openshift-storage - annotations: - openshift.io/cluster-monitoring: "true" - argocd.argoproj.io/sync-wave: "26" - - rhtpa-operator: - operatorGroup: true - targetNamespace: rhtpa-operator - annotations: - argocd.argoproj.io/sync-wave: "26" - - trusted-profile-analyzer: - annotations: - argocd.argoproj.io/sync-wave: "32" - labels: - openshift.io/cluster-monitoring: "true" - - quay-enterprise: - annotations: - argocd.argoproj.io/sync-wave: "32" - labels: - openshift.io/cluster-monitoring: "true" + - open-cluster-management + - vault + - qtodo + - golang-external-secrets + - keycloak-system: + operatorGroup: true + targetNamespace: keycloak-system + - cert-manager + - cert-manager-operator: + operatorGroup: true + targetNamespace: cert-manager-operator + # Layer 1: Storage and Registry + # Required for RHTPA and QUAY (provides NooBaa object storage backend) + # - openshift-storage: + # operatorGroup: true + # targetNamespace: openshift-storage + # annotations: + # openshift.io/cluster-monitoring: "true" + # argocd.argoproj.io/sync-wave: "26" # Propagated to OperatorGroup by framework + # - quay-enterprise: + # annotations: + # argocd.argoproj.io/sync-wave: "32" # Create before NooBaa and all Quay components + # labels: + # openshift.io/cluster-monitoring: "true" + # RHTAS namespace (required when RHTAS application is enabled) + # COMMENTED OUT: Uncomment to enable RHTAS with SPIFFE signing + # - trusted-artifact-signer: + # annotations: + # argocd.argoproj.io/sync-wave: "32" # Auto-created by RHTAS operator + # labels: + # openshift.io/cluster-monitoring: "true" + # - rhtpa-operator: + # operatorGroup: true + # targetNamespace: rhtpa-operator + # annotations: + # argocd.argoproj.io/sync-wave: "26" # Create before operator subscription + # - trusted-profile-analyzer: + # annotations: + # argocd.argoproj.io/sync-wave: "32" # Create before RHTPA components + # labels: + # openshift.io/cluster-monitoring: "true" + - zero-trust-workload-identity-manager: + operatorGroup: true + targetNamespace: zero-trust-workload-identity-manager + - openshift-compliance: + operatorGroup: true + targetNamespace: openshift-compliance + annotations: + openshift.io/cluster-monitoring: "true" + # Secure Supply Chain: Uncomment to enable OpenShift Pipelines + # - openshift-pipelines + # + # Red Hat Advanced Cluster Security (RHACS/StackRox) - Uncomment to enable + - stackrox: + operatorGroup: true + labels: + openshift.io/cluster-monitoring: "true" subscriptions: acm: name: advanced-cluster-management @@ -122,6 +119,10 @@ clusterGroup: namespace: cert-manager-operator channel: stable-v1 catalogSource: redhat-marketplace + # Secure Supply Chain: Uncomment to enable OpenShift Pipelines + # openshift-pipelines: + # name: openshift-pipelines-operator-rh + # namespace: openshift-operators rhbk: name: rhbk-operator namespace: keycloak-system @@ -140,46 +141,54 @@ clusterGroup: config: nodeSelector: node-role.kubernetes.io/worker: "" + # + # ACS Operator Subscription (Uncomment to enable) rhacs-operator: name: rhacs-operator namespace: openshift-operators channel: stable source: redhat-operators - openshift-pipelines: - name: openshift-pipelines-operator-rh - namespace: openshift-operators - rhtas-operator: - name: rhtas-operator - namespace: openshift-operators - channel: stable-v1.3 - annotations: - argocd.argoproj.io/sync-wave: "29" - catalogSource: redhat-operators - odf: - name: odf-operator - namespace: openshift-storage - channel: stable-4.20 - annotations: - argocd.argoproj.io/sync-wave: "27" - rhtpa-operator: - name: rhtpa-operator - namespace: rhtpa-operator - channel: stable-v1.1 - catalogSource: redhat-operators - annotations: - argocd.argoproj.io/sync-wave: "27" - quay-operator: - name: quay-operator - namespace: openshift-operators - channel: stable-3.15 - annotations: - argocd.argoproj.io/sync-wave: "28" + # + # Storage and Registry operator subscriptions + # Required for RHTPA and QUAY (provides NooBaa object storage backend) + # ODF provides object storage backend (NooBaa) for RHTPA and optionally Quay + # odf: + # name: odf-operator + # namespace: openshift-storage + # channel: stable-4.20 + # annotations: + # argocd.argoproj.io/sync-wave: "27" # Install after OperatorGroup (26) + # quay-operator: + # name: quay-operator + # namespace: openshift-operators + # channel: stable-3.15 + # annotations: + # argocd.argoproj.io/sync-wave: "28" # Install after ODF operator + # RHTAS operator subscription (required when RHTAS application is enabled) + # COMMENTED OUT: Uncomment to enable RHTAS with SPIFFE integration + # rhtas-operator: + # name: rhtas-operator + # namespace: openshift-operators + # channel: stable-v1.3 + # annotations: + # argocd.argoproj.io/sync-wave: "29" # Install after Quay operator, before applications + # catalogSource: redhat-operators + # RHTPA operator subscription + # Channel: stable-v1.1 provides latest 1.1.x patch updates + # Note: No direct upgrade path from 1.1.x to 2.x (requires fresh install) + # rhtpa-operator: + # name: rhtpa-operator + # namespace: rhtpa-operator # MUST use dedicated namespace (not openshift-operators) + # channel: stable-v1.1 # Use stable-v1.1 channel for 1.1.x updates + # catalogSource: redhat-operators + # annotations: + # argocd.argoproj.io/sync-wave: "27" # Install after OperatorGroup (26), before applications projects: - - hub + - hub # Explicitly mention the cluster-state based overrides we plan to use for this pattern. # We can use self-referential variables because the chart calls the tpl function with these variables defined sharedValueFiles: - - '/overrides/values-{{ $.Values.global.clusterPlatform }}.yaml' + - '/overrides/values-{{ $.Values.global.clusterPlatform }}.yaml' # sharedValueFiles is a flexible mechanism that will add the listed valuefiles to every app defined in the # applications section. We intend this to supplement and possibly even replace previous "magic" mechanisms, though # we do not at present have a target date for removal. @@ -204,33 +213,64 @@ clusterGroup: path: charts/ztvp-certificates annotations: argocd.argoproj.io/sync-wave: "21" + # Ignore the ACM-replicated policy in local-cluster namespace + # ACM automatically creates policy replicas with name pattern: . ignoreDifferences: - - group: policy.open-cluster-management.io - kind: Policy - name: openshift-config.ztvp-certificates-distribution - namespace: local-cluster - jsonPointers: - - / + - group: policy.open-cluster-management.io + kind: Policy + name: openshift-config.ztvp-certificates-distribution + namespace: local-cluster + jsonPointers: + - / + # Use extraValueFiles for complex nested structures like additionalCertificates + # The validated patterns framework only processes 'overrides' as --set parameters + # Edit /overrides/values-ztvp-certificates.yaml to configure: + # - Additional CA certificates (additionalCertificates array) + # - Automatic rollout restart for consuming applications extraValueFiles: - - /overrides/values-ztvp-certificates.yaml - - '/overrides/values-ztvp-certificates-{{ $.Values.global.clusterPlatform }}.yaml' + - /overrides/values-ztvp-certificates.yaml + - '/overrides/values-ztvp-certificates-{{ $.Values.global.clusterPlatform }}.yaml' overrides: - - name: debug.keepFailedJobs - value: "true" - - name: customCA.secretRef.name - value: custom-ca-bundle - - name: customCA.secretRef.namespace - value: openshift-config - - name: customCA.secretRef.key - value: ca.crt - - name: rollout.enabled - value: "true" - - name: rollout.strategy - value: labeled - - name: imagePullTrust.enabled - value: "true" - - name: imagePullTrust.registries[0] - value: "quay-registry-quay-quay-enterprise.apps.{{ $.Values.global.clusterDomain }}" + # Disable Job TTL to prevent ArgoCD OutOfSync when Kubernetes deletes completed Jobs + # The initial Job runs once during first sync; CronJob handles ongoing extraction + - name: debug.keepFailedJobs + value: "true" + + # Enable verbose logging for troubleshooting (uncomment if needed) + # - name: debug.verbose + # value: "true" + + # Primary custom CA: Use secretRef to reference an existing Kubernetes secret containing CA certificates + # Uncomment to add a primary custom CA: + # Single cert: oc create secret generic custom-ca-bundle --from-file=ca.crt=/path/to/ca.crt -n openshift-config + # Multiple certs: cat corp-root.crt intermediate.crt partner.crt > combined-ca.crt && oc create secret generic custom-ca-bundle --from-file=ca.crt=combined-ca.crt -n openshift-config + # Disabled for now - using auto-detection only + # - name: customCA.secretRef.enabled + # value: "true" + - name: customCA.secretRef.name + value: custom-ca-bundle + - name: customCA.secretRef.namespace + value: openshift-config + - name: customCA.secretRef.key + value: ca.crt + + # Automatic rollout configuration (simple overrides work fine) + - name: rollout.enabled + value: "true" + - name: rollout.strategy + value: labeled + + # Node-level image pull trust for kubelet + # Required when pulling images from registries behind the cluster ingress + # (e.g. built-in Quay, embedded OpenShift registry). Patches image.config.openshift.io/cluster. + # Uncomment and set the registry hostname when enabling Option 1 (Quay) or Option 3 (embedded OpenShift). + # - name: imagePullTrust.enabled + # value: "true" + # - name: imagePullTrust.registries[0] + # value: default-route-openshift-image-registry.apps.{{ $.Values.global.clusterDomain }} + + # Note: additionalCertificates (complex nested array) temporarily disabled + # Need to find proper way to pass complex structures in Validated Patterns acm: name: acm namespace: open-cluster-management @@ -240,13 +280,14 @@ clusterGroup: annotations: argocd.argoproj.io/sync-wave: "5" ignoreDifferences: - - group: internal.open-cluster-management.io - kind: ManagedClusterInfo - jsonPointers: - - /spec/loggingCA + - group: internal.open-cluster-management.io + kind: ManagedClusterInfo + jsonPointers: + - /spec/loggingCA + # We override the secret store because we are not provisioning clusters overrides: - - name: global.secretStore.backend - value: none + - name: global.secretStore.backend + value: none acm-managed-clusters: name: acm-managed-clusters project: hub @@ -254,11 +295,11 @@ clusterGroup: annotations: argocd.argoproj.io/sync-wave: "10" ignoreDifferences: - - group: cluster.open-cluster-management.io - kind: ManagedCluster - jsonPointers: - - /metadata/labels/cloud - - /metadata/labels/vendor + - group: cluster.open-cluster-management.io + kind: ManagedCluster + jsonPointers: + - /metadata/labels/cloud + - /metadata/labels/vendor compliance-scanning: name: compliance-scanning namespace: openshift-compliance @@ -268,59 +309,179 @@ clusterGroup: chart: ocp-compliance-scanning chartVersion: 0.0.* overrides: - - name: compliance.storage.enabled - value: "false" + # Disable unused PVC - compliance operator creates its own PVCs per scan + # via rawResultStorage in scan-setting.yaml. The explicit PVC causes + # ArgoCD 'Progressing' status on storage with WaitForFirstConsumer mode. + - name: compliance.storage.enabled + value: "false" vault: name: vault namespace: vault project: hub chart: hashicorp-vault chartVersion: 0.1.* + extraValueFiles: + - /overrides/values-vault-network-policy.yaml annotations: argocd.argoproj.io/sync-wave: "25" + # Custom Vault policies for least-privilege access + # Each application gets access only to its specific secrets path + # + # TWO types of policies needed: + # 1. -k8s-secret - for Kubernetes auth (ClusterSecretStore/ExternalSecrets) + # 2. -jwt-secret - for JWT/SPIFFE auth (application workloads) + # + # NOTE: K8s auth policies are auto-created by Ansible from vaultPrefixes + # JWT auth policies below are manually defined for apps that need direct Vault access policies: - - name: apps-qtodo-jwt-secret - policy: | - path "secret/data/apps/qtodo/*" { - capabilities = ["read"] - } - - name: hub-infra-rhtpa-jwt-secret - policy: | - path "secret/data/hub/infra/rhtpa/*" { - capabilities = ["read"] - } - - name: hub-supply-chain-jwt-secret - policy: | - path "secret/data/hub/infra/quay/*" { - capabilities = ["read"] - } - path "secret/data/hub/infra/registry/*" { - capabilities = ["read", "create", "update"] - } - path "secret/data/hub/infra/rhtpa/rhtpa-oidc-cli" { - capabilities = ["read"] - } + # ============================================================ + # JWT/SPIFFE Auth Policies (for application workloads) + # These are used by apps authenticating via SPIFFE JWT tokens + # Only define policies for apps that need direct Vault access + # K8s auth policies (-k8s-secret) are auto-created by Ansible + # ============================================================ + - name: apps-qtodo-jwt-secret + policy: | + path "secret/data/apps/qtodo/*" { + capabilities = ["read"] + } + - name: hub-infra-rhtpa-jwt-secret + policy: | + path "secret/data/hub/infra/rhtpa/*" { + capabilities = ["read"] + } + - name: hub-supply-chain-jwt-secret + policy: | + path "secret/data/hub/infra/quay/*" { + capabilities = ["read"] + } + path "secret/data/hub/infra/registry/*" { + capabilities = ["read", "create", "update"] + } + path "secret/data/hub/infra/rhtpa/rhtpa-oidc-cli" { + capabilities = ["read"] + } jwt: enabled: true oidcDiscoveryUrl: https://spire-spiffe-oidc-discovery-provider.zero-trust-workload-identity-manager.svc.cluster.local oidcDiscoveryCa: /run/secrets/kubernetes.io/serviceaccount/service-ca.crt defaultRole: qtodo roles: - - name: qtodo - audience: https://keycloak.apps.{{ $.Values.global.clusterDomain }}/realms/ztvp - subject: spiffe://apps.{{ $.Values.global.clusterDomain }}/ns/qtodo/sa/qtodo - policies: - - apps-qtodo-jwt-secret - - name: rhtpa - audience: rhtpa - subject: "spiffe://apps.{{ $.Values.global.clusterDomain }}/ns/trusted-profile-analyzer/sa/rhtpa" - policies: - - hub-infra-rhtpa-jwt-secret - - name: supply-chain - audience: supply-chain - subject: "spiffe://apps.{{ $.Values.global.clusterDomain }}/ns/{{ $.Values.global.pattern }}-hub/sa/pipeline" - policies: - - hub-supply-chain-jwt-secret + - name: qtodo + audience: https://keycloak.apps.{{ $.Values.global.clusterDomain }}/realms/ztvp + subject: spiffe://apps.{{ $.Values.global.clusterDomain }}/ns/qtodo/sa/qtodo + policies: + - apps-qtodo-jwt-secret + # RHTPA vault role + # - name: rhtpa + # audience: rhtpa + # subject: spiffe://apps.{{ $.Values.global.clusterDomain }}/ns/trusted-profile-analyzer/sa/rhtpa + # policies: + # - hub-infra-rhtpa-jwt-secret + # Supply chain vault role (for Tekton pipelines; enable with supply-chain app / Option 3 or BYO registry) + # - name: supply-chain + # audience: supply-chain + # subject: spiffe://apps.{{ $.Values.global.clusterDomain }}/ns/{{ $.Values.global.pattern }}-hub/sa/pipeline + # policies: + # - hub-supply-chain-jwt-secret + # Shared Object Storage Backend + # Required for RHTPA and QUAY (provides S3-compatible storage via NooBaa MCG) + # NooBaa MCG provides S3-compatible object storage for multiple applications + # noobaa-mcg: + # name: noobaa-mcg + # namespace: openshift-storage + # project: hub + # path: charts/noobaa-mcg + # annotations: + # argocd.argoproj.io/sync-wave: "36" # Deploy after core services + # Quay Container Registry (uses NooBaa for storage) + # quay-registry: + # name: quay-registry + # namespace: quay-enterprise + # project: hub + # chart: quay + # chartVersion: 0.1.* + # annotations: + # argocd.argoproj.io/sync-wave: "41" # Deploy after NooBaa storage backend + # overrides: + # - name: job.image + # value: "registry.redhat.io/openshift4/ose-cli-rhel9:latest" + # - name: job.resources.limits.memory + # value: "512Mi" + # RHTAS with SPIFFE Integration + # COMMENTED OUT: Uncomment to enable RHTAS with SPIFFE and Email issuers + # Depends on: Vault, SPIRE, Keycloak (for Email OIDC issuer if used) + # trusted-artifact-signer: + # name: trusted-artifact-signer + # namespace: trusted-artifact-signer + # project: hub + # path: charts/rhtas-operator + # annotations: + # argocd.argoproj.io/sync-wave: "46" # Deploy after dependencies + # overrides: + # # OIDC Issuer Configuration - Both can be enabled simultaneously + # # Enable SPIFFE issuer for workload identity + # - name: rhtas.zeroTrust.spire.enabled + # value: "true" + # - name: rhtas.zeroTrust.spire.trustDomain + # value: "apps.{{ $.Values.global.clusterDomain }}" + # - name: rhtas.zeroTrust.spire.issuer + # value: "https://spire-spiffe-oidc-discovery-provider.apps.{{ $.Values.global.clusterDomain }}" + # # Enable Keycloak issuer for user/email authentication + # - name: rhtas.zeroTrust.email.enabled + # value: "true" + # - name: rhtas.zeroTrust.email.issuer + # value: https://keycloak.apps.{{ $.Values.global.clusterDomain }}/realms/ztvp + # RHTPA (Red Hat Trusted Profile Analyzer) with SPIFFE Integration + # Depends on: NooBaa MCG (storage), Vault (secrets), SPIRE (identity), Keycloak (auth) + # trusted-profile-analyzer: + # name: trusted-profile-analyzer + # namespace: trusted-profile-analyzer + # project: hub + # path: charts/rhtpa-operator + # annotations: + # argocd.argoproj.io/sync-wave: "41" # Create chart resources (OBC, DB, etc.) + # # Note: The TrustedProfileAnalyzer CR is created by ACM Policy at wave 81 + # # to ensure the operator is fully ready (mitigates v1.1.0 initialization bug) + # # Ignore differences to prevent OutOfSync status + # ignoreDifferences: + # # Ignore Job status changes (completion, failure counts, conditions) + # # Jobs are created by hooks and their status changes don't require re-sync + # - group: batch + # kind: Job + # jsonPointers: + # - /status + # overrides: + # # Vault Integration + # # - name: rhtpa.zeroTrust.vault.url + # # value: https://vault.vault.svc.cluster.local:8200 + # # Keycloak URL is automatically constructed from global.localClusterDomain + # # TLS Configuration - Custom Ingress CA (for Azure/AWS/GCP with custom certs) + # # For standard OpenShift deployments, auto-detection works without overrides + # # For cloud platforms with custom ingress certs in non-standard locations: + # # - name: rhtpa.tls.ingressCA.customSource.enabled + # # value: "true" + # # - name: rhtpa.tls.ingressCA.customSource.secretName + # # value: "custom-ingress-cert" + # # - name: rhtpa.tls.ingressCA.customSource.secretNamespace + # # value: "openshift-ingress" + # # - name: rhtpa.tls.ingressCA.customSource.secretKey + # # value: "tls.crt" + # # Importer Configuration + # # Enable all 5 importers explicitly (chart defaults: cve and osv-github enabled) + # # Period defaults to 1d for all importers (configured in chart) + # # Default importers + # # - name: rhtpa.modules.createImporters.importers.cve.cve.disabled + # # value: "false" + # # - name: rhtpa.modules.createImporters.importers.osv-github.osv.disabled + # # value: "false" + # # Additional importers (disabled by default due to large datasets) + # # - name: rhtpa.modules.createImporters.importers.redhat-csaf.csaf.disabled + # # value: "false" + # # - name: rhtpa.modules.createImporters.importers.quay-redhat-user-workloads.quay.disabled + # # value: "false" + # # - name: rhtpa.modules.createImporters.importers.redhat-sboms.sbom.disabled + # # value: "false" golang-external-secrets: name: golang-external-secrets namespace: golang-external-secrets @@ -337,6 +498,13 @@ clusterGroup: chartVersion: 0.0.* annotations: argocd.argoproj.io/sync-wave: "35" + # SPIFFE Identity Provider is enabled by default in the chart. + # Override issuer/jwksUrl only if auto-generated values from cluster domain are not suitable. + # overrides: + # - name: keycloak.spiffeIdentityProvider.config.config.issuer + # value: "spiffe://apps.example.com" + # - name: keycloak.spiffeIdentityProvider.config.config.jwksUrl + # value: "https://spire-spiffe-oidc-discovery-provider.apps.example.com/keys" rh-cert-manager: name: rh-cert-manager namespace: cert-manager-operator @@ -354,8 +522,8 @@ clusterGroup: annotations: argocd.argoproj.io/sync-wave: "30" overrides: - - name: spire.clusterName - value: hub + - name: spire.clusterName + value: hub qtodo: name: qtodo namespace: qtodo @@ -364,57 +532,125 @@ clusterGroup: annotations: argocd.argoproj.io/sync-wave: "38" ignoreDifferences: - - kind: ServiceAccount - jqPathExpressions: - - .imagePullSecrets[]|select(.name | contains("-dockercfg-")) + - kind: ServiceAccount + jqPathExpressions: + - .imagePullSecrets[]|select(.name | contains("-dockercfg-")) overrides: - - name: app.oidc.enabled - value: "true" - - name: app.spire.enabled - value: "true" - - name: app.vault.url - value: https://vault.vault.svc.cluster.local:8200 - - name: app.vault.role - value: qtodo - - name: app.vault.secretPath - value: secret/data/apps/qtodo/qtodo-db + - name: app.oidc.enabled + value: "true" + - name: app.spire.enabled + value: "true" + - name: app.vault.url + value: https://vault.vault.svc.cluster.local:8200 + - name: app.vault.role + value: qtodo + - name: app.vault.secretPath + value: secret/data/apps/qtodo/qtodo-db + # Secure Supply Chain: when global.registry.enabled=true the chart + # automatically derives the image from global.registry.domain/repository. + # No override needed here. + # Uncomment to seed the registry with the upstream qtodo image + # before the supply-chain pipeline runs (avoids ImagePullBackOff on first install) + # - name: app.seedImage.enabled + # value: "true" + # Tekton Chains - Configures Tekton Chains for supply chain security + # Requires: OpenShift Pipelines operator (openshift-pipelines subscription) + # Requires: RHTAS (trusted-artifact-signer) for keyless signing via SPIFFE + # Uses a PostSync Job to patch the operator-managed TektonConfig CR + # tekton-chains: + # name: tekton-chains + # project: hub + # path: charts/tekton-chains + # annotations: + # argocd.argoproj.io/sync-wave: "47" + # + # Secure Supply Chain - Uncomment to enable (required for Option 1, 2, or 3 registry flows in docs) + # supply-chain: + # name: supply-chain + # project: hub + # path: charts/supply-chain + # annotations: + # argocd.argoproj.io/sync-wave: "48" + # ignoreDifferences: + # - kind: ServiceAccount + # jqPathExpressions: + # - .imagePullSecrets[]|select(.name | contains("-dockercfg-")) + # overrides: + # # Registry credentials are inherited from global.registry. + # # Only set app-specific overrides below. + # # Built-in Quay: uncomment to enable the Quay user provisioner CronJob + # # - name: quay.enabled + # # value: "true" + # # Built-in Quay: self-signed certs require TLS verify off + # # - name: registry.tlsVerify + # # value: "false" + # # Embedded OpenShift (Option 3): create image namespace and grant push RBAC + # # - name: registry.embeddedOpenShift.ensureImageNamespaceRBAC + # # value: "true" + # # Embedded OpenShift (Option 3): periodically refresh pipeline SA token in Vault + # # - name: registry.embeddedOpenShift.tokenRefresher.enabled + # # value: "true" + # # Enable RHTAS signing + # # - name: rhtas.enabled + # # value: "true" + # # Enable RHTPA SBOM upload + # # - name: rhtpa.enabled + # # value: "true" + # # Uncomment to auto-trigger a pipeline run on every ArgoCD sync + # # - name: pipelinerun.enabled + # # value: "true" + # + # ACS Central Services acs-central: name: acs-central-services namespace: stackrox project: hub path: charts/acs-central overrides: - - name: central.exposure.route.enabled - value: "true" - - name: integration.keycloak.enabled - value: "true" - - name: integration.keycloak.realm - value: "ztvp" - - name: integration.keycloak.clientId - value: "acs-central" + # Uncomment and set if you need a specific StorageClass: + # - name: central.persistence.storageClass + # value: gp3-csi # Example for AWS + - name: central.exposure.route.enabled + value: "true" + - name: central.exposure.route.reencrypt.host + value: "central.{{ $.Values.global.localClusterDomain }}" + - name: integration.keycloak.enabled + value: "true" + - name: integration.keycloak.realm + value: "ztvp" + - name: integration.keycloak.clientId + value: "acs-central" + # ACS to scan images stored in Quay (Uncomment to enable) + # - name: integration.quay.enabled + # value: "true" + # - name: integration.quay.url + # value: "quay-quay-enterprise.apps.{{ .Values.global.domain }}" extraValueFiles: - - /values-global.yaml - - /values-{{ .Values.global.pattern }}-hub.yaml + - /values-global.yaml + - /values-{{ .Values.global.pattern }}-hub.yaml ignoreDifferences: - - group: platform.stackrox.io - kind: Central - jsonPointers: - - /spec/scanner/scannerComponent + - group: platform.stackrox.io + kind: Central + jsonPointers: + - /spec/scanner/scannerComponent annotations: argocd.argoproj.io/sync-wave: "41" + + # ACS Secured Cluster acs-secured-cluster: name: acs-secured-cluster namespace: stackrox project: hub path: charts/acs-secured-cluster overrides: - - name: clusterName - value: hub + - name: clusterName + value: hub extraValueFiles: - - /values-global.yaml - - /values-{{ .Values.global.pattern }}-hub.yaml + - /values-global.yaml + - /values-{{ .Values.global.pattern }}-hub.yaml annotations: argocd.argoproj.io/sync-wave: "46" + # ACS Policies acs-policies: name: acs-policies namespace: stackrox @@ -422,133 +658,58 @@ clusterGroup: path: charts/acs-policies annotations: argocd.argoproj.io/sync-wave: "51" - trusted-artifact-signer: - name: trusted-artifact-signer - namespace: trusted-artifact-signer - project: hub - path: charts/rhtas-operator - annotations: - argocd.argoproj.io/sync-wave: "46" - overrides: - - name: rhtas.zeroTrust.spire.enabled - value: "true" - - name: rhtas.zeroTrust.spire.trustDomain - value: "apps.{{ $.Values.global.clusterDomain }}" - - name: rhtas.zeroTrust.spire.issuer - value: "https://spire-spiffe-oidc-discovery-provider.apps.{{ $.Values.global.clusterDomain }}" - - name: rhtas.zeroTrust.email.enabled - value: "true" - - name: rhtas.zeroTrust.email.issuer - value: "https://keycloak.apps.{{ $.Values.global.clusterDomain }}/realms/ztvp" - tekton-chains: - name: tekton-chains - project: hub - path: charts/tekton-chains - annotations: - argocd.argoproj.io/sync-wave: "47" - noobaa-mcg: - name: noobaa-mcg - namespace: openshift-storage - project: hub - path: charts/noobaa-mcg - annotations: - argocd.argoproj.io/sync-wave: "36" - trusted-profile-analyzer: - name: trusted-profile-analyzer - namespace: trusted-profile-analyzer - project: hub - path: charts/rhtpa-operator - annotations: - argocd.argoproj.io/sync-wave: "41" - ignoreDifferences: - - group: batch - kind: Job - jsonPointers: - - /status - supply-chain: - name: supply-chain - project: hub - path: charts/supply-chain - annotations: - argocd.argoproj.io/sync-wave: "48" - ignoreDifferences: - - kind: ServiceAccount - jqPathExpressions: - - ".imagePullSecrets[]|select(.name | contains(\"-dockercfg-\"))" - overrides: - - name: quay.enabled - value: "true" - - name: registry.tlsVerify - value: "false" - - name: rhtas.enabled - value: "true" - - name: rhtpa.enabled - value: "true" - quay-registry: - name: quay-registry - namespace: quay-enterprise - project: hub - chart: quay - chartVersion: 0.1.* - annotations: - argocd.argoproj.io/sync-wave: "41" - overrides: - - name: job.image - value: "registry.redhat.io/openshift4/ose-cli:latest" - - name: job.resources.limits.memory - value: "512Mi" argoCD: resourceHealthChecks: - - check: | - local hs = {} - if obj.status ~= nil and obj.status.phase ~= nil then - if obj.status.phase == "Bound" then - hs.status = "Healthy" - hs.message = "PVC is bound" - elseif obj.status.phase == "Pending" then - hs.status = "Healthy" - hs.message = "PVC is pending" - elseif obj.status.phase == "Lost" then - hs.status = "Degraded" - hs.message = "PVC is lost" + - check: | + local hs = {} + if obj.status ~= nil and obj.status.phase ~= nil then + if obj.status.phase == "Bound" then + hs.status = "Healthy" + hs.message = "PVC is bound" + elseif obj.status.phase == "Pending" then + hs.status = "Healthy" + hs.message = "PVC is pending" + elseif obj.status.phase == "Lost" then + hs.status = "Degraded" + hs.message = "PVC is lost" + else + hs.status = "Progressing" + hs.message = obj.status.phase + end else hs.status = "Progressing" - hs.message = obj.status.phase + hs.message = "Waiting for PVC status" end - else + return hs + kind: PersistentVolumeClaim + - check: | + local hs = {} hs.status = "Progressing" - hs.message = "Waiting for PVC status" - end - return hs - kind: PersistentVolumeClaim - - check: | - local hs = {} - hs.status = "Progressing" - hs.message = "Waiting for status update." - if obj.status ~= nil then - if obj.status.conditions ~= nil then - for i, condition in ipairs(obj.status.conditions) do - if condition.type == "Done" and condition.status == "True" then - hs.status = "Healthy" - hs.message = condition.message - return hs - end - if condition.type == "Started" and condition.status == "True" then - hs.status = "Progressing" - hs.message = "Realm import is running" - return hs - end - if condition.type == "HasErrors" and condition.status == "True" then - hs.status = "Degraded" - hs.message = condition.message - return hs + hs.message = "Waiting for status update." + if obj.status ~= nil then + if obj.status.conditions ~= nil then + for i, condition in ipairs(obj.status.conditions) do + if condition.type == "Done" and condition.status == "True" then + hs.status = "Healthy" + hs.message = condition.message + return hs + end + if condition.type == "Started" and condition.status == "True" then + hs.status = "Progressing" + hs.message = "Realm import is running" + return hs + end + if condition.type == "HasErrors" and condition.status == "True" then + hs.status = "Degraded" + hs.message = condition.message + return hs + end end end end - end - return hs - group: k8s.keycloak.org - kind: KeycloakRealmImport + return hs + group: k8s.keycloak.org + kind: KeycloakRealmImport resourceExclusions: | - apiGroups: - internal.open-cluster-management.io