Ticket: pal-e-services — var.services entry + Keycloak client

ticket-westside-ops-services-entry Doc

active backlog westside-ops ticket

Ticket: pal-e-services — var.services entry + Keycloak client

Story: story-westside-ops-spreadsheet-access
Architecture: arch-deployment-westside-ops (pal-e-services as the tenancy layer)
Labels: story:spreadsheet-access,arch:services-tf,type:infra,track:devops,scope:planned
Blocks: Woodpecker pipeline (needs Harbor project + CI robot), k8s overlay (needs namespace + Keycloak client secret)
Blocked by: Streamlit spike ticket

Purpose

Register westside-ops as a service in pal-e-services so terraform provisions: Harbor project, CI robot, pull robot, namespace, harbor-creds image pull secret, ArgoCD application pointing at the westside-ops repo's k8s/ directory, and a Tailscale ingress (explicitly NOT a funnel). Also register a new Keycloak client westside-ops in the existing westside realm.

Scope

  • Edit ~/pal-e-services/terraform/k3s.tfvars (the GPG-decrypted or local copy — do not commit)
  • Add the service entry and Keycloak client below
  • Run tofu plan -var-file=k3s.tfvars -lock=false and review for expected resources (Harbor project, 2 robots, namespace, secret, ArgoCD app, ingress, Keycloak client)
  • Run tofu apply -var-file=k3s.tfvars -lock=false per feedback_tofu_lock_false
  • Capture the CI robot credentials via tofu output and hand them to the Woodpecker pipeline ticket
  • Capture the Keycloak client secret from the Keycloak admin console and hand it to the k8s overlay ticket (it will be SOPS-encrypted into secrets.enc.yaml)
  • Add Marcus's Keycloak account to the new westside-ops-user role within the westside realm (manual step in Keycloak admin UI, or via mcp__pal-e-docs if Keycloak MCP exists)

Exact tfvars additions

Append to the services map in k3s.tfvars:
Append to the keycloak_clients map in k3s.tfvars:
Also needed: add westside-ops-user to the roles list of the existing westside realm definition in tfvars (if realms are declared there), or create the role manually in the Keycloak admin console if realms are managed outside tfvars.

Important: verify the funnel=false code path

Reading pal-e-services/terraform/services.tf: the current funnel resource is conditional on each.value.funnel being true and applies the tailscale.com/funnel: "true" annotation. For westside-ops, we need tailscale.com/expose: "true" instead — the private variant.
The current terraform module does not create an expose-style ingress when funnel=false — it just skips the ingress entirely. That means one of:
  • Option A: westside-ops manages its own ingress inside ~/westside-ops/k8s/ingress.yaml with the tailscale.com/expose annotation (the k8s overlay ticket handles this). funnel=false in tfvars just means "tofu doesn't create any ingress — the overlay does." This is the recommended path because it's consistent with how westside-landing / westsidekingsandqueens already manages its own ingress via its overlay.
  • Option B: Extend pal-e-services's services.tf to support a third mode (expose). More invasive, defer as a separate ticket.
Go with Option A. The ingress resource lives in ~/westside-ops/k8s/ingress.yaml, declared in the k8s overlay ticket.

Acceptance Criteria

  • [ ] tofu plan -var-file=k3s.tfvars -lock=false shows expected new resources: harbor_project.service["westside-ops"], harbor_robot_account.service_ci["westside-ops"], harbor_robot_account.service_pull["westside-ops"], kubernetes_namespace_v1.service["westside-ops"], kubernetes_secret_v1.harbor_creds["westside-ops"], argocd_application.service["westside-ops"], and the new Keycloak client
  • [ ] Plan does NOT show kubernetes_ingress_v1.service_funnel["westside-ops"] (funnel=false so the funnel resource is skipped)
  • [ ] tofu apply -var-file=k3s.tfvars -lock=false succeeds
  • [ ] CI robot credentials captured from tofu output ci_robot_usernames and tofu output -json ci_robot_passwords; handed to Woodpecker pipeline ticket
  • [ ] Keycloak client secret captured from the admin console; encrypted into the k8s overlay's secrets.enc.yaml
  • [ ] Marcus's Keycloak account has the westside-ops-user role assigned
  • [ ] Namespace westside-ops exists in the cluster (kubectl get ns westside-ops)
  • [ ] Harbor project westside-ops exists (verified in Harbor UI)
  • [ ] ArgoCD application westside-ops exists but is OutOfSync (expected — the k8s overlay ticket hasn't committed manifests yet)

Files touched

  • ~/pal-e-services/terraform/k3s.tfvars (local, not committed)
  • Cluster state (Harbor project, 2 robots, namespace, harbor-creds secret, ArgoCD Application, Keycloak client, Keycloak role, Keycloak user→role assignment)

Rollback

Remove the westside-ops entry from services and keycloak_clients in tfvars. Run tofu apply -var-file=k3s.tfvars -lock=false. Terraform destroys everything it created. ArgoCD pruning may race with namespace deletion — transient errors are harmless per SERVICE_ONBOARDING.md.

Out of scope

  • The westside_ops_reader Postgres role — separate ticket
  • Application manifests (Deployment, Service, Ingress, Secrets) — k8s overlay ticket
  • The Streamlit image build — Woodpecker pipeline ticket

Dependencies

Blocked by: Streamlit spike ticket. Can proceed in parallel with repo bootstrap and Postgres role.