Skip to content

Commit 1ec4a41

Browse files
committed
feat(lab-05): Traefik integration -- ForwardAuth+KC+oauth2-proxy+Prometheus scraping
1 parent dbf583c commit 1ec4a41

4 files changed

Lines changed: 309 additions & 75 deletions

File tree

.github/workflows/ci.yml

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,15 @@ jobs:
2525
echo "Validating: docker/docker-compose.lan.yml"
2626
docker compose -f docker/docker-compose.lan.yml config -q
2727
echo "OK: docker/docker-compose.lan.yml"
28-
for f in docker/docker-compose.advanced.yml \
29-
docker/docker-compose.sso.yml docker/docker-compose.integration.yml \
30-
docker/docker-compose.production.yml; do
28+
for f in docker/docker-compose.advanced.yml docker/docker-compose.sso.yml; do
29+
echo "Checking scaffold: $f"
30+
docker compose -f "$f" config --no-interpolate -q 2>&1 && echo "OK: $f" \
31+
|| echo "WARN: $f has placeholder variables (scaffold — not yet built out)"
32+
done
33+
echo "Validating: docker/docker-compose.integration.yml"
34+
docker compose -f docker/docker-compose.integration.yml config -q
35+
echo "OK: docker/docker-compose.integration.yml"
36+
for f in docker/docker-compose.production.yml; do
3137
echo "Checking scaffold: $f"
3238
docker compose -f "$f" config --no-interpolate -q 2>&1 && echo "OK: $f" \
3339
|| echo "WARN: $f has placeholder variables (scaffold — not yet built out)"
@@ -207,4 +213,37 @@ jobs:
207213

