Skip to content

Cilium PR2: Hubble UI on hubble.fzymgc.house — Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Expose the existing hubble-ui ClusterIP service on hubble.fzymgc.house behind Authentik forward-auth, gated by a new hubble-users group.

Architecture: Dedicated hubble namespace owns Cert + Middleware + IngressRoute; IngressRoute cross-references hubble-ui.kube-system.svc:80. A new ArgoCD Application (in argocd/cluster-app/templates/hubble-ui.yaml) carries resources-finalizer.argocd.argoproj.io and CreateNamespace=true. Authentik integration via tf/authentik/hubble-ui.tf mirrors the temporal.tf pattern (groups → forward_single proxy provider → application → policy bindings); the embedded outpost on authentik-server auto-discovers the new provider — no outpost-registration step required.

Tech Stack: ArgoCD (GitOps), Traefik (IngressRoute + forward-auth Middleware), cert-manager (Certificate via vault-issuer), Authentik (proxy provider + application + groups), Hubble (already deployed via Cilium chart).

Spec: docs/engineering/specs/2026-05-12-cilium-post-migration-hardening-design.md §“PR2: Hubble UI on hubble.fzymgc.house”.


PathActionPurpose
argocd/app-configs/hubble-ui/namespace.yamlCREATENamespace hubble (managed by ArgoCD’s CreateNamespace=true, but explicit manifest keeps labels/annotations declarative)
argocd/app-configs/hubble-ui/certificate.yamlCREATEcert-manager Certificate hubble-tls (vault-issuer ClusterIssuer)
argocd/app-configs/hubble-ui/traefik-middleware.yamlCREATETraefik Middleware modern-auth (forwardAuth → authentik-server embedded outpost)
argocd/app-configs/hubble-ui/ingress-route.yamlCREATETraefik IngressRoute hubble-ui (cross-ns service ref to hubble-ui.kube-system.svc:80, router-hosts.fzymgc.house/enabled annotation)
argocd/app-configs/hubble-ui/kustomization.yamlCREATEBundle the 4 resources
argocd/cluster-app/templates/hubble-ui.yamlCREATEArgoCD Application for argocd/app-configs/hubble-ui/. MUST include resources-finalizer.argocd.argoproj.io and CreateNamespace=true
tf/authentik/hubble-ui.tfCREATEauthentik_group.hubble_users, authentik_group.hubble_admin, authentik_provider_proxy.hubble, authentik_application.hubble, two authentik_policy_binding resources
docs/operations/hubble-ui.mdCREATEOperator runbook: how to access, common queries, debugging recipes
mkdocs.ymlMODIFYAdd nav entry for docs/operations/hubble-ui.md (memory: mkdocs-nav-curated)

Task 0: Verify Pre-State and Capture Baseline

Section titled “Task 0: Verify Pre-State and Capture Baseline”

Files: none (verification only).

  • Step 0.1: Confirm you are in the correct workspace

Run:

Terminal window
jj --no-pager workspace list 2>&1 | head -6
pwd

Expected: working from a worktree on top of trunk(), no in-flight commits.

  • Step 0.2: Confirm Hubble UI is deployed and reachable in-cluster

Run:

Terminal window
kubectl get svc -n kube-system hubble-ui -o jsonpath='{.spec.type}{"\t"}{.spec.clusterIP}{"\t"}{.spec.ports[0].port}{"\n"}'
kubectl get pod -n kube-system -l k8s-app=hubble-ui -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.phase}{"\n"}{end}'

Expected:

  • Line 1: ClusterIP <ip> 80
  • Line 2: at least one hubble-ui-* Running pod.

If Hubble UI is not running, STOP. The plan assumes it’s deployed via the Cilium chart and reachable cluster-internal.

  • Step 0.3: Confirm hubble.fzymgc.house does not yet resolve to anything cluster-routed

Run:

Terminal window
dig +short hubble.fzymgc.house

