# Render placeholders before use. Apply the migration Job first, wait for completion, # then apply this file. See docs/deployment.md for IAM, secrets and ingress. apiVersion: v1 kind: ServiceAccount metadata: name: meguri annotations: iam.gke.io/gcp-service-account: MEGURI_GSA@PROJECT_ID.iam.gserviceaccount.com --- apiVersion: v1 kind: ConfigMap metadata: name: meguri-instance-config data: # Declarative instance configuration (see deploy/instance-config.example.yaml for the commented # reference and docs/deployment.md). Replace the placeholders. The migrate Job synchronizes it; # replicas only read it. Change it, run the migrate Job for the release, then restart replicas. config.yaml: | auth: # Lets ordinary password accounts (created by an instance administrator) sign in. # Keep false in production where everyone signs in through SSO. password_login: false # Break-glass instance administrators. Omit this whole block in production; add it only to get # back in when SSO is broken, then remove it again. While present, the generated password is # written to the log of the process that synchronized the configuration (the migrate Job), and # anyone who can read that log can sign in as an instance administrator. The password is derived # from a database-held secret, the username and the current UTC hour; it rotates every hour. # bootstrap_admin: # usernames: [rescue] # OpenID Connect provider. Confidential client, authorization-code flow with PKCE. # Redirect URI to register: {MEGURI_PUBLIC_URL}/api/oidc/callback oidc: issuer: https://sso.example.internal/realms/corp # HTTPS; discovery is read from /.well-known/openid-configuration client_id: meguri scopes: [openid, profile, email] # default; must include openid; email links people planned by email # Where the groups are. A dotted path into the token claims (for example realm_access.roles). # Keycloak: add a "Group Membership" mapper with this claim name, "Add to ID token" and # "Add to userinfo" on. Matching below is by exact string, so "Full group path" decides # whether values look like /payments/leads or leads. groups_claim: groups groups_sources: [id_token, userinfo] # searched in this order # Groups whose members are instance administrators: they see and may act in every enabled # workspace, manage password users and delete disabled workspaces. Not tied to any workspace. instance_admin_groups: - /meguri/admins # Workspaces. `key` is the permanent identifier (3-64 characters: a-z, 0-9, hyphen); never reuse # it for something else. `name` is unique and is what people see; changing it renames the # workspace. A workspace that exists without a key and has exactly this name is adopted. # Removing an entry here DISABLES the workspace (nobody can open it, nothing is published, data is # kept); listing it again re-enables it. Deleting it for good is a manual action on the # instance administrator's page. workspaces: - key: payments name: Payments # Workspace administrators (team leads): every permission in this workspace only. At least one group. admin_groups: - /payments/leads # Employees: the workspace's employee permission set, by default calendar, schedule editing # and replacement requests. Administrators change that set in the workspace settings. member_groups: - /payments/team - key: customer-support name: Customer Support admin_groups: - /support/leads member_groups: - /support/team - /support/contractors --- apiVersion: v1 kind: ConfigMap metadata: name: meguri-config data: MEGURI_BIND: 0.0.0.0:3000 MEGURI_PUBLIC_URL: https://meguri.example.internal MEGURI_ROLE: all MEGURI_SKIP_MIGRATIONS: "true" MEGURI_CONFIG_FILE: /etc/meguri/config.yaml MEGURI_SEED_DEMO: "false" RUST_LOG: meguri=info,cot=warn --- apiVersion: apps/v1 kind: Deployment metadata: name: meguri spec: replicas: 2 selector: matchLabels: {app: meguri} template: metadata: labels: {app: meguri} spec: serviceAccountName: meguri terminationGracePeriodSeconds: 60 securityContext: runAsNonRoot: true seccompProfile: {type: RuntimeDefault} initContainers: - name: cloud-sql-proxy restartPolicy: Always image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.14.1 args: ["--private-ip", "--structured-logs", "--port=5432", "--health-check", "--http-address=0.0.0.0", "--http-port=9090", "PROJECT_ID:REGION:INSTANCE"] securityContext: allowPrivilegeEscalation: false capabilities: {drop: [ALL]} resources: requests: {cpu: 100m, memory: 128Mi} limits: {memory: 256Mi} startupProbe: httpGet: {path: /startup, port: 9090} periodSeconds: 2 failureThreshold: 30 volumes: - name: instance-config configMap: {name: meguri-instance-config} containers: - name: meguri image: REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY/meguri:RELEASE ports: [{name: http, containerPort: 3000}] envFrom: - configMapRef: {name: meguri-config} - secretRef: {name: meguri-secrets} env: - name: MEGURI_OIDC_CLIENT_SECRET valueFrom: secretKeyRef: {name: meguri-secrets, key: MEGURI_OIDC_CLIENT_SECRET, optional: true} volumeMounts: - {name: instance-config, mountPath: /etc/meguri, readOnly: true} securityContext: readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: {drop: [ALL]} resources: requests: {cpu: 250m, memory: 256Mi} limits: {memory: 512Mi} startupProbe: httpGet: {path: /health/ready, port: http} periodSeconds: 2 failureThreshold: 60 readinessProbe: httpGet: {path: /health/ready, port: http} livenessProbe: httpGet: {path: /health/live, port: http} --- apiVersion: v1 kind: Service metadata: name: meguri spec: type: ClusterIP selector: {app: meguri} ports: [{port: 80, targetPort: http}] --- apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: meguri spec: minAvailable: 1 selector: matchLabels: {app: meguri}