refactor: 문서 개선 중
This commit is contained in:
+24
@@ -0,0 +1,24 @@
|
||||
# 외부 IdP 인증은 Keycloak broker에서 application credential로 다시 경계가 나뉜다
|
||||
|
||||
## Alternative text
|
||||
|
||||
Upstream IdP zone의 Google identity assertion이 Keycloak broker zone의 validation과 account linking을 거쳐 Keycloak authorization code가 되고 기존 AP1~AP4 application 경계로 이어지는 다이어그램.
|
||||
|
||||
## Long description
|
||||
|
||||
왼쪽 upstream IdP zone의 Google이 identity assertion을 Keycloak broker에 넘긴다. Keycloak은 assertion을 검증하고 provider alias와 upstream sub로 local identity를 연결한 뒤 자기 authorization code를 발급한다. 이 code가 기존 AP1·AP2·AP3·AP4 application 경계 중 하나로 이어지므로 application이 신뢰하는 issuer는 계속 Keycloak이다.
|
||||
|
||||
## Elements and evidence
|
||||
|
||||
- **Boundary: Upstream IdP** (system): Keycloak 앞에서 사용자 인증을 수행하는 외부 identity provider 경계. Evidence: L1152–L1157.
|
||||
- **Boundary: Keycloak → Application** (system): Keycloak이 upstream 결과를 local identity와 자기 authorization code로 바꿔 application OAuth 경계로 넘기는 구간. Evidence: L1152–L1165.
|
||||
- **Google IdP** (service): Upstream authorization을 수행하고 identity assertion을 Keycloak에 돌려주는 IdP. Evidence: L1152–L1157.
|
||||
- **Keycloak broker** (service): Upstream response를 검증하고 provider alias와 upstream sub로 local user와 session을 연결하는 broker. Evidence: L1152–L1160.
|
||||
- **Keycloak authorization code** (data): Upstream token이 아니라 Keycloak이 downstream application에 발급하는 authorization code. Evidence: L1161–L1165.
|
||||
- **AP1 · AP2 · AP3 · AP4** (service): 외부 IdP와 무관하게 기존 application credential boundary 중 하나가 이어지는 downstream 경계. Evidence: L1162–L1165.
|
||||
|
||||
## Relationships
|
||||
|
||||
- **Google IdP → Keycloak broker:** identity assertion. Evidence: L1157–L1158.
|
||||
- **Keycloak broker → Keycloak authorization code:** issue code. Evidence: L1158–L1161.
|
||||
- **Keycloak authorization code → AP1 · AP2 · AP3 · AP4:** Keycloak issuer. Evidence: L1161–L1165.
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
# 외부 IdP 인증은 Keycloak broker에서 application credential로 다시 경계가 나뉜다
|
||||
# Question: 외부 IdP의 인증 결과는 Keycloak broker에서 어떻게 local identity와 Keycloak-issued authorization code로 바뀌고 기존 AP1~AP4 경계로 이어지는가?
|
||||
direction: right
|
||||
g0: "Upstream IdP" {
|
||||
n0: "Google IdP" {
|
||||
shape: rectangle
|
||||
}
|
||||
}
|
||||
g1: "Keycloak → Application" {
|
||||
n1: "Keycloak broker" {
|
||||
shape: rectangle
|
||||
}
|
||||
n2: "Keycloak authorization code" {
|
||||
shape: rectangle
|
||||
}
|
||||
n3: "AP1 · AP2 · AP3 · AP4" {
|
||||
shape: rectangle
|
||||
}
|
||||
}
|
||||
g0.n0 -> g1.n1: "identity assertion"
|
||||
g1.n1 -> g1.n2: "issue code"
|
||||
g1.n2 -> g1.n3: "Keycloak issuer"
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
digraph techviz {
|
||||
graph [rankdir=LR, splines=ortho, nodesep=0.55, ranksep=0.85];
|
||||
node [fontname=Helvetica, fontsize=11, margin="0.18,0.12", style="rounded,filled", fillcolor=white, color="#2d4357", penwidth=1.5];
|
||||
edge [fontname=Helvetica, fontsize=10, color="#364b5f", penwidth=1.4, arrowsize=0.75];
|
||||
subgraph cluster_0 {
|
||||
label="Upstream IdP";
|
||||
style="rounded,dashed";
|
||||
color="#66788a";
|
||||
n0 [label="Google IdP", shape=box, style="rounded,filled"];
|
||||
}
|
||||
subgraph cluster_1 {
|
||||
label="Keycloak → Application";
|
||||
style="rounded,dashed";
|
||||
color="#66788a";
|
||||
n1 [label="Keycloak broker", shape=box, style="rounded,filled"];
|
||||
n2 [label="Keycloak authorization code", shape=box, style="rounded,filled"];
|
||||
n3 [label="AP1 · AP2 · AP3 · AP4", shape=box, style="rounded,filled"];
|
||||
}
|
||||
n0 -> n1 [label="identity assertion", style=solid];
|
||||
n1 -> n2 [label="issue code", style=solid];
|
||||
n2 -> n3 [label="Keycloak issuer", style=solid];
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mxfile host="app.diagrams.net" modified="2026-07-23T00:00:00.000Z" agent="techviz-harness" version="24.7.17" type="device">
|
||||
<diagram id="idp-broker-upstream-downstream-boundary" name="외부 IdP 인증은 Keycloak broker에서 application credential로 다시 경계가 나뉜다">
|
||||
<mxGraphModel dx="1080" dy="395" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1080" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="g_upstream-zone" value="Upstream IdP" style="swimlane;html=1;rounded=1;startSize=30;horizontal=1;dashed=1;strokeWidth=1.5;fillColor=#f7f9fb;strokeColor=#66788a;fontStyle=1;fontSize=13;" vertex="1" parent="1">
|
||||
<mxGeometry x="45.0" y="49.0" width="250.0" height="143.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="g_broker-app-zone" value="Keycloak → Application" style="swimlane;html=1;rounded=1;startSize=30;horizontal=1;dashed=1;strokeWidth=1.5;fillColor=#f7f9fb;strokeColor=#66788a;fontStyle=1;fontSize=13;" vertex="1" parent="1">
|
||||
<mxGeometry x="565.0" y="49.0" width="470.0" height="281.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_google" value="Google IdP<br/>identity assertion" tooltip="Upstream authorization을 수행하고 identity assertion을 Keycloak에 돌려주는 IdP. | Evidence: L1152-L1157" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
|
||||
<mxGeometry x="75.0" y="95.0" width="190.0" height="71.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_broker" value="Keycloak broker<br/>broker validation<br/>provider alias + sub<br/>local user · session" tooltip="Upstream response를 검증하고 provider alias와 upstream sub로 local user와 session을 연결하는 broker. | Evidence: L1152-L1160" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
|
||||
<mxGeometry x="595.0" y="95.0" width="190.0" height="105.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_keycloak-code" value="Keycloak authorization code" tooltip="Upstream token이 아니라 Keycloak이 downstream application에 발급하는 authorization code. | Evidence: L1161-L1165" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
|
||||
<mxGeometry x="815.0" y="95.0" width="190.0" height="74.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="n_downstream" value="AP1 · AP2 · AP3 · AP4" tooltip="외부 IdP와 무관하게 기존 application credential boundary 중 하나가 이어지는 downstream 경계. | Evidence: L1162-L1165" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
|
||||
<mxGeometry x="595.0" y="240.0" width="190.0" height="64.0" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="e_b1" value="identity assertion" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_google" target="n_broker">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="454.0" y="139.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_b2" value="issue code" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_broker" target="n_keycloak-code">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="812.2" y="31.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="e_b3" value="Keycloak issuer" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_keycloak-code" target="n_downstream">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="867.5" y="322.0" as="offset"/>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
+732
@@ -0,0 +1,732 @@
|
||||
{
|
||||
"type": "excalidraw",
|
||||
"version": 2,
|
||||
"source": "techviz-harness",
|
||||
"elements": [
|
||||
{
|
||||
"id": "group-upstream-zone",
|
||||
"type": "rectangle",
|
||||
"x": 45.0,
|
||||
"y": 49.0,
|
||||
"width": 250.0,
|
||||
"height": 143.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "#f8f9fa",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "dashed",
|
||||
"roughness": 0,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 843220907,
|
||||
"version": 1,
|
||||
"versionNonce": 1715574101,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"id": "group-label-upstream-zone",
|
||||
"type": "text",
|
||||
"x": 61.0,
|
||||
"y": 55.0,
|
||||
"width": 108,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 0,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 73837189,
|
||||
"version": 1,
|
||||
"versionNonce": 1087599900,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 14,
|
||||
"fontFamily": 5,
|
||||
"text": "Upstream IdP",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "Upstream IdP",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "group-broker-app-zone",
|
||||
"type": "rectangle",
|
||||
"x": 565.0,
|
||||
"y": 49.0,
|
||||
"width": 470.0,
|
||||
"height": 281.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "#f8f9fa",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "dashed",
|
||||
"roughness": 0,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 843169464,
|
||||
"version": 1,
|
||||
"versionNonce": 766837970,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"id": "group-label-broker-app-zone",
|
||||
"type": "text",
|
||||
"x": 581.0,
|
||||
"y": 55.0,
|
||||
"width": 198,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 0,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 1618498892,
|
||||
"version": 1,
|
||||
"versionNonce": 1933137034,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 14,
|
||||
"fontFamily": 5,
|
||||
"text": "Keycloak → Application",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "Keycloak → Application",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "edge-b1",
|
||||
"type": "arrow",
|
||||
"x": 265.0,
|
||||
"y": 130.5,
|
||||
"width": 330.0,
|
||||
"height": 17.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": null,
|
||||
"seed": 1881077425,
|
||||
"version": 1,
|
||||
"versionNonce": 1053322627,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"points": [
|
||||
[
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
[
|
||||
165.0,
|
||||
0.0
|
||||
],
|
||||
[
|
||||
165.0,
|
||||
17.0
|
||||
],
|
||||
[
|
||||
330.0,
|
||||
17.0
|
||||
]
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"startBinding": {
|
||||
"elementId": "node-google",
|
||||
"focus": 0,
|
||||
"gap": 4
|
||||
},
|
||||
"endBinding": {
|
||||
"elementId": "node-broker",
|
||||
"focus": 0,
|
||||
"gap": 4
|
||||
},
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow",
|
||||
"elbowed": true
|
||||
},
|
||||
{
|
||||
"id": "edge-label-b1",
|
||||
"type": "text",
|
||||
"x": 382.0,
|
||||
"y": 127.0,
|
||||
"width": 144,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 0,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 1939821942,
|
||||
"version": 1,
|
||||
"versionNonce": 1675635312,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "identity assertion",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "identity assertion",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "edge-b2",
|
||||
"type": "arrow",
|
||||
"x": 785.0,
|
||||
"y": 59.0,
|
||||
"width": 30.0,
|
||||
"height": 88.5,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": null,
|
||||
"seed": 1090225723,
|
||||
"version": 1,
|
||||
"versionNonce": 719927994,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"points": [
|
||||
[
|
||||
0.0,
|
||||
88.5
|
||||
],
|
||||
[
|
||||
30.0,
|
||||
88.5
|
||||
],
|
||||
[
|
||||
30.0,
|
||||
0.0
|
||||
],
|
||||
[
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
[
|
||||
0.0,
|
||||
64.0
|
||||
],
|
||||
[
|
||||
30.0,
|
||||
64.0
|
||||
]
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"startBinding": {
|
||||
"elementId": "node-broker",
|
||||
"focus": 0,
|
||||
"gap": 4
|
||||
},
|
||||
"endBinding": {
|
||||
"elementId": "node-keycloak-code",
|
||||
"focus": 0,
|
||||
"gap": 4
|
||||
},
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow",
|
||||
"elbowed": true
|
||||
},
|
||||
{
|
||||
"id": "edge-label-b2",
|
||||
"type": "text",
|
||||
"x": 767.25,
|
||||
"y": 19.0,
|
||||
"width": 90,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 0,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 92689614,
|
||||
"version": 1,
|
||||
"versionNonce": 938215730,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "issue code",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "issue code",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "edge-b3",
|
||||
"type": "arrow",
|
||||
"x": 690.0,
|
||||
"y": 169.0,
|
||||
"width": 220.0,
|
||||
"height": 181.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": null,
|
||||
"seed": 920777401,
|
||||
"version": 1,
|
||||
"versionNonce": 1003519303,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"points": [
|
||||
[
|
||||
220.0,
|
||||
0.0
|
||||
],
|
||||
[
|
||||
220.0,
|
||||
181.0
|
||||
],
|
||||
[
|
||||
0.0,
|
||||
181.0
|
||||
],
|
||||
[
|
||||
0.0,
|
||||
135.0
|
||||
]
|
||||
],
|
||||
"lastCommittedPoint": null,
|
||||
"startBinding": {
|
||||
"elementId": "node-keycloak-code",
|
||||
"focus": 0,
|
||||
"gap": 4
|
||||
},
|
||||
"endBinding": {
|
||||
"elementId": "node-downstream",
|
||||
"focus": 0,
|
||||
"gap": 4
|
||||
},
|
||||
"startArrowhead": null,
|
||||
"endArrowhead": "arrow",
|
||||
"elbowed": true
|
||||
},
|
||||
{
|
||||
"id": "edge-label-b3",
|
||||
"type": "text",
|
||||
"x": 807.5,
|
||||
"y": 310.0,
|
||||
"width": 120,
|
||||
"height": 24,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 0,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 48429281,
|
||||
"version": 1,
|
||||
"versionNonce": 1797138124,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 13,
|
||||
"fontFamily": 5,
|
||||
"text": "Keycloak issuer",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "Keycloak issuer",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "node-google",
|
||||
"type": "rectangle",
|
||||
"x": 75.0,
|
||||
"y": 95.0,
|
||||
"width": 190.0,
|
||||
"height": 71.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "#ffffff",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 1505940743,
|
||||
"version": 1,
|
||||
"versionNonce": 397167959,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"id": "node-label-google",
|
||||
"type": "text",
|
||||
"x": 85.0,
|
||||
"y": 105.0,
|
||||
"width": 170.0,
|
||||
"height": 51.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 0,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 1045077956,
|
||||
"version": 1,
|
||||
"versionNonce": 1546820915,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "Google IdP\nidentity assertion",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "Google IdP\nidentity assertion",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "node-broker",
|
||||
"type": "rectangle",
|
||||
"x": 595.0,
|
||||
"y": 95.0,
|
||||
"width": 190.0,
|
||||
"height": 105.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "#ffffff",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 21942044,
|
||||
"version": 1,
|
||||
"versionNonce": 1744191102,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"id": "node-label-broker",
|
||||
"type": "text",
|
||||
"x": 605.0,
|
||||
"y": 105.0,
|
||||
"width": 170.0,
|
||||
"height": 85.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 0,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 1714928728,
|
||||
"version": 1,
|
||||
"versionNonce": 423573481,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "Keycloak broker\nbroker validation\nprovider alias + sub\nlocal user · session",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "Keycloak broker\nbroker validation\nprovider alias + sub\nlocal user · session",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "node-keycloak-code",
|
||||
"type": "rectangle",
|
||||
"x": 815.0,
|
||||
"y": 95.0,
|
||||
"width": 190.0,
|
||||
"height": 74.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "#ffffff",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 1259207617,
|
||||
"version": 1,
|
||||
"versionNonce": 382015936,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"id": "node-label-keycloak-code",
|
||||
"type": "text",
|
||||
"x": 825.0,
|
||||
"y": 105.0,
|
||||
"width": 170.0,
|
||||
"height": 54.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 0,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 1761782804,
|
||||
"version": 1,
|
||||
"versionNonce": 78085105,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "Keycloak authorization code",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "Keycloak authorization code",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
},
|
||||
{
|
||||
"id": "node-downstream",
|
||||
"type": "rectangle",
|
||||
"x": 595.0,
|
||||
"y": 240.0,
|
||||
"width": 190.0,
|
||||
"height": 64.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "#ffffff",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 422578816,
|
||||
"version": 1,
|
||||
"versionNonce": 1949897943,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"id": "node-label-downstream",
|
||||
"type": "text",
|
||||
"x": 605.0,
|
||||
"y": 250.0,
|
||||
"width": 170.0,
|
||||
"height": 44.0,
|
||||
"angle": 0,
|
||||
"strokeColor": "#1e1e1e",
|
||||
"backgroundColor": "transparent",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 0,
|
||||
"opacity": 100,
|
||||
"groupIds": [],
|
||||
"frameId": null,
|
||||
"index": null,
|
||||
"roundness": {
|
||||
"type": 3
|
||||
},
|
||||
"seed": 74338888,
|
||||
"version": 1,
|
||||
"versionNonce": 790089632,
|
||||
"isDeleted": false,
|
||||
"boundElements": [],
|
||||
"updated": 0,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 15,
|
||||
"fontFamily": 5,
|
||||
"text": "AP1 · AP2 · AP3 · AP4",
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "AP1 · AP2 · AP3 · AP4",
|
||||
"autoResize": true,
|
||||
"lineHeight": 1.25
|
||||
}
|
||||
],
|
||||
"appState": {
|
||||
"gridSize": 10,
|
||||
"viewBackgroundColor": "#ffffff",
|
||||
"currentItemFontFamily": 5
|
||||
},
|
||||
"files": {}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"harness_version": "0.2.0",
|
||||
"spec_id": "idp-broker-upstream-downstream-boundary",
|
||||
"spec_version": "1.1",
|
||||
"spec_sha256": "9bb6a11aba2502fbe9ea9c0a0519073a1a04b9b3cae944720d592ffdc3be9511",
|
||||
"source_context": {
|
||||
"document": "docs/keycloak/final/document.md",
|
||||
"document_sha256": "ea10df24b892e2c57123a37a4b4f0d821e4f394353e6746f50df6a48342353e9",
|
||||
"anchor": {
|
||||
"kind": "heading",
|
||||
"value": "Google login이 들어와도 네 애플리케이션 경계는 바뀌지 않는다",
|
||||
"line": 1150
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
"idp-broker-upstream-downstream-boundary.svg",
|
||||
"idp-broker-upstream-downstream-boundary.mmd",
|
||||
"idp-broker-upstream-downstream-boundary.d2",
|
||||
"idp-broker-upstream-downstream-boundary.dot",
|
||||
"idp-broker-upstream-downstream-boundary.drawio",
|
||||
"idp-broker-upstream-downstream-boundary.excalidraw",
|
||||
"idp-broker-upstream-downstream-boundary.alt.md"
|
||||
],
|
||||
"lint_issue_count": 0,
|
||||
"assumption_count": 0,
|
||||
"assumptions_allowed": false,
|
||||
"composition_profile": "two-zone-pipeline",
|
||||
"reference_ids": [
|
||||
"localization-pipeline"
|
||||
],
|
||||
"diagram_only": true
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
%% 외부 IdP 인증은 Keycloak broker에서 application credential로 다시 경계가 나뉜다
|
||||
%% question: 외부 IdP의 인증 결과는 Keycloak broker에서 어떻게 local identity와 Keycloak-issued authorization code로 바뀌고 기존 AP1~AP4 경계로 이어지는가?
|
||||
flowchart LR
|
||||
subgraph g_upstream_zone["Upstream IdP"]
|
||||
n0["Google IdP"]
|
||||
end
|
||||
subgraph g_broker_app_zone["Keycloak → Application"]
|
||||
n1["Keycloak broker"]
|
||||
n2["Keycloak authorization code"]
|
||||
n3["AP1 · AP2 · AP3 · AP4"]
|
||||
end
|
||||
n0 -->|"identity assertion"| n1
|
||||
n1 -->|"issue code"| n2
|
||||
n2 -->|"Keycloak issuer"| n3
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1080" height="395" viewBox="0 0 1080 395" role="img" aria-labelledby="diagram-title diagram-description">
|
||||
<title id="diagram-title">외부 IdP 인증은 Keycloak broker에서 application credential로 다시 경계가 나뉜다</title>
|
||||
<desc id="diagram-description">왼쪽 upstream IdP zone의 Google이 identity assertion을 Keycloak broker에 넘긴다. Keycloak은 assertion을 검증하고 provider alias와 upstream sub로 local identity를 연결한 뒤 자기 authorization code를 발급한다. 이 code가 기존 AP1·AP2·AP3·AP4 application 경계 중 하나로 이어지므로 application이 신뢰하는 issuer는 계속 Keycloak이다.</desc>
|
||||
<metadata>{"techviz":{"spec_version":"1.1","id":"idp-broker-upstream-downstream-boundary","profile":"two-zone-pipeline"},"source_context":{"document":"docs/keycloak/final/document.md","document_sha256":"ea10df24b892e2c57123a37a4b4f0d821e4f394353e6746f50df6a48342353e9","anchor":{"kind":"heading","value":"Google login이 들어와도 네 애플리케이션 경계는 바뀌지 않는다","line":1150}},"evidence_policy":"Each factual element cites source lines or is marked assumption.","diagram_only":true}</metadata>
|
||||
<defs>
|
||||
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M 0 0 L 10 5 L 0 10 z" />
|
||||
</marker>
|
||||
<style>
|
||||
:root { color-scheme: light; }
|
||||
text { font-family: Inter, Pretendard, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; fill: #111827; }
|
||||
.canvas { fill: #ffffff; }
|
||||
.group-box { fill: #ffffff; stroke: #9ca3af; stroke-width: 1.4; stroke-dasharray: 7 5; }
|
||||
.group-label-bg { fill: #ffffff; }
|
||||
.group-label { font-size: 13px; font-weight: 650; fill: #374151; }
|
||||
.edge { fill: none; stroke: #374151; stroke-width: 1.8; stroke-linejoin: round; stroke-linecap: round; marker-end: url(#arrow); }
|
||||
.edge.style-dashed, .edge.semantic-dashed, .edge.assumption { stroke-dasharray: 7 5; }
|
||||
.edge.style-dotted { stroke-dasharray: 2 5; }
|
||||
.edge.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
|
||||
.edge.emphasis-muted { stroke: #9ca3af; }
|
||||
.edge.emphasis-warning, .edge.kind-failure, .edge.kind-error { stroke: #dc2626; stroke-width: 2.2; }
|
||||
.edge-label-bg { fill: #ffffff; }
|
||||
.edge-label { font-size: 12px; font-weight: 560; text-anchor: middle; }
|
||||
.node-shape { fill: #ffffff; stroke: #4b5563; stroke-width: 1.7; }
|
||||
.node-shape.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
|
||||
.node-shape.emphasis-muted { stroke: #9ca3af; fill: #f9fafb; }
|
||||
.node-shape.emphasis-warning { stroke: #d97706; stroke-width: 2; fill: #fffdf5; }
|
||||
.node-shape.kind-database, .node-shape.kind-datastore, .node-shape.kind-storage { fill: #f8fafc; }
|
||||
.node-shape.kind-queue, .node-shape.kind-event, .node-shape.kind-topic { fill: #fafafa; }
|
||||
.node-shape.assumption { stroke-dasharray: 4 4; }
|
||||
.storage-bottom, .controller-divider { fill: none; stroke: #4b5563; stroke-width: 1.4; }
|
||||
.controller-led { fill: #4b5563; }
|
||||
.actor-symbol { fill: none; stroke: #4b5563; stroke-width: 1.8; stroke-linecap: round; }
|
||||
.actor-symbol.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
|
||||
.node-label { font-size: 14px; font-weight: 650; text-anchor: middle; }
|
||||
.node-role { font-size: 10px; letter-spacing: 0.04em; text-anchor: middle; fill: #6b7280; }
|
||||
.node-detail-divider { stroke: #d1d5db; stroke-width: 1; }
|
||||
.node-detail { font-size: 11px; fill: #374151; }
|
||||
.assumption-badge { font-size: 9px; font-weight: 700; fill: #92400e; }
|
||||
.failure-mark { stroke: #dc2626; stroke-width: 4; stroke-linecap: round; }
|
||||
.lifeline { stroke: #9ca3af; stroke-width: 1.2; stroke-dasharray: 5 5; }
|
||||
.timeline-axis { stroke: #374151; stroke-width: 1.8; marker-end: url(#arrow); }
|
||||
.timeline-stem { stroke: #6b7280; stroke-width: 1.3; }
|
||||
.timeline-marker { fill: #ffffff; stroke: #374151; stroke-width: 1.7; }
|
||||
.timeline-marker.primary { fill: #2563eb; stroke: #2563eb; }
|
||||
.timeline-marker.warning { fill: #dc2626; stroke: #dc2626; }
|
||||
.timeline-label { font-size: 13px; font-weight: 650; text-anchor: middle; }
|
||||
.timeline-detail { font-size: 11px; fill: #4b5563; text-anchor: middle; }
|
||||
</style>
|
||||
</defs>
|
||||
<rect class="canvas" width="1080" height="395" />
|
||||
<rect class="group-box" x="45.0" y="49.0" width="250.0" height="143.0" rx="8" />
|
||||
<rect class="group-label-bg" x="59.0" y="39.0" width="106.0" height="22" />
|
||||
<text class="group-label" x="69.0" y="54.0">Upstream IdP</text>
|
||||
<rect class="group-box" x="565.0" y="49.0" width="470.0" height="281.0" rx="8" />
|
||||
<rect class="group-label-bg" x="579.0" y="39.0" width="176.0" height="22" />
|
||||
<text class="group-label" x="589.0" y="54.0">Keycloak → Application</text>
|
||||
<polyline class="edge kind-data style-solid emphasis-normal" points="265.0,130.5 430.0,130.5 430.0,147.5 595.0,147.5" data-evidence="1157-1158" />
|
||||
<rect class="edge-label-bg" x="384.7" y="125.0" width="138.6" height="22" rx="3" />
|
||||
<text class="edge-label" x="454.0" y="140.0">identity assertion</text>
|
||||
<polyline class="edge kind-data style-solid emphasis-primary" points="785.0,147.5 815.0,147.5 815.0,59.0 785.0,59.0 785.0,123.0 815.0,123.0" data-evidence="1158-1161" />
|
||||
<rect class="edge-label-bg" x="769.8" y="17.0" width="85.0" height="22" rx="3" />
|
||||
<text class="edge-label" x="812.2" y="32.0">issue code</text>
|
||||
<polyline class="edge kind-data style-solid emphasis-normal" points="910.0,169.0 910.0,350.0 690.0,350.0 690.0,304.0" data-evidence="1161-1165" />
|
||||
<rect class="edge-label-bg" x="808.2" y="308.0" width="118.5" height="22" rx="3" />
|
||||
<text class="edge-label" x="867.5" y="323.0">Keycloak issuer</text>
|
||||
<g id="node-google">
|
||||
<rect class="node-shape kind-service emphasis-normal role-source" data-evidence="1152-1157" x="75.0" y="95.0" width="190.0" height="71.0" rx="7" />
|
||||
<text class="node-label" x="170.0" y="122.0">Google IdP</text>
|
||||
<line class="node-detail-divider" x1="89.0" y1="143.0" x2="251.0" y2="143.0" />
|
||||
<text class="node-detail" x="91.0" y="160.0">identity assertion</text>
|
||||
</g>
|
||||
<g id="node-broker">
|
||||
<rect class="node-shape kind-service emphasis-primary role-service" data-evidence="1152-1160" x="595.0" y="95.0" width="190.0" height="105.0" rx="7" />
|
||||
<text class="node-label" x="690.0" y="122.0">Keycloak broker</text>
|
||||
<line class="node-detail-divider" x1="609.0" y1="143.0" x2="771.0" y2="143.0" />
|
||||
<text class="node-detail" x="611.0" y="160.0">broker validation</text>
|
||||
<text class="node-detail" x="611.0" y="176.0">provider alias + sub</text>
|
||||
<text class="node-detail" x="611.0" y="192.0">local user · session</text>
|
||||
</g>
|
||||
<g id="node-keycloak-code">
|
||||
<rect class="node-shape kind-data emphasis-normal role-service" data-evidence="1161-1165" x="815.0" y="95.0" width="190.0" height="74.0" rx="7" />
|
||||
<text class="node-label" x="910.0" y="122.0">Keycloak authorization</text>
|
||||
<text class="node-label" x="910.0" y="140.0">code</text>
|
||||
</g>
|
||||
<g id="node-downstream">
|
||||
<rect class="node-shape kind-service emphasis-normal role-sink" data-evidence="1162-1165" x="595.0" y="240.0" width="190.0" height="64.0" rx="7" />
|
||||
<text class="node-label" x="690.0" y="270.0">AP1 · AP2 · AP3 · AP4</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.3 KiB |
Reference in New Issue
Block a user