Expected: empty (no existing route), OR returns a CNAME / A record but kubectl shows no matching IngressRoute (the host is fresh). If a previous attempt exists, surface it before continuing.

  • Step 0.4: Confirm the embedded outpost auto-discovery path is healthy

Run:

Terminal window
kubectl run -it --rm authentik-check --image=curlimages/curl --restart=Never --quiet -- \
curl -sS -o /dev/null -w "%{http_code}\n" \
"http://authentik-server.authentik.svc/outpost.goauthentik.io/auth/traefik" \
-H "X-Original-URL: https://temporal.fzymgc.house"

Expected: HTTP 302 (redirect to login) — confirms the embedded outpost is serving forward-auth requests. Any other status → investigate before proceeding.

  • Step 0.5: Read the existing temporal Authentik integration end-to-end

Run:

Terminal window
cat tf/authentik/temporal.tf

You will pattern-match tf/authentik/hubble-ui.tf on this file. Confirm the structure: group → admin group with parent → proxy provider (forward_single) → application → two policy bindings.


Task 1: Create app-configs/hubble-ui/ Directory

Section titled “Task 1: Create app-configs/hubble-ui/ Directory”

Files: all 5 new under argocd/app-configs/hubble-ui/.

  • Step 1.1: Start a new commit

Run:

Terminal window
jj --no-pager new -m "feat(hubble-ui): expose Hubble UI on hubble.fzymgc.house via Authentik forward-auth
Adds ArgoCD-managed Hubble UI ingress in a dedicated 'hubble' namespace.
The IngressRoute cross-references the existing hubble-ui ClusterIP service
in kube-system (deployed by the Cilium chart). Authentik forward-auth is
wired via the existing embedded outpost in authentik-server.
Companion Terraform changes in tf/authentik/hubble-ui.tf provision the
Authentik proxy provider, application, and access groups.
Refs spec: docs/engineering/specs/2026-05-12-cilium-post-migration-hardening-design.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"
  • Step 1.2: Create the namespace manifest

Write file argocd/app-configs/hubble-ui/namespace.yaml:

apiVersion: v1
kind: Namespace
metadata:
name: hubble
labels:
app.kubernetes.io/name: hubble
app.kubernetes.io/component: ui-ingress
  • Step 1.3: Create the Certificate manifest

Write file argocd/app-configs/hubble-ui/certificate.yaml:

# TLS certificate for Hubble UI
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: hubble-tls
namespace: hubble
spec:
secretName: hubble-tls
issuerRef:
name: vault-issuer
kind: ClusterIssuer
dnsNames:
- hubble.fzymgc.house
usages:
- server auth

Rationale: matches argocd/app-configs/service-ingresses/longhorn-dashboard.yaml Certificate stanza. vault-issuer is the in-cluster CA backed by Vault PKI (per tf/vault/policy-cert-manager.tf and similar).

  • Step 1.4: Create the Traefik Middleware manifest

Write file argocd/app-configs/hubble-ui/traefik-middleware.yaml:

apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: modern-auth
namespace: hubble
spec:
forwardAuth:
address: http://authentik-server.authentik.svc/outpost.goauthentik.io/auth/traefik
trustForwardHeader: true
authResponseHeaders:
- Remote-User
- Remote-Groups
- Remote-Email
- Remote-Name
- X-authentik-username
- X-authentik-groups
- X-authentik-entitlements
- X-authentik-email
- X-authentik-name
- X-authentik-uid
- X-authentik-jwt
- X-authentik-meta-jwks
- X-authentik-meta-outpost
- X-authentik-meta-provider
- X-authentik-meta-app
- X-authentik-meta-version

Rationale: matches argocd/app-configs/service-ingresses/traefik-dashboard.yaml Middleware (the most complete header allowlist of the existing patterns — strictly a superset of the longhorn header list).

  • Step 1.5: Create the IngressRoute manifest

