Files
llm-wiki/raw/diagrams/keycloak-patterns/architecture-p3b-single-ec2-google-2026-05-26.drawio
T

107 lines
10 KiB
Plaintext

<mxfile host="Claude Code" agent="ca-superpowers + diagram-standards v2 minimalist" version="24.0.0" type="device">
<diagram name="P3B-Single-EC2-Google" id="p3b">
<mxGraphModel dx="1200" dy="700" grid="0" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1200" pageHeight="800" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="title" value="P3B — Single EC2 + Google federation" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=20;fontStyle=1;fontFamily=Pretendard,Helvetica;fontColor=#1F2937;" vertex="1" parent="1">
<mxGeometry x="40" y="20" width="800" height="32" as="geometry" />
</mxCell>
<mxCell id="subtitle" value="P3A 에 Google 을 붙이려면 왜 EC2 외부 HTTPS endpoint(tunnel/RP)가 강제되는가?" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=12;fontStyle=0;fontFamily=Pretendard,Helvetica;fontColor=#6B7280;" vertex="1" parent="1">
<mxGeometry x="40" y="52" width="1000" height="20" as="geometry" />
</mxCell>
<!-- Public HTTPS zone (강조 — Google 요구 사항) -->
<mxCell id="grp-public" value="Public HTTPS (tunnel / RP — Google 요구)" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#FFF7ED;strokeColor=#FB923C;strokeWidth=2;dashed=0;fontSize=12;fontStyle=1;fontFamily=Pretendard,Helvetica;fontColor=#9A3412;align=left;verticalAlign=top;spacingLeft=10;spacingTop=6;" vertex="1" parent="1">
<mxGeometry x="280" y="100" width="240" height="280" as="geometry" />
</mxCell>
<!-- EC2 zone -->
<mxCell id="grp-ec2" value="Single EC2 (localhost)" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#FBFCFD;strokeColor=#1F6FEB;strokeWidth=2;dashed=0;fontSize=12;fontStyle=1;fontFamily=Pretendard,Helvetica;fontColor=#1F6FEB;align=left;verticalAlign=top;spacingLeft=10;spacingTop=6;" vertex="1" parent="1">
<mxGeometry x="560" y="100" width="380" height="280" as="geometry" />
</mxCell>
<mxCell id="user" value="&lt;b&gt;User&lt;/b&gt;&#10;Browser" style="rounded=8;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#57606A;strokeWidth=1.5;fontSize=12;fontFamily=Pretendard,Helvetica;fontColor=#24292F;align=center;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="100" y="220" width="140" height="80" as="geometry" />
</mxCell>
<!-- Tunnel: 주인공 (public HTTPS 강제) -->
<mxCell id="tunnel" value="&lt;b&gt;HTTPS tunnel&lt;/b&gt;&#10;cloudflared / ngrok / Caddy" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#FFEDD5;strokeColor=#FB923C;strokeWidth=2.5;fontSize=12;fontFamily=Pretendard,Helvetica;fontColor=#9A3412;align=center;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="320" y="220" width="180" height="80" as="geometry" />
</mxCell>
<mxCell id="nginx" value="&lt;b&gt;nginx&lt;/b&gt;&#10;SPA + reverse proxy" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#57606A;strokeWidth=1.5;fontSize=12;fontFamily=Pretendard,Helvetica;fontColor=#24292F;align=center;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="600" y="140" width="160" height="60" as="geometry" />
</mxCell>
<mxCell id="backend" value="&lt;b&gt;Backend&lt;/b&gt;&#10;Spring Boot RS" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#57606A;strokeWidth=1.5;fontSize=12;fontFamily=Pretendard,Helvetica;fontColor=#24292F;align=center;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="780" y="140" width="140" height="60" as="geometry" />
</mxCell>
<mxCell id="keycloak" value="&lt;b&gt;Keycloak&lt;/b&gt;&#10;+ Google IdP brokering" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#FFFFFF;strokeColor=#57606A;strokeWidth=1.5;fontSize=11;fontFamily=Pretendard,Helvetica;fontColor=#24292F;align=center;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="600" y="240" width="320" height="80" as="geometry" />
</mxCell>
<!-- Google (외부, 점선) -->
<mxCell id="google" value="&lt;b&gt;Google OIDC&lt;/b&gt;&#10;(External IdP)" style="rounded=8;whiteSpace=wrap;html=1;fillColor=#F6F8FA;strokeColor=#D0D7DE;strokeWidth=1.5;dashed=1;fontSize=12;fontFamily=Pretendard,Helvetica;fontColor=#6B7280;align=center;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="980" y="240" width="160" height="80" as="geometry" />
</mxCell>
<!-- EDGES -->
<mxCell id="e1" value="① HTTPS" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeColor=#FB923C;strokeWidth=2.5;fontSize=11;fontStyle=1;fontFamily=Pretendard,Helvetica;fontColor=#9A3412;" edge="1" parent="1" source="user" target="tunnel">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e2" value="② localhost (HTTP)" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.3;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeColor=#FB923C;strokeWidth=2.5;fontSize=11;fontStyle=1;fontFamily=Pretendard,Helvetica;fontColor=#9A3412;" edge="1" parent="1" source="tunnel" target="nginx">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e3" value="③ proxy_pass /api" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeColor=#57606A;strokeWidth=1.5;fontSize=11;fontFamily=Pretendard,Helvetica;fontColor=#24292F;" edge="1" parent="1" source="nginx" target="backend">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e4" value="④ JWKS" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=1;entryY=0.2;entryDx=0;entryDy=0;strokeColor=#57606A;strokeWidth=1.5;fontSize=11;fontFamily=Pretendard,Helvetica;fontColor=#24292F;" edge="1" parent="1" source="backend" target="keycloak">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e5" value="⑤ Google 로그인 (공개 HTTPS)" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;strokeColor=#FB923C;strokeWidth=2.5;fontSize=11;fontStyle=1;fontFamily=Pretendard,Helvetica;fontColor=#9A3412;" edge="1" parent="1" source="keycloak" target="google">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="e6" value="⑥ id_token" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.8;exitDx=0;exitDy=0;entryX=1;entryY=0.8;entryDx=0;entryDy=0;strokeColor=#57606A;strokeWidth=1.5;fontSize=11;fontFamily=Pretendard,Helvetica;fontColor=#24292F;dashed=1;" edge="1" parent="1" source="google" target="keycloak">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<!-- CALLOUT -->
<mxCell id="callout" value="⚠️ &lt;b&gt;KC_HOSTNAME = 공개 hostname (P3A 와 결정적 차이)&lt;/b&gt;&#10;&#10;Google 이 검증하는 redirect_uri 와 Keycloak issuer 가 모두 공개 HTTPS host 여야 함.&#10;P3A 처럼 localhost 로 설정 시 Google 흐름 실패 / issuer 불일치 401.&#10;✅ KC_HOSTNAME=&lt;public&gt; + Keycloak Realm Client redirect_uri = public URL." style="rounded=8;whiteSpace=wrap;html=1;fillColor=#FEF2F2;strokeColor=#DC2626;strokeWidth=1.5;fontSize=11;fontFamily=Pretendard,Helvetica;fontColor=#7F1D1D;align=left;verticalAlign=top;spacingLeft=12;spacingTop=8;" vertex="1" parent="1">
<mxGeometry x="100" y="430" width="660" height="120" as="geometry" />
</mxCell>
<!-- LEGEND -->
<mxCell id="leg-title" value="Legend" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=11;fontStyle=1;fontFamily=Pretendard,Helvetica;fontColor=#374151;" vertex="1" parent="1">
<mxGeometry x="100" y="590" width="100" height="20" as="geometry" />
</mxCell>
<mxCell id="leg-tunnel" value="주황 zone + 주황 굵은 화살 = Public HTTPS 경로 (Google이 강제, P3A 와의 결정적 차이)" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=11;fontFamily=Pretendard,Helvetica;fontColor=#9A3412;" vertex="1" parent="1">
<mxGeometry x="100" y="615" width="800" height="20" as="geometry" />
</mxCell>
<mxCell id="leg-ec2" value="파란 zone = Single EC2 localhost (P3A 와 동일 신뢰 모델)" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=11;fontFamily=Pretendard,Helvetica;fontColor=#1F6FEB;" vertex="1" parent="1">
<mxGeometry x="100" y="635" width="800" height="20" as="geometry" />
</mxCell>
<mxCell id="leg-warn" value="빨간 박스 = 함정 (KC_HOSTNAME 을 localhost 로 두면 Google 흐름 실패)" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=11;fontFamily=Pretendard,Helvetica;fontColor=#DC2626;" vertex="1" parent="1">
<mxGeometry x="100" y="655" width="800" height="20" as="geometry" />
</mxCell>
<mxCell id="footer" value="v1 (minimalist) · 2026-05-26" style="text;html=1;strokeColor=none;fillColor=none;align=right;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=10;fontStyle=2;fontFamily=Pretendard,Helvetica;fontColor=#9CA3AF;" vertex="1" parent="1">
<mxGeometry x="900" y="750" width="200" height="20" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>