FLEX-WP-0013. Production had been rolled back to sha256:c25fc34a
(four actions), so tenant.update / tenant.retire / tenant.reactivate
denied unknown_action. Re-pin and apply the previously-live
sha256:9320df39 image (e9911eb). Live probe after restore: all seven
actions allow; misspelled action and unknown subject still deny.
user-engine pin unchanged. TEN-WP-0006 guardrail actions not added.
97 lines
4.8 KiB
Markdown
97 lines
4.8 KiB
Markdown
# flex-auth production deployment
|
|
|
|
The sanctioned promotion path is the Railiance overlay in
|
|
[`../railiance/`](../railiance/README.md) (`railiance/app.toml`,
|
|
`charts/flex-auth`, `values/*.yaml`). These flattened files are the
|
|
emergency kubectl path recovered on 2026-08-11 from live
|
|
`last-applied-configuration`, kept so a rollback does not depend on a
|
|
cluster annotation or on Helm history.
|
|
|
|
Manifests for the two cluster-local flex-auth policy-decision services.
|
|
|
|
| File | Deployment | Consumer | Service DNS |
|
|
| --- | --- | --- | --- |
|
|
| `flex-auth-tenant-engine.yaml` | `flex-auth-tenant-engine` | tenant-engine write API | `flex-auth-tenant-engine.flex-auth.svc.cluster.local:8080` |
|
|
| `flex-auth-user-engine.yaml` | `flex-auth-user-engine` | user-engine portal | `flex-auth-user-engine.flex-auth.svc.cluster.local:8080` |
|
|
|
|
Each file is a three-document manifest: `Deployment`, `Service`, and a
|
|
default-deny `NetworkPolicy` whose ingress is restricted to the one approved
|
|
consumer workload and which permits no egress.
|
|
|
|
### A harmless diff on apply
|
|
|
|
`kubectl apply` reports the two NetworkPolicies as `configured` rather than
|
|
`unchanged`, every time. That is not drift: the manifests carry an explicit
|
|
`egress: []`, which the API server normalises away on read. With
|
|
`policyTypes: [Ingress, Egress]` and no egress rules, deny-all egress holds
|
|
either way. The empty list is kept because it states the intent to a reader
|
|
instead of leaving it implicit. Deployments and Services do round-trip as
|
|
`unchanged`.
|
|
|
|
## One image, two deployments
|
|
|
|
Both Deployments run the **same image repository** and differ only in their
|
|
`--registry` / `--policy` arguments. The `Containerfile` does
|
|
`COPY examples /opt/flex-auth/examples`, so every image contains *every*
|
|
consumer's policy package; the arguments select which one that instance
|
|
serves.
|
|
|
|
Consequence worth remembering: rebuilding to pick up one consumer's policy
|
|
change also re-bakes every other consumer's policy into the new image. The
|
|
two Deployments are pinned to **different digests** precisely so that one can
|
|
be rolled without moving the other. Roll only the Deployment whose policy
|
|
actually changed.
|
|
|
|
## Rolling out a policy change
|
|
|
|
The policy packages are baked into the image, not mounted from a ConfigMap,
|
|
so a policy change requires a rebuild — there is no hot reload.
|
|
|
|
**Do not build images on a workstation.** The fleet builds in CI so that an
|
|
artifact's provenance is a forge revision rather than someone's working tree.
|
|
`.forgejo/workflows/image.yaml` handles it, and `examples/**` is one of its
|
|
trigger paths precisely because policy changes are image changes.
|
|
|
|
```bash
|
|
# 1. Push the commit you intend to ship; CI builds it on the container-build
|
|
# runner and pushes :latest and :main-<short-sha>
|
|
git push origin main
|
|
|
|
# 2. Take the immutable digest from the workflow's "Report immutable digest"
|
|
# step -- deploy by digest, never by tag
|
|
|
|
# 3. Edit the image digest in the relevant manifest, then apply
|
|
kubectl apply -f deploy/flex-auth-<consumer>.yaml
|
|
kubectl -n flex-auth rollout status deploy/flex-auth-<consumer> --timeout=120s
|
|
|
|
# 4. Verify the new policy actually took effect, from outside the cluster
|
|
kubectl -n flex-auth port-forward svc/flex-auth-<consumer> 19099:8080 &
|
|
curl -s -X POST http://127.0.0.1:19099/v1/check \
|
|
-H 'Content-Type: application/json' \
|
|
-d @examples/<consumer>/<a request that exercises the change>.json
|
|
```
|
|
|
|
Step 4 is not optional. Because the policy ships inside the image, a
|
|
successful `rollout status` only proves the container started — it says
|
|
nothing about which policy revision is being served.
|
|
|
|
## Rollback
|
|
|
|
```bash
|
|
kubectl -n flex-auth rollout undo deploy/flex-auth-<consumer>
|
|
```
|
|
|
|
If the ReplicaSet history has been pruned, re-apply the manifest with the
|
|
last-known-good digest below.
|
|
|
|
| Deployment | Last-known-good digest | Policy state |
|
|
| --- | --- | --- |
|
|
| `flex-auth-tenant-engine` | `sha256:9320df394a642eff24da8af4a0ee8886a7bb78b0f14d8ee1deeb30ea8eeeaba7` | **live 2026-08-16** — seven-action policy restored (FLEX-WP-0013); CI-built from `e9911eb` |
|
|
| `flex-auth-tenant-engine` *(rollback)* | `sha256:c25fc34a6cd7e64d955f8723ec70e176a583d5ae71d76280c4e2d89fba0fe0aa` | four-action policy; lifecycle actions deny `unknown_action` |
|
|
| `flex-auth-user-engine` | `sha256:1f5290376dc5fcf456dc7a785e394d8b90949dabecd1d3e856f38557149bb5f4` | **current** — FLEX-WP-0009-T04, nine fixtures (incl. registration-applicant) verified live 2026-08-16 |
|
|
| `flex-auth-user-engine` *(previous)* | `sha256:a31961c45215aa6baf3bc748c6741ab703c2c8325e61aa7983a355026195e51b` | FLEX-WP-0009-T03, six fixtures verified live 2026-08-10 |
|
|
|
|
Rolling back the tenant-engine service to `c25fc34a…` restores fail-closed
|
|
behaviour for the lifecycle actions — tenant-engine's lifecycle endpoints
|
|
return `403 write_denied` rather than writing. That is a safe failure mode,
|
|
not an outage of the older four actions, which keep working.
|