Write file argocd/app-configs/hubble-ui/ingress-route.yaml:

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: hubble-ui
namespace: hubble
annotations:
router-hosts.fzymgc.house/enabled: "true"
spec:
entryPoints:
- websecure
routes:
- match: Host(`hubble.fzymgc.house`)
kind: Rule
middlewares:
- name: modern-auth
namespace: hubble
services:
- name: hubble-ui
namespace: kube-system
port: 80
tls:
secretName: hubble-tls

Note the cross-namespace service reference: name: hubble-ui, namespace: kube-system, port: 80. Traefik must be configured to allow cross-namespace IngressRoute service refs (it is, in this cluster — traefik-dashboard.yaml and longhorn-dashboard.yaml use same-namespace refs but the Helm chart’s providers.kubernetesCRD.allowCrossNamespace is true by default in upstream and confirmed by previous integrations).

  • Step 1.6: Create the kustomization manifest

Write file argocd/app-configs/hubble-ui/kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- certificate.yaml
- traefik-middleware.yaml
- ingress-route.yaml
  • Step 1.7: yamllint the new directory

Run:

Terminal window
yamllint argocd/app-configs/hubble-ui/
echo "exit: $?"

Expected: exit 0.

  • Step 1.8: kustomize build sanity check

Run:

Terminal window
kubectl kustomize argocd/app-configs/hubble-ui/ >/tmp/hubble-ui-render.yaml 2>&1
echo "exit: $?"
grep -c "^kind:" /tmp/hubble-ui-render.yaml

Expected: exit 0; kind: count exactly 4 (Namespace + Certificate + Middleware + IngressRoute).

  • Step 1.9: Verify commit diff

Run:

Terminal window
jj --no-pager diff --summary

Expected: 5 A entries, all under argocd/app-configs/hubble-ui/.


Task 2: Add hubble-ui Application to cluster-app

Section titled “Task 2: Add hubble-ui Application to cluster-app”

Files:

  • Create: argocd/cluster-app/templates/hubble-ui.yaml

  • Step 2.1: Start a new commit

Run:

Terminal window
jj --no-pager new -m "feat(hubble-ui): ArgoCD Application template with cascading finalizer
Adds the hubble-ui Application under cluster-app/templates/, carrying
resources-finalizer.argocd.argoproj.io so future teardown cascades
cleanly to all child resources (memory: argocd-application-deletion).
syncPolicy uses automated prune+selfHeal and CreateNamespace=true so
the dedicated 'hubble' namespace is bootstrapped on first sync.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"
  • Step 2.2: Write the Application template

Write file argocd/cluster-app/templates/hubble-ui.yaml:

# SPDX-License-Identifier: MIT-0
# ArgoCD Application for Hubble UI ingress
# Exposes the Cilium-deployed hubble-ui service on hubble.fzymgc.house
# behind Authentik forward-auth. Authentik integration is provisioned
# separately by tf/authentik/hubble-ui.tf.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: hubble-ui
namespace: argocd
annotations:
# Deploy in the standard wave (no special ordering)
argocd.argoproj.io/sync-wave: "0"
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: observability
sources:
- repoURL: https://github.com/fzymgc-house/selfhosted-cluster
targetRevision: HEAD
path: argocd/app-configs/hubble-ui
destination:
server: https://kubernetes.default.svc
namespace: hubble
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true

The observability AppProject already groups the cluster’s monitoring-related Applications (grafana-operator, monitoring-prometheus, uptime-kuma, etc.). Hubble UI fits there naturally.

  • Step 2.3: Helm-template render of cluster-app

Run (per memory cluster-app-helm-template-trap):

Terminal window
helm template argocd/cluster-app --name-template cluster-app --namespace argocd >/tmp/cluster-app-render.yaml 2>&1
echo "exit: $?"
grep -A 3 "name: hubble-ui$" /tmp/cluster-app-render.yaml | head -10

Expected: exit 0; the Application is in the rendered output with finalizer, syncPolicy, and CreateNamespace=true.

  • Step 2.4: yamllint
Terminal window
yamllint argocd/cluster-app/templates/hubble-ui.yaml
echo "exit: $?"

Expected: exit 0.

  • Step 2.5: Verify commit diff