208214
- name: Cleanup
209215
if: always()
210-
run: docker compose -f docker/docker-compose.sso.yml down -v
216+
run: docker compose -f docker/docker-compose.sso.yml down -v
217+
218+
lab-05-smoke:
219+
name: Lab 05 -- Traefik + Keycloak + ForwardAuth + Prometheus
220+
runs-on: ubuntu-latest
221+
needs: validate
222+
continue-on-error: true
223+
steps:
224+
- uses: actions/checkout@v4
225+
226+
- name: Install tools
227+
run: sudo apt-get install -y curl netcat-openbsd
228+
229+
- name: Start integration stack
230+
run: docker compose -f docker/docker-compose.integration.yml up -d
231+
232+
- name: Wait for Keycloak
233+
run: timeout 200 bash -c 'until curl -sf http://localhost:8080/health/ready | grep -q UP; do sleep 5; done'
234+
235+
- name: Wait for Traefik
236+
run: timeout 60 bash -c 'until curl -sf http://localhost:8080/api/version | grep -q Version; do sleep 3; done'
237+
238+
- name: Run Lab 18-05 test script
239+
env:
240+
KC_PASS: "Lab05Password!"
241+
run: bash tests/labs/test-lab-18-05.sh
242+
243+
- name: Collect logs on failure
244+
if: failure()
245+
run: docker compose -f docker/docker-compose.integration.yml logs
246+
247+
- name: Cleanup
248+
if: always()
249+
run: docker compose -f docker/docker-compose.integration.yml down -v
Lines changed: 152 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,160 @@
1-
# Lab 05 — Advanced Integration: traefik with full IT-Stack ecosystem
2-
---
31
services:
2+
3+
# ── Keycloak DB ───────────────────────────────────────────────────
4+
kc-db:
5+
image: postgres:16-alpine
6+
environment:
7+
POSTGRES_DB: keycloak
8+
POSTGRES_USER: kcadmin
9+
POSTGRES_PASSWORD: Lab05Password!
10+
networks:
11+
- kc-db-net
12+
volumes:
13+
- kc-db-int:/var/lib/postgresql/data
14+
healthcheck:
15+
test: ["CMD-SHELL", "pg_isready -U kcadmin"]
16+
interval: 5s
17+
timeout: 3s
18+
retries: 20
19+
20+
# ── Keycloak SSO ──────────────────────────────────────────────────
21+
keycloak:
22+
image: quay.io/keycloak/keycloak:24.0
23+
command: start-dev
24+
depends_on:
25+
kc-db:
26+
condition: service_healthy
27+
environment:
28+
KC_BOOTSTRAP_ADMIN_USERNAME: admin
29+
KC_BOOTSTRAP_ADMIN_PASSWORD: Lab05Password!
30+
KC_DB: postgres
31+
KC_DB_URL: "jdbc:postgresql://kc-db:5432/keycloak"
32+
KC_DB_USERNAME: kcadmin
33+
KC_DB_PASSWORD: Lab05Password!
34+
KC_HTTP_PORT: "8080"
35+
KC_HOSTNAME_STRICT: "false"
36+
KC_PROXY: edge
37+
networks:
38+
- proxy-int-net
39+
- kc-db-net
40+
healthcheck:
41+
test: ["CMD-SHELL", "curl -sf http://localhost:8080/health/ready || exit 1"]
42+
interval: 10s
43+
timeout: 5s
44+
retries: 30
45+
start_period: 60s
46+
labels:
47+
- "traefik.enable=true"
48+
- "traefik.http.routers.keycloak.rule=PathPrefix(`/realms`) || PathPrefix(`/admin/realms`)"
49+
- "traefik.http.routers.keycloak.entrypoints=web"
50+
- "traefik.http.services.keycloak.loadbalancer.server.port=8080"
51+
52+
# ── oauth2-proxy (ForwardAuth) ────────────────────────────────────
53+
oauth2-proxy:
54+
image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0
55+
depends_on:
56+
keycloak:
57+
condition: service_healthy
58+
command:
59+
- --provider=oidc
60+
- --oidc-issuer-url=http://keycloak:8080/realms/it-stack
61+
- --client-id=oauth2-proxy
62+
- --client-secret=Lab05Password!
63+
- --cookie-secret=YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4
64+
- --email-domain=*
65+
- --upstream=static://202
66+
- --http-address=0.0.0.0:4180
67+
- --redirect-url=http://localhost:4180/oauth2/callback
68+
- --cookie-secure=false
69+
- --skip-jwt-bearer-tokens=true
70+
networks:
71+
- proxy-int-net
72+
labels:
73+
- "traefik.enable=true"
74+
- "traefik.http.routers.oauth2.rule=PathPrefix(`/oauth2`)"
75+
- "traefik.http.routers.oauth2.entrypoints=web"
76+
- "traefik.http.services.oauth2.loadbalancer.server.port=4180"
77+
78+
# ── Protected app (requires SSO) ─────────────────────────────────
79+
app-protected:
80+
image: traefik/whoami:latest
81+
environment:
82+
WHOAMI_NAME: "protected-app"
83+
networks:
84+
- proxy-int-net
85+
labels:
86+
- "traefik.enable=true"
87+
- "traefik.http.routers.app-protected.rule=PathPrefix(`/protected`)"
88+
- "traefik.http.routers.app-protected.entrypoints=web"
89+
- "traefik.http.routers.app-protected.middlewares=forward-auth,secure-headers"
90+
- "traefik.http.middlewares.forward-auth.forwardauth.address=http://oauth2-proxy:4180"
91+
- "traefik.http.middlewares.forward-auth.forwardauth.trustForwardHeader=true"
92+
- "traefik.http.middlewares.secure-headers.headers.stsSeconds=31536000"
93+
- "traefik.http.middlewares.secure-headers.headers.contentTypeNosniff=true"
94+
- "traefik.http.services.app-protected.loadbalancer.server.port=80"
95+
96+
# ── Public app (no auth) ──────────────────────────────────────────
97+
app-public:
98+
image: traefik/whoami:latest
99+
environment:
100+
WHOAMI_NAME: "public-app"
101+
networks:
102+
- proxy-int-net
103+
labels:
104+
- "traefik.enable=true"
105+
- "traefik.http.routers.app-public.rule=PathPrefix(`/public`)"
106+
- "traefik.http.routers.app-public.entrypoints=web"
107+
- "traefik.http.services.app-public.loadbalancer.server.port=80"
108+
109+
# ── Prometheus: scrapes Traefik metrics ───────────────────────────
110+
prometheus:
111+
image: prom/prometheus:latest
112+
command:
113+
- --config.file=/etc/prometheus/prometheus.yml
114+
- --storage.tsdb.retention.time=1h
115+
volumes:
116+
- ./integration/prometheus.yml:/etc/prometheus/prometheus.yml:ro
117+
ports:
118+
- "9090:9090"
119+
networks:
120+
- proxy-int-net
121+
122+
# ── Traefik ───────────────────────────────────────────────────────
4123
traefik:
5124
image: traefik:v3.0
6-
container_name: it-stack-traefik
7-
restart: unless-stopped
125+
command:
126+
- --api.dashboard=true
127+
- --api.insecure=true
128+
- --entrypoints.web.address=:80
129+
- --entrypoints.metrics.address=:8082
130+
- --metrics.prometheus=true
131+
- --metrics.prometheus.entrypoint=metrics
132+
- --metrics.prometheus.addRoutersLabels=true
133+
- --metrics.prometheus.addServicesLabels=true
134+
- --providers.docker=true
135+
- --providers.docker.exposedbydefault=false
136+
- --accesslog=true
137+
- --accesslog.format=json
8138
ports:
9-
- "80:$firstPort"
10-
environment:
11-
- IT_STACK_ENV=lab-05-integration
12-
- KEYCLOAK_URL=
13-
- DB_HOST=
14-
- REDIS_HOST=
15-
- SMTP_HOST=
16-
- GRAYLOG_HOST=
17-
extra_hosts:
18-
- "lab-id1:10.0.50.11"
19-
- "lab-db1:10.0.50.12"
20-
- "lab-proxy1:10.0.50.15"
139+
- "80:80"
140+
- "8080:8080"
141+
- "8082:8082"
142+
volumes:
143+
- /var/run/docker.sock:/var/run/docker.sock:ro
144+
- traefik-logs:/var/log/traefik
21145
networks:
22-
- it-stack-net
146+
- proxy-int-net
147+
depends_on:
148+
keycloak:
149+
condition: service_healthy
23150

24151
networks:
25-
it-stack-net:
152+
proxy-int-net:
26153
driver: bridge
154+
kc-db-net:
155+
driver: bridge
156+
internal: true
157+
158+
volumes:
159+
kc-db-int:
160+
traefik-logs:

docker/integration/prometheus.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
global:
2+
scrape_interval: 15s
3+
evaluation_interval: 15s
4+
5+
scrape_configs:
6+
- job_name: traefik
7+
static_configs:
8+
- targets: ["traefik:8082"]
9+
metrics_path: /metrics

0 commit comments

Comments
 (0)