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