Terminal window
jj --no-pager diff --summary

Expected: 1 A argocd/cluster-app/templates/hubble-ui.yaml.


Files:

  • Create: tf/authentik/hubble-ui.tf

  • Step 3.1: Start a new commit

Run:

Terminal window
jj --no-pager new -m "feat(tf/authentik): hubble-ui proxy provider, application, and access groups
Mirrors the temporal.tf integration pattern:
- hubble-users group (base) + hubble-admin group (parented)
- authentik_provider_proxy in forward_single mode for hubble.fzymgc.house
- authentik_application bound to the provider
- Two policy bindings (one per group)
The embedded outpost on authentik-server auto-discovers forward_single
providers, so no outpost registration is needed.
HCP Terraform will plan + apply on PR merge.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"
  • Step 3.2: Read temporal.tf one more time for line-by-line reference
Terminal window
cat tf/authentik/temporal.tf

Confirm the structure you’ll mirror.

  • Step 3.3: Write tf/authentik/hubble-ui.tf
# Hubble UI Forward Auth Integration
# Provides SSO and group-based access control for the Cilium Hubble UI dashboard
# exposed via Traefik ingress at https://hubble.fzymgc.house
# (manifests under argocd/app-configs/hubble-ui/, ArgoCD Application
# under argocd/cluster-app/templates/hubble-ui.yaml).
# Groups for Hubble UI access control
resource "authentik_group" "hubble_users" {
name = "hubble-users"
lifecycle { prevent_destroy = true }
}
resource "authentik_group" "hubble_admin" {
name = "hubble-admin"
parents = [authentik_group.hubble_users.id]
is_superuser = false
lifecycle { prevent_destroy = true }
}
# Proxy Provider for Hubble UI (Forward Auth mode)
resource "authentik_provider_proxy" "hubble" {
name = "Provider for Hubble UI"
external_host = "https://hubble.fzymgc.house"
mode = "forward_single"
authorization_flow = data.authentik_flow.default_provider_authorization_explicit_consent.id
invalidation_flow = data.authentik_flow.default_provider_invalidation_flow.id
# Token validity
access_token_validity = "hours=24"
}
# Hubble UI Application
resource "authentik_application" "hubble" {
name = "Hubble UI"
slug = "hubble"
protocol_provider = authentik_provider_proxy.hubble.id
meta_launch_url = "https://hubble.fzymgc.house"
meta_description = "Cilium network flow observability dashboard"
meta_icon = "https://cilium.io/favicon-32x32.png"
# Policy engine mode: "any" allows access if any bound policy passes
policy_engine_mode = "any"
}
# Policy to restrict access to hubble-users group
resource "authentik_policy_binding" "hubble_access" {
target = authentik_application.hubble.uuid
group = authentik_group.hubble_users.id
order = 0
}
# Grant hubble-admin direct access (workaround for broken group hierarchy)
# See: https://github.com/goauthentik/authentik/issues/15159
resource "authentik_policy_binding" "hubble_admin_access" {
target = authentik_application.hubble.uuid
group = authentik_group.hubble_admin.id
order = 1
}
  • Step 3.4: Validate Terraform
Terminal window
cd tf/authentik && terraform fmt -check -diff hubble-ui.tf && terraform validate 2>&1; cd -

Expected: exit 0. If terraform validate reports a missing provider plugin, run terraform init -backend=false once in tf/authentik/ and retry.

  • Step 3.5: Verify commit diff
Terminal window
jj --no-pager diff --summary

Expected: 1 A tf/authentik/hubble-ui.tf.


Task 4: Add Operations Runbook + mkdocs Nav

Section titled “Task 4: Add Operations Runbook + mkdocs Nav”

Files:

  • Create: docs/operations/hubble-ui.md
  • Modify: mkdocs.yml (nav)
  • Step 4.1: Start a new commit

Run:

