151 lines
6.0 KiB
YAML
151 lines
6.0 KiB
YAML
# Apps do tenant demo:
|
|
# - backend: Spring Boot OAuth2 Resource Server (imagem athletic-map-backend:1.2, porta 8083)
|
|
# - frontend: SPA OIDC Authorization Code + PKCE (keycloak-js) chamando /api/me
|
|
# - bff: stub (whoami)
|
|
---
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata: { name: backend, namespace: demo-prod }
|
|
spec:
|
|
replicas: 1
|
|
selector: { matchLabels: { app: backend } }
|
|
template:
|
|
metadata: { labels: { app: backend } }
|
|
spec:
|
|
containers:
|
|
- name: backend
|
|
image: docker.io/library/athletic-map-backend:1.2
|
|
imagePullPolicy: Never
|
|
env:
|
|
- { name: ATM_JWK_SET_URI, value: "http://keycloak:8080/realms/athleticmap/protocol/openid-connect/certs" }
|
|
- { name: ATM_ISSUER, value: "https://auth-demo.athleticmap.influxdigital.com.br/realms/athleticmap" }
|
|
- { name: ATM_TENANT, value: "demo" }
|
|
ports: [{ containerPort: 8083 }]
|
|
readinessProbe:
|
|
httpGet: { path: /api/public/health, port: 8083 }
|
|
initialDelaySeconds: 20
|
|
periodSeconds: 10
|
|
failureThreshold: 24
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata: { name: backend, namespace: demo-prod }
|
|
spec:
|
|
selector: { app: backend }
|
|
ports: [{ port: 80, targetPort: 8083 }]
|
|
---
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata: { name: bff, namespace: demo-prod }
|
|
spec:
|
|
replicas: 1
|
|
selector: { matchLabels: { app: bff } }
|
|
template:
|
|
metadata: { labels: { app: bff } }
|
|
spec:
|
|
containers:
|
|
- name: whoami
|
|
image: traefik/whoami:latest
|
|
args: ["--name", "athletic-map-bff demo (stub)"]
|
|
ports: [{ containerPort: 80 }]
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata: { name: bff, namespace: demo-prod }
|
|
spec:
|
|
selector: { app: bff }
|
|
ports: [{ port: 80, targetPort: 80 }]
|
|
---
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata: { name: frontend-index, namespace: demo-prod }
|
|
data:
|
|
index.html: |
|
|
<!doctype html>
|
|
<html lang="pt-br"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Athletic Map — Demo</title>
|
|
<script src="https://auth-demo.athleticmap.influxdigital.com.br/js/keycloak.js"></script>
|
|
<style>
|
|
body{font-family:system-ui,sans-serif;background:#155eef;color:#eaf2ff;margin:0;padding:2rem}
|
|
.card{max-width:760px;margin:2rem auto;background:#0e2f57;border-top:4px solid #ffd23f;border-radius:12px;padding:2rem;box-shadow:0 12px 40px rgba(0,0,0,.4)}
|
|
h1{color:#ffd23f;margin:0 0 .3rem}.muted{color:#bcd3f5}b{color:#fff}
|
|
pre{background:#06182e;padding:1rem;border-radius:8px;overflow:auto;color:#9fe8aa;font-size:.85rem}
|
|
button{background:#188bf6;color:#fff;border:0;border-radius:8px;padding:.6rem 1.2rem;cursor:pointer;font-weight:700}
|
|
.tag{display:inline-block;background:#0a2547;border-radius:20px;padding:.15rem .7rem;margin:.15rem;font-size:.8rem}
|
|
</style></head>
|
|
<body><div class="card" id="app"><p class="muted">Carregando…</p></div>
|
|
<script>
|
|
const kc = new Keycloak({ url: 'https://auth-demo.athleticmap.influxdigital.com.br', realm: 'athleticmap', clientId: 'spa' });
|
|
kc.init({ onLoad: 'login-required', pkceMethod: 'S256', checkLoginIframe: false }).then(function (auth) {
|
|
if (!auth) { document.getElementById('app').innerHTML = '<p>Nao autenticado.</p>'; return; }
|
|
var t = kc.tokenParsed;
|
|
var roles = ((t.realm_access && t.realm_access.roles) || []).map(function (r) { return '<span class="tag">' + r + '</span>'; }).join('');
|
|
document.getElementById('app').innerHTML =
|
|
'<h1>Athletic Map</h1>' +
|
|
'<p class="muted">tenant <b>demo</b> · login OIDC (Authorization Code + PKCE)</p>' +
|
|
'<p>Bem-vindo, <b>' + t.preferred_username + '</b></p>' +
|
|
'<p>Roles no token: ' + roles + '</p>' +
|
|
'<h3>Backend <code>/api/me</code> (JWT validado no servidor):</h3>' +
|
|
'<pre id="me">chamando…</pre>' +
|
|
'<button onclick="kc.logout()">Sair</button>';
|
|
fetch('/api/me', { headers: { Authorization: 'Bearer ' + kc.token } })
|
|
.then(function (r) { return r.json(); })
|
|
.then(function (me) { document.getElementById('me').textContent = JSON.stringify(me, null, 2); })
|
|
.catch(function (e) { document.getElementById('me').textContent = 'erro: ' + e; });
|
|
}).catch(function (e) { document.getElementById('app').innerHTML = '<p>Erro ao iniciar Keycloak: ' + e + '</p>'; });
|
|
</script></body></html>
|
|
---
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata: { name: frontend, namespace: demo-prod }
|
|
spec:
|
|
replicas: 1
|
|
selector: { matchLabels: { app: frontend } }
|
|
template:
|
|
metadata:
|
|
labels: { app: frontend }
|
|
annotations: { configVersion: "spa-2" }
|
|
spec:
|
|
containers:
|
|
- name: nginx
|
|
image: nginx:alpine
|
|
ports: [{ containerPort: 80 }]
|
|
volumeMounts:
|
|
- { name: html, mountPath: /usr/share/nginx/html }
|
|
volumes:
|
|
- name: html
|
|
configMap: { name: frontend-index }
|
|
---
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata: { name: frontend, namespace: demo-prod }
|
|
spec:
|
|
selector: { app: frontend }
|
|
ports: [{ port: 80, targetPort: 80 }]
|
|
---
|
|
apiVersion: networking.k8s.io/v1
|
|
kind: Ingress
|
|
metadata:
|
|
name: demo
|
|
namespace: demo-prod
|
|
annotations:
|
|
cert-manager.io/cluster-issuer: letsencrypt-prod
|
|
traefik.ingress.kubernetes.io/router.middlewares: demo-prod-redirect-https@kubernetescrd
|
|
spec:
|
|
ingressClassName: traefik
|
|
tls:
|
|
- hosts:
|
|
- demo.athleticmap.influxdigital.com.br
|
|
- auth-demo.athleticmap.influxdigital.com.br
|
|
secretName: demo-tls
|
|
rules:
|
|
- host: demo.athleticmap.influxdigital.com.br
|
|
http:
|
|
paths:
|
|
- { path: /api, pathType: Prefix, backend: { service: { name: backend, port: { number: 80 } } } }
|
|
- { path: /, pathType: Prefix, backend: { service: { name: frontend, port: { number: 80 } } } }
|
|
- host: auth-demo.athleticmap.influxdigital.com.br
|
|
http:
|
|
paths:
|
|
- { path: /, pathType: Prefix, backend: { service: { name: keycloak, port: { number: 8080 } } } }
|