From 9964b253e9d62c4ccbc5f47ea9a570dd6fb7587a Mon Sep 17 00:00:00 2001 From: Gus Parvin Date: Fri, 26 Jan 2024 08:34:00 -0500 Subject: [PATCH] Enable the quay bridge operator by default in the opp policyset This sets up and configures the quay bridge operator by default in the opp policysets. The quay bridge operator is deployed to all openshift managed clusters and will trust the default cert from the hub for the image registry. This will allow a cross product interop test for OPP since now an application can be deployed that uses quay's image registry which is on ODF. ACS will scan the registry. ACM will manage the app deployment. Signed-off-by: Gus Parvin (cherry picked from commit 0ca216a47ee2dfa5be8602a3e593023d07bf9c16) --- .../input-quay/policy-config-quay.yaml | 139 +++++++++++++----- .../input-quay/policy-hub-quay-bridge.yaml | 46 +++++- .../input-quay/policy-install-quay.yaml | 11 +- .../input-quay/policy-quay-bridge.yaml | 26 ++++ .../openshift-plus/policyGenerator.yaml | 43 +++--- 5 files changed, 201 insertions(+), 64 deletions(-) diff --git a/policygenerator/policy-sets/stable/openshift-plus/input-quay/policy-config-quay.yaml b/policygenerator/policy-sets/stable/openshift-plus/input-quay/policy-config-quay.yaml index 8d9d19aa9..672687078 100644 --- a/policygenerator/policy-sets/stable/openshift-plus/input-quay/policy-config-quay.yaml +++ b/policygenerator/policy-sets/stable/openshift-plus/input-quay/policy-config-quay.yaml @@ -33,64 +33,127 @@ spec: - | #!/usr/bin/env bash - # Wait for quay to be ready - attempt_counter=0 - max_attempts=80 - echo "Waiting for quay to be available..." - until $(curl --output /dev/null --silent --head --fail http://registry-quay-app); do - if [ ${attempt_counter} -eq ${max_attempts} ];then - echo "Max attempts reached" - exit 1 + function quay_cmd() { + DATA='{}' + if [ ! -z "$4" ]; then + DATA=$4 + fi + echo "[$1] $2 $3 --data $DATA" 1>&2 + AUTH="Fake: dummy" + if [ $1 = "Basic" ]; then + COUNT=$(oc -n $QUAY_NAMESPACE get --ignore-not-found=true secret $QUAY_USER_SECRET | wc -l) + if [ $COUNT -gt 1 ]; then + BASIC=$(oc -n $QUAY_NAMESPACE extract secret/$QUAY_USER_SECRET --keys=basic --to=-) fi + AUTH="Authorization: Basic $BASIC" - printf '.' - attempt_counter=$(($attempt_counter+1)) - echo "Made attempt $attempt_counter, waiting..." - sleep 30 + elif [ $1 = "Bearer" ]; then + AUTH="Authorization: Bearer $TOKEN" + fi + curl -X $2 $CURL_OPTS -H 'Content-Type: application/json' -H "$AUTH" https://$QUAY_HOST$3 --data "$DATA" + echo "[INFO] Success" 1>&2 + } + echo -n "Waiting for the Quay Registry CR to be available ." + RC=$(oc wait QuayRegistry -n local-quay registry --for=condition=Available=true > /dev/null 2>&1;echo $?) + + while [ $RC -ne 0 ]; do + sleep 2 + echo -n "." + RC=$(oc wait QuayRegistry -n local-quay registry --for=condition=Available=true > /dev/null 2>&1;echo $?) done + echo "done" - QUAYHOST=$(oc get route -n local-quay registry-quay -o jsonpath='{.spec.host}') + CURL_OPTS="-fsk" + QUAY_ADMIN=quayadmin + QUAY_USER=quaydevel + QUAY_USER_SECRET=$QUAY_USER + QUAY_NAMESPACE=local-quay + QUAY_HOST=$(oc get route -n $QUAY_NAMESPACE registry-quay -o jsonpath='{.spec.host}') + QUAY_ORG=devel + QUAY_ORG_EMAIL=devel@myorg.com + QUAY_REPO=example if [ $? -ne 0 ]; then echo "Quay route does not exist yet, please wait and try again." exit 1 fi - RESULT=$(oc get secret -n local-quay quayadmin) + RESULT=$(oc get secret -n $QUAY_NAMESPACE $QUAY_USER_SECRET) if [ $? -eq 0 ]; then - echo "Quay user configuration secret already exists: quayadmin in namespace local-quay" + echo "Quay user configuration secret already exists: $QUAY_USER_SECRET in namespace $QUAY_NAMESPACE" exit 1 fi ADMINPASS=`head -c 8 /dev/urandom | base64 | sed 's/=//'` - - RESULT=$(curl -X POST -k -s https://$QUAYHOST/api/v1/user/initialize --header 'Content-Type: application/json' --data "{ \"username\": \"quayadmin\", \"password\":\"${ADMINPASS}\", \"email\": \"quayadmin@example.com\", \"access_token\": true}") + BASE64AUTH=`echo -n $QUAY_USER:$QUAY_PASSWORD | base64 -w0` + RESULT=$(curl -X POST -k -s https://$QUAY_HOST/api/v1/user/initialize --header 'Content-Type: application/json' --data "{ \"username\": \"quayadmin\", \"password\":\"${ADMINPASS}\", \"email\": \"quayadmin@example.com\", \"access_token\": true}") echo "$RESULT" | grep -q "non-empty database" if [ $? -eq 0 ]; then echo "Quay user configuration failed, the database has been initialized." exit 1 else - cat < Applications -> {app} -> Generate Token + # If there was a programatic way to do it here, we could avoid the problem with the bearer token expiring after 150min + APPLICATION=automation + COUNT=$(quay_cmd Bearer GET /api/v1/organization/$QUAY_ORG/applications | grep $APPLICATION | wc -l) + if [ $COUNT = 0 ]; then + echo "[INFO] Creating $APPLICATION application..." + quay_cmd Bearer POST /api/v1/organization/$QUAY_ORG/applications "{\"name\": \"$QUAY_ORG-automation\", \"description\": \"automation app\" }" + fi + + echo "[INFO] Looking for initial repo ..." + COUNT=$(quay_cmd Bearer GET /api/v1/repository/$QUAY_ORG/$QUAY_REPO | grep -v not_found | wc -l) + if [ $COUNT = 0 ]; then + echo "[INFO] Creating $QUAY_REPO repo..." + quay_cmd Bearer POST /api/v1/repository "{\"namespace\":\"$QUAY_ORG\", \"repository\":\"$QUAY_REPO\", \"visibility\":\"public\", \"description\":\"Development Repo\", \"repo_kind\":\"image\"}" + fi + + echo "[INFO] Looking for $QUAY_ORG members ..." + COUNT=$(quay_cmd Bearer GET /api/v1/organization/$QUAY_ORG/team/owners/members | grep "name\": \"$QUAY_USER\"" | wc -l) + if [ $COUNT = 0 ]; then + echo "[INFO] Associating $QUAY_USER with $QUAY_ORG ..." + quay_cmd Bearer PUT /api/v1/organization/$QUAY_ORG/team/owners/members/$QUAY_USER '{}' + fi + + echo "[INFO] Looking for $QUAY_REPO admins ..." + COUNT=$(quay_cmd Bearer GET /api/v1/repository/$QUAY_ORG/$QUAY_REPO/permissions/user/$QUAY_USER | grep '"role": "admin"' | wc -l) + if [ $COUNT = 0 ]; then + echo "[INFO] Give $QUAY_USER admin rights to the repo ..." + quay_cmd Bearer PUT /api/v1/repository/$QUAY_ORG/$QUAY_REPO/permissions/user/$QUAY_USER '{ "role": "admin"}' + fi + + echo "[INFO] Job finished" image: image-registry.openshift-image-registry.svc:5000/openshift/cli:latest imagePullPolicy: Always name: create-admin-user diff --git a/policygenerator/policy-sets/stable/openshift-plus/input-quay/policy-hub-quay-bridge.yaml b/policygenerator/policy-sets/stable/openshift-plus/input-quay/policy-hub-quay-bridge.yaml index b97441941..274d24eab 100644 --- a/policygenerator/policy-sets/stable/openshift-plus/input-quay/policy-hub-quay-bridge.yaml +++ b/policygenerator/policy-sets/stable/openshift-plus/input-quay/policy-hub-quay-bridge.yaml @@ -11,6 +11,24 @@ spec: source: redhat-operators sourceNamespace: openshift-marketplace --- +kind: Secret +type: Opaque +metadata: + name: quay-integration + namespace: openshift-operators +apiVersion: v1 +data: + token: '{{ fromSecret "local-quay" "quay-integration" "token" }}' +--- +kind: Secret +type: Opaque +metadata: + name: quay-integration + namespace: policies +apiVersion: v1 +data: + token: '{{ fromSecret "local-quay" "quay-integration" "token" }}' +--- apiVersion: quay.redhat.com/v1 kind: QuayIntegration metadata: @@ -25,11 +43,29 @@ spec: insecureRegistry: false quayHostname: https://{{ fromConfigMap "policies" "quay-config" "host" }} --- -kind: Secret -type: Opaque +apiVersion: v1 +data: + '{{ (lookup "route.openshift.io/v1" "Route" "local-quay" "registry-quay" ).spec.host }}': | + {{ ( fromSecret "openshift-ingress-operator" "router-ca" "tls.crt" ) | base64dec | autoindent }} +kind: ConfigMap metadata: - name: quay-integration - namespace: policies + name: opp-ingres-ca + namespace: openshift-config +--- +apiVersion: config.openshift.io/v1 +kind: Image +metadata: + name: cluster +spec: + additionalTrustedCA: + name: opp-ingres-ca +--- apiVersion: v1 data: - token: '{{ fromSecret "openshift-operators" "quay-integration" "token" }}' + registry-quay-local-quay: | + {{ ( fromSecret "openshift-ingress-operator" "router-ca" "tls.crt" ) }} +kind: Secret +metadata: + name: opp-ingres-ca + namespace: policies +type: Opaque diff --git a/policygenerator/policy-sets/stable/openshift-plus/input-quay/policy-install-quay.yaml b/policygenerator/policy-sets/stable/openshift-plus/input-quay/policy-install-quay.yaml index 4f0ebd786..b6253ca3b 100644 --- a/policygenerator/policy-sets/stable/openshift-plus/input-quay/policy-install-quay.yaml +++ b/policygenerator/policy-sets/stable/openshift-plus/input-quay/policy-install-quay.yaml @@ -27,6 +27,7 @@ rules: - create - patch - update + - delete - apiGroups: - route.openshift.io resources: @@ -34,6 +35,14 @@ rules: verbs: - get - list +- apiGroups: + - quay.redhat.com + resources: + - quayregistries + verbs: + - get + - list + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding @@ -73,7 +82,7 @@ spec: --- apiVersion: v1 data: - config.yaml: RkVBVFVSRV9VU0VSX0lOSVRJQUxJWkU6IHRydWUKQlJPV1NFUl9BUElfQ0FMTFNfWEhSX09OTFk6IGZhbHNlClNVUEVSX1VTRVJTOgotIHF1YXlhZG1pbgpGRUFUVVJFX1VTRVJfQ1JFQVRJT046IHRydWUK + config.yaml: RkVBVFVSRV9VU0VSX0lOSVRJQUxJWkU6IHRydWUKQlJPV1NFUl9BUElfQ0FMTFNfWEhSX09OTFk6IGZhbHNlClNVUEVSX1VTRVJTOgotIHF1YXlhZG1pbgpGRUFUVVJFX1VTRVJfQ1JFQVRJT046IHRydWUKRkVBVFVSRV9TVVBFUlVTRVJTX0ZVTExfQUNDRVNTOiB0cnVlCg== kind: Secret metadata: name: init-config-bundle-secret diff --git a/policygenerator/policy-sets/stable/openshift-plus/input-quay/policy-quay-bridge.yaml b/policygenerator/policy-sets/stable/openshift-plus/input-quay/policy-quay-bridge.yaml index 2847ef589..32c702b5e 100644 --- a/policygenerator/policy-sets/stable/openshift-plus/input-quay/policy-quay-bridge.yaml +++ b/policygenerator/policy-sets/stable/openshift-plus/input-quay/policy-quay-bridge.yaml @@ -33,3 +33,29 @@ metadata: apiVersion: v1 data: token: '{{hub fromSecret "" "quay-integration" "token" hub}}' +--- +apiVersion: v1 +data: + quay-integration: '{{hub fromSecret "policies" "opp-ingres-ca" "registry-quay-local-quay" hub}}' +kind: Secret +metadata: + name: opp-ingres-ca + namespace: openshift-config +type: Opaque +--- +apiVersion: v1 +data: + '{{hub fromConfigMap "" "quay-config" "host" hub}}': | + {{ ( fromSecret "openshift-config" "opp-ingres-ca" "quay-integration" ) | base64dec | autoindent }} +kind: ConfigMap +metadata: + name: opp-ingres-ca + namespace: openshift-config +--- +apiVersion: config.openshift.io/v1 +kind: Image +metadata: + name: cluster +spec: + additionalTrustedCA: + name: opp-ingres-ca diff --git a/policygenerator/policy-sets/stable/openshift-plus/policyGenerator.yaml b/policygenerator/policy-sets/stable/openshift-plus/policyGenerator.yaml index be54ff316..c1c4b8708 100644 --- a/policygenerator/policy-sets/stable/openshift-plus/policyGenerator.yaml +++ b/policygenerator/policy-sets/stable/openshift-plus/policyGenerator.yaml @@ -172,27 +172,30 @@ policies: manifests: - path: input-quay/policy-quay-status.yaml remediationAction: inform -# Quay Bridge requires a token that needs to be populated in a secret. Uncomment the following -# 2 policies if you need to use the quay bridge. After quay is running, see the instructions: +# Quay Bridge is configured with a temporary token that will expire quickly after +# deployment. After quay is running, see the instructions: # https://hybrid-cloud-patterns.io/devsecops/getting-started/#completing-the-quay-bridge-with-a-bearer-token -# The command below is needed to place the secret where the policies expect to find it. -# oc create secret -n openshift-operators generic quay-integration --from-literal=token= -#- name: policy-hub-quay-bridge -# categories: -# - SI System and Information Integrity -# controls: -# - SI-7 Software Firmware and Information Integrity -# manifests: -# - path: input-quay/policy-hub-quay-bridge.yaml -#- name: policy-quay-bridge -# categories: -# - SI System and Information Integrity -# controls: -# - SI-7 Software Firmware and Information Integrity -# manifests: -# - path: input-quay/policy-quay-bridge.yaml -# policySets: -# - openshift-plus-clusters +# Update the token in the quayadmin secret in the local-quay namespace with your +# bearer token. It will be propagated to the managed clusters automatically. +- name: policy-hub-quay-bridge + categories: + - SI System and Information Integrity + controls: + - SI-7 Software Firmware and Information Integrity + dependencies: + - name: policy-quay-status + manifests: + - path: input-quay/policy-hub-quay-bridge.yaml +- name: policy-quay-bridge + categories: + - SI System and Information Integrity + controls: + - SI-7 Software Firmware and Information Integrity + manifests: + - path: input-quay/policy-quay-bridge.yaml + orderManifests: true + policySets: + - openshift-plus-clusters # Quay Policies - end # Compliance Operator Policies - start - name: policy-compliance-operator-install