# knoe-onboard: tiny static-content service that renders an engineer's # psql onboarding details from a URL fragment. # # How it fits: # etc/onboard_engineer.sh # -> CREATE ROLE + temp password (24h) # -> Builds URL: https://db.0.knoe.dev/onboard.html#user=...&pw=...&exp=... # -> Outputs URL + QR-code rendering for chrisfu to email or screenshare # Engineer clicks URL or scans QR # -> oauth2-proxy `--skip-auth-route` matches /onboard.* (page itself is # ungated; URL secrecy + 24h expiry + immediate rotation = the security # envelope, since URL fragments don't survive an OAuth redirect anyway) # -> Kong routes /onboard/* to this nginx pod # -> Browser loads onboard.html; vanilla JS reads window.location.hash, # decodes the password, displays it with [Copy] buttons + a ready-to-paste # psql connection string. No backend calls. No state. # # Phase 2 (Junie's queue): when libpq OAUTHBEARER lands, the script stops # generating passwords; the onboard page becomes "you're already authorized # (Google), here's your connection string with oauth_issuer=...". The # Deployment + Service + Kong route here stay; only the HTML changes. --- apiVersion: v1 kind: ConfigMap metadata: name: knoe-onboard-html namespace: supabase labels: app: knoe-onboard app.kubernetes.io/managed-by: knoe-installer data: onboard.html: | knoe-db onboarding
--- apiVersion: v1 kind: Service metadata: name: knoe-onboard namespace: supabase labels: app: knoe-onboard app.kubernetes.io/managed-by: knoe-installer spec: type: ClusterIP selector: app: knoe-onboard ports: - name: http port: 80 targetPort: 80 protocol: TCP --- apiVersion: apps/v1 kind: Deployment metadata: name: knoe-onboard namespace: supabase labels: app: knoe-onboard app.kubernetes.io/managed-by: knoe-installer spec: replicas: 1 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 selector: matchLabels: app: knoe-onboard template: metadata: labels: app: knoe-onboard spec: securityContext: runAsNonRoot: true runAsUser: 101 # nginx in alpine image runAsGroup: 101 seccompProfile: type: RuntimeDefault containers: - name: nginx image: nginx:1.27-alpine imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 protocol: TCP volumeMounts: # ConfigMap mounted directly at the nginx html root so we don't # need a writable rootfs (readOnlyRootFilesystem: true). - name: html mountPath: /usr/share/nginx/html readOnly: true - name: nginx-cache mountPath: /var/cache/nginx - name: nginx-run mountPath: /var/run livenessProbe: httpGet: path: /onboard.html port: http initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 3 readinessProbe: httpGet: path: /onboard.html port: http initialDelaySeconds: 2 periodSeconds: 5 timeoutSeconds: 3 resources: requests: cpu: 10m memory: 16Mi limits: cpu: 50m memory: 32Mi securityContext: allowPrivilegeEscalation: false capabilities: drop: ["ALL"] readOnlyRootFilesystem: true volumes: - name: html configMap: name: knoe-onboard-html items: # Two paths under the same volume: nginx serves /onboard.html # directly, and / falls back to index.html (same content) for # convenience if the trailing .html ever gets dropped. - key: onboard.html path: onboard.html - key: onboard.html path: index.html - name: nginx-cache emptyDir: {} - name: nginx-run emptyDir: {}