From e3c23c09e998de5b4895ab5f9d199d0381b0695c Mon Sep 17 00:00:00 2001 From: Simon Gerber Date: Mon, 2 Nov 2026 14:24:28 +0100 Subject: [PATCH 1/5] Add support for managing credentials for containers.isovalent.com The component supports three different types of credentials: static, direct-eso, and projectsyn. The component adds the credentials to the OpenShift cluster-wide pull secret via the Espejote ManagedResource defined in component-openshift4-config. For credential type `static`, the component deploys a Secret that's populated with a static access token that's stored in Vault. Because we can't pre-compute a valid `dockerconfigjson` value before revealing the Vault references, the component deploys an Espejote ManagedResource which takes the static credentials and renders them as a `dockerconfigjson`. For credential type `direct-eso`, the component requires that component-external-secrets-operator is present on the cluster and configures an ESO webhook generator which is configured to request new access tokens from the Isovalent container registry and an ExternalSecret which uses the generator to render the Cilium pull secret that's merged into the cluster-wide pull secret. For this credential type, the component requires that parameter `enterprise.registry.hostname` is set to `containers.isovalent.com`. For credential type `projectsyn`, the component deploys an Espejote ManagedResource which takes the provided registry hostname and username, and configures the registry password as the SHA-256 hash of the cluster's Steward token. For this credential type, the component requires that parameter `enterprise.registry.hostname` is set to something other than `containers.isovalent.com`. --- class/cilium.yml | 1 + class/defaults.yml | 9 + component/enterprise.jsonnet | 14 + .../cilium-pull-secret.jsonnet | 62 +++ component/icr-config.libsonnet | 386 ++++++++++++++++++ tests/enterprise-bgp.yml | 3 + .../80_enterprise_pull_secret_config.yaml | 15 + ...terprise_pull_secret_managed_resource.yaml | 154 +++++++ ..._enterprise_pull_secret_bootstrap_job.yaml | 140 +++++++ .../cilium/80_enterprise_pull_secret_eso.yaml | 62 +++ tests/olm-enterprise.yml | 10 + 11 files changed, 856 insertions(+) create mode 100644 component/enterprise.jsonnet create mode 100644 component/espejote-templates/cilium-pull-secret.jsonnet create mode 100644 component/icr-config.libsonnet create mode 100644 tests/golden/enterprise-bgp/cilium/cilium/80_enterprise_pull_secret_config.yaml create mode 100644 tests/golden/enterprise-bgp/cilium/cilium/80_enterprise_pull_secret_managed_resource.yaml create mode 100644 tests/golden/olm-enterprise/cilium/cilium/80_enterprise_pull_secret_bootstrap_job.yaml create mode 100644 tests/golden/olm-enterprise/cilium/cilium/80_enterprise_pull_secret_eso.yaml diff --git a/class/cilium.yml b/class/cilium.yml index 3dc73fe72..a80f5fe09 100644 --- a/class/cilium.yml +++ b/class/cilium.yml @@ -14,6 +14,7 @@ parameters: - ${_base_directory}/component/alerts.jsonnet - ${_base_directory}/component/rbac.jsonnet - ${_base_directory}/component/cert-manager-ca.jsonnet + - ${_base_directory}/component/enterprise.jsonnet olm: dependencies: - type: https diff --git a/class/defaults.yml b/class/defaults.yml index 47bebcae2..1ffdc1663 100644 --- a/class/defaults.yml +++ b/class/defaults.yml @@ -120,6 +120,15 @@ parameters: deploy_cert_manager_ca: false + enterprise: + registry: + hostname: containers.isovalent.com + credentials: + # options: "static", "direct-eso", "projectsyn" + type: static + username: ?{vaultkv:${cluster:tenant}/${cluster:name}/isovalent/username} + access_token: ?{vaultkv:${cluster:tenant}/${cluster:name}/isovalent/access_token} + olm: source: opensource: https://github.com/isovalent/olm-for-cilium/archive/main.tar.gz diff --git a/component/enterprise.jsonnet b/component/enterprise.jsonnet new file mode 100644 index 000000000..132cae761 --- /dev/null +++ b/component/enterprise.jsonnet @@ -0,0 +1,14 @@ +local kap = import 'lib/kapitan.libjsonnet'; + +local inv = kap.inventory(); +local params = inv.parameters.cilium; + +local icr_config = import 'icr-config.libsonnet'; + +if params.release == 'enterprise' then + { + ['80_enterprise_%s' % k]: icr_config[k] + for k in std.objectFields(icr_config) + } +else + {} diff --git a/component/espejote-templates/cilium-pull-secret.jsonnet b/component/espejote-templates/cilium-pull-secret.jsonnet new file mode 100644 index 000000000..e511ce48c --- /dev/null +++ b/component/espejote-templates/cilium-pull-secret.jsonnet @@ -0,0 +1,62 @@ +local esp = import 'espejote.libsonnet'; + +local read_context_secret(ctxname) = + if ctxname in esp.context() then + local secret = esp.context()[ctxname]; + assert std.length(secret) == 1 : 'Expected %s context to have length 1' % ctxname; + secret[0] + else + null; + +local config = + local secret = read_context_secret('isovalent_registry_config'); + assert secret != null : 'Context isovalent_registry_config missing'; + assert + std.objectHas(secret.data, 'hostname') + && std.objectHas(secret.data, 'username') + && std.objectHas(secret.data, 'pull_secret_name') + : 'Expected Isovalent registry config secret to have fields `hostname`, `username` and `pull_secret_name`'; + { + [k]: std.base64Decode(secret.data[k]) + for k in std.objectFields(secret.data) + }; + +local access_token = + local steward_token = + local secret = read_context_secret('steward_token'); + assert secret != null : 'Context steward_token missing'; + assert std.objectHas(secret.data, 'token') : 'Expected Steward token secret to have field `token`'; + std.base64Decode(secret.data.token); + // NOTE(sg): This should make the template suitable for both 'static' and + // 'projectsyn' credentials type. We read the access token from the config + // secret, if it's present (which it is for credentials type 'static'), and + // fall back to the steward token otherwise. + std.get(config, 'access_token', std.sha256(steward_token)); + +{ + apiVersion: 'v1', + kind: 'Secret', + metadata: { + name: config.pull_secret_name, + namespace: 'openshift-config', + labels: { + 'pull-secret.openshift-config.syn.tools/include': '', + 'app.kubernetes.io/managed-by': 'espejote', + }, + }, + type: 'kubernetes.io/dockerconfigjson', + stringData: { + '.dockerconfigjson': std.manifestJsonMinified({ + auths: { + [config.hostname]: { + auth: std.base64( + '%(username)s:%(password)s' % { + username: config.username, + password: access_token, + } + ), + }, + }, + }), + }, +} diff --git a/component/icr-config.libsonnet b/component/icr-config.libsonnet new file mode 100644 index 000000000..eb388526d --- /dev/null +++ b/component/icr-config.libsonnet @@ -0,0 +1,386 @@ +local kap = import 'lib/kapitan.libjsonnet'; +local kube = import 'lib/kube.libjsonnet'; +local util = import 'util.libsonnet'; + +local esp = import 'lib/espejote.libsonnet'; +local eso = import 'lib/external-secrets-operator.libsonnet'; + +local inv = kap.inventory(); +local params = inv.parameters.cilium; + +local pull_secret_name = 'cilium-pull-secret'; + +local credentials_type = + local t = params.enterprise.registry.credentials.type; + if std.member([ 'static', 'direct-eso', 'projectsyn' ], t) then + t + else + error "The component only supports enterprise credentials types 'static', 'direct-eso', and 'projectsyn'; Got %s." % t; + +local pull_secret_managed_resource(syn) = + local rbac_name = 'cilium-pull-secret-manager'; + local sa = kube.ServiceAccount(rbac_name) { + metadata+: { + namespace: 'openshift-config', + }, + }; + local role = kube.Role(rbac_name) { + metadata+: { + namespace: 'openshift-config', + }, + rules: [ + { + apiGroups: [ '' ], + resources: [ 'secrets' ], + resourceNames: [ pull_secret_name ], + verbs: [ 'get', 'list', 'watch', 'create', 'update', 'patch' ], + }, + { + apiGroups: [ '' ], + resources: [ 'secrets' ], + resourceNames: [ 'isovalent-registry-config' ], + verbs: [ 'get', 'list', 'watch' ], + }, + ], + }; + local syn_role = kube.Role(rbac_name) { + metadata+: { + namespace: 'syn', + }, + rules: [ + { + apiGroups: [ '' ], + resources: [ 'secrets' ], + resourceNames: [ 'steward' ], + verbs: [ 'get', 'list', 'watch' ], + }, + ], + }; + local rolebinding = kube.RoleBinding(rbac_name) { + metadata+: { + namespace: 'openshift-config', + }, + roleRef_: role, + subjects_: [ sa ], + }; + local syn_rolebinding = kube.RoleBinding(rbac_name) { + metadata+: { + namespace: 'syn', + }, + roleRef_: syn_role, + subjects_: [ sa ], + }; + [ + esp.managedResource('cilium-pull-secret', 'openshift-config') { + spec: { + serviceAccountRef: { + name: sa.metadata.name, + }, + context: [ + { + name: 'cilium_pull_secret', + resource: { + apiVersion: 'v1', + kind: 'Secret', + name: pull_secret_name, + namespace: 'openshift-config', + }, + }, + { + name: 'isovalent_registry_config', + resource: { + apiVersion: 'v1', + kind: 'Secret', + name: 'isovalent-registry-config', + namespace: 'openshift-config', + }, + }, + ] + if syn then [ + { + name: 'steward_token', + resource: { + apiVersion: 'v1', + kind: 'Secret', + name: 'steward', + namespace: 'syn', + }, + }, + ] else [], + triggers: [ + { + name: 'cilium_pull_secret', + watchContextResource: { + name: 'cilium_pull_secret', + }, + }, + { + name: 'isovalent_registry_config', + watchContextResource: { + name: 'isovalent_registry_config', + }, + }, + ] + if syn then [ + { + name: 'steward_token', + watchContextResource: { + name: 'steward_token', + }, + }, + ] else [], + template: importstr 'espejote-templates/cilium-pull-secret.jsonnet', + }, + }, + sa, + role, + rolebinding, + ] + if syn then [ syn_role, syn_rolebinding ] else []; + +local pull_secret_bootstrap_job = + local rbac_name = 'cilium-pull-secret-bootstrapper'; + local sa = kube.ServiceAccount(rbac_name) { + metadata+: { + namespace: 'openshift-config', + }, + }; + local role = kube.Role(rbac_name) { + metadata+: { + namespace: 'openshift-config', + }, + rules: [ + { + apiGroups: [ '' ], + resources: [ 'secrets' ], + resourceNames: [ 'isovalent-registry-config' ], + verbs: [ 'get', 'list', 'watch' ], + }, + { + apiGroups: [ '' ], + resources: [ 'secrets' ], + resourceNames: [ pull_secret_name ], + verbs: [ 'get', 'list', 'watch', 'create', 'update', 'patch' ], + }, + ], + }; + local rolebinding = kube.RoleBinding(rbac_name) { + metadata+: { + namespace: 'openshift-config', + }, + roleRef_: role, + subjects_: [ sa ], + }; + [ + kube.Secret('isovalent-registry-config') { + metadata+: { + namespace: 'openshift-config', + }, + stringData: { + access_token: params.enterprise.registry.credentials.access_token, + 'pull_secret_template.yaml': std.manifestJsonMinified({ + apiVersion: 'v1', + kind: 'Secret', + metadata: { + labels: { + 'external-secrets.io/type': 'webhook', + }, + }, + type: 'kubernetes.io/dockerconfigjson', + stringData: { + '.dockerconfigjson': '{}', + }, + }), + }, + }, + kube.Job('bootstrap-cilium-pull-secret') { + metadata+: { + namespace: 'openshift-config', + annotations+: { + 'argocd.argoproj.io/hook': 'Sync', + }, + }, + spec+: { + activeDeadlineSeconds: 30, + backoffLimit: 1, + template+: { + spec+: { + serviceAccountName: sa.metadata.name, + containers_: { + bootstrap: kube.Container('pull-secret-bootstrap') { + image: '%(registry)s/%(repository)s:%(tag)s' % params.images.oc, + command: [ + 'bash', + '-c', + ||| + if ! kubectl -n "${NAMESPACE}" get secret "${PULL_SECRET}" &>/dev/null; then + echo "Creating initial secret '${PULL_SECRET}'" + yq '.metadata.name=strenv(PULL_SECRET) | .stringData.access_token=strenv(ACCESS_TOKEN)' \ + /config/pull_secret_template.yaml \ + | kubectl -n "${NAMESPACE}" apply --server-side -f- + else + echo "Secret '${PULL_SECRET}' already exists, nothing to do." + fi + |||, + ], + env_: { + NAMESPACE: { + fieldRef: { + fieldPath: 'metadata.namespace', + }, + }, + PULL_SECRET: pull_secret_name, + ACCESS_TOKEN: { + secretKeyRef: { + name: 'isovalent-registry-config', + key: 'access_token', + }, + }, + }, + volumeMounts_: { + config: { + mountPath: '/config', + }, + }, + }, + }, + volumes_: { + config: { + secret: { + secretName: 'isovalent-registry-config', + items: [ + { + key: 'pull_secret_template.yaml', + path: 'pull_secret_template.yaml', + mode: std.parseOctal('0600'), + }, + ], + }, + }, + }, + }, + }, + }, + }, + sa, + role, + rolebinding, + ]; + +local ocp_credentials_manifests = { + static: { + assert std.member(inv.applications, 'espejote') : 'Static Isovalent registry credentials management requires Espejote', + pull_secret_config: kube.Secret('isovalent-registry-config') { + metadata+: { + namespace: 'openshift-config', + }, + stringData: { + pull_secret_name: pull_secret_name, + hostname: params.enterprise.registry.hostname, + username: params.enterprise.registry.credentials.username, + access_token: params.enterprise.registry.credentials.access_token, + }, + }, + // NOTE(sg): we need the ManagedResource here, because we can't precompute + // the base64-encoded pull secret contents which are based on Vault + // references in Commodore. + pull_secret_managed_resource: pull_secret_managed_resource(syn=false), + }, + 'direct-eso': { + assert std.member(inv.applications, 'external-secrets-operator') : 'Isovalent registry credentials management type `direct-eso` requires External Secrets Operator', + assert params.enterprise.registry.hostname == 'containers.isovalent.com' : 'Isovalent registry credentials management type `direct-eso` is only supported for registry hostname containers.isovalent.com', + pull_secret_bootstrap_job: pull_secret_bootstrap_job, + pull_secret_eso: [ + eso._Generator('Webhook', 'registry-isovalent-com') { + metadata+: { + namespace: 'openshift-config', + }, + spec: { + url: 'https://registry.isovalent.com/access/api/v1/tokens', + result: { + jsonPath: '$', + }, + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: 'Bearer {{ print .pull.access_token }}', + }, + body: std.manifestJsonMinified({ + description: '%s_pull-secret' % inv.parameters.cluster.name, + token_type: 'access_token', + }), + secrets: [ + { + name: 'pull', + secretRef: { + name: pull_secret_name, + }, + }, + ], + }, + }, + eso.ExternalSecret('cilium-pull-secret') { + metadata+: { + namespace: 'openshift-config', + }, + spec: { + refreshInterval: '720h', // 30 days + target: { + creationPolicy: 'Owner', + deletionPolicy: 'Retain', + name: pull_secret_name, + template: { + metadata: { + labels: { + 'pull-secret.openshift-config.syn.tools/include': '', + 'external-secrets.io/type': 'webhook', + }, + }, + data: { + access_token: '{{ print .access_token }}', + '.dockerconfigjson': ||| + { + "auths": { + "containers.isovalent.com": { + "auth": "{{ printf "%s:%s" .username .access_token | b64enc }}" + } + } + } + |||, + }, + engineVersion: 'v2', + mergePolicy: 'Replace', + type: 'kubernetes.io/dockerconfigjson', + }, + }, + dataFrom: [ { + sourceRef: { + generatorRef: { + apiVersion: 'generators.external-secrets.io/v1alpha1', + kind: 'Webhook', + name: 'registry-isovalent-com', + }, + }, + } ], + }, + }, + ], + }, + projectsyn: { + assert std.member(inv.applications, 'espejote') : 'Project Syn-aware Isovalent registry credentials management requires Espejote', + assert params.enterprise.registry.hostname != 'containers.isovalent.com' : 'Project Syn-aware Isovalent registry credentials management requires a Project-Syn managed pull through registry for containers.isovalent.com', + pull_secret_config: kube.Secret('isovalent-registry-config') { + metadata+: { + namespace: 'openshift-config', + }, + stringData: { + pull_secret_name: pull_secret_name, + hostname: params.enterprise.registry.hostname, + username: params.enterprise.registry.credentials.username, + }, + }, + pull_secret_managed_resource: pull_secret_managed_resource(syn=true), + }, +}; + +if !util.isOpenshift then + error 'Isovalent credentials management NYI for non-OpenShift' +else + ocp_credentials_manifests[credentials_type] diff --git a/tests/enterprise-bgp.yml b/tests/enterprise-bgp.yml index afcbfd53e..b2e388ecc 100644 --- a/tests/enterprise-bgp.yml +++ b/tests/enterprise-bgp.yml @@ -1,3 +1,6 @@ +applications: + - espejote + parameters: facts: distribution: openshift4 diff --git a/tests/golden/enterprise-bgp/cilium/cilium/80_enterprise_pull_secret_config.yaml b/tests/golden/enterprise-bgp/cilium/cilium/80_enterprise_pull_secret_config.yaml new file mode 100644 index 000000000..bdff0be65 --- /dev/null +++ b/tests/golden/enterprise-bgp/cilium/cilium/80_enterprise_pull_secret_config.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +data: {} +kind: Secret +metadata: + annotations: {} + labels: + name: isovalent-registry-config + name: isovalent-registry-config + namespace: openshift-config +stringData: + access_token: t-silent-test-1234/c-green-test-1234/isovalent/access_token + hostname: containers.isovalent.com + pull_secret_name: cilium-pull-secret + username: t-silent-test-1234/c-green-test-1234/isovalent/username +type: Opaque diff --git a/tests/golden/enterprise-bgp/cilium/cilium/80_enterprise_pull_secret_managed_resource.yaml b/tests/golden/enterprise-bgp/cilium/cilium/80_enterprise_pull_secret_managed_resource.yaml new file mode 100644 index 000000000..1787259db --- /dev/null +++ b/tests/golden/enterprise-bgp/cilium/cilium/80_enterprise_pull_secret_managed_resource.yaml @@ -0,0 +1,154 @@ +apiVersion: espejote.io/v1alpha1 +kind: ManagedResource +metadata: + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + labels: + app.kubernetes.io/name: cilium-pull-secret + name: cilium-pull-secret + namespace: openshift-config +spec: + context: + - name: cilium_pull_secret + resource: + apiVersion: v1 + kind: Secret + name: cilium-pull-secret + namespace: openshift-config + - name: isovalent_registry_config + resource: + apiVersion: v1 + kind: Secret + name: isovalent-registry-config + namespace: openshift-config + serviceAccountRef: + name: cilium-pull-secret-manager + template: | + local esp = import 'espejote.libsonnet'; + + local read_context_secret(ctxname) = + if ctxname in esp.context() then + local secret = esp.context()[ctxname]; + assert std.length(secret) == 1 : 'Expected %s context to have length 1' % ctxname; + secret[0] + else + null; + + local config = + local secret = read_context_secret('isovalent_registry_config'); + assert secret != null : 'Context isovalent_registry_config missing'; + assert + std.objectHas(secret.data, 'hostname') + && std.objectHas(secret.data, 'username') + && std.objectHas(secret.data, 'pull_secret_name') + : 'Expected Isovalent registry config secret to have fields `hostname`, `username` and `pull_secret_name`'; + { + [k]: std.base64Decode(secret.data[k]) + for k in std.objectFields(secret.data) + }; + + local access_token = + local steward_token = + local secret = read_context_secret('steward_token'); + assert secret != null : 'Context steward_token missing'; + assert std.objectHas(secret.data, 'token') : 'Expected Steward token secret to have field `token`'; + std.base64Decode(secret.data.token); + // NOTE(sg): This should make the template suitable for both 'static' and + // 'projectsyn' credentials type. We read the access token from the config + // secret, if it's present (which it is for credentials type 'static'), and + // fall back to the steward token otherwise. + std.get(config, 'access_token', std.sha256(steward_token)); + + { + apiVersion: 'v1', + kind: 'Secret', + metadata: { + name: config.pull_secret_name, + namespace: 'openshift-config', + labels: { + 'pull-secret.openshift-config.syn.tools/include': '', + 'app.kubernetes.io/managed-by': 'espejote', + }, + }, + type: 'kubernetes.io/dockerconfigjson', + stringData: { + '.dockerconfigjson': std.manifestJsonMinified({ + auths: { + [config.hostname]: { + auth: std.base64( + '%(username)s:%(password)s' % { + username: config.username, + password: access_token, + } + ), + }, + }, + }), + }, + } + triggers: + - name: cilium_pull_secret + watchContextResource: + name: cilium_pull_secret + - name: isovalent_registry_config + watchContextResource: + name: isovalent_registry_config +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + annotations: {} + labels: + name: cilium-pull-secret-manager + name: cilium-pull-secret-manager + namespace: openshift-config +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + annotations: {} + labels: + name: cilium-pull-secret-manager + name: cilium-pull-secret-manager + namespace: openshift-config +rules: + - apiGroups: + - '' + resourceNames: + - cilium-pull-secret + resources: + - secrets + verbs: + - get + - list + - watch + - create + - update + - patch + - apiGroups: + - '' + resourceNames: + - isovalent-registry-config + resources: + - secrets + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + annotations: {} + labels: + name: cilium-pull-secret-manager + name: cilium-pull-secret-manager + namespace: openshift-config +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: cilium-pull-secret-manager +subjects: + - kind: ServiceAccount + name: cilium-pull-secret-manager + namespace: openshift-config diff --git a/tests/golden/olm-enterprise/cilium/cilium/80_enterprise_pull_secret_bootstrap_job.yaml b/tests/golden/olm-enterprise/cilium/cilium/80_enterprise_pull_secret_bootstrap_job.yaml new file mode 100644 index 000000000..e00876415 --- /dev/null +++ b/tests/golden/olm-enterprise/cilium/cilium/80_enterprise_pull_secret_bootstrap_job.yaml @@ -0,0 +1,140 @@ +apiVersion: v1 +data: {} +kind: Secret +metadata: + annotations: {} + labels: + name: isovalent-registry-config + name: isovalent-registry-config + namespace: openshift-config +stringData: + access_token: t-silent-test-1234/c-green-test-1234/isovalent/access_token + pull_secret_template.yaml: '{"apiVersion":"v1","kind":"Secret","metadata":{"labels":{"external-secrets.io/type":"webhook"}},"stringData":{".dockerconfigjson":"{}"},"type":"kubernetes.io/dockerconfigjson"}' +type: Opaque +--- +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + argocd.argoproj.io/hook: Sync + labels: + name: bootstrap-cilium-pull-secret + name: bootstrap-cilium-pull-secret + namespace: openshift-config +spec: + activeDeadlineSeconds: 30 + backoffLimit: 1 + completions: 1 + parallelism: 1 + template: + metadata: + labels: + name: bootstrap-cilium-pull-secret + spec: + containers: + - args: [] + command: + - bash + - -c + - | + if ! kubectl -n "${NAMESPACE}" get secret "${PULL_SECRET}" &>/dev/null; then + echo "Creating initial secret '${PULL_SECRET}'" + yq '.metadata.name=strenv(PULL_SECRET) | .stringData.access_token=strenv(ACCESS_TOKEN)' \ + /config/pull_secret_template.yaml \ + | kubectl -n "${NAMESPACE}" apply --server-side -f- + else + echo "Secret '${PULL_SECRET}' already exists, nothing to do." + fi + env: + - name: ACCESS_TOKEN + valueFrom: + secretKeyRef: + key: access_token + name: isovalent-registry-config + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: PULL_SECRET + value: cilium-pull-secret + image: quay.io/appuio/oc:v4.22@sha256:0bcefd308c7efa7d7f7b460b68f43efc886e333cc8ee0c6ca20e8e05a182b76b + imagePullPolicy: IfNotPresent + name: pull-secret-bootstrap + ports: [] + stdin: false + tty: false + volumeMounts: + - mountPath: /config + name: config + imagePullSecrets: [] + initContainers: [] + restartPolicy: OnFailure + serviceAccountName: cilium-pull-secret-bootstrapper + terminationGracePeriodSeconds: 30 + volumes: + - name: config + secret: + items: + - key: pull_secret_template.yaml + mode: 384 + path: pull_secret_template.yaml + secretName: isovalent-registry-config +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + annotations: {} + labels: + name: cilium-pull-secret-bootstrapper + name: cilium-pull-secret-bootstrapper + namespace: openshift-config +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + annotations: {} + labels: + name: cilium-pull-secret-bootstrapper + name: cilium-pull-secret-bootstrapper + namespace: openshift-config +rules: + - apiGroups: + - '' + resourceNames: + - isovalent-registry-config + resources: + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - '' + resourceNames: + - cilium-pull-secret + resources: + - secrets + verbs: + - get + - list + - watch + - create + - update + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + annotations: {} + labels: + name: cilium-pull-secret-bootstrapper + name: cilium-pull-secret-bootstrapper + namespace: openshift-config +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: cilium-pull-secret-bootstrapper +subjects: + - kind: ServiceAccount + name: cilium-pull-secret-bootstrapper + namespace: openshift-config diff --git a/tests/golden/olm-enterprise/cilium/cilium/80_enterprise_pull_secret_eso.yaml b/tests/golden/olm-enterprise/cilium/cilium/80_enterprise_pull_secret_eso.yaml new file mode 100644 index 000000000..24a2a56cd --- /dev/null +++ b/tests/golden/olm-enterprise/cilium/cilium/80_enterprise_pull_secret_eso.yaml @@ -0,0 +1,62 @@ +apiVersion: generators.external-secrets.io/v1alpha1 +kind: Webhook +metadata: + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + labels: + name: registry-isovalent-com + name: registry-isovalent-com + namespace: openshift-config +spec: + body: '{"description":"c-green-test-1234_pull-secret","token_type":"access_token"}' + headers: + Authorization: Bearer {{ print .pull.access_token }} + Content-Type: application/json + method: POST + result: + jsonPath: $ + secrets: + - name: pull + secretRef: + name: cilium-pull-secret + url: https://registry.isovalent.com/access/api/v1/tokens +--- +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + labels: + name: cilium-pull-secret + name: cilium-pull-secret + namespace: openshift-config +spec: + dataFrom: + - sourceRef: + generatorRef: + apiVersion: generators.external-secrets.io/v1alpha1 + kind: Webhook + name: registry-isovalent-com + refreshInterval: 720h + target: + creationPolicy: Owner + deletionPolicy: Retain + name: cilium-pull-secret + template: + data: + .dockerconfigjson: | + { + "auths": { + "containers.isovalent.com": { + "auth": "{{ printf "%s:%s" .username .access_token | b64enc }}" + } + } + } + access_token: '{{ print .access_token }}' + engineVersion: v2 + mergePolicy: Replace + metadata: + labels: + external-secrets.io/type: webhook + pull-secret.openshift-config.syn.tools/include: '' + type: kubernetes.io/dockerconfigjson diff --git a/tests/olm-enterprise.yml b/tests/olm-enterprise.yml index 5d04c4100..5e26f9e63 100644 --- a/tests/olm-enterprise.yml +++ b/tests/olm-enterprise.yml @@ -1,5 +1,7 @@ applications: - openshift-upgrade-controller + - espejote + - external-secrets-operator parameters: facts: @@ -16,6 +18,9 @@ parameters: - type: https source: https://raw.githubusercontent.com/projectsyn/component-espejote/master/lib/espejote.libsonnet output_path: vendor/lib/espejote.libsonnet + - type: https + source: https://raw.githubusercontent.com/projectsyn/component-external-secrets-operator/master/lib/external-secrets-operator.libsonnet + output_path: vendor/lib/external-secrets-operator.libsonnet espejote: namespace: syn-espejote @@ -38,5 +43,10 @@ parameters: k8sServiceHost: 172.30.0.1 k8sServicePort: 443 + enterprise: + registry: + credentials: + type: direct-eso + openshift_upgrade_controller: namespace: appuio-openshift-upgrade-controller From 1c79ecda866fab80d7c021188b1f33b366888dab Mon Sep 17 00:00:00 2001 From: Simon Gerber Date: Tue, 3 Nov 2026 13:44:37 +0100 Subject: [PATCH 2/5] Add test case for enterprise registry credentials type `projectsyn` Rendered from template version: main (d0e9f8d) --- .cruft.json | 6 +- .github/workflows/test.yaml | 2 + Makefile.vars.mk | 2 +- .../cilium/apps/cilium.yaml | 0 .../cilium/02_aggregated_clusterroles.yaml | 67 ++++++ .../cilium/10_cilium_features_metrics.yaml | 22 ++ .../cilium/cilium/10_ebpf_alerts.yaml | 50 +++++ .../cilium/cilium/10_pods_alerts.yaml | 24 +++ .../80_enterprise_pull_secret_config.yaml | 14 ++ ...terprise_pull_secret_managed_resource.yaml | 200 ++++++++++++++++++ .../99_networkoperator_kube_proxy_patch.yaml | 86 ++++++++ .../cilium/olm/97_migrate_to_clife.yaml | 123 +++++++++++ .../olm/98_unmanage_olm_deployment.yaml | 91 ++++++++ .../olm/99_olm_approval_upgradejobhook.yaml | 108 ++++++++++ ...r-network-03-cilium-ciliumconfigs-crd.yaml | 44 ++++ ...work-06-cilium-00000-cilium-namespace.yaml | 11 + ...ilium-00001-cilium-olm-serviceaccount.yaml | 7 + ...rk-06-cilium-00003-cilium-olm-service.yaml | 14 ++ ...00004-cilium-olm-leader-election-role.yaml | 24 +++ ...ium-00006-leader-election-rolebinding.yaml | 13 ++ ...6-cilium-00007-cilium-olm-rolebinding.yaml | 13 ++ ...m-00008-cilium-cilium-olm-clusterrole.yaml | 35 +++ ...ilium-00009-cilium-cilium-clusterrole.yaml | 82 +++++++ ...-cilium-cilium-olm-clusterrolebinding.yaml | 12 ++ ...0011-cilium-cilium-clusterrolebinding.yaml | 12 ++ ...-06-cilium-00012-cilium-operatorgroup.yaml | 8 + ...k-06-cilium-00013-cilium-subscription.yaml | 24 +++ ...luster-network-07-cilium-ciliumconfig.yaml | 71 +++++++ tests/projectsyn-registry-credentials.yml | 50 +++++ 29 files changed, 1211 insertions(+), 4 deletions(-) create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/apps/cilium.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/02_aggregated_clusterroles.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/10_cilium_features_metrics.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/10_ebpf_alerts.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/10_pods_alerts.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/80_enterprise_pull_secret_config.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/80_enterprise_pull_secret_managed_resource.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/99_networkoperator_kube_proxy_patch.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/97_migrate_to_clife.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/98_unmanage_olm_deployment.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/99_olm_approval_upgradejobhook.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-03-cilium-ciliumconfigs-crd.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00000-cilium-namespace.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00001-cilium-olm-serviceaccount.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00003-cilium-olm-service.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00004-cilium-olm-leader-election-role.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00006-leader-election-rolebinding.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00007-cilium-olm-rolebinding.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00008-cilium-cilium-olm-clusterrole.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00009-cilium-cilium-clusterrole.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00010-cilium-cilium-olm-clusterrolebinding.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00011-cilium-cilium-clusterrolebinding.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00012-cilium-operatorgroup.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00013-cilium-subscription.yaml create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-07-cilium-ciliumconfig.yaml create mode 100644 tests/projectsyn-registry-credentials.yml diff --git a/.cruft.json b/.cruft.json index bd88369df..c5086f9b9 100644 --- a/.cruft.json +++ b/.cruft.json @@ -1,13 +1,13 @@ { "template": "https://github.com/projectsyn/commodore-component-template.git", - "commit": "e181d48cf389cc0db56825e47044d881c8e91e4d", + "commit": "d0e9f8dc2b85344a283aea02369d3ec7548e388d", "checkout": "main", "context": { "cookiecutter": { "name": "Cilium", "slug": "cilium", "parameter_key": "cilium", - "test_cases": "defaults helm-opensource egress-gateway bgp-control-plane kubeproxyreplacement-strict l2-announcement clustermesh enterprise-bgp hubble-access lib-ipcalc olm-enterprise transparent-encryption talos custom-namespace", + "test_cases": "defaults helm-opensource egress-gateway bgp-control-plane kubeproxyreplacement-strict l2-announcement clustermesh enterprise-bgp hubble-access lib-ipcalc olm-enterprise transparent-encryption talos custom-namespace projectsyn-registry-credentials", "add_lib": "n", "add_pp": "n", "add_golden": "y", @@ -25,7 +25,7 @@ "github_name": "component-cilium", "github_url": "https://github.com/projectsyn/component-cilium", "_template": "https://github.com/projectsyn/commodore-component-template.git", - "_commit": "e181d48cf389cc0db56825e47044d881c8e91e4d" + "_commit": "d0e9f8dc2b85344a283aea02369d3ec7548e388d" } }, "directory": null diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index f9acd5951..6d73e2931 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -45,6 +45,7 @@ jobs: - transparent-encryption - talos - custom-namespace + - projectsyn-registry-credentials defaults: run: working-directory: ${{ env.COMPONENT_NAME }} @@ -73,6 +74,7 @@ jobs: - transparent-encryption - talos - custom-namespace + - projectsyn-registry-credentials defaults: run: working-directory: ${{ env.COMPONENT_NAME }} diff --git a/Makefile.vars.mk b/Makefile.vars.mk index 8efd1136f..39fc44750 100644 --- a/Makefile.vars.mk +++ b/Makefile.vars.mk @@ -57,4 +57,4 @@ KUBENT_IMAGE ?= ghcr.io/doitintl/kube-no-trouble:latest KUBENT_DOCKER ?= $(DOCKER_CMD) $(DOCKER_ARGS) $(root_volume) --entrypoint=/app/kubent $(KUBENT_IMAGE) instance ?= defaults -test_instances = tests/defaults.yml tests/helm-opensource.yml tests/egress-gateway.yml tests/bgp-control-plane.yml tests/kubeproxyreplacement-strict.yml tests/l2-announcement.yml tests/clustermesh.yml tests/enterprise-bgp.yml tests/hubble-access.yml tests/lib-ipcalc.yml tests/olm-enterprise.yml tests/transparent-encryption.yml tests/talos.yml tests/custom-namespace.yml +test_instances = tests/defaults.yml tests/helm-opensource.yml tests/egress-gateway.yml tests/bgp-control-plane.yml tests/kubeproxyreplacement-strict.yml tests/l2-announcement.yml tests/clustermesh.yml tests/enterprise-bgp.yml tests/hubble-access.yml tests/lib-ipcalc.yml tests/olm-enterprise.yml tests/transparent-encryption.yml tests/talos.yml tests/custom-namespace.yml tests/projectsyn-registry-credentials.yml diff --git a/tests/golden/projectsyn-registry-credentials/cilium/apps/cilium.yaml b/tests/golden/projectsyn-registry-credentials/cilium/apps/cilium.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/02_aggregated_clusterroles.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/02_aggregated_clusterroles.yaml new file mode 100644 index 000000000..652b0ab1c --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/02_aggregated_clusterroles.yaml @@ -0,0 +1,67 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: {} + labels: + name: syn-cilium-view + rbac.authorization.k8s.io/aggregate-to-admin: 'true' + rbac.authorization.k8s.io/aggregate-to-edit: 'true' + rbac.authorization.k8s.io/aggregate-to-view: 'true' + name: syn-cilium-view +rules: + - apiGroups: + - cilium.io + resources: + - ciliumnetworkpolicies + - ciliumendpoints + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: {} + labels: + name: syn-cilium-edit + rbac.authorization.k8s.io/aggregate-to-admin: 'true' + rbac.authorization.k8s.io/aggregate-to-edit: 'true' + name: syn-cilium-edit +rules: + - apiGroups: + - cilium.io + resources: + - ciliumnetworkpolicies + verbs: + - create + - delete + - deletecollection + - patch + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: {} + labels: + name: syn-cilium-cluster-reader + rbac.authorization.k8s.io/aggregate-to-cluster-reader: 'true' + name: syn-cilium-cluster-reader +rules: + - apiGroups: + - cilium.io + resources: + - '*' + verbs: + - get + - list + - watch + - apiGroups: + - isovalent.com + resources: + - '*' + verbs: + - get + - list + - watch diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/10_cilium_features_metrics.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/10_cilium_features_metrics.yaml new file mode 100644 index 000000000..c380d48d6 --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/10_cilium_features_metrics.yaml @@ -0,0 +1,22 @@ +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + labels: + name: cilium-features + name: cilium-features +spec: + groups: + - name: cilium-feature-metrics.rules + rules: + - expr: vector(0) + labels: + feature: clustermesh + record: cilium_features + - expr: vector(0) + labels: + feature: egress-gateway + record: cilium_features + - expr: vector(0) + labels: + feature: transparent-encryption + record: cilium_features diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/10_ebpf_alerts.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/10_ebpf_alerts.yaml new file mode 100644 index 000000000..b35c5b0e3 --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/10_ebpf_alerts.yaml @@ -0,0 +1,50 @@ +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + labels: + name: cilium-ebpf + name: cilium-ebpf +spec: + groups: + - name: cilium-ebpf.rules + rules: + - alert: CiliumBpfMapUtilizationHigh + annotations: + description: | + BPF map utilization for map {{ $labels.map_name }} has been above + 50% on node {{ $labels.node }} for the last 10m. + message: High BPF map utilization on {{ $labels.node }} + runbook_url: https://hub.syn.tools/cilium/runbooks/CiliumBpfMapPressureHigh.html + expr: cilium_bpf_map_pressure > 0.5 + for: 10m + labels: + severity: warning + syn: 'true' + syn_component: cilium + - alert: CiliumBpfMapUtilizationExtremelyHigh + annotations: + description: | + BPF map utilization for map {{ $labels.map_name }} has been above + 90% on node {{ $labels.node }} for the last 10m. + message: Extremely High BPF map utilization on {{ $labels.node }} + runbook_url: https://hub.syn.tools/cilium/runbooks/CiliumBpfMapPressureExtremelyHigh.html + expr: cilium_bpf_map_pressure > 0.9 + for: 10m + labels: + severity: critical + syn: 'true' + syn_component: cilium + - alert: CiliumBpfOperationErrorRateHigh + annotations: + description: | + BPF error rate for map {{ $labels.map_name }} has been above + 50% on node {{ $labels.node }} for the last 10m. + message: High BPF error rate on {{ $labels.node }} + runbook_url: https://hub.syn.tools/cilium/runbooks/CiliumBpfOperationErrorRateHigh.html + expr: (rate(cilium_bpf_map_ops_total{outcome="fail"}[1m]) / rate(cilium_bpf_map_ops_total{}[1m])) + > 0.5 + for: 10m + labels: + severity: critical + syn: 'true' + syn_component: cilium diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/10_pods_alerts.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/10_pods_alerts.yaml new file mode 100644 index 000000000..07f09d8e4 --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/10_pods_alerts.yaml @@ -0,0 +1,24 @@ +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + labels: + name: cilium-pods + name: cilium-pods +spec: + groups: + - name: cilium-pods.rules + rules: + - alert: CiliumAgentUnexpectedCount + annotations: + description: | + The cluster has had {{ $value }} Cilium agents for the last 5m + instead of the expected {{ query "count(kube_node_info)" }}. + message: Number of Cilium agents doesn't match node count + runbook_url: https://hub.syn.tools/cilium/runbooks/CiliumAgentUnexpectedCount.html + expr: count(kube_pod_labels{namespace="cilium", label_app_kubernetes_io_name="cilium-agent"}) + != count(kube_node_info) + for: 5m + labels: + severity: critical + syn: 'true' + syn_component: cilium diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/80_enterprise_pull_secret_config.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/80_enterprise_pull_secret_config.yaml new file mode 100644 index 000000000..bc58eab29 --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/80_enterprise_pull_secret_config.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +data: {} +kind: Secret +metadata: + annotations: {} + labels: + name: isovalent-registry-config + name: isovalent-registry-config + namespace: openshift-config +stringData: + hostname: icr-mirror.example.com + pull_secret_name: cilium-pull-secret + username: c-green-test-1234 +type: Opaque diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/80_enterprise_pull_secret_managed_resource.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/80_enterprise_pull_secret_managed_resource.yaml new file mode 100644 index 000000000..9760f0953 --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/80_enterprise_pull_secret_managed_resource.yaml @@ -0,0 +1,200 @@ +apiVersion: espejote.io/v1alpha1 +kind: ManagedResource +metadata: + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + labels: + app.kubernetes.io/name: cilium-pull-secret + name: cilium-pull-secret + namespace: openshift-config +spec: + context: + - name: cilium_pull_secret + resource: + apiVersion: v1 + kind: Secret + name: cilium-pull-secret + namespace: openshift-config + - name: isovalent_registry_config + resource: + apiVersion: v1 + kind: Secret + name: isovalent-registry-config + namespace: openshift-config + - name: steward_token + resource: + apiVersion: v1 + kind: Secret + name: steward + namespace: syn + serviceAccountRef: + name: cilium-pull-secret-manager + template: | + local esp = import 'espejote.libsonnet'; + + local read_context_secret(ctxname) = + if ctxname in esp.context() then + local secret = esp.context()[ctxname]; + assert std.length(secret) == 1 : 'Expected %s context to have length 1' % ctxname; + secret[0] + else + null; + + local config = + local secret = read_context_secret('isovalent_registry_config'); + assert secret != null : 'Context isovalent_registry_config missing'; + assert + std.objectHas(secret.data, 'hostname') + && std.objectHas(secret.data, 'username') + && std.objectHas(secret.data, 'pull_secret_name') + : 'Expected Isovalent registry config secret to have fields `hostname`, `username` and `pull_secret_name`'; + { + [k]: std.base64Decode(secret.data[k]) + for k in std.objectFields(secret.data) + }; + + local access_token = + local steward_token = + local secret = read_context_secret('steward_token'); + assert secret != null : 'Context steward_token missing'; + assert std.objectHas(secret.data, 'token') : 'Expected Steward token secret to have field `token`'; + std.base64Decode(secret.data.token); + // NOTE(sg): This should make the template suitable for both 'static' and + // 'projectsyn' credentials type. We read the access token from the config + // secret, if it's present (which it is for credentials type 'static'), and + // fall back to the steward token otherwise. + std.get(config, 'access_token', std.sha256(steward_token)); + + { + apiVersion: 'v1', + kind: 'Secret', + metadata: { + name: config.pull_secret_name, + namespace: 'openshift-config', + labels: { + 'pull-secret.openshift-config.syn.tools/include': '', + 'app.kubernetes.io/managed-by': 'espejote', + }, + }, + type: 'kubernetes.io/dockerconfigjson', + stringData: { + '.dockerconfigjson': std.manifestJsonMinified({ + auths: { + [config.hostname]: { + auth: std.base64( + '%(username)s:%(password)s' % { + username: config.username, + password: access_token, + } + ), + }, + }, + }), + }, + } + triggers: + - name: cilium_pull_secret + watchContextResource: + name: cilium_pull_secret + - name: isovalent_registry_config + watchContextResource: + name: isovalent_registry_config + - name: steward_token + watchContextResource: + name: steward_token +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + annotations: {} + labels: + name: cilium-pull-secret-manager + name: cilium-pull-secret-manager + namespace: openshift-config +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + annotations: {} + labels: + name: cilium-pull-secret-manager + name: cilium-pull-secret-manager + namespace: openshift-config +rules: + - apiGroups: + - '' + resourceNames: + - cilium-pull-secret + resources: + - secrets + verbs: + - get + - list + - watch + - create + - update + - patch + - apiGroups: + - '' + resourceNames: + - isovalent-registry-config + resources: + - secrets + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + annotations: {} + labels: + name: cilium-pull-secret-manager + name: cilium-pull-secret-manager + namespace: openshift-config +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: cilium-pull-secret-manager +subjects: + - kind: ServiceAccount + name: cilium-pull-secret-manager + namespace: openshift-config +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + annotations: {} + labels: + name: cilium-pull-secret-manager + name: cilium-pull-secret-manager + namespace: syn +rules: + - apiGroups: + - '' + resourceNames: + - steward + resources: + - secrets + verbs: + - get + - list + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + annotations: {} + labels: + name: cilium-pull-secret-manager + name: cilium-pull-secret-manager + namespace: syn +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: cilium-pull-secret-manager +subjects: + - kind: ServiceAccount + name: cilium-pull-secret-manager + namespace: openshift-config diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/99_networkoperator_kube_proxy_patch.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/99_networkoperator_kube_proxy_patch.yaml new file mode 100644 index 000000000..0783a1827 --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/99_networkoperator_kube_proxy_patch.yaml @@ -0,0 +1,86 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + annotations: + syn.tools/source: https://github.com/projectsyn/component-cilium.git + labels: + app.kubernetes.io/component: cilium + app.kubernetes.io/managed-by: espejote + app.kubernetes.io/part-of: syn + name: operator-openshift-io-networks-cluster-manager + namespace: syn-espejote +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + syn.tools/source: https://github.com/projectsyn/component-cilium.git + labels: + app.kubernetes.io/component: cilium + app.kubernetes.io/managed-by: espejote + app.kubernetes.io/part-of: syn + name: syn-espejote:operator-openshift-io-networks-cluster-manager +rules: + - apiGroups: + - operator.openshift.io + resourceNames: + - cluster + resources: + - networks + verbs: + - '*' +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + annotations: + syn.tools/source: https://github.com/projectsyn/component-cilium.git + labels: + app.kubernetes.io/component: cilium + app.kubernetes.io/managed-by: espejote + app.kubernetes.io/part-of: syn + name: syn-espejote:operator-openshift-io-networks-cluster-manager +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: syn-espejote:operator-openshift-io-networks-cluster-manager +subjects: + - kind: ServiceAccount + name: operator-openshift-io-networks-cluster-manager + namespace: syn-espejote +--- +apiVersion: espejote.io/v1alpha1 +kind: ManagedResource +metadata: + annotations: + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + syn.tools/source: https://github.com/projectsyn/component-cilium.git + labels: + app.kubernetes.io/component: cilium + app.kubernetes.io/managed-by: espejote + app.kubernetes.io/name: operator-openshift-io-networks-cluster-manager + app.kubernetes.io/part-of: syn + name: operator-openshift-io-networks-cluster-manager + namespace: syn-espejote +spec: + applyOptions: + force: true + serviceAccountRef: + name: operator-openshift-io-networks-cluster-manager + template: |- + { + "apiVersion": "operator.openshift.io/v1", + "kind": "Network", + "metadata": { + "name": "cluster" + }, + "spec": { + "deployKubeProxy": false + } + } + triggers: + - name: target + watchResource: + apiVersion: operator.openshift.io/v1 + kind: Network + name: cluster diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/97_migrate_to_clife.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/97_migrate_to_clife.yaml new file mode 100644 index 000000000..bb0706ebf --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/97_migrate_to_clife.yaml @@ -0,0 +1,123 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + labels: + name: prepare-upgrade-to-clife + name: prepare-upgrade-to-clife +rules: + - apiGroups: + - '*' + resources: + - '*' + verbs: + - '*' +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + labels: + name: prepare-upgrade-to-clife + name: prepare-upgrade-to-clife + namespace: cilium +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + labels: + name: prepare-upgrade-to-clife + name: prepare-upgrade-to-clife +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: prepare-upgrade-to-clife +subjects: + - kind: ServiceAccount + name: prepare-upgrade-to-clife + namespace: cilium +--- +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + argocd.argoproj.io/hook-delete-policy: HookSucceeded + labels: + name: prepare-upgrade-to-clife + name: prepare-upgrade-to-clife + namespace: cilium +spec: + completions: 1 + parallelism: 1 + template: + metadata: + labels: + name: prepare-upgrade-to-clife + spec: + containers: + - args: + - | + if ! kubectl -n cilium get sa clife-controller-manager &>/dev/null; then + echo "Preparing migration from cilium-ee-olm to clife-controller-manager..." + kubectl -n cilium delete deploy cilium-ee-olm --ignore-not-found=true + kubectl delete operator cilium-enterprise.cilium --ignore-not-found=true + kubectl delete operator cilium.cilium --ignore-not-found=true + kubectl -n cilium delete cm cilium-ee-olm --ignore-not-found=true + kubectl -n cilium delete cm cilium-olm --ignore-not-found=true + for object in $(kubectl -n cilium get serviceaccount,role,rolebinding,deploy,daemonset,configmap,secret -o yaml | \ + yq '.items[] + | select( (.metadata.ownerReferences // []) | map(.kind == "CiliumConfig") | contains([true]) ) + | (.kind + "/" + .metadata.name)') + do + kubectl -n cilium patch $object --type json -p='[{"op": "remove", "path": "/metadata/ownerReferences"}]' + done + for object in $(kubectl -n cilium get serviceaccount,role,rolebinding,clusterrole,clusterrolebinding,deploy,daemonset,configmap,secret -o yaml | \ + yq '.items[] + | select(.metadata.annotations."meta.helm.sh/release-name" == "cilium-enterprise") + | (.kind + "/" + .metadata.name)') + do + kubectl -n cilium patch $object --type json -p='[{"op": "replace", "path": "/metadata/annotations/meta.helm.sh~1release-name", "value": "cilium-release"}]' + done + kubectl -n cilium delete secret -l owner=helm + kubectl -n cilium patch ciliumconfig cilium-enterprise --type json -p='[{"op": "remove", "path": "/metadata/finalizers"}]' + kubectl -n cilium delete ciliumconfig cilium-enterprise + kubectl delete crd ciliumconfigs.cilium.io + kubectl api-resources --api-group=cilium.io + # NOTE(sg): We need to delete the cilium DaemonSet because + # otherwise the clife OLM operator doesn't correctly + # remove the envoy ports from the DaemonSet. + kubectl -n cilium delete ds cilium --cascade=orphan + kubectl -n syn delete pods syn-argocd-application-controller-0 + else + echo "clife-controller-manager is already present on the cluster, doing nothing." + fi + command: + - bash + - -e + - -c + env: + - name: HOME + value: /home + image: quay.io/appuio/oc:v4.22@sha256:0bcefd308c7efa7d7f7b460b68f43efc886e333cc8ee0c6ca20e8e05a182b76b + imagePullPolicy: IfNotPresent + name: prepare-upgrade-to-clife + ports: [] + stdin: false + tty: false + volumeMounts: + - mountPath: /home + name: home + workingDir: /home + imagePullSecrets: [] + initContainers: [] + restartPolicy: OnFailure + serviceAccountName: prepare-upgrade-to-clife + terminationGracePeriodSeconds: 30 + volumes: + - emptyDir: {} + name: home diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/98_unmanage_olm_deployment.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/98_unmanage_olm_deployment.yaml new file mode 100644 index 000000000..55b5f148d --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/98_unmanage_olm_deployment.yaml @@ -0,0 +1,91 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + labels: + name: unmanage-olm-deployment + name: unmanage-olm-deployment +rules: + - apiGroups: + - apps + resources: + - deployments + verbs: + - get + - patch +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + labels: + name: unmanage-olm-deployment + name: unmanage-olm-deployment + namespace: cilium +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + labels: + name: unmanage-olm-deployment + name: unmanage-olm-deployment +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: unmanage-olm-deployment +subjects: + - kind: ServiceAccount + name: unmanage-olm-deployment + namespace: cilium +--- +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + argocd.argoproj.io/hook-delete-policy: HookSucceeded + labels: + name: unmanage-olm-deployment + name: unmanage-olm-deployment + namespace: cilium +spec: + completions: 1 + parallelism: 1 + template: + metadata: + labels: + name: unmanage-olm-deployment + spec: + containers: + - args: + - | + kubectl -n cilium label deploy clife-controller-manager argocd.argoproj.io/instance- + command: + - bash + - -e + - -c + env: + - name: HOME + value: /home + image: quay.io/appuio/oc:v4.22@sha256:0bcefd308c7efa7d7f7b460b68f43efc886e333cc8ee0c6ca20e8e05a182b76b + imagePullPolicy: IfNotPresent + name: unmanage-olm-deployment + ports: [] + stdin: false + tty: false + volumeMounts: + - mountPath: /home + name: home + workingDir: /home + imagePullSecrets: [] + initContainers: [] + restartPolicy: OnFailure + serviceAccountName: unmanage-olm-deployment + terminationGracePeriodSeconds: 30 + volumes: + - emptyDir: {} + name: home diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/99_olm_approval_upgradejobhook.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/99_olm_approval_upgradejobhook.yaml new file mode 100644 index 000000000..f6d5fab77 --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/99_olm_approval_upgradejobhook.yaml @@ -0,0 +1,108 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + annotations: {} + labels: + name: cilium-upgrade-approval + name: cilium-upgrade-approval + namespace: appuio-openshift-upgrade-controller +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + annotations: {} + labels: + name: cilium-upgrade-approval + name: cilium-upgrade-approval + namespace: cilium +rules: + - apiGroups: + - operators.coreos.com + resources: + - installplans + verbs: + - get + - list + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + annotations: {} + labels: + name: cilium-upgrade-approval + name: cilium-upgrade-approval + namespace: cilium +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: cilium-upgrade-approval +subjects: + - kind: ServiceAccount + name: cilium-upgrade-approval + namespace: appuio-openshift-upgrade-controller +--- +apiVersion: v1 +data: + approve: | + #!/bin/bash + cilium_installplan=$(kubectl -n "${CILIUM_NAMESPACE}" get installplan -ojson | \ + jq -r --argjson upgrade_job "${JOB_metadata_creationTimestamp}" \ + '.items | sort_by(.metadata.creationTimestamp) | reverse + | [.[] | + select((.spec.approved != true) + and (.metadata.creationTimestamp < $upgrade_job)) + ][0] | .metadata.name') + + if [ "${cilium_installplan}" != "null" ]; then + kubectl patch installplan "${cilium_installplan}" -n "${CILIUM_NAMESPACE}" \ + --type merge --patch '{"spec":{"approved":true}}' + fi +kind: ConfigMap +metadata: + annotations: {} + labels: + name: cilium-upgrade-approval + name: cilium-upgrade-approval + namespace: appuio-openshift-upgrade-controller +--- +apiVersion: managedupgrade.appuio.io/v1beta1 +kind: UpgradeJobHook +metadata: + name: cilium-upgrade-approval + namespace: appuio-openshift-upgrade-controller +spec: + events: + - Start + selector: {} + template: + spec: + activeDeadlineSeconds: 900 + template: + spec: + containers: + - args: [] + command: + - /usr/local/bin/approve + env: + - name: CILIUM_NAMESPACE + value: cilium + image: quay.io/appuio/oc:v4.22@sha256:0bcefd308c7efa7d7f7b460b68f43efc886e333cc8ee0c6ca20e8e05a182b76b + imagePullPolicy: IfNotPresent + name: approve + ports: [] + stdin: false + tty: false + volumeMounts: + - mountPath: /usr/local/bin/approve + name: scripts + readOnly: true + subPath: approve + priorityClassName: system-cluster-critical + restartPolicy: Never + serviceAccountName: cilium-upgrade-approval + volumes: + - configMap: + defaultMode: 360 + name: cilium-upgrade-approval + name: scripts diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-03-cilium-ciliumconfigs-crd.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-03-cilium-ciliumconfigs-crd.yaml new file mode 100644 index 000000000..885611827 --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-03-cilium-ciliumconfigs-crd.yaml @@ -0,0 +1,44 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: ciliumconfigs.cilium.io +spec: + group: cilium.io + names: + kind: CiliumConfig + listKind: CiliumConfigList + plural: ciliumconfigs + singular: ciliumconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Schema for the CiliumConfigs API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource + this object represents. Servers may infer this from the endpoint the + client submits requests to. Cannot be updated. In CamelCase. More + info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of CiliumConfig + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: Status defines the observed state of CiliumConfig + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00000-cilium-namespace.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00000-cilium-namespace.yaml new file mode 100644 index 000000000..cc210b1ed --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00000-cilium-namespace.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Namespace +metadata: + annotations: + openshift.io/node-selector: '' + labels: + name: cilium + openshift.io/cluster-logging: 'true' + openshift.io/cluster-monitoring: 'true' + openshift.io/run-level: '0' + name: cilium diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00001-cilium-olm-serviceaccount.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00001-cilium-olm-serviceaccount.yaml new file mode 100644 index 000000000..79efd5251 --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00001-cilium-olm-serviceaccount.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + name: cilium-olm + name: cilium-olm + namespace: cilium diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00003-cilium-olm-service.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00003-cilium-olm-service.yaml new file mode 100644 index 000000000..f8c1889e9 --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00003-cilium-olm-service.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + name: cilium-olm + name: cilium-olm + namespace: cilium +spec: + ports: + - name: https + port: 443 + targetPort: 9443 + selector: + name: cilium-olm diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00004-cilium-olm-leader-election-role.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00004-cilium-olm-leader-election-role.yaml new file mode 100644 index 000000000..ff2d0f158 --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00004-cilium-olm-leader-election-role.yaml @@ -0,0 +1,24 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: cilium-olm-leader-election + namespace: cilium +rules: + - apiGroups: + - '' + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - '' + resources: + - events + verbs: + - create diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00006-leader-election-rolebinding.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00006-leader-election-rolebinding.yaml new file mode 100644 index 000000000..b08b96361 --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00006-leader-election-rolebinding.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: leader-election + namespace: cilium +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: leader-election +subjects: + - kind: ServiceAccount + name: cilium-olm + namespace: cilium diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00007-cilium-olm-rolebinding.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00007-cilium-olm-rolebinding.yaml new file mode 100644 index 000000000..e61eccdab --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00007-cilium-olm-rolebinding.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: cilium-olm + namespace: cilium +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: cilium-olm +subjects: + - kind: ServiceAccount + name: cilium-olm + namespace: cilium diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00008-cilium-cilium-olm-clusterrole.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00008-cilium-cilium-olm-clusterrole.yaml new file mode 100644 index 000000000..6a2370fd0 --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00008-cilium-cilium-olm-clusterrole.yaml @@ -0,0 +1,35 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cilium-cilium-olm +rules: + - apiGroups: + - security.openshift.io + resourceNames: + - hostnetwork + resources: + - securitycontextconstraints + verbs: + - use + - apiGroups: + - rbac.authorization.k8s.io + resources: + - roles + - rolebindings + - clusterroles + - clusterrolebindings + verbs: + - create + - get + - patch + - update + - delete + - list + - watch + - apiGroups: + - '' + resources: + - services/status + verbs: + - patch + - update diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00009-cilium-cilium-clusterrole.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00009-cilium-cilium-clusterrole.yaml new file mode 100644 index 000000000..2589be32b --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00009-cilium-cilium-clusterrole.yaml @@ -0,0 +1,82 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: cilium-cilium +rules: + - apiGroups: + - cilium.io + resources: + - '*' + verbs: + - '*' + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - '*' + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - get + - update + - apiGroups: + - '' + resources: + - services/status + verbs: + - patch + - update + - apiGroups: + - '' + resources: + - pods + - pods/status + - pods/finalizers + verbs: + - get + - list + - watch + - update + - delete + - apiGroups: + - '' + resources: + - nodes + - nodes/status + verbs: + - get + - list + - watch + - update + - patch + - apiGroups: + - '' + resources: + - namespaces + - services + - endpoints + - componentstatuses + verbs: + - get + - list + - watch + - apiGroups: + - discovery.k8s.io + resources: + - endpointslices + verbs: + - get + - list + - watch + - apiGroups: + - networking.k8s.io + resources: + - networkpolicies + verbs: + - get + - list + - watch diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00010-cilium-cilium-olm-clusterrolebinding.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00010-cilium-cilium-olm-clusterrolebinding.yaml new file mode 100644 index 000000000..86c933cfe --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00010-cilium-cilium-olm-clusterrolebinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cilium-cilium-olm +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cilium-cilium-olm +subjects: + - kind: ServiceAccount + name: cilium-olm + namespace: cilium diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00011-cilium-cilium-clusterrolebinding.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00011-cilium-cilium-clusterrolebinding.yaml new file mode 100644 index 000000000..edd063ffb --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00011-cilium-cilium-clusterrolebinding.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cilium-cilium +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cilium-cilium +subjects: + - kind: ServiceAccount + name: cilium-olm + namespace: cilium diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00012-cilium-operatorgroup.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00012-cilium-operatorgroup.yaml new file mode 100644 index 000000000..49ca1a823 --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00012-cilium-operatorgroup.yaml @@ -0,0 +1,8 @@ +apiVersion: operators.coreos.com/v1alpha2 +kind: OperatorGroup +metadata: + name: cilium + namespace: cilium +spec: + targetNamespaces: + - cilium diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00013-cilium-subscription.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00013-cilium-subscription.yaml new file mode 100644 index 000000000..eac0afdaa --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-06-cilium-00013-cilium-subscription.yaml @@ -0,0 +1,24 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: cilium + namespace: cilium +spec: + channel: '1.15' + config: + env: + - name: KUBERNETES_SERVICE_HOST + value: 172.30.0.1 + - name: KUBERNETES_SERVICE_PORT + value: 443 + resources: + limits: + cpu: 100m + memory: 500Mi + requests: + cpu: 100m + memory: 250Mi + installPlanApproval: Manual + name: cilium + source: certified-operators + sourceNamespace: openshift-marketplace diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-07-cilium-ciliumconfig.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-07-cilium-ciliumconfig.yaml new file mode 100644 index 000000000..a8c5a2d14 --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/olm/cluster-network-07-cilium-ciliumconfig.yaml @@ -0,0 +1,71 @@ +apiVersion: cilium.io/v1alpha1 +kind: CiliumConfig +metadata: + name: cilium + namespace: cilium +spec: + bgpControlPlane: + enabled: false + secretsNamespace: + name: cilium + bpf: + masquerade: true + clustermesh: + apiserver: + metrics: + serviceMonitor: + enabled: true + cni: + binPath: /var/lib/cni/bin + confPath: /var/run/multus/cni/net.d + egressGateway: + enabled: false + endpointRoutes: + enabled: false + enterprise: + egressGatewayHA: + enabled: false + envoy: + enabled: true + hubble: + metrics: + enabled: + - dns:sourceContext=workload|namespace|reserved-identity;destinationContext=workload|namespace|reserved-identity + - drop:sourceContext=workload|namespace|reserved-identity;destinationContext=workload|namespace|reserved-identity + - httpV2:sourceContext=workload|namespace|reserved-identity;destinationContext=workload|namespace|reserved-identity + serviceMonitor: + enabled: true + relay: + enabled: true + tls: + enabled: false + ipam: + mode: cluster-pool + operator: + clusterPoolIPv4MaskSize: 24 + clusterPoolIPv4PodCIDRList: + - 10.0.0.0/8 + k8sClientRateLimit: + burst: 30 + qps: 15 + k8sServiceHost: 172.30.0.1 + k8sServicePort: 443 + kubeProxyReplacement: 'true' + l2announcements: + enabled: false + l7Proxy: true + operator: + prometheus: + enabled: false + serviceMonitor: + enabled: true + resources: + limits: + memory: 500Mi + requests: + cpu: 100m + memory: 300Mi + prometheus: + enabled: true + serviceMonitor: + enabled: true diff --git a/tests/projectsyn-registry-credentials.yml b/tests/projectsyn-registry-credentials.yml new file mode 100644 index 000000000..c82afa488 --- /dev/null +++ b/tests/projectsyn-registry-credentials.yml @@ -0,0 +1,50 @@ +applications: + - openshift-upgrade-controller + - espejote + +parameters: + facts: + distribution: openshift4 + + kapitan: + dependencies: + - type: https + source: https://raw.githubusercontent.com/appuio/component-openshift4-monitoring/master/lib/openshift4-monitoring-prom.libsonnet + output_path: vendor/lib/prom.libsonnet + - type: https + source: https://raw.githubusercontent.com/appuio/component-openshift4-monitoring/master/lib/openshift4-monitoring-alert-patching.libsonnet + output_path: vendor/lib/alert-patching.libsonnet + - type: https + source: https://raw.githubusercontent.com/projectsyn/component-espejote/master/lib/espejote.libsonnet + output_path: vendor/lib/espejote.libsonnet + + espejote: + namespace: syn-espejote + + cilium: + install_method: olm + release: enterprise + __mock_enterprise: true + olm: + # util.version will use this parameter to return a "fake" version, + # falling back to `olm.full_version`. + __test_full_version: '1.18.11' + # 1.15.1 is the latest available OSS OLM version + full_version: '1.15.1' + source: + enterprise: https://github.com/isovalent/olm-for-cilium/archive/main.tar.gz + generate_subscription: true + + cilium_helm_values: + k8sServiceHost: 172.30.0.1 + k8sServicePort: 443 + + enterprise: + registry: + hostname: icr-mirror.example.com + credentials: + type: projectsyn + username: ${cluster:name} + + openshift_upgrade_controller: + namespace: appuio-openshift-upgrade-controller From df6dd1af4157f2fa20d51f32cb7a343b60ac3135 Mon Sep 17 00:00:00 2001 From: Simon Gerber Date: Tue, 3 Nov 2026 13:55:13 +0100 Subject: [PATCH 3/5] Configure enterprise registry mirror in OpenShift Deploy a `ImageTagMirrorSet` and `ImageDigestMirrorSet` custom resource with `mirrorSourcePolicy: NeverContactSource` to ensure that all image pulls for containers.isovalent.com are redirected to the mirror when parameter `enterprise.registry.hostname` is set to anything other than `containers.isovalent.com`. --- component/icr-config.libsonnet | 36 +++++++++++++++++++ ...rise_isovalent_registry_mirror_config.yaml | 27 ++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 tests/golden/projectsyn-registry-credentials/cilium/cilium/80_enterprise_isovalent_registry_mirror_config.yaml diff --git a/component/icr-config.libsonnet b/component/icr-config.libsonnet index eb388526d..bac8874e4 100644 --- a/component/icr-config.libsonnet +++ b/component/icr-config.libsonnet @@ -380,7 +380,43 @@ local ocp_credentials_manifests = { }, }; +local registry_mirror = + if params.enterprise.registry.hostname != 'containers.isovalent.com' then + { + isovalent_registry_mirror_config: [ + kube._Object( + 'config.openshift.io/v1', + 'ImageTagMirrorSet', + 'containers-isovalent-com' + ) { + spec: { + imageTagMirrors: [ { + mirrorSourcePolicy: 'NeverContactSource', + mirrors: [ params.enterprise.registry.hostname ], + source: 'containers.isovalent.com', + } ], + }, + }, + kube._Object( + 'config.openshift.io/v1', + 'ImageDigestMirrorSet', + 'containers-isovalent-com' + ) { + spec: { + imageDigestMirrors: [ { + mirrorSourcePolicy: 'NeverContactSource', + mirrors: [ params.enterprise.registry.hostname ], + source: 'containers.isovalent.com', + } ], + }, + }, + ], + } + else + {}; + if !util.isOpenshift then error 'Isovalent credentials management NYI for non-OpenShift' else ocp_credentials_manifests[credentials_type] + + registry_mirror diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/80_enterprise_isovalent_registry_mirror_config.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/80_enterprise_isovalent_registry_mirror_config.yaml new file mode 100644 index 000000000..daf34374e --- /dev/null +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/80_enterprise_isovalent_registry_mirror_config.yaml @@ -0,0 +1,27 @@ +apiVersion: config.openshift.io/v1 +kind: ImageTagMirrorSet +metadata: + annotations: {} + labels: + name: containers-isovalent-com + name: containers-isovalent-com +spec: + imageTagMirrors: + - mirrorSourcePolicy: NeverContactSource + mirrors: + - icr-mirror.example.com + source: containers.isovalent.com +--- +apiVersion: config.openshift.io/v1 +kind: ImageDigestMirrorSet +metadata: + annotations: {} + labels: + name: containers-isovalent-com + name: containers-isovalent-com +spec: + imageDigestMirrors: + - mirrorSourcePolicy: NeverContactSource + mirrors: + - icr-mirror.example.com + source: containers.isovalent.com From c4da3ffb2afc135ff01f29fe9d949f13b0ad63d6 Mon Sep 17 00:00:00 2001 From: Simon Gerber Date: Tue, 3 Nov 2026 14:36:19 +0100 Subject: [PATCH 4/5] Document new parameters --- .../ROOT/pages/references/parameters.adoc | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/docs/modules/ROOT/pages/references/parameters.adoc b/docs/modules/ROOT/pages/references/parameters.adoc index 056e8b750..07544993e 100644 --- a/docs/modules/ROOT/pages/references/parameters.adoc +++ b/docs/modules/ROOT/pages/references/parameters.adoc @@ -1296,6 +1296,80 @@ The CA certificate is configured with a lifetime of 2 years. When the parameter is set to `true`, the component also deploys cert-manager resources to issue mTLS certificates for Hubble Relay and configures Hubble to use mTLS for connections between Hubble Relay and the Cilium agents. +== `enterprise` + +[horizontal] +type:: object + +This parameter holds configurations that are only applicable when the component is configured with `release: enterprise`. + +=== `registry` + +[horizontal] +type:: object +default:: ++ +[source,yaml] +---- +hostname: containers.isovalent.com +credentials: + type: static + username: ?{vaultkv:${cluster:tenant}/${cluster:name}/isovalent/username} + access_token: ?{vaultkv:${cluster:tenant}/${cluster:name}/isovalent/access_token} +---- + +[IMPORTANT] +==== +Currently, the component only supports configuring credentials on OpenShift. +==== + +[NOTE] +==== +Currently, the component doesn't modify the Cilium manifests themselves to use the provided registry hostname. +==== + +This parameter enables users to configure credentials for `containers.isovalent.com`. +Container images for Isovalent Networking for Kubernetes (previously "Cilium Enterprise") v1.19 and newer are only available from `containers.isovalent.com`. +Pulling images from `containers.isovalent.com` requires credentials. + +The component supports multiple different credentials types (configured in field `credentials.type`): + +static:: +The `static` credential type uses credentials stored in Vault. +This credentials type is suitable for deployments which use a registry mirror that's configured with arbitrary static credentials. +For this credentials type, the component deploys an Espejote `ManagedResource` which renders the provided credentials into a `dockerconfigjson`. + +direct-eso:: +The `direct-eso` credential type uses https://hub.syn.tools/external-secrets-operator[External Secrets Operator] to manage the short-lived access tokens for `containers.isovalent.com`. +This credentials type is only supported when field `hostname` is set to `containers.isovalent.com`. +The component configures an ESO webhook generator which queries the registry.isovalent.com API for new access tokens, and an `ExternalSecret` resource which uses the generator to refresh and render the pull secret. ++ +The `ExternalSecret` is configured to refresh the registry access token every 30 days (`720h`). +Currently, the refresh interval is hard-coded in the component. ++ +The ESO webhook generator is currently hard-coded to make a `POST` request to `https://registry.isovalent.com/access/api/v1/tokens` with the current access token. +This configuration should be suitable as long as the Isovalent registry is backed by JFrog Artifactory. + +projectsyn:: +The `projectsyn` credential type configures the pull secret with the provided registry hostname and username and sets the password to the SHA-256 hexdigest of the cluster's Steward token. +This credentials type is implemented as an Espejote `ManagedResource` and is only supported when field `hostname` is set to a value other than `containers.isovalent.com`. + +NOTE: Any other value for field `credentials.type` results in a compilation error. + +On OpenShift, the component renders the credentials as a `kubernetes.io/dockerconfigjson` secret in namespace `openshift-config` which is labeled with `pull-secret.openshift-config.syn.tools/include=""`. +The secret is picked up by the Espejote `ManagedResource` deployed by https://hub.syn.tools/openshift4-config/how-tos/pull-secret-config.html[component-openshift4-config] and added to the OpenShift cluster-wide pull secret because of the label. + +Additionally, on OpenShift, the component deploys an `ImageTagMirrorSet` and `ImageDigestMirrorSet` if field `hostname` is set to a value other than `containers.isovalent.com`. +The two resources are configured with `mirrorSourcePolicy: NeverContactSource`, so that clusters that are configured with a mirror (which therefore don't have valid credentials for `containers.isovalent.com`) never try to fetch images directly from `containers.isovalent.com`. +This enables users to configure a registry mirror for `containers.isovalent.com` without having to find and modify each Helm value that references `containers.isovalent.com`. + +IMPORTANT: On OpenShift, changing the value of `registry.hostname` triggers node drains because such changes apply, remove, or modify the `ImageTagMirrorSet` and `ImageDigestMirrorSet` resources. + +[TIP] +==== +If you're using https://hub.syn.tools/registry-cache/[component-registry-cache] to deploy a pull-through registry cache for `containers.isovalent.com`, you can use that component's https://hub.syn.tools/registry-cache/references/parameters.html#_externalhtpasswdsecret[`projectsynHtpasswd`] feature to generate a `htpasswd` file that is suitable for credentials type `projectsyn`. +==== + == Example [source,yaml] From 7ecf213e586ca8f5072cc01ddac5326d44021df2 Mon Sep 17 00:00:00 2001 From: Simon Gerber Date: Wed, 4 Nov 2026 15:03:09 +0100 Subject: [PATCH 5/5] Add apply option force=true to enterprise pull secret Espejote ManagedResource --- component/icr-config.libsonnet | 6 ++++++ .../cilium/80_enterprise_pull_secret_managed_resource.yaml | 2 ++ .../cilium/80_enterprise_pull_secret_managed_resource.yaml | 2 ++ 3 files changed, 10 insertions(+) diff --git a/component/icr-config.libsonnet b/component/icr-config.libsonnet index bac8874e4..87e604db2 100644 --- a/component/icr-config.libsonnet +++ b/component/icr-config.libsonnet @@ -73,6 +73,12 @@ local pull_secret_managed_resource(syn) = [ esp.managedResource('cilium-pull-secret', 'openshift-config') { spec: { + applyOptions: { + // NOTE(sg): We set apply option force=true, so that the + // managedresource can properly revert external changes to the + // target secret. + force: true, + }, serviceAccountRef: { name: sa.metadata.name, }, diff --git a/tests/golden/enterprise-bgp/cilium/cilium/80_enterprise_pull_secret_managed_resource.yaml b/tests/golden/enterprise-bgp/cilium/cilium/80_enterprise_pull_secret_managed_resource.yaml index 1787259db..642122fc8 100644 --- a/tests/golden/enterprise-bgp/cilium/cilium/80_enterprise_pull_secret_managed_resource.yaml +++ b/tests/golden/enterprise-bgp/cilium/cilium/80_enterprise_pull_secret_managed_resource.yaml @@ -8,6 +8,8 @@ metadata: name: cilium-pull-secret namespace: openshift-config spec: + applyOptions: + force: true context: - name: cilium_pull_secret resource: diff --git a/tests/golden/projectsyn-registry-credentials/cilium/cilium/80_enterprise_pull_secret_managed_resource.yaml b/tests/golden/projectsyn-registry-credentials/cilium/cilium/80_enterprise_pull_secret_managed_resource.yaml index 9760f0953..bf2eaafe5 100644 --- a/tests/golden/projectsyn-registry-credentials/cilium/cilium/80_enterprise_pull_secret_managed_resource.yaml +++ b/tests/golden/projectsyn-registry-credentials/cilium/cilium/80_enterprise_pull_secret_managed_resource.yaml @@ -8,6 +8,8 @@ metadata: name: cilium-pull-secret namespace: openshift-config spec: + applyOptions: + force: true context: - name: cilium_pull_secret resource: