infra(cx2-5): DNS auth/NetPol substrate, air-gap landing, arm64 ARC runner + tenant landing manifests

- fc-dns: add OnePasswordItem CRD for DNS API keys + NetworkPolicy for Phase 0 auth hardening; bump dns-web image tag
- fc-landing: rewrite landing HTML to remove CDN dependencies (air-gap safe); add preview.html standalone preview
- github-runner: add TOOLCACHE_ARCH to install-ruby-toolcache.sh for arm64 support; add Dockerfile.arm64 for arm64 ARC runner image
- docs/gx10-tenant-landing: per-user Deployment+IngressRoute manifests (andrew/dustin/erik/fit/matt) + CUTOVER-RUNBOOK.md

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Andrew Stoltz
2026-06-21 11:53:26 -05:00
parent 9dd170a9ac
commit eae7b4ed7a
16 changed files with 2122 additions and 140 deletions

View File

@@ -26,6 +26,20 @@ metadata:
spec:
itemPath: "vaults/IAmWorkin/items/dns-oidc-client"
---
# Service X-Api-Key for the cert-manager ACME webhook -> dns-web call path
# (Phase 0 auth-flip). The 1Password operator resolves this item into a K8s
# Secret of the same name; the `api_key` field becomes Secret key `api_key`.
# dns-web reads it as FlowerCore__Auth__ApiKey (FcApiKey scheme, Operator
# principal); dns-acme-webhook sends it as the X-Api-Key header. Dormant while
# FlowerCore__Auth__Enabled=false (all policies allow-all).
apiVersion: onepassword.com/v1
kind: OnePasswordItem
metadata:
name: dns-api-keys
namespace: fc-dns
spec:
itemPath: "vaults/IAmWorkin/items/FlowerCore DNS API Keys"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
@@ -111,7 +125,7 @@ spec:
fsGroup: 1654
containers:
- name: dns-web
image: localhost/fc-dns-web:v20260614-wave5-isolation-6124856
image: localhost/fc-dns-web:v20260615-phase0-hybrid-f77fb94
imagePullPolicy: Never
securityContext:
readOnlyRootFilesystem: true
@@ -148,6 +162,16 @@ spec:
name: dns-oidc-client
key: client_secret
optional: true
# Service X-Api-Key accepted by the FcApiKey scheme. The standard
# key maps to an Operator principal (satisfies OperatorPolicy on the
# ACME present/cleanup endpoints). optional:true keeps the pod
# starting if the 1P operator has not yet produced the secret.
- name: FlowerCore__Auth__ApiKey
valueFrom:
secretKeyRef:
name: dns-api-keys
key: api_key
optional: true
- name: FlowerCore__Auth__Enabled
value: "false"
- name: FlowerCore__Auth__Oidc__Enabled
@@ -209,6 +233,54 @@ spec:
targetPort: 5320
type: ClusterIP
---
# Defense-in-depth ingress isolation for dns-web (Phase 0). NetworkPolicy is
# L3/L4 and cannot path-scope, so it CANNOT restrict only present/cleanup — the
# real control on those endpoints is the X-Api-Key + OperatorPolicy. This policy
# simply confines who may reach dns-web:5320 to known network zones without
# breaking any live path:
# * Traefik pods -> UI/API on dns.iamworkin.lan
# * same fc-dns namespace -> dns-acme-webhook -> present/cleanup
# * cluster pod CIDR (10.42/16) -> in-cluster Prometheus scrape, etc.
# * node + LAN CIDRs -> kubelet probes, noc1 host-net Prometheus
# Egress is intentionally left unrestricted: dns-web must reach pfSense
# (diag_command.php / HTTPS), the K8s API, Authentik OIDC discovery, step-ca,
# and DNS — over-tight egress would break the provider + auth paths.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: dns-web-ingress-isolation
namespace: fc-dns
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: dns-web
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: traefik-system
podSelector:
matchLabels:
app.kubernetes.io/name: traefik
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: fc-dns
- ipBlock:
cidr: 10.42.0.0/16
- ipBlock:
cidr: 10.0.56.0/24
- ipBlock:
cidr: 10.0.57.0/24
- ipBlock:
cidr: 10.0.58.0/24
- ipBlock:
cidr: 10.0.68.0/27
ports:
- port: 5320
protocol: TCP
---
apiVersion: v1
kind: ServiceAccount
metadata:
@@ -303,7 +375,7 @@ spec:
fsGroup: 1654
containers:
- name: dns-acme-webhook
image: localhost/fc-dns-acme-webhook:v20260614-wave5-isolation-6124856
image: localhost/fc-dns-acme-webhook:v20260615-phase0-hybrid-f77fb94
imagePullPolicy: Never
securityContext:
readOnlyRootFilesystem: true
@@ -322,6 +394,16 @@ spec:
value: /tls/tls.key
- name: FlowerCore__Dns__AcmeWebhook__ServiceBaseUrl
value: http://dns-web:5320
# X-Api-Key sent to dns-web on present/cleanup so the webhook
# authenticates as an Operator once dns-web auth is enabled.
# optional:true keeps the webhook starting before the 1P secret
# exists; the header is simply omitted when the value is empty.
- name: FlowerCore__Dns__AcmeWebhook__ApiKey
valueFrom:
secretKeyRef:
name: dns-api-keys
key: api_key
optional: true
- name: FlowerCore__Dns__AcmeWebhook__GroupName
value: acme.flowercore.io
- name: FlowerCore__Dns__AcmeWebhook__SolverName