Terminal window
jj --no-pager new -m "docs(hubble-ui): operations runbook + mkdocs nav entry
Adds a short operator-facing runbook covering how to reach Hubble UI,
common debugging queries, and the access-group model. Updates the
mkdocs.yml nav so the new doc is discoverable (memory: mkdocs-nav-curated).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>"
  • Step 4.2: Write docs/operations/hubble-ui.md
# Hubble UI Operations
Operator guide for the Cilium Hubble UI dashboard exposed at
[https://hubble.fzymgc.house](https://hubble.fzymgc.house).
## Access
- Auth: Authentik forward-auth via Traefik
- Required group: `hubble-users` (or `hubble-admin`)
- Add yourself: in Authentik UI (`auth.fzymgc.house`) → Directory → Groups → `hubble-users` → Add member
## Architecture
| Component | Location |
|---|---|
| Hubble UI service | `hubble-ui.kube-system.svc:80` (deployed by Cilium chart) |
| TLS certificate | `hubble-tls` Secret in `hubble` namespace (issued by `vault-issuer`) |
| Forward-auth middleware | `modern-auth` Middleware in `hubble` namespace |
| IngressRoute | `hubble-ui` IngressRoute in `hubble` namespace, host `hubble.fzymgc.house` |
| Authentik proxy provider | `Provider for Hubble UI` (forward_single mode) |
| ArgoCD Application | `hubble-ui` (under `argocd/cluster-app/templates/hubble-ui.yaml`) |
## Common queries
The UI supports filtering live flow data by namespace, source/destination pod,
verdict (forwarded vs dropped), HTTP method, and L4 port. Useful operator
queries:
- **Dropped flows in any namespace** — set Verdict filter to `DROPPED`. Catches
policy mismatches and connectivity issues.
- **Flows to/from a specific namespace** — set Namespace filter. Use when
validating a new CiliumNetworkPolicy rollout (PR3+).
- **Service Map view** — visualizes pod-to-pod traffic patterns. Useful for
understanding actual cross-namespace dependencies before writing policies.
## Debugging
If `https://hubble.fzymgc.house` returns 502 or stays at the Authentik login:
1. Check the IngressRoute and Middleware exist:
```bash
kubectl get ingressroute,middleware -n hubble
```
2. Confirm cert is Ready:
```bash
kubectl get certificate -n hubble hubble-tls
```
3. Confirm the upstream Hubble UI service:
```bash
kubectl get svc -n kube-system hubble-ui
kubectl get pod -n kube-system -l k8s-app=hubble-ui
```
4. Test forward-auth directly against the embedded outpost:
```bash
curl -sI -H "X-Original-URL: https://hubble.fzymgc.house" \
http://authentik-server.authentik.svc/outpost.goauthentik.io/auth/traefik
```
Expected: 302 to Authentik login flow.
## Removing access
To revoke a user, remove them from the `hubble-users` group in Authentik UI.
Group membership changes propagate within ~60s (Authentik session re-evaluates
on next forward-auth request).
  • Step 4.3: Add nav entry to mkdocs.yml

Edit mkdocs.yml. Find the Operations: section (under nav:). Add a Hubble UI entry, in alphabetical position within the Operations sub-list. The exact line to add (alphabetical placement):

- Hubble UI: operations/hubble-ui.md

If unsure of the alphabetical spot, run grep -n "operations/" mkdocs.yml and slot the new line so the file paths under Operations: remain alphabetical.

  • Step 4.4: rumdl + mkdocs build
Terminal window
rumdl check docs/operations/hubble-ui.md
echo "exit: $?"
uvx --with mkdocs-material mkdocs build --strict 2>&1 | tail -10
echo "exit: $?"

Expected: rumdl exit 0; mkdocs may abort if optional plugins (e.g., git-revision-date-localized) aren’t installed locally, but it MUST NOT report a missing-file error for operations/hubble-ui.md or an unresolved nav entry.

  • Step 4.5: Verify commit diff
Terminal window
jj --no-pager diff --summary

Expected: A docs/operations/hubble-ui.md, M mkdocs.yml.


Files: none (verification only).

  • Step 5.1: Full PR contents review
Terminal window
jj --no-pager log -r 'trunk()..@'
jj --no-pager diff -r 'trunk()..@' --summary

Expected: 4 commits, file summary:

  • 5 A files under argocd/app-configs/hubble-ui/
  • 1 A file: argocd/cluster-app/templates/hubble-ui.yaml
  • 1 A file: tf/authentik/hubble-ui.tf
  • 1 A file: docs/operations/hubble-ui.md
  • 1 M file: mkdocs.yml

Total: 8 A + 1 M.

  • Step 5.2: Confirm no incidental files
Terminal window
jj --no-pager diff -r 'trunk()..@' --summary | grep -vE "^A (argocd|tf|docs)|^M mkdocs.yml"

Expected: empty. If anything matches, restore it out.

  • Step 5.3: lefthook pre-commit
Terminal window
lefthook run pre-commit 2>&1 | tail -20
echo "exit: $?"

Expected: exit 0.

  • Step 5.4: No regression in existing Authentik integrations

Read each tf/authentik/*.tf file you DID NOT create:

Terminal window
ls tf/authentik/ | grep -v hubble-ui.tf

You should not have touched any of these. Confirm with:

Terminal window
jj --no-pager diff -r 'trunk()..@' --summary | grep "tf/authentik"

Expected: exactly one line, A tf/authentik/hubble-ui.tf.


Files: none (push + PR + post-merge verification).

  • Step 6.1: Create the bookmark and push
Terminal window
jj --no-pager bookmark create feat/cilium-pr2-hubble-ui -r @
jj --no-pager git push -b feat/cilium-pr2-hubble-ui
  • Step 6.2: Open the PR
Terminal window
gh pr create --head feat/cilium-pr2-hubble-ui --title "feat(hubble-ui): expose Hubble UI on hubble.fzymgc.house (PR2/5)" --body "$(cat <<'EOF'
## Summary
Second PR of the cilium-post-migration-hardening initiative. Exposes the existing `hubble-ui` ClusterIP service on `hubble.fzymgc.house` behind Authentik forward-auth.
**Plan:** `docs/engineering/plans/2026-05-12-cilium-pr2-hubble-ui.md` (committed in this PR).
## Changes
Four commits:
1. **Hubble UI manifests** — new `argocd/app-configs/hubble-ui/` directory with Namespace, Certificate (vault-issuer), forward-auth Middleware, and cross-namespace IngressRoute to `hubble-ui.kube-system.svc:80`.
2. **ArgoCD Application** — new `argocd/cluster-app/templates/hubble-ui.yaml` with `resources-finalizer.argocd.argoproj.io` and `CreateNamespace=true`.
3. **Authentik integration** — new `tf/authentik/hubble-ui.tf` mirroring the temporal.tf pattern: `hubble-users` + `hubble-admin` groups, forward_single proxy provider, application, two policy bindings.
4. **Docs** — operator runbook + mkdocs nav entry.
## Test plan
- [ ] HCP Terraform Authentik workspace plan shows: create 2 groups, 1 proxy provider, 1 application, 2 policy bindings. **No destroys.**
- [ ] Post-merge: `kubectl get application hubble-ui -n argocd` shows `Synced/Healthy`.
- [ ] Post-merge: `kubectl get cert -n hubble hubble-tls` reaches `Ready=True`.
- [ ] Post-merge: `dig +short hubble.fzymgc.house` resolves via Traefik.
- [ ] Post-merge: anonymous `curl -sI https://hubble.fzymgc.house/` returns `302` to Authentik login.
- [ ] Post-merge: after adding self to `hubble-users` group in Authentik UI, browser request to `https://hubble.fzymgc.house` loads the Hubble UI with live flow data.
Refs: spec in `docs/engineering/specs/2026-05-12-cilium-post-migration-hardening-design.md`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
EOF
)"

Expected: PR URL printed.

  • Step 6.3: Verify HCP Terraform plan

Wait for HCP Terraform to comment (~2 min). Confirm the Authentik workspace plan shows:

  • 2 creates: authentik_group.hubble_users, authentik_group.hubble_admin
  • 1 create: authentik_provider_proxy.hubble
  • 1 create: authentik_application.hubble
  • 2 creates: authentik_policy_binding.hubble_access, authentik_policy_binding.hubble_admin_access
  • No destroys. No drift on other resources.

If any unexpected change appears, STOP; ask before merging.

  • Step 6.4: Merge
Terminal window
gh pr merge --squash
  • Step 6.5: Watch the rollout

Run a state-change monitor (per memory cluster-reconciliation-monitoring) for the hubble-ui Application + namespace + certificate readiness. Exit when all three reach a healthy terminal state:

Terminal window
prev=""; while true; do
app=$(kubectl get application hubble-ui -n argocd -o jsonpath='{.status.sync.status}/{.status.health.status}' 2>&1)
ns=$(kubectl get ns hubble -o jsonpath='{.status.phase}' 2>&1)
cert=$(kubectl get certificate -n hubble hubble-tls -o jsonpath='{range .status.conditions[?(@.type=="Ready")]}{.status}{end}' 2>&1)
ingress=$(kubectl get ingressroute -n hubble hubble-ui -o jsonpath='{.metadata.name}' 2>&1)
cur="app=$app ns=$ns cert=$cert ingress=$ingress"
if [ "$cur" != "$prev" ]; then echo "$(date +%H:%M:%S) $cur"; prev="$cur"; fi
echo "$app $ns $cert" | grep -q "Synced/Healthy.*Active.*True" && { echo "TERMINAL: healthy"; break; }
sleep 20
done

Expected: within ~3 min, app=Synced/Healthy, ns=Active, cert=True, ingress=hubble-ui.

  • Step 6.6: End-to-end browser test
  1. In Authentik UI (auth.fzymgc.house), add yourself to the hubble-users group.

  2. Open https://hubble.fzymgc.house in a browser.

  3. Confirm: redirected to Authentik login, log in, redirected back, Hubble UI loads with live flow data.

  4. Anonymous (unauthenticated) check from CLI:

    Terminal window
    curl -sI https://hubble.fzymgc.house/ | head -5

    Expected: HTTP 302 redirect to auth.fzymgc.house.

  • Step 6.7: File no follow-up beads (none expected)

Unlike PR1, PR2 has no orphaned artifacts that defer to follow-ups. The ArgoCD finalizer + label-keyed namespace means future teardown cascades cleanly. Confirm by closing the PR2 tracking bead (filed at start of execution).


This implementation plan was checked against the spec on 2026-05-12.

  1. Spec coverage — All “Repo changes” items in spec §“PR2: Hubble UI on hubble.fzymgc.house” map to tasks above:

    • argocd/app-configs/hubble-ui/ directory with namespace, certificate, middleware, ingress-route, kustomization → Task 1
    • argocd/cluster-app/templates/hubble-ui.yaml with finalizer + CreateNamespace=true → Task 2
    • tf/authentik/ proxy provider + application + group restriction → Task 3
    • Documentation runbook + mkdocs nav update (spec §“PR2: Hubble UI … Documentation Pointers”) → Task 4
  2. Surface area beyond the spec — none expected; all changes contained to the directories spec named. If audit during implementation surfaces additional references, fold into the appropriate commit.

  3. Placeholder scan — no TBDs. Every step has exact commands and exact content.

  4. Type/name consistency — Confirmed across tasks:

    • hubble namespace name consistent across Task 1.2, 1.3, 1.4, 1.5, 2.2.
    • hubble-tls Certificate secretName and IngressRoute tls.secretName match.
    • modern-auth Middleware name consistent with namespace ref in IngressRoute.
    • hubble-users / hubble-admin group names consistent across Task 3 resources and docs/operations/hubble-ui.md.
    • Bookmark name feat/cilium-pr2-hubble-ui consistent in Task 6.1 and 6.2.