Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64175266df | ||
|
|
bb8fd9333d | ||
|
|
42957abfed | ||
|
|
5026b79fc0 | ||
|
|
b42db5e93b | ||
|
|
aee01c9e90 | ||
|
|
4a55ee71a9 | ||
|
|
1341645cf5 | ||
|
|
a289aa2799 | ||
|
|
a63c901407 |
@@ -11,3 +11,6 @@ e2e/node_modules/
|
|||||||
google-e2e/node_modules/
|
google-e2e/node_modules/
|
||||||
frontend/node_modules/
|
frontend/node_modules/
|
||||||
frontend/dist/
|
frontend/dist/
|
||||||
|
|
||||||
|
token-mediator/target
|
||||||
|
bff/target
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# AP1 internal SPA direct: Google-federated profile
|
||||||
|
|
||||||
|
```text
|
||||||
|
SPA -> Keycloak -> Google
|
||||||
|
SPA <- Keycloak code/token <- Keycloak
|
||||||
|
SPA -> Spring API with Keycloak access token
|
||||||
|
```
|
||||||
|
|
||||||
|
Google은 upstream authentication만 담당한다. SPA와 Resource Server의 trust
|
||||||
|
anchor는 계속 Keycloak issuer/JWKS/audience다. 따라서 Spring이 Google
|
||||||
|
ID token을 직접 받거나 Google JWKS를 검증하지 않는다.
|
||||||
|
|
||||||
|
추가 운영 항목은 Google client secret, exact broker redirect URI, safe First
|
||||||
|
Broker Login, `sub` account key, claim mapper다. 로컬에서는 두 번째 Keycloak
|
||||||
|
realm이 Google 역할을 하므로 외부 credential 없이 같은 hop을 재현한다.
|
||||||
|
|
||||||
|
`verify-internal-spa-google-contract.sh`는 broker 설정과 기존 AP1 SPA의
|
||||||
|
zero-change federation E2E를 함께 실행한다.
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Single EC2 with Google federation
|
||||||
|
|
||||||
|
local-identity single-EC2 topology에 다음 네 요소가 추가된다.
|
||||||
|
|
||||||
|
1. 고정 public HTTPS hostname
|
||||||
|
2. trusted TLS/reverse proxy와 Keycloak public hostname
|
||||||
|
3. Google OAuth client의 exact broker callback
|
||||||
|
4. Keycloak Google IdP secret과 safe First Broker Login policy
|
||||||
|
|
||||||
|
학습 profile은 Cloudflare named tunnel을 사용할 수 있어 EC2 inbound에
|
||||||
|
Keycloak 8080을 열지 않는다. containerized cloudflared의 origin은
|
||||||
|
`127.0.0.1`이 아니라 Compose service DNS의 reverse proxy다.
|
||||||
|
|
||||||
|
실제 Google secret은 `.env`/secret store에만 두며 realm export나 Git에
|
||||||
|
포함하지 않는다. credential이 없는 CI는 mock OIDC realm으로 broker 계약을
|
||||||
|
검증하고, 실제 Google callback은 사용자 소유 credential/domain 환경에서
|
||||||
|
별도 실행한다.
|
||||||
|
|
||||||
|
`verify-single-ec2-google-profile.sh`는 tunnel, proxy headers, redirect URI,
|
||||||
|
broker realm 계약을 묶어 검증한다.
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Single EC2, AP1, no Google
|
||||||
|
|
||||||
|
한 VM의 Docker Compose에 PostgreSQL, Keycloak, Spring API, nginx SPA를 둔다.
|
||||||
|
외부 진입점만 nginx/TLS proxy로 제한하고 Keycloak 8080, API 8081, PostgreSQL은
|
||||||
|
loopback 또는 Docker private network에 둔다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
Internet :443 -> TLS proxy/SPA
|
||||||
|
|-> Spring API:8081
|
||||||
|
Browser ----------->|-> Keycloak:8080 (public auth path만 proxy)
|
||||||
|
Keycloak ----------> PostgreSQL:5432
|
||||||
|
```
|
||||||
|
|
||||||
|
이 profile은 Google credential과 tunnel이 필요 없다. EC2 보안 그룹은 22
|
||||||
|
(관리 정책에 따른 제한), 80/443만 열고 container 내부 포트를 공개하지 않는다.
|
||||||
|
backup 대상은 PostgreSQL 데이터와 realm/config/secret이며 Keycloak 개발
|
||||||
|
모드 `start-dev`는 production에서 사용하지 않는다.
|
||||||
|
|
||||||
|
`verify-single-ec2-no-google.sh`는 Compose rendering, loopback binding,
|
||||||
|
AP1 local-identity 계약을 확인한다.
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# Three-leg trust chain
|
||||||
|
|
||||||
|
| Hop | 발급자/행위자 | 검증자 | 핵심 검증 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | Google/mock IdP | Keycloak broker | signature, upstream issuer, client audience, expiry, nonce |
|
||||||
|
| 2 | Keycloak | SPA | state, PKCE code binding, Keycloak issuer, token response |
|
||||||
|
| 3 | Keycloak access token | Spring Resource Server | Keycloak signature/JWKS, issuer, expiry, API audience, roles |
|
||||||
|
|
||||||
|
Keycloak은 upstream ID token을 그대로 SPA에 전달하지 않는다. upstream
|
||||||
|
identity를 검증·연결한 뒤 자신의 realm key로 새 token을 발급한다. 그 결과
|
||||||
|
backend의 trust store와 issuer 설정은 Google 로그인 여부와 무관하게 하나다.
|
||||||
|
|
||||||
|
`verify-three-leg-trust-chain.sh`는 두 realm의 discovery issuer가 서로 다르고,
|
||||||
|
Spring 코드가 main Keycloak issuer만 신뢰하는지 확인한다. 실제 hop 전체는
|
||||||
|
`verify-federation-spa-zero-change.sh`로 검증한다.
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
./scripts/verify-google-broker-config.sh
|
||||||
|
./scripts/verify-federation-spa-zero-change.sh
|
||||||
|
echo "AP1 Google-federated profile verified"
|
||||||
Executable
+8
@@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
./scripts/verify-public-tunnel-config.sh
|
||||||
|
./scripts/verify-reverse-proxy-headers.sh
|
||||||
|
./scripts/verify-google-redirect-uri-policy.sh
|
||||||
|
./scripts/verify-google-broker-config.sh
|
||||||
|
echo "Single-EC2 Google federation deployment profile verified"
|
||||||
Executable
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
rendered="$(docker compose config --format json)"
|
||||||
|
printf '%s\n' "$rendered" | jq -e '
|
||||||
|
(.services.keycloak.ports[] | .host_ip == "127.0.0.1" and .target == 8080)
|
||||||
|
and
|
||||||
|
(.services.app.ports[] | .host_ip == "127.0.0.1" and .target == 8081)
|
||||||
|
and
|
||||||
|
(.networks["keycloak-net"].driver == "bridge")
|
||||||
|
' >/dev/null
|
||||||
|
|
||||||
|
./scripts/verify-internal-spa-no-google-contract.sh
|
||||||
|
echo "Single-EC2 local-identity topology verified"
|
||||||
Executable
+19
@@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
base="${KEYCLOAK_URL:-http://localhost:8080}"
|
||||||
|
main_issuer="$base/realms/keycloak-patterns"
|
||||||
|
mock_issuer="$base/realms/mock-google"
|
||||||
|
|
||||||
|
test "$(curl -fsS "$main_issuer/.well-known/openid-configuration" | jq -r .issuer)" \
|
||||||
|
= "$main_issuer"
|
||||||
|
test "$(curl -fsS "$mock_issuer/.well-known/openid-configuration" | jq -r .issuer)" \
|
||||||
|
= "$mock_issuer"
|
||||||
|
|
||||||
|
rg -Fq 'SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI:' docker-compose.yml
|
||||||
|
if rg -qi 'accounts\\.google\\.com|realms/mock-google' backend/src/main; then
|
||||||
|
echo "backend must trust only the Keycloak issuer, not the upstream IdP" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Three-leg trust anchors verified: upstream -> Keycloak -> Resource Server"
|
||||||
Reference in New Issue
Block a user