diff --git a/clusters/atlas/applications/kustomization.yaml b/clusters/atlas/applications/kustomization.yaml index c29dbb7..209790b 100644 --- a/clusters/atlas/applications/kustomization.yaml +++ b/clusters/atlas/applications/kustomization.yaml @@ -9,4 +9,3 @@ resources: - ../../services/monitoring - ../../services/pegasus - ../../services/vault - - ../../services/zot diff --git a/clusters/atlas/flux-system/applications/kustomization.yaml b/clusters/atlas/flux-system/applications/kustomization.yaml index 9b388c8..93e10bf 100644 --- a/clusters/atlas/flux-system/applications/kustomization.yaml +++ b/clusters/atlas/flux-system/applications/kustomization.yaml @@ -2,7 +2,6 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - - zot/kustomization.yaml - gitea/kustomization.yaml - vault/kustomization.yaml - jitsi/kustomization.yaml diff --git a/clusters/atlas/flux-system/applications/zot/kustomization.yaml b/clusters/atlas/flux-system/applications/zot/kustomization.yaml deleted file mode 100644 index c60ae5b..0000000 --- a/clusters/atlas/flux-system/applications/zot/kustomization.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# clusters/atlas/flux-system/applications/zot/kustomization.yaml -apiVersion: kustomize.toolkit.fluxcd.io/v1 -kind: Kustomization -metadata: - name: zot - namespace: flux-system -spec: - interval: 10m - path: ./services/zot - targetNamespace: zot - prune: false - sourceRef: - kind: GitRepository - name: flux-system - namespace: flux-system - wait: true - dependsOn: - - name: core diff --git a/scripts/zot_cred_sync.sh b/scripts/zot_cred_sync.sh deleted file mode 100755 index e33c379..0000000 --- a/scripts/zot_cred_sync.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env bash -# Sync Keycloak users into Zot htpasswd. -# Intended to be rendered into a ConfigMap/Job; keep real secrets out of git. - -set -euo pipefail - -require() { command -v "$1" >/dev/null 2>&1 || { echo "missing required binary: $1" >&2; exit 1; }; } -require curl; require jq; require kubectl; require htpasswd - -: "${KEYCLOAK_URL:=https://sso.bstein.dev}" -: "${KEYCLOAK_REALM:=atlas}" -: "${KEYCLOAK_CLIENT_ID:?set KEYCLOAK_CLIENT_ID or export via secret}" -: "${KEYCLOAK_CLIENT_SECRET:?set KEYCLOAK_CLIENT_SECRET or export via secret}" -: "${ZOT_NAMESPACE:=zot}" -: "${HTPASSWD_SECRET_NAME:=zot-htpasswd}" -: "${DEFAULT_PASSWORD:=TempSsoPass!2025}" -: "${UI_PROXY_USER:=zot-ui-proxy}" -: "${UI_PROXY_PASSWORD:=TempSsoUiPass!2025}" - -fetch_token() { - curl -fsS -X POST \ - -d "grant_type=client_credentials" \ - -d "client_id=${KEYCLOAK_CLIENT_ID}" \ - -d "client_secret=${KEYCLOAK_CLIENT_SECRET}" \ - "${KEYCLOAK_URL}/realms/${KEYCLOAK_REALM}/protocol/openid-connect/token" \ - | jq -r '.access_token' -} - -pull_users() { - local token="$1" - curl -fsS -H "Authorization: Bearer ${token}" \ - "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/users?max=500" \ - | jq -r '.[] | select(.enabled == true) | select(.username | startswith("service-account-") | not) | .username' -} - -decode_secret_file() { - local ns="$1" name="$2" key="$3" out="$4" - if kubectl -n "${ns}" get secret "${name}" >/dev/null 2>&1; then - kubectl -n "${ns}" get secret "${name}" -o "jsonpath={.data.${key}}" | base64 -d > "${out}" || true - else - : > "${out}" - fi -} - -ensure_htpasswd_line() { - local user="$1" password="$2" file="$3" - if ! grep -q "^${user}:" "${file}" 2>/dev/null; then - htpasswd -nbB "${user}" "${password}" >> "${file}" - echo "added user ${user} to htpasswd" - fi -} - -main() { - local token tmp existing - tmp="$(mktemp)" - existing="$(mktemp)" - trap 'rm -f "${tmp}" "${existing}"' EXIT - - decode_secret_file "${ZOT_NAMESPACE}" "${HTPASSWD_SECRET_NAME}" htpasswd "${existing}" - cp "${existing}" "${tmp}" - - ensure_htpasswd_line "${UI_PROXY_USER}" "${UI_PROXY_PASSWORD}" "${tmp}" - - token="$(fetch_token)" - readarray -t users < <(pull_users "${token}") - for user in "${users[@]}"; do - ensure_htpasswd_line "${user}" "${DEFAULT_PASSWORD}" "${tmp}" - done - - kubectl create secret generic "${HTPASSWD_SECRET_NAME}" \ - --namespace "${ZOT_NAMESPACE}" \ - --from-file=htpasswd="${tmp}" \ - --dry-run=client -o yaml | kubectl apply -f - -} - -main "$@" diff --git a/services/zot/configmap.yaml b/services/zot/configmap.yaml deleted file mode 100644 index 3046d78..0000000 --- a/services/zot/configmap.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# services/zot/config.map -apiVersion: v1 -kind: ConfigMap -metadata: - name: zot-config - namespace: zot -data: - config.json: | - { - "storage": { - "rootDirectory": "/var/lib/registry", - "dedupe": true, - "gc": true, - "gcDelay": "1h", - "gcInterval": "1h" - }, - "http": { - "address": "0.0.0.0", - "port": "5000", - "realm": "zot-registry", - "compat": ["docker2s2"], - "auth": { - "htpasswd": { "path": "/etc/zot/htpasswd" } - }, - "accessControl": { - "repositories": { - "**": { - "policies": [ - { "users": ["bstein", "zot-ui-proxy"], "actions": ["read", "create", "update", "delete"] } - ], - "defaultPolicy": [], - "anonymousPolicy": [] - } - }, - "adminPolicy": { - "users": ["bstein", "zot-ui-proxy"], - "actions": ["read", "create", "update", "delete"] - } - } - }, - "log": { "level": "info" }, - "extensions": { - "ui": { "enable": true }, - "search": { "enable": true }, - "metrics": { "enable": true } - } - } diff --git a/services/zot/deployment.yaml b/services/zot/deployment.yaml deleted file mode 100644 index 14dc724..0000000 --- a/services/zot/deployment.yaml +++ /dev/null @@ -1,102 +0,0 @@ -# services/zot/deployment.yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: zot - namespace: zot - labels: { app: zot } -spec: - replicas: 1 - selector: - matchLabels: { app: zot } - template: - metadata: - labels: { app: zot } - spec: - nodeSelector: - node-role.kubernetes.io/worker: "true" - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: hardware - operator: In - values: ["rpi4","rpi5"] - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 50 - preference: - matchExpressions: - - key: hardware - operator: In - values: ["rpi4"] - containers: - - name: zot - image: ghcr.io/project-zot/zot-linux-arm64:v2.1.8 - imagePullPolicy: IfNotPresent - args: ["serve", "/etc/zot/config.json"] - env: - - name: UI_PROXY_HTPASSWD - value: "zot-ui-proxy:$2y$05$ctfbLo5KBoNA6pluLGGWde6TK8eOPnIH9u8x/IivAhcE/k0qCCR3y" - ports: - - { name: http, containerPort: 5000 } - volumeMounts: - - name: cfg - mountPath: /etc/zot/config.json - subPath: config.json - readOnly: true - - name: htpasswd-merged - mountPath: /etc/zot/htpasswd - subPath: htpasswd - - name: zot-data - mountPath: /var/lib/registry - readinessProbe: - tcpSocket: - port: 5000 - initialDelaySeconds: 2 - periodSeconds: 5 - livenessProbe: - tcpSocket: - port: 5000 - initialDelaySeconds: 5 - periodSeconds: 10 - resources: - requests: { cpu: "50m", memory: "64Mi" } - initContainers: - - name: merge-htpasswd - image: busybox:1.36 - command: - - sh - - -c - - | - set -e - if [ -f /src/htpasswd ]; then - cp /src/htpasswd /merged/htpasswd - else - touch /merged/htpasswd - fi - if [ -n "${UI_PROXY_HTPASSWD}" ]; then - echo "${UI_PROXY_HTPASSWD}" >> /merged/htpasswd - fi - env: - - name: UI_PROXY_HTPASSWD - value: "zot-ui-proxy:$2y$05$ctfbLo5KBoNA6pluLGGWde6TK8eOPnIH9u8x/IivAhcE/k0qCCR3y" - volumeMounts: - - name: htpasswd-source - mountPath: /src - readOnly: true - - name: htpasswd-merged - mountPath: /merged - volumes: - - name: cfg - configMap: - name: zot-config - - name: htpasswd-source - secret: - secretName: zot-htpasswd - optional: true - - name: htpasswd-merged - emptyDir: {} - - name: zot-data - persistentVolumeClaim: - claimName: zot-data diff --git a/services/zot/ingress.yaml b/services/zot/ingress.yaml deleted file mode 100644 index 6c23709..0000000 --- a/services/zot/ingress.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# services/zot/ingress.yaml -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: zot-cli - namespace: zot - annotations: - cert-manager.io/cluster-issuer: letsencrypt - traefik.ingress.kubernetes.io/router.entrypoints: websecure - traefik.ingress.kubernetes.io/router.tls: "true" - traefik.ingress.kubernetes.io/router.middlewares: zot-zot-resp-headers@kubernetescrd -spec: - ingressClassName: traefik - tls: - - hosts: [ "cli.registry.bstein.dev" ] - secretName: cli-registry-bstein-dev-tls - rules: - - host: cli.registry.bstein.dev - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: zot - port: - number: 5000 ---- -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: zot-ui - namespace: zot - annotations: - cert-manager.io/cluster-issuer: letsencrypt - traefik.ingress.kubernetes.io/router.entrypoints: websecure - traefik.ingress.kubernetes.io/router.tls: "true" - traefik.ingress.kubernetes.io/router.middlewares: zot-zot-resp-headers@kubernetescrd -spec: - ingressClassName: traefik - tls: - - hosts: [ "web.registry.bstein.dev" ] - secretName: web-registry-bstein-dev-tls - rules: - - host: web.registry.bstein.dev - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: zot-oauth2-proxy - port: - number: 80 diff --git a/services/zot/kustomization.yaml b/services/zot/kustomization.yaml deleted file mode 100644 index 22d76ae..0000000 --- a/services/zot/kustomization.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# services/zot/kustomization.yaml -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - namespace.yaml - - pvc.yaml - - deployment.yaml - - configmap.yaml - - service.yaml - - oauth2-proxy-deployment.yaml - - oauth2-proxy-service.yaml - - ingress.yaml - - middleware.yaml diff --git a/services/zot/middleware.yaml b/services/zot/middleware.yaml deleted file mode 100644 index 166b070..0000000 --- a/services/zot/middleware.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# services/zot/middleware.yaml -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: zot-resp-headers - namespace: zot -spec: - headers: - customResponseHeaders: - Docker-Distribution-Api-Version: "registry/2.0" - accessControlAllowOriginList: - - "*" - accessControlAllowCredentials: true - accessControlAllowHeaders: - - Authorization - - Content-Type - - Docker-Distribution-Api-Version - - X-Registry-Auth - accessControlAllowMethods: - - GET - - HEAD - - OPTIONS - - POST - - PUT - - PATCH - - DELETE diff --git a/services/zot/namespace.yaml b/services/zot/namespace.yaml deleted file mode 100644 index b91de10..0000000 --- a/services/zot/namespace.yaml +++ /dev/null @@ -1,5 +0,0 @@ -# services/zot/namespace.yaml -apiVersion: v1 -kind: Namespace -metadata: - name: zot diff --git a/services/zot/oauth2-proxy-deployment.yaml b/services/zot/oauth2-proxy-deployment.yaml deleted file mode 100644 index 9761e6e..0000000 --- a/services/zot/oauth2-proxy-deployment.yaml +++ /dev/null @@ -1,84 +0,0 @@ -# services/zot/oauth2-proxy-deployment.yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: zot-oauth2-proxy - namespace: zot - labels: { app: zot-oauth2-proxy } -spec: - replicas: 1 - selector: - matchLabels: { app: zot-oauth2-proxy } - template: - metadata: - labels: { app: zot-oauth2-proxy } - spec: - nodeSelector: - node-role.kubernetes.io/worker: "true" - affinity: - nodeAffinity: - preferredDuringSchedulingIgnoredDuringExecution: - - weight: 50 - preference: - matchExpressions: - - key: hardware - operator: In - values: ["rpi4","rpi5"] - containers: - - name: oauth2-proxy - image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0 - imagePullPolicy: IfNotPresent - args: - - --provider=oidc - - --redirect-url=https://web.registry.bstein.dev/oauth2/callback - - --oidc-issuer-url=https://sso.bstein.dev/realms/atlas - - --scope=openid profile email - - --email-domain=* - - --cookie-domain=web.registry.bstein.dev - - --cookie-name=_zot_ui_oauth - - --set-xauthrequest=true - - --set-authorization-header=false - - --pass-authorization-header=false - - --pass-access-token=false - - --pass-basic-auth=true - - --cookie-secure=true - - --cookie-samesite=lax - - --cookie-refresh=20m - - --cookie-expire=168h - - --upstream=http://zot-ui-proxy:TempSsoUiPass%212025@zot:5000 - - --http-address=0.0.0.0:4180 - - --skip-provider-button=true - - --skip-jwt-bearer-tokens=true - env: - - name: OAUTH2_PROXY_CLIENT_ID - valueFrom: - secretKeyRef: - name: zot-oidc - key: client_id - - name: OAUTH2_PROXY_CLIENT_SECRET - valueFrom: - secretKeyRef: - name: zot-oidc - key: client_secret - - name: OAUTH2_PROXY_COOKIE_SECRET - valueFrom: - secretKeyRef: - name: zot-oidc - key: client_secret - ports: - - containerPort: 4180 - name: http - readinessProbe: - httpGet: - path: /ping - port: 4180 - initialDelaySeconds: 5 - periodSeconds: 10 - livenessProbe: - httpGet: - path: /ping - port: 4180 - initialDelaySeconds: 20 - periodSeconds: 20 - resources: - requests: { cpu: "25m", memory: "64Mi" } diff --git a/services/zot/oauth2-proxy-service.yaml b/services/zot/oauth2-proxy-service.yaml deleted file mode 100644 index 4a7e96a..0000000 --- a/services/zot/oauth2-proxy-service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# services/zot/oauth2-proxy-service.yaml -apiVersion: v1 -kind: Service -metadata: - name: zot-oauth2-proxy - namespace: zot - labels: { app: zot-oauth2-proxy } -spec: - type: ClusterIP - selector: { app: zot-oauth2-proxy } - ports: - - name: http - port: 80 - targetPort: 4180 diff --git a/services/zot/pvc.yaml b/services/zot/pvc.yaml deleted file mode 100644 index b3af86c..0000000 --- a/services/zot/pvc.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# services/zot/pvc.yaml -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: zot-data - namespace: zot -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 25Gi - storageClassName: asteria diff --git a/services/zot/service.yaml b/services/zot/service.yaml deleted file mode 100644 index e41c8d4..0000000 --- a/services/zot/service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# services/zot/service.yaml -apiVersion: v1 -kind: Service -metadata: - name: zot - namespace: zot - labels: { app: zot } -spec: - type: ClusterIP - selector: { app: zot } - ports: - - name: http - port: 5000 - targetPort: 5000