The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.
Follows the import procedure in README.md.
source/ the originating repository verbatim — 78 documents, 28 SVGs,
8 manifests, plus .source-revision recording the commit
final/ the SSOT
document.md 729 lines written from the 29 experiment documents, not
concatenated: what was predicted, what was measured, and
where the measurement itself was wrong
evidence/raw 125 outputs, flattened to <experiment>__<file> because
the originals collided (01-baseline.txt appeared three
times) and the audit only globs the top level
evidence/meta one per raw file; command and exitCode are null and the
README says why rather than inventing them
evidence/browser 22 captures
assets/ three diagrams through techviz
.techviz/ their VizSpecs
A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.
Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.
verify-pipeline.py passes. audit-records.py reports no issues.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
114 lines
3.4 KiB
YAML
114 lines
3.4 KiB
YAML
# Header echo workload for the two-hop proxy contract measurement.
|
|
#
|
|
# browser -> host nginx (TLS termination) -> Traefik -> this pod
|
|
#
|
|
# The image is built from backend/ and imported straight into each node's
|
|
# containerd, so imagePullPolicy must stay Never. See scripts/build-and-import.sh.
|
|
apiVersion: v1
|
|
kind: Namespace
|
|
metadata:
|
|
name: header-lab
|
|
---
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: echo
|
|
namespace: header-lab
|
|
spec:
|
|
replicas: 2
|
|
selector:
|
|
matchLabels:
|
|
app: echo
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: echo
|
|
spec:
|
|
# One replica per node so the sticky-session switch on the host nginx
|
|
# upstream has something observable to route between.
|
|
topologySpreadConstraints:
|
|
- maxSkew: 1
|
|
topologyKey: kubernetes.io/hostname
|
|
whenUnsatisfiable: ScheduleAnyway
|
|
labelSelector:
|
|
matchLabels:
|
|
app: echo
|
|
containers:
|
|
- name: echo
|
|
image: keycloak-pattern-api:lab
|
|
imagePullPolicy: Never
|
|
ports:
|
|
- containerPort: 8081
|
|
name: http
|
|
env:
|
|
- name: SERVER_PORT
|
|
value: "8081"
|
|
# "none" makes the app report the raw connection, so scheme/secure/
|
|
# requestUrl show what arrives without any forwarded-header handling.
|
|
# Set to "native" and redeploy to see the same request interpreted
|
|
# with X-Forwarded-* honoured. Keycloak's KC_PROXY_HEADERS is the
|
|
# same opt-in, which is why measuring both sides matters here.
|
|
- name: SERVER_FORWARD_HEADERS_STRATEGY
|
|
value: "native"
|
|
# The JVM sizes its heap from the container limit, not the host.
|
|
- name: JAVA_TOOL_OPTIONS
|
|
value: "-XX:MaxRAMPercentage=70"
|
|
# /api/echo is permitAll, so the JWT decoder is never exercised.
|
|
# These stay pointed at the future Keycloak service name.
|
|
- name: SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI
|
|
value: "https://auth.hyeonworks.com/realms/keycloak-patterns"
|
|
- name: SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI
|
|
value: "https://auth.hyeonworks.com/realms/keycloak-patterns/protocol/openid-connect/certs"
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /actuator/health/readiness
|
|
port: http
|
|
initialDelaySeconds: 15
|
|
periodSeconds: 5
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /actuator/health/liveness
|
|
port: http
|
|
initialDelaySeconds: 45
|
|
periodSeconds: 15
|
|
resources:
|
|
requests:
|
|
memory: 320Mi
|
|
cpu: 100m
|
|
limits:
|
|
memory: 512Mi
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
name: echo
|
|
namespace: header-lab
|
|
spec:
|
|
selector:
|
|
app: echo
|
|
ports:
|
|
- port: 8081
|
|
targetPort: http
|
|
name: http
|
|
---
|
|
apiVersion: networking.k8s.io/v1
|
|
kind: Ingress
|
|
metadata:
|
|
name: echo
|
|
namespace: header-lab
|
|
spec:
|
|
# k3s ships Traefik as the default ingress controller. Keeping it is what
|
|
# makes this lab a faithful two-hop replica.
|
|
ingressClassName: traefik
|
|
rules:
|
|
- host: app1.hyeonworks.com
|
|
http:
|
|
paths:
|
|
- path: /api
|
|
pathType: Prefix
|
|
backend:
|
|
service:
|
|
name: echo
|
|
port:
|
|
number: 8081
|