forked from baron/baron-sso
ory스택 버전업 및 하드코딩URL 제거
This commit is contained in:
19
.env.sample
19
.env.sample
@@ -76,20 +76,20 @@ HYDRA_DB=ory_hydra
|
||||
KETO_DB=ory_keto
|
||||
|
||||
# Ory Kratos Configuration
|
||||
KRATOS_VERSION=v25.4.0-distroless
|
||||
KRATOS_VERSION=v26.2.0-distroless
|
||||
# KRATOS_PUBLIC_PORT=4433 # Internal only
|
||||
# KRATOS_ADMINFRONT_PORT=4434 # Internal only
|
||||
|
||||
KRATOS_UI_NODE_VERSION=v25.4.0
|
||||
KRATOS_UI_NODE_VERSION=v26.2.0
|
||||
# KRATOS_UI_PORT=4455 # Internal only
|
||||
|
||||
# Ory Hydra Configuration
|
||||
HYDRA_VERSION=v25.4.0-distroless
|
||||
HYDRA_VERSION=v26.2.0-distroless
|
||||
# HYDRA_PUBLIC_PORT=4441 # Internal only
|
||||
# HYDRA_ADMINFRONT_PORT=4445 # Internal only
|
||||
|
||||
# Ory Keto Configuration
|
||||
KETO_VERSION=v25.4.0-distroless
|
||||
KETO_VERSION=v26.2.0-distroless
|
||||
# KETO_READ_PORT=4466 # Internal only
|
||||
# KETO_WRITE_PORT=4467 # Internal only
|
||||
KETO_READ_URL=http://keto:4466
|
||||
@@ -109,16 +109,21 @@ KRATOS_UI_URL=http://localhost:5000
|
||||
HYDRA_ADMIN_URL=http://hydra:4445
|
||||
# Oathkeeper가 /oidc 경로를 Hydra Public API로 라우팅합니다.
|
||||
HYDRA_PUBLIC_URL=${OATHKEEPER_PUBLIC_URL}/oidc
|
||||
# 선택: Hydra 화면 핸드오프 URL을 USERFRONT_URL 기준 기본값과 다르게 둘 때만 설정합니다.
|
||||
# HYDRA_LOGIN_URL=https://sso.hmac.kr/login
|
||||
# HYDRA_CONSENT_URL=https://sso.hmac.kr/consent
|
||||
# HYDRA_ERROR_URL=https://sso.hmac.kr/error
|
||||
|
||||
# Kratos allowed_return_urls 확장 목록 (콤마 구분, 선택)
|
||||
# 기본값은 KRATOS_UI_URL, USERFRONT_URL, 각 callback URL을 자동 포함합니다.
|
||||
KRATOS_ALLOWED_RETURN_URLS_EXTRA=[]
|
||||
KRATOS_ALLOWED_RETURN_URLS_JSON=["http://localhost:5000","http://localhost:5000/","https://sso.hmac.kr","https://sso.hmac.kr/","https://sso.hmac.kr/ko","https://sso.hmac.kr/ko/","https://sso.hmac.kr/en","https://sso.hmac.kr/en/","https://sso.hmac.kr/auth/callback","https://sso.hmac.kr/ko/auth/callback","https://sso.hmac.kr/en/auth/callback","http://localhost:5173/auth/callback","http://localhost:5174/auth/callback","http://localhost:5175/auth/callback","https://sso.hmac.kr/orgfront/auth/callback"]
|
||||
|
||||
# Oathkeeper JWKS (내부 통신용)
|
||||
JWKS_URL=http://oathkeeper:4456/.well-known/jwks.json
|
||||
|
||||
# Oathkeeper 실행 사용자/프로브 설정
|
||||
OATHKEEPER_VERSION=v25.4.0
|
||||
OATHKEEPER_VERSION=v26.2.0
|
||||
OATHKEEPER_UID=1001
|
||||
OATHKEEPER_GID=1001
|
||||
OATHKEEPER_HEALTH_URL=http://oathkeeper:4456/health/ready
|
||||
@@ -140,5 +145,5 @@ VITE_OIDC_CLIENT_ID=devfront
|
||||
VITE_OIDC_AUTHORITY=https://sso.hmac.kr/oidc
|
||||
DEVFRONT_URL=http://localhost:5174
|
||||
DEVFRONT_CALLBACK_URLS=http://localhost:5174/auth/callback,https://sso.hmac.kr/devfront/auth/callback
|
||||
ORGFRONT_CALLBACK_URLS=http://localhost:5175/auth/callback,http://172.16.10.176:5175/auth/callback,https://baron-orgchart.hmac.kr/auth/callback
|
||||
VITE_ORGCHART_URL=
|
||||
ORGFRONT_CALLBACK_URLS=http://localhost:5175/auth/callback,https://sso.hmac.kr/orgfront/auth/callback
|
||||
VITE_ORGCHART_URL=
|
||||
|
||||
@@ -124,11 +124,13 @@ jobs:
|
||||
CSRF_COOKIE_NAME=${{ vars.CSRF_COOKIE_NAME }}
|
||||
CSRF_COOKIE_SECRET=${{ secrets.STG_CSRF_COOKIE_SECRET }}
|
||||
|
||||
# Frontend OIDC configs for Staging
|
||||
VITE_OIDC_AUTHORITY=https://sso.hmac.kr/oidc
|
||||
ADMINFRONT_CALLBACK_URLS=http://localhost:5173/auth/callback,https://sso.hmac.kr/auth/callback,http://172.16.10.176:5173/auth/callback,https://sadmin.hmac.kr/auth/callback
|
||||
DEVFRONT_CALLBACK_URLS=http://localhost:5174/auth/callback,https://sso.hmac.kr/devfront/auth/callback,http://172.16.10.176:5174/auth/callback,https://sdev.hmac.kr/auth/callback
|
||||
ORGFRONT_CALLBACK_URLS=http://localhost:5175/auth/callback,http://172.16.10.176:5175/auth/callback,https://baron-orgchart.hmac.kr/auth/callback
|
||||
# Frontend/Ory URL configs for Staging
|
||||
VITE_OIDC_AUTHORITY=${{ vars.VITE_OIDC_AUTHORITY }}
|
||||
ADMINFRONT_CALLBACK_URLS=${{ vars.ADMINFRONT_CALLBACK_URLS }}
|
||||
DEVFRONT_CALLBACK_URLS=${{ vars.DEVFRONT_CALLBACK_URLS }}
|
||||
ORGFRONT_CALLBACK_URLS=${{ vars.ORGFRONT_CALLBACK_URLS }}
|
||||
KRATOS_ALLOWED_RETURN_URLS_JSON=${{ vars.KRATOS_ALLOWED_RETURN_URLS_JSON }}
|
||||
KRATOS_ALLOWED_RETURN_URLS_EXTRA=${{ vars.KRATOS_ALLOWED_RETURN_URLS_EXTRA }}
|
||||
# OATHKEEPER_INTROSPECT_CLIENT_ID=${{ vars.OATHKEEPER_INTROSPECT_CLIENT_ID }}
|
||||
# OATHKEEPER_INTROSPECT_CLIENT_SECRET=${{ secrets.STG_OATHKEEPER_INTROSPECT_CLIENT_SECRET }}
|
||||
EOF
|
||||
|
||||
6
Makefile
6
Makefile
@@ -29,7 +29,7 @@ ifneq (,$(wildcard ./.env))
|
||||
COMPOSE_DROP_ENV_ARGS += --env-file .env
|
||||
endif
|
||||
|
||||
.PHONY: build-auth-config validate-auth-config verify-auth-config up-all up-infra up-ory up-app up-backend ensure-networks ensure-infra ensure-ory up-dev up-front-dev dev down drop down-app down-backend down-infra down-ory check-infra ps logs-infra logs-ory logs-app
|
||||
.PHONY: build-auth-config validate-auth-config verify-auth-config up up-all up-infra up-ory up-app up-backend ensure-networks ensure-infra ensure-ory up-dev up-front-dev dev down drop down-app down-backend down-infra down-ory check-infra ps logs-infra logs-ory logs-app
|
||||
|
||||
# --- 인증 설정 빌드/검증 ---
|
||||
build-auth-config:
|
||||
@@ -47,6 +47,8 @@ verify-auth-config: validate-auth-config
|
||||
|
||||
# --- 기본 실행 ---
|
||||
# 주의: --remove-orphan 사용 금지 (다른 스택이 orphan으로 판단되어 종료될 수 있음)
|
||||
up: up-all
|
||||
|
||||
up-all: ensure-networks validate-auth-config
|
||||
@echo "Starting ALL stacks (infra + ory + app)..."
|
||||
docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_INFRA) -f $(COMPOSE_ORY) -f $(COMPOSE_APP) up -d
|
||||
@@ -61,7 +63,7 @@ up-ory: ensure-networks validate-auth-config
|
||||
docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_ORY) up -d
|
||||
|
||||
up-app: ensure-networks validate-auth-config
|
||||
@echo "Starting App stack (backend/userfront/adminfront/devfront)..."
|
||||
@echo "Starting App stack (backend/userfront/adminfront/devfront/orgfront)..."
|
||||
docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_APP) up -d
|
||||
|
||||
up-backend: ensure-networks validate-auth-config
|
||||
|
||||
@@ -395,11 +395,13 @@ USERFRONT_URL=https://sso.example.com
|
||||
- `KRATOS_BROWSER_URL`: 보통 `${OATHKEEPER_PUBLIC_URL}/auth`
|
||||
- `KRATOS_UI_URL`: UserFront UI URL (로컬 예: `http://localhost:5000`)
|
||||
- `ADMINFRONT_CALLBACK_URLS`: 콤마 구분 콜백 목록 (예: `http://localhost:5173/auth/callback`)
|
||||
- `DEVFRONT_CALLBACK_URLS`: 콤마 구분 콜백 목록 (예: `http://localhost:5174/callback`)
|
||||
- `DEVFRONT_CALLBACK_URLS`: 콤마 구분 콜백 목록 (예: `http://localhost:5174/auth/callback`)
|
||||
- 주의: callback URL 끝에 `/`가 붙으면 `make validate-auth-config`에서 실패 처리됩니다.
|
||||
- `KRATOS_ALLOWED_RETURN_URLS_EXTRA`: 추가 허용 return URL (선택)
|
||||
- 빈값: `[]`
|
||||
- 다중값: `["https://a.example.com/callback","https://b.example.com/callback"]` 또는 `https://a.example.com/callback,https://b.example.com/callback`
|
||||
- `KRATOS_ALLOWED_RETURN_URLS_JSON`: stage/prod에서 권장하는 전체 허용 return URL 목록
|
||||
- 공개 도메인, `/ko`, `/en`, `/auth/callback`, `/ko/auth/callback`, `/en/auth/callback`, 각 front callback을 포함해야 합니다.
|
||||
- `CLIENT_LOG_DEBUG`: 클라이언트 로그 디버그 모드 강제 (기본: 비운영 `true`, 운영 `false`)
|
||||
- 운영(`APP_ENV=production|prod`)에서 `true|1|on|yes` 설정 시 `INFO/DEBUG` 클라이언트 로그 수집 허용
|
||||
- 미설정(기본) 시 운영에서는 `WARN/ERROR`만 수집
|
||||
|
||||
157
compose.ory.yaml
157
compose.ory.yaml
@@ -23,20 +23,20 @@ services:
|
||||
|
||||
# --- Kratos ---
|
||||
kratos-migrate:
|
||||
image: oryd/kratos:${KRATOS_VERSION:-v25.4.0}
|
||||
image: oryd/kratos:${KRATOS_VERSION:-v26.2.0}
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KRATOS_DB:-ory_kratos}?sslmode=disable&max_conns=20
|
||||
- KRATOS_SERVE_PUBLIC_BASE_URL=${KRATOS_BROWSER_URL:-http://localhost:4433}
|
||||
- KRATOS_SERVE_ADMIN_BASE_URL=${KRATOS_ADMIN_URL:-http://kratos:4434}
|
||||
- KRATOS_SELFSERVICE_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL:-http://localhost:5000}
|
||||
- KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=${KRATOS_ALLOWED_RETURN_URLS_JSON:-["http://localhost:5000","http://localhost:5000/"]}
|
||||
- KRATOS_SELFSERVICE_FLOWS_ERROR_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/error
|
||||
- KRATOS_SELFSERVICE_FLOWS_SETTINGS_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/error?error=settings_disabled
|
||||
- KRATOS_SELFSERVICE_FLOWS_RECOVERY_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/recovery
|
||||
- KRATOS_SELFSERVICE_FLOWS_VERIFICATION_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/verification
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGIN_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/login
|
||||
- KRATOS_SELFSERVICE_FLOWS_REGISTRATION_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/registration
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGOUT_AFTER_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL:-http://localhost:5000}/login
|
||||
- KRATOS_SERVE_PUBLIC_BASE_URL=${KRATOS_BROWSER_URL}
|
||||
- KRATOS_SERVE_ADMIN_BASE_URL=${KRATOS_ADMIN_URL}
|
||||
- KRATOS_SELFSERVICE_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL}
|
||||
- KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=${KRATOS_ALLOWED_RETURN_URLS_JSON:-["${KRATOS_UI_URL}","${KRATOS_UI_URL}/"]}
|
||||
- KRATOS_SELFSERVICE_FLOWS_ERROR_UI_URL=${KRATOS_UI_URL}/error
|
||||
- KRATOS_SELFSERVICE_FLOWS_SETTINGS_UI_URL=${KRATOS_UI_URL}/error?error=settings_disabled
|
||||
- KRATOS_SELFSERVICE_FLOWS_RECOVERY_UI_URL=${KRATOS_UI_URL}/recovery
|
||||
- KRATOS_SELFSERVICE_FLOWS_VERIFICATION_UI_URL=${KRATOS_UI_URL}/verification
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGIN_UI_URL=${KRATOS_UI_URL}/login
|
||||
- KRATOS_SELFSERVICE_FLOWS_REGISTRATION_UI_URL=${KRATOS_UI_URL}/registration
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGOUT_AFTER_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL}/login
|
||||
volumes:
|
||||
- ./docker/ory/kratos:/etc/config/kratos
|
||||
command: migrate sql up -e -c /etc/config/kratos/kratos.yml --yes
|
||||
@@ -47,22 +47,22 @@ services:
|
||||
- ory-net
|
||||
|
||||
kratos:
|
||||
image: oryd/kratos:${KRATOS_VERSION:-v25.4.0}
|
||||
image: oryd/kratos:${KRATOS_VERSION:-v26.2.0}
|
||||
container_name: ory_kratos
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KRATOS_DB:-ory_kratos}?sslmode=disable&max_conns=20
|
||||
- COOKIE_SECRET=${COOKIE_SECRET:-localcookie123}
|
||||
- KRATOS_SERVE_PUBLIC_BASE_URL=${KRATOS_BROWSER_URL:-http://localhost:4433}
|
||||
- KRATOS_SERVE_ADMIN_BASE_URL=${KRATOS_ADMIN_URL:-http://kratos:4434}
|
||||
- KRATOS_SELFSERVICE_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL:-http://localhost:5000}
|
||||
- KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=${KRATOS_ALLOWED_RETURN_URLS_JSON:-["http://localhost:5000","http://localhost:5000/"]}
|
||||
- KRATOS_SELFSERVICE_FLOWS_ERROR_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/error
|
||||
- KRATOS_SELFSERVICE_FLOWS_SETTINGS_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/error?error=settings_disabled
|
||||
- KRATOS_SELFSERVICE_FLOWS_RECOVERY_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/recovery
|
||||
- KRATOS_SELFSERVICE_FLOWS_VERIFICATION_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/verification
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGIN_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/login
|
||||
- KRATOS_SELFSERVICE_FLOWS_REGISTRATION_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/registration
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGOUT_AFTER_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL:-http://localhost:5000}/login
|
||||
- KRATOS_SERVE_PUBLIC_BASE_URL=${KRATOS_BROWSER_URL}
|
||||
- KRATOS_SERVE_ADMIN_BASE_URL=${KRATOS_ADMIN_URL}
|
||||
- KRATOS_SELFSERVICE_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL}
|
||||
- KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=${KRATOS_ALLOWED_RETURN_URLS_JSON:-["${KRATOS_UI_URL}","${KRATOS_UI_URL}/"]}
|
||||
- KRATOS_SELFSERVICE_FLOWS_ERROR_UI_URL=${KRATOS_UI_URL}/error
|
||||
- KRATOS_SELFSERVICE_FLOWS_SETTINGS_UI_URL=${KRATOS_UI_URL}/error?error=settings_disabled
|
||||
- KRATOS_SELFSERVICE_FLOWS_RECOVERY_UI_URL=${KRATOS_UI_URL}/recovery
|
||||
- KRATOS_SELFSERVICE_FLOWS_VERIFICATION_UI_URL=${KRATOS_UI_URL}/verification
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGIN_UI_URL=${KRATOS_UI_URL}/login
|
||||
- KRATOS_SELFSERVICE_FLOWS_REGISTRATION_UI_URL=${KRATOS_UI_URL}/registration
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGOUT_AFTER_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL}/login
|
||||
volumes:
|
||||
- ./docker/ory/kratos:/etc/config/kratos
|
||||
command: serve -c /etc/config/kratos/kratos.yml --dev --watch-courier
|
||||
@@ -75,7 +75,7 @@ services:
|
||||
|
||||
# --- Hydra ---
|
||||
hydra-migrate:
|
||||
image: oryd/hydra:${HYDRA_VERSION:-v25.4.0}
|
||||
image: oryd/hydra:${HYDRA_VERSION:-v26.2.0}
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${HYDRA_DB:-ory_hydra}?sslmode=disable&max_conns=20
|
||||
command: migrate sql up -e --yes
|
||||
@@ -86,14 +86,14 @@ services:
|
||||
- ory-net
|
||||
|
||||
hydra:
|
||||
image: oryd/hydra:${HYDRA_VERSION:-v25.4.0}
|
||||
image: oryd/hydra:${HYDRA_VERSION:-v26.2.0}
|
||||
container_name: ory_hydra
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${HYDRA_DB:-ory_hydra}?sslmode=disable&max_conns=20
|
||||
- URLS_SELF_ISSUER=${USERFRONT_URL:-http://localhost:5000}/oidc
|
||||
- URLS_LOGIN=${USERFRONT_URL:-http://localhost:5000}/login
|
||||
- URLS_CONSENT=${USERFRONT_URL:-http://localhost:5000}/consent
|
||||
- URLS_ERROR=${USERFRONT_URL:-http://localhost:5000}/error
|
||||
- URLS_SELF_ISSUER=${HYDRA_PUBLIC_URL}
|
||||
- URLS_LOGIN=${HYDRA_LOGIN_URL:-${USERFRONT_URL}/login}
|
||||
- URLS_CONSENT=${HYDRA_CONSENT_URL:-${USERFRONT_URL}/consent}
|
||||
- URLS_ERROR=${HYDRA_ERROR_URL:-${USERFRONT_URL}/error}
|
||||
- SECRETS_SYSTEM=${ORY_POSTGRES_PASSWORD}
|
||||
volumes:
|
||||
- ./docker/ory/hydra:/etc/config/hydra
|
||||
@@ -107,7 +107,7 @@ services:
|
||||
|
||||
# --- Keto ---
|
||||
keto-migrate:
|
||||
image: oryd/keto:${KETO_VERSION:-v25.4.0}
|
||||
image: oryd/keto:${KETO_VERSION:-v26.2.0}
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KETO_DB:-ory_keto}?sslmode=disable&max_conns=20
|
||||
volumes:
|
||||
@@ -120,7 +120,7 @@ services:
|
||||
- ory-net
|
||||
|
||||
keto:
|
||||
image: oryd/keto:${KETO_VERSION:-v25.4.0}
|
||||
image: oryd/keto:${KETO_VERSION:-v26.2.0}
|
||||
container_name: ory_keto
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KETO_DB:-ory_keto}?sslmode=disable&max_conns=20
|
||||
@@ -136,14 +136,19 @@ services:
|
||||
# --- Oathkeeper ---
|
||||
oathkeeper_logs_init:
|
||||
image: alpine:latest
|
||||
command: ["sh", "-c", "mkdir -p /var/log/oathkeeper && chown -R ${OATHKEEPER_UID:-1001}:${OATHKEEPER_GID:-1001} /var/log/oathkeeper"]
|
||||
command:
|
||||
[
|
||||
"sh",
|
||||
"-c",
|
||||
"mkdir -p /var/log/oathkeeper && chown -R ${OATHKEEPER_UID:-1001}:${OATHKEEPER_GID:-1001} /var/log/oathkeeper",
|
||||
]
|
||||
volumes:
|
||||
- oathkeeper_logs:/var/log/oathkeeper
|
||||
networks:
|
||||
- ory-net
|
||||
|
||||
oathkeeper:
|
||||
image: oryd/oathkeeper:${OATHKEEPER_VERSION:-v25.4.0}
|
||||
image: oryd/oathkeeper:${OATHKEEPER_VERSION:-v26.2.0}
|
||||
container_name: ory_oathkeeper
|
||||
user: "${OATHKEEPER_UID:-1001}:${OATHKEEPER_GID:-1001}"
|
||||
ports:
|
||||
@@ -220,56 +225,56 @@ services:
|
||||
- /bin/sh
|
||||
- -ec
|
||||
- |
|
||||
apk add --no-cache curl tar
|
||||
HYDRA_CLI_VERSION="$${HYDRA_VERSION:-v26.2.0}"
|
||||
HYDRA_CLI_VERSION="$${HYDRA_CLI_VERSION%-distroless}"
|
||||
HYDRA_CLI_ARCHIVE_VERSION="$${HYDRA_CLI_VERSION#v}"
|
||||
curl -fsSLo /tmp/hydra.tar.gz "https://github.com/ory/hydra/releases/download/$${HYDRA_CLI_VERSION}/hydra_$${HYDRA_CLI_ARCHIVE_VERSION}-linux_64bit.tar.gz"
|
||||
tar -xzf /tmp/hydra.tar.gz -C /usr/local/bin hydra
|
||||
rm /tmp/hydra.tar.gz
|
||||
apk add --no-cache curl tar
|
||||
HYDRA_CLI_VERSION="$${HYDRA_VERSION:-v26.2.0}"
|
||||
HYDRA_CLI_VERSION="$${HYDRA_CLI_VERSION%-distroless}"
|
||||
HYDRA_CLI_ARCHIVE_VERSION="$${HYDRA_CLI_VERSION#v}"
|
||||
curl -fsSLo /tmp/hydra.tar.gz "https://github.com/ory/hydra/releases/download/$${HYDRA_CLI_VERSION}/hydra_$${HYDRA_CLI_ARCHIVE_VERSION}-linux_64bit.tar.gz"
|
||||
tar -xzf /tmp/hydra.tar.gz -C /usr/local/bin hydra
|
||||
rm /tmp/hydra.tar.gz
|
||||
|
||||
hydra delete oauth2-client --endpoint http://hydra:4445 adminfront >/dev/null 2>&1 || true
|
||||
hydra delete oauth2-client --endpoint http://hydra:4445 devfront >/dev/null 2>&1 || true
|
||||
hydra delete oauth2-client --endpoint http://hydra:4445 orgfront >/dev/null 2>&1 || true
|
||||
hydra delete oauth2-client --endpoint http://hydra:4445 ${OATHKEEPER_INTROSPECT_CLIENT_ID:-oathkeeper-introspect} >/dev/null 2>&1 || true
|
||||
hydra delete oauth2-client --endpoint "$${HYDRA_ADMIN_URL}" adminfront >/dev/null 2>&1 || true
|
||||
hydra delete oauth2-client --endpoint "$${HYDRA_ADMIN_URL}" devfront >/dev/null 2>&1 || true
|
||||
hydra delete oauth2-client --endpoint "$${HYDRA_ADMIN_URL}" orgfront >/dev/null 2>&1 || true
|
||||
hydra delete oauth2-client --endpoint "$${HYDRA_ADMIN_URL}" "$${OATHKEEPER_INTROSPECT_CLIENT_ID:-oathkeeper-introspect}" >/dev/null 2>&1 || true
|
||||
|
||||
hydra create oauth2-client \
|
||||
--endpoint http://hydra:4445 \
|
||||
--id adminfront \
|
||||
--name "AdminFront" \
|
||||
hydra create oauth2-client \
|
||||
--endpoint "$${HYDRA_ADMIN_URL}" \
|
||||
--id adminfront \
|
||||
--name "AdminFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri ${ADMINFRONT_CALLBACK_URLS}
|
||||
|
||||
hydra create oauth2-client \
|
||||
--endpoint "$${HYDRA_ADMIN_URL}" \
|
||||
--id devfront \
|
||||
--name "DevFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri ${ADMINFRONT_CALLBACK_URLS:-http://localhost:5173/auth/callback}
|
||||
--redirect-uri ${DEVFRONT_CALLBACK_URLS}
|
||||
|
||||
hydra create oauth2-client \
|
||||
--endpoint http://hydra:4445 \
|
||||
--id devfront \
|
||||
--name "DevFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri ${DEVFRONT_CALLBACK_URLS:-http://localhost:5174/auth/callback}
|
||||
hydra create oauth2-client \
|
||||
--endpoint "$${HYDRA_ADMIN_URL}" \
|
||||
--id orgfront \
|
||||
--name "OrgFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri ${ORGFRONT_CALLBACK_URLS}
|
||||
|
||||
hydra create oauth2-client \
|
||||
--endpoint http://hydra:4445 \
|
||||
--id orgfront \
|
||||
--name "OrgFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri ${ORGFRONT_CALLBACK_URLS:-http://localhost:5175/auth/callback,https://baron-orgchart.hmac.kr/auth/callback}
|
||||
|
||||
hydra create oauth2-client \
|
||||
--endpoint http://hydra:4445 \
|
||||
--id ${OATHKEEPER_INTROSPECT_CLIENT_ID:-oathkeeper-introspect} \
|
||||
--secret ${OATHKEEPER_INTROSPECT_CLIENT_SECRET:-oathkeeper-secret} \
|
||||
--grant-type client_credentials \
|
||||
--response-type token \
|
||||
--scope openid,offline_access,profile,email
|
||||
hydra create oauth2-client \
|
||||
--endpoint "$${HYDRA_ADMIN_URL}" \
|
||||
--id "$${OATHKEEPER_INTROSPECT_CLIENT_ID:-oathkeeper-introspect}" \
|
||||
--secret "$${OATHKEEPER_INTROSPECT_CLIENT_SECRET:-oathkeeper-secret}" \
|
||||
--grant-type client_credentials \
|
||||
--response-type token \
|
||||
--scope openid,offline_access,profile,email
|
||||
depends_on:
|
||||
ory_stack_check:
|
||||
condition: service_completed_successfully
|
||||
|
||||
@@ -18,11 +18,15 @@ echo "🚀 Creating instance: ${INSTANCE_NAME} (Port Prefix: ${PORT_PREFIX}xxx)"
|
||||
|
||||
# 1. 폴더 구조 생성
|
||||
mkdir -p "${TARGET_DIR}/gateway"
|
||||
mkdir -p "${TARGET_DIR}/ory/init-db"
|
||||
mkdir -p "${TARGET_DIR}/ory/kratos"
|
||||
mkdir -p "${TARGET_DIR}/ory/hydra"
|
||||
mkdir -p "${TARGET_DIR}/ory/keto"
|
||||
mkdir -p "${TARGET_DIR}/ory/oathkeeper"
|
||||
mkdir -p "${TARGET_DIR}/userfront"
|
||||
mkdir -p "${TARGET_DIR}/adminfront"
|
||||
mkdir -p "${TARGET_DIR}/devfront"
|
||||
mkdir -p "${TARGET_DIR}/orgfront"
|
||||
|
||||
# 2. .env 생성 및 변수 로드
|
||||
sed "s/{{INSTANCE_NAME}}/${INSTANCE_NAME}/g; s/{{PORT_PREFIX}}/${PORT_PREFIX}/g" \
|
||||
@@ -34,6 +38,7 @@ USERFRONT_PORT="${PORT_PREFIX}500"
|
||||
DOMAIN_SUFFIX=$(grep "DOMAIN_SUFFIX=" "${TARGET_DIR}/.env" | cut -d'=' -f2 | tr -d '\r')
|
||||
ADMINFRONT_DOMAIN="${INSTANCE_NAME}-admin.${DOMAIN_SUFFIX}"
|
||||
DEVFRONT_DOMAIN="${INSTANCE_NAME}-dev.${DOMAIN_SUFFIX}"
|
||||
ORGFRONT_DOMAIN="${INSTANCE_NAME}-org.${DOMAIN_SUFFIX}"
|
||||
|
||||
# 3. Docker Compose & Config 복사 및 치환
|
||||
cp "${BASE_DIR}/templates/docker-compose.yaml" "${TARGET_DIR}/"
|
||||
@@ -55,15 +60,22 @@ sed "s/{{ADMINFRONT_DOMAIN}}/${ADMINFRONT_DOMAIN}/g; s/{{BACKEND_PORT}}/${BACKEN
|
||||
"${BASE_DIR}/templates/adminfront/vite.config.ts" > "${TARGET_DIR}/adminfront/vite.config.ts"
|
||||
sed "s/{{DEVFRONT_DOMAIN}}/${DEVFRONT_DOMAIN}/g; s/{{BACKEND_PORT}}/${BACKEND_PORT}/g" \
|
||||
"${BASE_DIR}/templates/devfront/vite.config.ts" > "${TARGET_DIR}/devfront/vite.config.ts"
|
||||
sed "s/{{ORGFRONT_DOMAIN}}/${ORGFRONT_DOMAIN}/g; s/{{BACKEND_PORT}}/${BACKEND_PORT}/g" \
|
||||
"${BASE_DIR}/templates/orgfront/vite.config.ts" > "${TARGET_DIR}/orgfront/vite.config.ts"
|
||||
|
||||
# 4. 프론트엔드 auth.ts 주입 (하드코딩된 포트 해결)
|
||||
sed "s/{{USERFRONT_PORT}}/${USERFRONT_PORT}/g; s/{{CLIENT_ID}}/adminfront/g" \
|
||||
"${BASE_DIR}/templates/auth.template.ts" > "${TARGET_DIR}/adminfront/auth.ts"
|
||||
sed "s/{{USERFRONT_PORT}}/${USERFRONT_PORT}/g; s/{{CLIENT_ID}}/devfront/g" \
|
||||
"${BASE_DIR}/templates/auth.template.ts" > "${TARGET_DIR}/devfront/auth.ts"
|
||||
sed "s/{{USERFRONT_PORT}}/${USERFRONT_PORT}/g" \
|
||||
"${BASE_DIR}/templates/orgfront/auth.ts" > "${TARGET_DIR}/orgfront/auth.ts"
|
||||
|
||||
# 5. Ory 정적 설정 복사
|
||||
if [ -d "${BASE_DIR}/../docker/ory/init-db" ]; then cp -n "${BASE_DIR}/../docker/ory/init-db/"* "${TARGET_DIR}/ory/init-db/" 2>/dev/null || true; fi
|
||||
if [ -d "${BASE_DIR}/../docker/ory/kratos" ]; then cp -n "${BASE_DIR}/../docker/ory/kratos/"* "${TARGET_DIR}/ory/kratos/" 2>/dev/null || true; fi
|
||||
if [ -d "${BASE_DIR}/../docker/ory/hydra" ]; then cp -n "${BASE_DIR}/../docker/ory/hydra/"* "${TARGET_DIR}/ory/hydra/" 2>/dev/null || true; fi
|
||||
if [ -d "${BASE_DIR}/../docker/ory/keto" ]; then cp -n "${BASE_DIR}/../docker/ory/keto/"* "${TARGET_DIR}/ory/keto/" 2>/dev/null || true; fi
|
||||
if [ -d "${BASE_DIR}/../docker/ory/oathkeeper" ]; then cp -n "${BASE_DIR}/../docker/ory/oathkeeper/"* "${TARGET_DIR}/ory/oathkeeper/" 2>/dev/null || true; fi
|
||||
|
||||
# 6. 마무리
|
||||
|
||||
@@ -17,6 +17,7 @@ BACKEND_PORT=${P}000
|
||||
USERFRONT_PORT=${P}500
|
||||
ADMINFRONT_PORT=${P}173
|
||||
DEVFRONT_PORT=${P}174
|
||||
ORGFRONT_PORT=${P}175
|
||||
OATHKEEPER_PROXY_PORT=${P}467
|
||||
|
||||
# === [3] 도메인 설정 (별도 도메인 구조) ===
|
||||
@@ -25,23 +26,44 @@ DOMAIN_SUFFIX=hmac.kr
|
||||
USERFRONT_URL=https://{{INSTANCE_NAME}}-sso.${DOMAIN_SUFFIX}
|
||||
ADMINFRONT_URL=https://{{INSTANCE_NAME}}-admin.${DOMAIN_SUFFIX}
|
||||
DEVFRONT_URL=https://{{INSTANCE_NAME}}-dev.${DOMAIN_SUFFIX}
|
||||
ORGFRONT_URL=https://{{INSTANCE_NAME}}-org.${DOMAIN_SUFFIX}
|
||||
|
||||
# OIDC/Auth URL
|
||||
VITE_OIDC_AUTHORITY=${USERFRONT_URL}/oidc
|
||||
ADMINFRONT_CALLBACK_URLS=${ADMINFRONT_URL}/auth/callback
|
||||
DEVFRONT_CALLBACK_URLS=${DEVFRONT_URL}/auth/callback
|
||||
ORGFRONT_CALLBACK_URLS=${ORGFRONT_URL}/auth/callback
|
||||
|
||||
# Ory URL
|
||||
KRATOS_UI_URL=${USERFRONT_URL}/auth
|
||||
KRATOS_BROWSER_URL=${USERFRONT_URL}/auth
|
||||
KRATOS_ADMIN_URL=http://kratos:4434
|
||||
HYDRA_PUBLIC_URL=${USERFRONT_URL}/oidc
|
||||
HYDRA_ADMIN_URL=http://hydra:4445
|
||||
OATHKEEPER_PUBLIC_URL=${USERFRONT_URL}
|
||||
KETO_READ_URL=http://keto:4466
|
||||
KETO_WRITE_URL=http://keto:4467
|
||||
|
||||
# Ory versions
|
||||
KRATOS_VERSION=v26.2.0
|
||||
HYDRA_VERSION=v26.2.0
|
||||
KETO_VERSION=v26.2.0
|
||||
OATHKEEPER_VERSION=v26.2.0
|
||||
ORY_POSTGRES_TAG=17-alpine
|
||||
|
||||
# === [4] IDP 및 DB Config ===
|
||||
IDP_PROVIDER=ory
|
||||
DB_PASSWORD=password
|
||||
ORY_POSTGRES_USER=ory
|
||||
ORY_POSTGRES_PASSWORD=generated_secret_here
|
||||
ORY_POSTGRES_DB=ory
|
||||
KRATOS_DB=ory_kratos
|
||||
HYDRA_DB=ory_hydra
|
||||
KETO_DB=ory_keto
|
||||
OATHKEEPER_UID=1001
|
||||
OATHKEEPER_GID=1001
|
||||
OATHKEEPER_INTROSPECT_CLIENT_ID=oathkeeper-introspect
|
||||
OATHKEEPER_INTROSPECT_CLIENT_SECRET=oathkeeper-secret
|
||||
CLICKHOUSE_PASSWORD=password
|
||||
REDIS_ADDR=redis:6379
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ services:
|
||||
ports:
|
||||
- "${DB_PORT}:5432"
|
||||
volumes:
|
||||
- db_data_${INSTANCE_NAME}:/var/lib/postgresql/data
|
||||
- db_data:/var/lib/postgresql/data
|
||||
networks: [app_net]
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
@@ -33,42 +33,228 @@ services:
|
||||
- "${CLICKHOUSE_PORT_HTTP}:8123"
|
||||
- "${CLICKHOUSE_PORT_NATIVE}:9000"
|
||||
volumes:
|
||||
- clickhouse_data_${INSTANCE_NAME}:/var/lib/clickhouse
|
||||
- clickhouse_data:/var/lib/clickhouse
|
||||
networks: [app_net]
|
||||
|
||||
# --- Ory Stack ---
|
||||
postgres_ory:
|
||||
image: postgres:17-alpine
|
||||
image: postgres:${ORY_POSTGRES_TAG:-17-alpine}
|
||||
container_name: ${COMPOSE_PROJECT_NAME}_ory_db
|
||||
environment:
|
||||
- POSTGRES_USER=${ORY_POSTGRES_USER}
|
||||
- POSTGRES_USER=${ORY_POSTGRES_USER:-ory}
|
||||
- POSTGRES_PASSWORD=${ORY_POSTGRES_PASSWORD}
|
||||
- POSTGRES_DB=${ORY_POSTGRES_DB:-ory}
|
||||
volumes:
|
||||
- ory_db_data_${INSTANCE_NAME}:/var/lib/postgresql/data
|
||||
- ory_db_data:/var/lib/postgresql/data
|
||||
- ./ory/init-db:/docker-entrypoint-initdb.d:ro
|
||||
networks: [app_net]
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${ORY_POSTGRES_USER}"]
|
||||
test: ["CMD-SHELL", "pg_isready -U ${ORY_POSTGRES_USER:-ory} -d ${KRATOS_DB:-ory_kratos}"]
|
||||
interval: 5s
|
||||
|
||||
kratos:
|
||||
image: oryd/kratos:v25.4.0
|
||||
container_name: ${COMPOSE_PROJECT_NAME}_kratos
|
||||
kratos-migrate:
|
||||
image: oryd/kratos:${KRATOS_VERSION:-v26.2.0}
|
||||
env_file: .env
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER:-ory}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KRATOS_DB:-ory_kratos}?sslmode=disable&max_conns=20
|
||||
- KRATOS_SERVE_PUBLIC_BASE_URL=${KRATOS_BROWSER_URL}
|
||||
- KRATOS_SERVE_ADMIN_BASE_URL=${KRATOS_ADMIN_URL:-http://kratos:4434}
|
||||
- KRATOS_SELFSERVICE_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL}
|
||||
- KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=${KRATOS_ALLOWED_RETURN_URLS_JSON:-["${KRATOS_UI_URL}","${KRATOS_UI_URL}/","${USERFRONT_URL}","${USERFRONT_URL}/","${USERFRONT_URL}/ko","${USERFRONT_URL}/ko/","${USERFRONT_URL}/en","${USERFRONT_URL}/en/","${USERFRONT_URL}/auth/callback","${USERFRONT_URL}/ko/auth/callback","${USERFRONT_URL}/en/auth/callback","${ADMINFRONT_URL}/auth/callback","${DEVFRONT_URL}/auth/callback","${ORGFRONT_URL}/auth/callback"]}
|
||||
- KRATOS_SELFSERVICE_FLOWS_ERROR_UI_URL=${KRATOS_UI_URL}/error
|
||||
- KRATOS_SELFSERVICE_FLOWS_SETTINGS_UI_URL=${KRATOS_UI_URL}/error?error=settings_disabled
|
||||
- KRATOS_SELFSERVICE_FLOWS_RECOVERY_UI_URL=${KRATOS_UI_URL}/recovery
|
||||
- KRATOS_SELFSERVICE_FLOWS_VERIFICATION_UI_URL=${KRATOS_UI_URL}/verification
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGIN_UI_URL=${KRATOS_UI_URL}/login
|
||||
- KRATOS_SELFSERVICE_FLOWS_REGISTRATION_UI_URL=${KRATOS_UI_URL}/registration
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGOUT_AFTER_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL}/login
|
||||
volumes:
|
||||
- ./ory/kratos:/etc/config/kratos:ro
|
||||
command: serve -c /etc/config/kratos/kratos.yml --dev
|
||||
command: migrate sql up -e -c /etc/config/kratos/kratos.yml --yes
|
||||
networks: [app_net]
|
||||
depends_on:
|
||||
postgres_ory: { condition: service_healthy }
|
||||
|
||||
kratos:
|
||||
image: oryd/kratos:${KRATOS_VERSION:-v26.2.0}
|
||||
container_name: ${COMPOSE_PROJECT_NAME}_kratos
|
||||
env_file: .env
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER:-ory}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KRATOS_DB:-ory_kratos}?sslmode=disable&max_conns=20
|
||||
- COOKIE_SECRET=${COOKIE_SECRET}
|
||||
- KRATOS_SERVE_PUBLIC_BASE_URL=${KRATOS_BROWSER_URL}
|
||||
- KRATOS_SERVE_ADMIN_BASE_URL=${KRATOS_ADMIN_URL:-http://kratos:4434}
|
||||
- KRATOS_SELFSERVICE_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL}
|
||||
- KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=${KRATOS_ALLOWED_RETURN_URLS_JSON:-["${KRATOS_UI_URL}","${KRATOS_UI_URL}/","${USERFRONT_URL}","${USERFRONT_URL}/","${USERFRONT_URL}/ko","${USERFRONT_URL}/ko/","${USERFRONT_URL}/en","${USERFRONT_URL}/en/","${USERFRONT_URL}/auth/callback","${USERFRONT_URL}/ko/auth/callback","${USERFRONT_URL}/en/auth/callback","${ADMINFRONT_URL}/auth/callback","${DEVFRONT_URL}/auth/callback","${ORGFRONT_URL}/auth/callback"]}
|
||||
- KRATOS_SELFSERVICE_FLOWS_ERROR_UI_URL=${KRATOS_UI_URL}/error
|
||||
- KRATOS_SELFSERVICE_FLOWS_SETTINGS_UI_URL=${KRATOS_UI_URL}/error?error=settings_disabled
|
||||
- KRATOS_SELFSERVICE_FLOWS_RECOVERY_UI_URL=${KRATOS_UI_URL}/recovery
|
||||
- KRATOS_SELFSERVICE_FLOWS_VERIFICATION_UI_URL=${KRATOS_UI_URL}/verification
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGIN_UI_URL=${KRATOS_UI_URL}/login
|
||||
- KRATOS_SELFSERVICE_FLOWS_REGISTRATION_UI_URL=${KRATOS_UI_URL}/registration
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGOUT_AFTER_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL}/login
|
||||
volumes:
|
||||
- ./ory/kratos:/etc/config/kratos:ro
|
||||
command: serve -c /etc/config/kratos/kratos.yml --dev --watch-courier
|
||||
networks: [app_net]
|
||||
depends_on:
|
||||
kratos-migrate: { condition: service_completed_successfully }
|
||||
|
||||
hydra-migrate:
|
||||
image: oryd/hydra:${HYDRA_VERSION:-v26.2.0}
|
||||
env_file: .env
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER:-ory}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${HYDRA_DB:-ory_hydra}?sslmode=disable&max_conns=20
|
||||
command: migrate sql up -e --yes
|
||||
networks: [app_net]
|
||||
depends_on:
|
||||
postgres_ory: { condition: service_healthy }
|
||||
|
||||
hydra:
|
||||
image: oryd/hydra:${HYDRA_VERSION:-v26.2.0}
|
||||
container_name: ${COMPOSE_PROJECT_NAME}_hydra
|
||||
env_file: .env
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER:-ory}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${HYDRA_DB:-ory_hydra}?sslmode=disable&max_conns=20
|
||||
- URLS_SELF_ISSUER=${HYDRA_PUBLIC_URL}
|
||||
- URLS_LOGIN=${HYDRA_LOGIN_URL:-${USERFRONT_URL}/login}
|
||||
- URLS_CONSENT=${HYDRA_CONSENT_URL:-${USERFRONT_URL}/consent}
|
||||
- URLS_ERROR=${HYDRA_ERROR_URL:-${USERFRONT_URL}/error}
|
||||
- SECRETS_SYSTEM=${ORY_POSTGRES_PASSWORD}
|
||||
volumes:
|
||||
- ./ory/hydra:/etc/config/hydra:ro
|
||||
command: serve -c /etc/config/hydra/hydra.yml all --dev
|
||||
networks: [app_net]
|
||||
depends_on:
|
||||
hydra-migrate: { condition: service_completed_successfully }
|
||||
|
||||
keto-migrate:
|
||||
image: oryd/keto:${KETO_VERSION:-v26.2.0}
|
||||
env_file: .env
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER:-ory}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KETO_DB:-ory_keto}?sslmode=disable&max_conns=20
|
||||
volumes:
|
||||
- ./ory/keto:/etc/config/keto:ro
|
||||
command: ["migrate", "up", "-c", "/etc/config/keto/keto.yml", "--yes"]
|
||||
networks: [app_net]
|
||||
depends_on:
|
||||
postgres_ory: { condition: service_healthy }
|
||||
|
||||
keto:
|
||||
image: oryd/keto:${KETO_VERSION:-v26.2.0}
|
||||
container_name: ${COMPOSE_PROJECT_NAME}_keto
|
||||
env_file: .env
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER:-ory}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KETO_DB:-ory_keto}?sslmode=disable&max_conns=20
|
||||
volumes:
|
||||
- ./ory/keto:/etc/config/keto:ro
|
||||
command: serve -c /etc/config/keto/keto.yml
|
||||
networks: [app_net]
|
||||
depends_on:
|
||||
keto-migrate: { condition: service_completed_successfully }
|
||||
|
||||
oathkeeper_logs_init:
|
||||
image: alpine:latest
|
||||
command: ["sh", "-c", "mkdir -p /var/log/oathkeeper && chown -R ${OATHKEEPER_UID:-1001}:${OATHKEEPER_GID:-1001} /var/log/oathkeeper"]
|
||||
volumes:
|
||||
- oathkeeper_logs:/var/log/oathkeeper
|
||||
networks: [app_net]
|
||||
|
||||
oathkeeper:
|
||||
image: oryd/oathkeeper:v25.4.0
|
||||
image: oryd/oathkeeper:${OATHKEEPER_VERSION:-v26.2.0}
|
||||
container_name: ${COMPOSE_PROJECT_NAME}_oathkeeper
|
||||
env_file: .env
|
||||
user: "${OATHKEEPER_UID:-1001}:${OATHKEEPER_GID:-1001}"
|
||||
ports:
|
||||
- "${OATHKEEPER_PROXY_PORT}:4455"
|
||||
environment:
|
||||
- APP_ENV=${APP_ENV:-production}
|
||||
- LOG_LEVEL=debug
|
||||
- OATHKEEPER_INTROSPECT_CLIENT_ID=${OATHKEEPER_INTROSPECT_CLIENT_ID:-oathkeeper-introspect}
|
||||
- OATHKEEPER_INTROSPECT_CLIENT_SECRET=${OATHKEEPER_INTROSPECT_CLIENT_SECRET:-oathkeeper-secret}
|
||||
volumes:
|
||||
- ./ory/oathkeeper:/etc/config/oathkeeper:ro
|
||||
- oathkeeper_logs:/var/log/oathkeeper
|
||||
entrypoint: ["/etc/config/oathkeeper/entrypoint.sh"]
|
||||
networks: [app_net]
|
||||
depends_on:
|
||||
oathkeeper_logs_init: { condition: service_completed_successfully }
|
||||
kratos: { condition: service_started }
|
||||
hydra: { condition: service_started }
|
||||
|
||||
ory_stack_check:
|
||||
image: alpine:latest
|
||||
container_name: ${COMPOSE_PROJECT_NAME}_ory_stack_check
|
||||
command: >
|
||||
/bin/sh -c "
|
||||
apk add --no-cache curl;
|
||||
echo 'Wait for Ory services...';
|
||||
until curl -s http://kratos:4433/health/ready; do sleep 1; done;
|
||||
until curl -s http://hydra:4444/health/ready; do sleep 1; done;
|
||||
until curl -s http://keto:4466/health/ready; do sleep 1; done;
|
||||
echo 'Ory stack is ready.';"
|
||||
depends_on:
|
||||
- kratos
|
||||
- hydra
|
||||
- keto
|
||||
networks: [app_net]
|
||||
|
||||
init-rp:
|
||||
image: alpine:latest
|
||||
env_file: .env
|
||||
command:
|
||||
- /bin/sh
|
||||
- -ec
|
||||
- |
|
||||
apk add --no-cache curl tar
|
||||
HYDRA_CLI_VERSION="$${HYDRA_VERSION:-v26.2.0}"
|
||||
HYDRA_CLI_VERSION="$${HYDRA_CLI_VERSION%-distroless}"
|
||||
HYDRA_CLI_ARCHIVE_VERSION="$${HYDRA_CLI_VERSION#v}"
|
||||
curl -fsSLo /tmp/hydra.tar.gz "https://github.com/ory/hydra/releases/download/$${HYDRA_CLI_VERSION}/hydra_$${HYDRA_CLI_ARCHIVE_VERSION}-linux_64bit.tar.gz"
|
||||
tar -xzf /tmp/hydra.tar.gz -C /usr/local/bin hydra
|
||||
rm /tmp/hydra.tar.gz
|
||||
|
||||
upsert_client() {
|
||||
ID=$$1
|
||||
shift
|
||||
if hydra get oauth2-client --endpoint "$${HYDRA_ADMIN_URL:-http://hydra:4445}" "$$ID" >/dev/null 2>&1; then
|
||||
hydra update oauth2-client --endpoint "$${HYDRA_ADMIN_URL:-http://hydra:4445}" "$$ID" "$$@"
|
||||
else
|
||||
hydra create oauth2-client --endpoint "$${HYDRA_ADMIN_URL:-http://hydra:4445}" --id "$$ID" "$$@"
|
||||
fi
|
||||
}
|
||||
|
||||
upsert_client "adminfront" \
|
||||
--name "AdminFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri "$${ADMINFRONT_CALLBACK_URLS:-$${ADMINFRONT_URL}/auth/callback}"
|
||||
|
||||
upsert_client "devfront" \
|
||||
--name "DevFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri "$${DEVFRONT_CALLBACK_URLS:-$${DEVFRONT_URL}/auth/callback}"
|
||||
|
||||
upsert_client "orgfront" \
|
||||
--name "OrgFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri "$${ORGFRONT_CALLBACK_URLS:-$${ORGFRONT_URL}/auth/callback}"
|
||||
|
||||
upsert_client "$${OATHKEEPER_INTROSPECT_CLIENT_ID:-oathkeeper-introspect}" \
|
||||
--secret "$${OATHKEEPER_INTROSPECT_CLIENT_SECRET:-oathkeeper-secret}" \
|
||||
--grant-type client_credentials \
|
||||
--response-type token \
|
||||
--scope openid,offline_access,profile,email
|
||||
depends_on:
|
||||
ory_stack_check: { condition: service_completed_successfully }
|
||||
networks: [app_net]
|
||||
|
||||
# --- Application Services ---
|
||||
@@ -78,6 +264,14 @@ services:
|
||||
env_file: .env
|
||||
environment:
|
||||
- PORT=${BACKEND_PORT}
|
||||
- APP_ENV=${APP_ENV:-production}
|
||||
- IDP_PROVIDER=${IDP_PROVIDER:-ory}
|
||||
- USERFRONT_URL=${USERFRONT_URL}
|
||||
- KRATOS_ADMIN_URL=${KRATOS_ADMIN_URL:-http://kratos:4434}
|
||||
- HYDRA_ADMIN_URL=${HYDRA_ADMIN_URL:-http://hydra:4445}
|
||||
- HYDRA_PUBLIC_URL=${HYDRA_PUBLIC_URL}
|
||||
- KETO_READ_URL=${KETO_READ_URL:-http://keto:4466}
|
||||
- KETO_WRITE_URL=${KETO_WRITE_URL:-http://keto:4467}
|
||||
- DB_HOST=postgres
|
||||
- REDIS_ADDR=redis:6379
|
||||
- CLICKHOUSE_HOST=clickhouse
|
||||
@@ -90,6 +284,7 @@ services:
|
||||
depends_on:
|
||||
postgres: { condition: service_healthy }
|
||||
redis: { condition: service_started }
|
||||
oathkeeper: { condition: service_started }
|
||||
|
||||
gateway:
|
||||
image: nginx:alpine
|
||||
@@ -147,6 +342,11 @@ networks:
|
||||
name: ${COMPOSE_PROJECT_NAME}_net
|
||||
|
||||
volumes:
|
||||
db_data_${INSTANCE_NAME}:
|
||||
ory_db_data_${INSTANCE_NAME}:
|
||||
clickhouse_data_${INSTANCE_NAME}:
|
||||
db_data:
|
||||
name: db_data_${INSTANCE_NAME}
|
||||
ory_db_data:
|
||||
name: ory_db_data_${INSTANCE_NAME}
|
||||
clickhouse_data:
|
||||
name: clickhouse_data_${INSTANCE_NAME}
|
||||
oathkeeper_logs:
|
||||
name: oathkeeper_logs_${INSTANCE_NAME}
|
||||
|
||||
@@ -29,7 +29,6 @@ http {
|
||||
}
|
||||
|
||||
location /oidc {
|
||||
rewrite ^/oidc/(.*)$ /$1 break;
|
||||
proxy_pass http://oathkeeper_srv;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
version: v25.4.0
|
||||
version: v26.2.0
|
||||
|
||||
dsn: ${DSN}
|
||||
|
||||
serve:
|
||||
public:
|
||||
base_url: http://localhost:4433/
|
||||
base_url: ${KRATOS_BROWSER_URL}
|
||||
cors:
|
||||
enabled: true
|
||||
allowed_origins:
|
||||
- http://backend:{{BACKEND_PORT}}
|
||||
- ${USERFRONT_URL}
|
||||
- ${ADMINFRONT_URL}
|
||||
- ${DEVFRONT_URL}
|
||||
- ${ORGFRONT_URL}
|
||||
admin:
|
||||
base_url: http://localhost:4434/
|
||||
base_url: ${KRATOS_ADMIN_URL}
|
||||
|
||||
session:
|
||||
cookie:
|
||||
@@ -19,30 +23,22 @@ session:
|
||||
path: /
|
||||
|
||||
selfservice:
|
||||
default_browser_return_url: http://localhost:{{USERFRONT_PORT}}/
|
||||
default_browser_return_url: ${KRATOS_UI_URL}
|
||||
allowed_return_urls:
|
||||
- http://backend:{{BACKEND_PORT}}
|
||||
- http://backend:{{BACKEND_PORT}}/
|
||||
- http://localhost:{{USERFRONT_PORT}}
|
||||
- https://app.brsw.kr
|
||||
- https://app.brsw.kr/
|
||||
- https://sss.hmac.kr
|
||||
- https://sss.hmac.kr/
|
||||
- https://sso.hmac.kr
|
||||
- https://sso.hmac.kr/
|
||||
- https://ssologin.hmac.kr
|
||||
- https://ssologin.hmac.kr/
|
||||
- https://sso-test.hmac.kr
|
||||
- https://sso-test.hmac.kr/
|
||||
- https://ssob.hmac.kr
|
||||
- https://ssob.hmac.kr/
|
||||
- https://ssob.hmac.kr/ko
|
||||
- https://ssob.hmac.kr/ko/
|
||||
- https://ssob.hmac.kr/en
|
||||
- https://ssob.hmac.kr/en/
|
||||
- https://ssob.hmac.kr/auth/callback
|
||||
- https://ssob.hmac.kr/ko/auth/callback
|
||||
- https://ssob.hmac.kr/en/auth/callback
|
||||
- ${KRATOS_UI_URL}
|
||||
- ${KRATOS_UI_URL}/
|
||||
- ${USERFRONT_URL}
|
||||
- ${USERFRONT_URL}/
|
||||
- ${USERFRONT_URL}/ko
|
||||
- ${USERFRONT_URL}/ko/
|
||||
- ${USERFRONT_URL}/en
|
||||
- ${USERFRONT_URL}/en/
|
||||
- ${USERFRONT_URL}/auth/callback
|
||||
- ${USERFRONT_URL}/ko/auth/callback
|
||||
- ${USERFRONT_URL}/en/auth/callback
|
||||
- ${ADMINFRONT_URL}/auth/callback
|
||||
- ${DEVFRONT_URL}/auth/callback
|
||||
- ${ORGFRONT_URL}/auth/callback
|
||||
|
||||
methods:
|
||||
password:
|
||||
@@ -55,24 +51,24 @@ selfservice:
|
||||
|
||||
flows:
|
||||
error:
|
||||
ui_url: http://localhost:{{USERFRONT_PORT}}/error
|
||||
ui_url: ${KRATOS_UI_URL}/error
|
||||
settings:
|
||||
ui_url: http://localhost:{{USERFRONT_PORT}}/error?error=settings_disabled
|
||||
ui_url: ${KRATOS_UI_URL}/error?error=settings_disabled
|
||||
privileged_session_max_age: 15m
|
||||
recovery:
|
||||
ui_url: http://localhost:{{USERFRONT_PORT}}/recovery
|
||||
ui_url: ${KRATOS_UI_URL}/recovery
|
||||
use: code
|
||||
verification:
|
||||
ui_url: http://localhost:{{USERFRONT_PORT}}/verification
|
||||
ui_url: ${KRATOS_UI_URL}/verification
|
||||
use: code
|
||||
logout:
|
||||
after:
|
||||
default_browser_return_url: http://localhost:{{USERFRONT_PORT}}/login
|
||||
default_browser_return_url: ${KRATOS_UI_URL}/login
|
||||
login:
|
||||
ui_url: http://localhost:{{USERFRONT_PORT}}/login
|
||||
ui_url: ${KRATOS_UI_URL}/login
|
||||
lifespan: 10m
|
||||
registration:
|
||||
ui_url: http://localhost:{{USERFRONT_PORT}}/registration
|
||||
ui_url: ${KRATOS_UI_URL}/registration
|
||||
lifespan: 10m
|
||||
|
||||
log:
|
||||
|
||||
@@ -1,9 +1,52 @@
|
||||
[
|
||||
{
|
||||
"id": "backend-api-rule",
|
||||
"id": "public-health",
|
||||
"description": "공개 헬스체크",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/api/v1/<.*>",
|
||||
"methods": ["GET", "POST", "PUT", "DELETE", "PATCH"]
|
||||
"url": "<.*>://<[^/]+>/health",
|
||||
"methods": ["GET"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://backend:{{BACKEND_PORT}}"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
},
|
||||
{
|
||||
"id": "public-preflight",
|
||||
"description": "CORS preflight",
|
||||
"match": {
|
||||
"url": "<.*>://<[^/]+>/api/v1/<.*>",
|
||||
"methods": ["OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://backend:{{BACKEND_PORT}}"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
},
|
||||
{
|
||||
"id": "public-auth",
|
||||
"description": "인증/회원가입 등 공개 엔드포인트",
|
||||
"match": {
|
||||
"url": "<.*>://<[^/]+>/api/v1/auth/<.*>",
|
||||
"methods": ["GET", "POST", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://backend:{{BACKEND_PORT}}"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
},
|
||||
{
|
||||
"id": "backend-command",
|
||||
"description": "Command 요청은 Backend로 전달 (Audit 강제)",
|
||||
"match": {
|
||||
"url": "<.*>://<[^/]+>/api/v1/<.*>",
|
||||
"methods": ["POST", "PUT", "PATCH", "DELETE"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://backend:{{BACKEND_PORT}}"
|
||||
@@ -11,5 +54,106 @@
|
||||
"authenticators": [{ "handler": "cookie_session" }],
|
||||
"authorizer": { "handler": "remote_json" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
},
|
||||
{
|
||||
"id": "backend-query",
|
||||
"description": "Backend Query (admin/dev 포함)",
|
||||
"match": {
|
||||
"url": "<.*>://<[^/]+>/api/v1/<.*>",
|
||||
"methods": ["GET"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://backend:{{BACKEND_PORT}}"
|
||||
},
|
||||
"authenticators": [{ "handler": "cookie_session" }],
|
||||
"authorizer": { "handler": "remote_json" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
},
|
||||
{
|
||||
"id": "hydra-well-known",
|
||||
"description": "Hydra OIDC Discovery & JWKS",
|
||||
"match": {
|
||||
"url": "<.*>://<[^/]+>/.well-known/<.*>",
|
||||
"methods": ["GET", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
},
|
||||
{
|
||||
"id": "hydra-well-known-oidc",
|
||||
"description": "Hydra OIDC Discovery & JWKS (with /oidc prefix)",
|
||||
"match": {
|
||||
"url": "<.*>://<[^/]+>/oidc/.well-known/<.*>",
|
||||
"methods": ["GET", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444",
|
||||
"strip_path": "/oidc"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
},
|
||||
{
|
||||
"id": "hydra-oauth2",
|
||||
"description": "Hydra OAuth2 Endpoints",
|
||||
"match": {
|
||||
"url": "<.*>://<[^/]+>/oauth2/<.*>",
|
||||
"methods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
},
|
||||
{
|
||||
"id": "hydra-oauth2-oidc",
|
||||
"description": "Hydra OAuth2 Endpoints (with /oidc prefix)",
|
||||
"match": {
|
||||
"url": "<.*>://<[^/]+>/oidc/oauth2/<.*>",
|
||||
"methods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444",
|
||||
"strip_path": "/oidc"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
},
|
||||
{
|
||||
"id": "hydra-userinfo",
|
||||
"description": "Hydra Userinfo",
|
||||
"match": {
|
||||
"url": "<.*>://<[^/]+>/userinfo",
|
||||
"methods": ["GET", "POST", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
},
|
||||
{
|
||||
"id": "hydra-userinfo-oidc",
|
||||
"description": "Hydra Userinfo (with /oidc prefix)",
|
||||
"match": {
|
||||
"url": "<.*>://<[^/]+>/oidc/userinfo",
|
||||
"methods": ["GET", "POST", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444",
|
||||
"strip_path": "/oidc"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -22,13 +22,13 @@ services:
|
||||
retries: 5
|
||||
|
||||
kratos-migrate:
|
||||
image: oryd/kratos:${KRATOS_VERSION:-v25.4.0}
|
||||
image: oryd/kratos:${KRATOS_VERSION:-v26.2.0}
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KRATOS_DB:-ory_kratos}?sslmode=disable&max_conns=20
|
||||
- KRATOS_SERVE_PUBLIC_BASE_URL="${KRATOS_BROWSER_URL:-http://localhost:4433}"
|
||||
- KRATOS_SERVE_ADMIN_BASE_URL="${KRATOS_ADMIN_URL:-http://kratos:4434}"
|
||||
- KRATOS_SELFSERVICE_DEFAULT_BROWSER_RETURN_URL="${KRATOS_UI_URL:-http://localhost:5000}"
|
||||
- KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS='["${KRATOS_UI_URL:-http://localhost:5000}","${USERFRONT_URL:-http://localhost:5000}"]'
|
||||
- KRATOS_SERVE_PUBLIC_BASE_URL=${KRATOS_BROWSER_URL}
|
||||
- KRATOS_SERVE_ADMIN_BASE_URL=${KRATOS_ADMIN_URL}
|
||||
- KRATOS_SELFSERVICE_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL}
|
||||
- KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=${KRATOS_ALLOWED_RETURN_URLS_JSON:-["${KRATOS_UI_URL}","${USERFRONT_URL}"]}
|
||||
volumes:
|
||||
- ./docker/ory/kratos:/etc/config/kratos
|
||||
command: migrate sql up -e -c /etc/config/kratos/kratos.yml --yes
|
||||
@@ -39,15 +39,15 @@ services:
|
||||
- ory-net
|
||||
|
||||
kratos:
|
||||
image: oryd/kratos:${KRATOS_VERSION:-v25.4.0}
|
||||
image: oryd/kratos:${KRATOS_VERSION:-v26.2.0}
|
||||
container_name: ory_kratos
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KRATOS_DB:-ory_kratos}?sslmode=disable&max_conns=20
|
||||
- COOKIE_SECRET="${COOKIE_SECRET:-localcookie123}"
|
||||
- KRATOS_SERVE_PUBLIC_BASE_URL="${KRATOS_BROWSER_URL:-http://localhost:4433}"
|
||||
- KRATOS_SERVE_ADMIN_BASE_URL="${KRATOS_ADMIN_URL:-http://kratos:4434}"
|
||||
- KRATOS_SELFSERVICE_DEFAULT_BROWSER_RETURN_URL="${KRATOS_UI_URL:-http://localhost:5000}"
|
||||
- KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS='["${KRATOS_UI_URL:-http://localhost:5000}","${USERFRONT_URL:-http://localhost:5000}"]'
|
||||
- COOKIE_SECRET=${COOKIE_SECRET:-localcookie123}
|
||||
- KRATOS_SERVE_PUBLIC_BASE_URL=${KRATOS_BROWSER_URL}
|
||||
- KRATOS_SERVE_ADMIN_BASE_URL=${KRATOS_ADMIN_URL}
|
||||
- KRATOS_SELFSERVICE_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL}
|
||||
- KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=${KRATOS_ALLOWED_RETURN_URLS_JSON:-["${KRATOS_UI_URL}","${USERFRONT_URL}"]}
|
||||
volumes:
|
||||
- ./docker/ory/kratos:/etc/config/kratos
|
||||
command: serve -c /etc/config/kratos/kratos.yml
|
||||
@@ -59,7 +59,7 @@ services:
|
||||
- kratosnet
|
||||
|
||||
hydra-migrate:
|
||||
image: oryd/hydra:${HYDRA_VERSION:-v25.4.0}
|
||||
image: oryd/hydra:${HYDRA_VERSION:-v26.2.0}
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${HYDRA_DB:-ory_hydra}?sslmode=disable&max_conns=20
|
||||
command: migrate sql up -e --yes
|
||||
@@ -70,13 +70,14 @@ services:
|
||||
- ory-net
|
||||
|
||||
hydra:
|
||||
image: oryd/hydra:${HYDRA_VERSION:-v25.4.0}
|
||||
image: oryd/hydra:${HYDRA_VERSION:-v26.2.0}
|
||||
container_name: ory_hydra
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${HYDRA_DB:-ory_hydra}?sslmode=disable&max_conns=20
|
||||
- URLS_SELF_ISSUER=${USERFRONT_URL:-http://localhost:5000}/oidc
|
||||
- URLS_LOGIN=${USERFRONT_URL:-http://localhost:5000}/login
|
||||
- URLS_CONSENT=${USERFRONT_URL:-http://localhost:5000}/consent
|
||||
- URLS_SELF_ISSUER=${HYDRA_PUBLIC_URL}
|
||||
- URLS_LOGIN=${HYDRA_LOGIN_URL:-${USERFRONT_URL}/login}
|
||||
- URLS_CONSENT=${HYDRA_CONSENT_URL:-${USERFRONT_URL}/consent}
|
||||
- URLS_ERROR=${HYDRA_ERROR_URL:-${USERFRONT_URL}/error}
|
||||
- SECRETS_SYSTEM=${ORY_POSTGRES_PASSWORD}
|
||||
volumes:
|
||||
- ./docker/ory/hydra:/etc/config/hydra
|
||||
@@ -89,7 +90,7 @@ services:
|
||||
- hydranet
|
||||
|
||||
keto-migrate:
|
||||
image: oryd/keto:${KETO_VERSION:-v25.4.0}
|
||||
image: oryd/keto:${KETO_VERSION:-v26.2.0}
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KETO_DB:-ory_keto}?sslmode=disable&max_conns=20
|
||||
volumes:
|
||||
@@ -102,7 +103,7 @@ services:
|
||||
- ory-net
|
||||
|
||||
keto:
|
||||
image: oryd/keto:${KETO_VERSION:-v25.4.0}
|
||||
image: oryd/keto:${KETO_VERSION:-v26.2.0}
|
||||
container_name: ory_keto
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KETO_DB:-ory_keto}?sslmode=disable&max_conns=20
|
||||
@@ -116,21 +117,24 @@ services:
|
||||
- ory-net
|
||||
|
||||
oathkeeper:
|
||||
image: oryd/oathkeeper:${OATHKEEPER_VERSION:-v0.40.6}
|
||||
image: oryd/oathkeeper:${OATHKEEPER_VERSION:-v26.2.0}
|
||||
container_name: oathkeeper
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
kratos:
|
||||
condition: service_started
|
||||
environment:
|
||||
- APP_ENV=${APP_ENV:-development}
|
||||
- LOG_LEVEL=debug
|
||||
command: serve proxy --config /etc/config/oathkeeper/oathkeeper.yml
|
||||
- OATHKEEPER_INTROSPECT_CLIENT_ID=${OATHKEEPER_INTROSPECT_CLIENT_ID:-oathkeeper-introspect}
|
||||
- OATHKEEPER_INTROSPECT_CLIENT_SECRET=${OATHKEEPER_INTROSPECT_CLIENT_SECRET:-oathkeeper-secret}
|
||||
volumes:
|
||||
- ./docker/ory/oathkeeper:/etc/config/oathkeeper
|
||||
- oathkeeper_logs:/var/log/oathkeeper
|
||||
entrypoint: ["/etc/config/oathkeeper/entrypoint.sh"]
|
||||
networks:
|
||||
- ory-net
|
||||
- baron_net
|
||||
- baron_net
|
||||
- public_net
|
||||
ports:
|
||||
- "4455:4455"
|
||||
@@ -168,47 +172,47 @@ services:
|
||||
- /bin/sh
|
||||
- -ec
|
||||
- |
|
||||
apk add --no-cache curl tar
|
||||
HYDRA_CLI_VERSION="$${HYDRA_VERSION:-v26.2.0}"
|
||||
HYDRA_CLI_VERSION="$${HYDRA_CLI_VERSION%-distroless}"
|
||||
HYDRA_CLI_ARCHIVE_VERSION="$${HYDRA_CLI_VERSION#v}"
|
||||
curl -fsSLo /tmp/hydra.tar.gz "https://github.com/ory/hydra/releases/download/$${HYDRA_CLI_VERSION}/hydra_$${HYDRA_CLI_ARCHIVE_VERSION}-linux_64bit.tar.gz"
|
||||
tar -xzf /tmp/hydra.tar.gz -C /usr/local/bin hydra
|
||||
rm /tmp/hydra.tar.gz
|
||||
apk add --no-cache curl tar
|
||||
HYDRA_CLI_VERSION="$${HYDRA_VERSION:-v26.2.0}"
|
||||
HYDRA_CLI_VERSION="$${HYDRA_CLI_VERSION%-distroless}"
|
||||
HYDRA_CLI_ARCHIVE_VERSION="$${HYDRA_CLI_VERSION#v}"
|
||||
curl -fsSLo /tmp/hydra.tar.gz "https://github.com/ory/hydra/releases/download/$${HYDRA_CLI_VERSION}/hydra_$${HYDRA_CLI_ARCHIVE_VERSION}-linux_64bit.tar.gz"
|
||||
tar -xzf /tmp/hydra.tar.gz -C /usr/local/bin hydra
|
||||
rm /tmp/hydra.tar.gz
|
||||
|
||||
echo "Creating/Updating OAuth2 Clients..."
|
||||
|
||||
hydra create oauth2-client \
|
||||
--endpoint http://hydra:4445 \
|
||||
--id adminfront \
|
||||
--name "AdminFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri ${ADMINFRONT_CALLBACK_URLS:-http://localhost:5173/auth/callback,http://172.16.10.176:5173/auth/callback}
|
||||
echo "Creating/Updating OAuth2 Clients..."
|
||||
|
||||
hydra create oauth2-client \
|
||||
--endpoint http://hydra:4445 \
|
||||
--id devfront \
|
||||
--name "DevFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri ${DEVFRONT_CALLBACK_URLS:-http://localhost:5174/auth/callback,http://172.16.10.176:5174/auth/callback}
|
||||
hydra create oauth2-client \
|
||||
--endpoint "$${HYDRA_ADMIN_URL}" \
|
||||
--id adminfront \
|
||||
--name "AdminFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri "$${ADMINFRONT_CALLBACK_URLS}"
|
||||
|
||||
hydra create oauth2-client \
|
||||
--endpoint http://hydra:4445 \
|
||||
--id orgfront \
|
||||
--name "OrgFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri ${ORGFRONT_CALLBACK_URLS:-http://localhost:5175/auth/callback,http://172.16.10.176:5175/auth/callback,https://baron-orgchart.hmac.kr/auth/callback}
|
||||
hydra create oauth2-client \
|
||||
--endpoint "$${HYDRA_ADMIN_URL}" \
|
||||
--id devfront \
|
||||
--name "DevFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri "$${DEVFRONT_CALLBACK_URLS}"
|
||||
|
||||
echo "All RP clients initialized successfully."
|
||||
hydra create oauth2-client \
|
||||
--endpoint "$${HYDRA_ADMIN_URL}" \
|
||||
--id orgfront \
|
||||
--name "OrgFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri "$${ORGFRONT_CALLBACK_URLS}"
|
||||
|
||||
echo "All RP clients initialized successfully."
|
||||
depends_on:
|
||||
ory_stack_check:
|
||||
condition: service_completed_successfully
|
||||
|
||||
@@ -4,23 +4,18 @@ dsn: ${DSN}
|
||||
|
||||
serve:
|
||||
public:
|
||||
base_url: http://localhost:4433/
|
||||
base_url: ${KRATOS_BROWSER_URL}
|
||||
cors:
|
||||
enabled: true
|
||||
allowed_origins:
|
||||
- http://localhost:5173
|
||||
- http://localhost:5174
|
||||
- http://localhost:5175
|
||||
- http://localhost:5000
|
||||
- ${USERFRONT_URL}
|
||||
- ${ADMINFRONT_URL}
|
||||
- ${DEVFRONT_URL}
|
||||
- ${ORGFRONT_URL}
|
||||
- http://backend:3000
|
||||
- http://baron_backend:3000
|
||||
- https://ssologin.hmac.kr
|
||||
- https://sso-test.hmac.kr
|
||||
- https://app.brsw.kr
|
||||
- https://sss.hmac.kr
|
||||
- https://sso.hmac.kr
|
||||
admin:
|
||||
base_url: http://localhost:4434/
|
||||
base_url: ${KRATOS_ADMIN_URL}
|
||||
|
||||
session:
|
||||
cookie:
|
||||
@@ -29,21 +24,22 @@ session:
|
||||
path: /
|
||||
|
||||
selfservice:
|
||||
default_browser_return_url: http://localhost:5000/
|
||||
default_browser_return_url: ${KRATOS_UI_URL}
|
||||
allowed_return_urls:
|
||||
- http://baron_backend:3000
|
||||
- http://baron_backend:3000/
|
||||
- http://localhost:5000
|
||||
- https://app.brsw.kr
|
||||
- https://app.brsw.kr/
|
||||
- https://sss.hmac.kr
|
||||
- https://sss.hmac.kr/
|
||||
- https://sso.hmac.kr
|
||||
- https://sso.hmac.kr/
|
||||
- https://ssologin.hmac.kr
|
||||
- https://ssologin.hmac.kr/
|
||||
- https://sso-test.hmac.kr
|
||||
- https://sso-test.hmac.kr/
|
||||
- ${KRATOS_UI_URL}
|
||||
- ${KRATOS_UI_URL}/
|
||||
- ${USERFRONT_URL}
|
||||
- ${USERFRONT_URL}/
|
||||
- ${USERFRONT_URL}/ko
|
||||
- ${USERFRONT_URL}/ko/
|
||||
- ${USERFRONT_URL}/en
|
||||
- ${USERFRONT_URL}/en/
|
||||
- ${USERFRONT_URL}/auth/callback
|
||||
- ${USERFRONT_URL}/ko/auth/callback
|
||||
- ${USERFRONT_URL}/en/auth/callback
|
||||
- ${ADMINFRONT_URL}/auth/callback
|
||||
- ${DEVFRONT_URL}/auth/callback
|
||||
- ${ORGFRONT_URL}/auth/callback
|
||||
|
||||
methods:
|
||||
password:
|
||||
@@ -56,24 +52,24 @@ selfservice:
|
||||
|
||||
flows:
|
||||
error:
|
||||
ui_url: http://localhost:5000/error
|
||||
ui_url: ${KRATOS_UI_URL}/error
|
||||
settings:
|
||||
ui_url: http://localhost:5000/error?error=settings_disabled
|
||||
ui_url: ${KRATOS_UI_URL}/error?error=settings_disabled
|
||||
privileged_session_max_age: 15m
|
||||
recovery:
|
||||
ui_url: http://localhost:5000/recovery
|
||||
ui_url: ${KRATOS_UI_URL}/recovery
|
||||
use: code
|
||||
verification:
|
||||
ui_url: http://localhost:5000/verification
|
||||
ui_url: ${KRATOS_UI_URL}/verification
|
||||
use: code
|
||||
logout:
|
||||
after:
|
||||
default_browser_return_url: http://localhost:5000/login
|
||||
default_browser_return_url: ${KRATOS_UI_URL}/login
|
||||
login:
|
||||
ui_url: http://localhost:5000/login
|
||||
ui_url: ${KRATOS_UI_URL}/login
|
||||
lifespan: 10m
|
||||
registration:
|
||||
ui_url: http://localhost:5000/registration
|
||||
ui_url: ${KRATOS_UI_URL}/registration
|
||||
lifespan: 10m
|
||||
|
||||
log:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"id": "public-health",
|
||||
"description": "공개 헬스체크",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/health",
|
||||
"url": "<.*>://<[^/]+>/health",
|
||||
"methods": ["GET"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -17,7 +17,7 @@
|
||||
"id": "public-preflight",
|
||||
"description": "CORS preflight",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/api/v1/<.*>",
|
||||
"url": "<.*>://<[^/]+>/api/v1/<.*>",
|
||||
"methods": ["OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -31,7 +31,7 @@
|
||||
"id": "public-auth",
|
||||
"description": "인증/회원가입 등 공개 엔드포인트",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/api/v1/auth/<.*>",
|
||||
"url": "<.*>://<[^/]+>/api/v1/auth/<.*>",
|
||||
"methods": ["GET", "POST", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -45,7 +45,7 @@
|
||||
"id": "backend-command",
|
||||
"description": "Command 요청은 Backend로 전달 (Audit 강제)",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/api/v1/<.*>",
|
||||
"url": "<.*>://<[^/]+>/api/v1/<.*>",
|
||||
"methods": ["POST", "PUT", "PATCH", "DELETE"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -59,7 +59,7 @@
|
||||
"id": "backend-query",
|
||||
"description": "Backend Query (admin/dev 포함)",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/api/v1/<.*>",
|
||||
"url": "<.*>://<[^/]+>/api/v1/<.*>",
|
||||
"methods": ["GET"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -73,7 +73,7 @@
|
||||
"id": "hydra-well-known",
|
||||
"description": "Hydra OIDC Discovery & JWKS",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/.well-known/<.*>",
|
||||
"url": "<.*>://<[^/]+>/.well-known/<.*>",
|
||||
"methods": ["GET", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -87,12 +87,12 @@
|
||||
"id": "hydra-well-known-oidc",
|
||||
"description": "Hydra OIDC Discovery & JWKS (with /oidc prefix)",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/oidc/.well-known/<.*>",
|
||||
"url": "<.*>://<[^/]+>/oidc/.well-known/<.*>",
|
||||
"methods": ["GET", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444",
|
||||
"strip_path_prefix": "/oidc"
|
||||
"strip_path": "/oidc"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
@@ -102,7 +102,7 @@
|
||||
"id": "hydra-oauth2",
|
||||
"description": "Hydra OAuth2 Endpoints",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/oauth2/<.*>",
|
||||
"url": "<.*>://<[^/]+>/oauth2/<.*>",
|
||||
"methods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -116,12 +116,12 @@
|
||||
"id": "hydra-oauth2-oidc",
|
||||
"description": "Hydra OAuth2 Endpoints (with /oidc prefix)",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/oidc/oauth2/<.*>",
|
||||
"url": "<.*>://<[^/]+>/oidc/oauth2/<.*>",
|
||||
"methods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444",
|
||||
"strip_path_prefix": "/oidc"
|
||||
"strip_path": "/oidc"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
@@ -131,7 +131,7 @@
|
||||
"id": "hydra-userinfo",
|
||||
"description": "Hydra Userinfo",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/userinfo",
|
||||
"url": "<.*>://<[^/]+>/userinfo",
|
||||
"methods": ["GET", "POST", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -145,12 +145,12 @@
|
||||
"id": "hydra-userinfo-oidc",
|
||||
"description": "Hydra Userinfo (with /oidc prefix)",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/oidc/userinfo",
|
||||
"url": "<.*>://<[^/]+>/oidc/userinfo",
|
||||
"methods": ["GET", "POST", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444",
|
||||
"strip_path_prefix": "/oidc"
|
||||
"strip_path": "/oidc"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"id": "public-health",
|
||||
"description": "공개 헬스체크",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/health",
|
||||
"url": "<.*>://<[^/]+>/health",
|
||||
"methods": ["GET"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -17,7 +17,7 @@
|
||||
"id": "public-preflight",
|
||||
"description": "CORS preflight",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/api/v1/<.*>",
|
||||
"url": "<.*>://<[^/]+>/api/v1/<.*>",
|
||||
"methods": ["OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -31,7 +31,7 @@
|
||||
"id": "public-auth",
|
||||
"description": "인증/회원가입 등 공개 엔드포인트",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/api/v1/auth/<.*>",
|
||||
"url": "<.*>://<[^/]+>/api/v1/auth/<.*>",
|
||||
"methods": ["GET", "POST", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -45,7 +45,7 @@
|
||||
"id": "backend-command",
|
||||
"description": "Command 요청은 Backend로 전달 (Audit 강제)",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/api/v1/<.*>",
|
||||
"url": "<.*>://<[^/]+>/api/v1/<.*>",
|
||||
"methods": ["POST", "PUT", "PATCH", "DELETE"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -59,7 +59,7 @@
|
||||
"id": "backend-query",
|
||||
"description": "Backend Query (admin/dev 포함)",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/api/v1/<.*>",
|
||||
"url": "<.*>://<[^/]+>/api/v1/<.*>",
|
||||
"methods": ["GET"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -73,7 +73,7 @@
|
||||
"id": "hydra-well-known",
|
||||
"description": "Hydra OIDC Discovery & JWKS",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/.well-known/<.*>",
|
||||
"url": "<.*>://<[^/]+>/.well-known/<.*>",
|
||||
"methods": ["GET", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -87,12 +87,12 @@
|
||||
"id": "hydra-well-known-oidc",
|
||||
"description": "Hydra OIDC Discovery & JWKS (with /oidc prefix)",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/oidc/.well-known/<.*>",
|
||||
"url": "<.*>://<[^/]+>/oidc/.well-known/<.*>",
|
||||
"methods": ["GET", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444",
|
||||
"strip_path_prefix": "/oidc"
|
||||
"strip_path": "/oidc"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
@@ -102,7 +102,7 @@
|
||||
"id": "hydra-oauth2",
|
||||
"description": "Hydra OAuth2 Endpoints",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/oauth2/<.*>",
|
||||
"url": "<.*>://<[^/]+>/oauth2/<.*>",
|
||||
"methods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -116,12 +116,12 @@
|
||||
"id": "hydra-oauth2-oidc",
|
||||
"description": "Hydra OAuth2 Endpoints (with /oidc prefix)",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/oidc/oauth2/<.*>",
|
||||
"url": "<.*>://<[^/]+>/oidc/oauth2/<.*>",
|
||||
"methods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444",
|
||||
"strip_path_prefix": "/oidc"
|
||||
"strip_path": "/oidc"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
@@ -131,7 +131,7 @@
|
||||
"id": "hydra-userinfo",
|
||||
"description": "Hydra Userinfo",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/userinfo",
|
||||
"url": "<.*>://<[^/]+>/userinfo",
|
||||
"methods": ["GET", "POST", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -145,12 +145,12 @@
|
||||
"id": "hydra-userinfo-oidc",
|
||||
"description": "Hydra Userinfo (with /oidc prefix)",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/oidc/userinfo",
|
||||
"url": "<.*>://<[^/]+>/oidc/userinfo",
|
||||
"methods": ["GET", "POST", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444",
|
||||
"strip_path_prefix": "/oidc"
|
||||
"strip_path": "/oidc"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
[
|
||||
{
|
||||
"id": "public-health",
|
||||
"description": "공개 헬스체크 (PROD 도메인)",
|
||||
"description": "공개 헬스체크 (PROD)",
|
||||
"match": {
|
||||
"url": "https://app.brsw.kr/health",
|
||||
"url": "<.*>://<[^/]+>/health",
|
||||
"methods": ["GET"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -15,9 +15,9 @@
|
||||
},
|
||||
{
|
||||
"id": "public-preflight",
|
||||
"description": "CORS preflight (PROD 도메인)",
|
||||
"description": "CORS preflight (PROD)",
|
||||
"match": {
|
||||
"url": "https://app.brsw.kr/api/v1/<.*>",
|
||||
"url": "<.*>://<[^/]+>/api/v1/<.*>",
|
||||
"methods": ["OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -29,9 +29,9 @@
|
||||
},
|
||||
{
|
||||
"id": "public-auth",
|
||||
"description": "인증/회원가입 등 공개 엔드포인트 (PROD 도메인)",
|
||||
"description": "인증/회원가입 등 공개 엔드포인트 (PROD)",
|
||||
"match": {
|
||||
"url": "https://app.brsw.kr/api/v1/auth/<.*>",
|
||||
"url": "<.*>://<[^/]+>/api/v1/auth/<.*>",
|
||||
"methods": ["GET", "POST", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -45,7 +45,7 @@
|
||||
"id": "backend-command",
|
||||
"description": "Command 요청은 Backend로 전달 (Audit 강제)",
|
||||
"match": {
|
||||
"url": "https://app.brsw.kr/api/v1/<.*>",
|
||||
"url": "<.*>://<[^/]+>/api/v1/<.*>",
|
||||
"methods": ["POST", "PUT", "PATCH", "DELETE"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -59,7 +59,7 @@
|
||||
"id": "backend-query",
|
||||
"description": "Backend Query (admin/dev 포함)",
|
||||
"match": {
|
||||
"url": "https://app.brsw.kr/api/v1/<.*>",
|
||||
"url": "<.*>://<[^/]+>/api/v1/<.*>",
|
||||
"methods": ["GET"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -68,5 +68,92 @@
|
||||
"authenticators": [{ "handler": "cookie_session" }],
|
||||
"authorizer": { "handler": "remote_json" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
},
|
||||
{
|
||||
"id": "hydra-well-known",
|
||||
"description": "Hydra OIDC Discovery & JWKS (PROD)",
|
||||
"match": {
|
||||
"url": "<.*>://<[^/]+>/.well-known/<.*>",
|
||||
"methods": ["GET", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
},
|
||||
{
|
||||
"id": "hydra-well-known-oidc",
|
||||
"description": "Hydra OIDC Discovery & JWKS with /oidc prefix (PROD)",
|
||||
"match": {
|
||||
"url": "<.*>://<[^/]+>/oidc/.well-known/<.*>",
|
||||
"methods": ["GET", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444",
|
||||
"strip_path": "/oidc"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
},
|
||||
{
|
||||
"id": "hydra-oauth2",
|
||||
"description": "Hydra OAuth2 Endpoints (PROD)",
|
||||
"match": {
|
||||
"url": "<.*>://<[^/]+>/oauth2/<.*>",
|
||||
"methods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
},
|
||||
{
|
||||
"id": "hydra-oauth2-oidc",
|
||||
"description": "Hydra OAuth2 Endpoints with /oidc prefix (PROD 도메인)",
|
||||
"match": {
|
||||
"url": "<.*>://<[^/]+>/oidc/oauth2/<.*>",
|
||||
"methods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444",
|
||||
"strip_path": "/oidc"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
},
|
||||
{
|
||||
"id": "hydra-userinfo",
|
||||
"description": "Hydra Userinfo (PROD)",
|
||||
"match": {
|
||||
"url": "<.*>://<[^/]+>/userinfo",
|
||||
"methods": ["GET", "POST", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
},
|
||||
{
|
||||
"id": "hydra-userinfo-oidc",
|
||||
"description": "Hydra Userinfo with /oidc prefix (PROD 도메인)",
|
||||
"match": {
|
||||
"url": "<.*>://<[^/]+>/oidc/userinfo",
|
||||
"methods": ["GET", "POST", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444",
|
||||
"strip_path": "/oidc"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
"mutators": [{ "handler": "noop" }]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"id": "public-health",
|
||||
"description": "공개 헬스체크",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/health",
|
||||
"url": "<.*>://<[^/]+>/health",
|
||||
"methods": ["GET"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -17,7 +17,7 @@
|
||||
"id": "public-preflight",
|
||||
"description": "CORS preflight",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/api/v1/<.*>",
|
||||
"url": "<.*>://<[^/]+>/api/v1/<.*>",
|
||||
"methods": ["OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -31,7 +31,7 @@
|
||||
"id": "public-auth",
|
||||
"description": "인증/회원가입 등 공개 엔드포인트",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/api/v1/auth/<.*>",
|
||||
"url": "<.*>://<[^/]+>/api/v1/auth/<.*>",
|
||||
"methods": ["GET", "POST", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -45,7 +45,7 @@
|
||||
"id": "backend-command",
|
||||
"description": "Command 요청은 Backend로 전달 (Audit 강제)",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/api/v1/<.*>",
|
||||
"url": "<.*>://<[^/]+>/api/v1/<.*>",
|
||||
"methods": ["POST", "PUT", "PATCH", "DELETE"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -59,7 +59,7 @@
|
||||
"id": "backend-query",
|
||||
"description": "Backend Query (admin/dev 포함)",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/api/v1/<.*>",
|
||||
"url": "<.*>://<[^/]+>/api/v1/<.*>",
|
||||
"methods": ["GET"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -73,7 +73,7 @@
|
||||
"id": "hydra-well-known",
|
||||
"description": "Hydra OIDC Discovery & JWKS",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/.well-known/<.*>",
|
||||
"url": "<.*>://<[^/]+>/.well-known/<.*>",
|
||||
"methods": ["GET", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -87,12 +87,12 @@
|
||||
"id": "hydra-well-known-oidc",
|
||||
"description": "Hydra OIDC Discovery & JWKS (with /oidc prefix)",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/oidc/.well-known/<.*>",
|
||||
"url": "<.*>://<[^/]+>/oidc/.well-known/<.*>",
|
||||
"methods": ["GET", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444",
|
||||
"strip_path_prefix": "/oidc"
|
||||
"strip_path": "/oidc"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
@@ -102,7 +102,7 @@
|
||||
"id": "hydra-oauth2",
|
||||
"description": "Hydra OAuth2 Endpoints",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/oauth2/<.*>",
|
||||
"url": "<.*>://<[^/]+>/oauth2/<.*>",
|
||||
"methods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -116,12 +116,12 @@
|
||||
"id": "hydra-oauth2-oidc",
|
||||
"description": "Hydra OAuth2 Endpoints (with /oidc prefix)",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/oidc/oauth2/<.*>",
|
||||
"url": "<.*>://<[^/]+>/oidc/oauth2/<.*>",
|
||||
"methods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444",
|
||||
"strip_path_prefix": "/oidc"
|
||||
"strip_path": "/oidc"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
@@ -131,7 +131,7 @@
|
||||
"id": "hydra-userinfo",
|
||||
"description": "Hydra Userinfo",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/userinfo",
|
||||
"url": "<.*>://<[^/]+>/userinfo",
|
||||
"methods": ["GET", "POST", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
@@ -145,12 +145,12 @@
|
||||
"id": "hydra-userinfo-oidc",
|
||||
"description": "Hydra Userinfo (with /oidc prefix)",
|
||||
"match": {
|
||||
"url": "<.*>://<.*>/oidc/userinfo",
|
||||
"url": "<.*>://<[^/]+>/oidc/userinfo",
|
||||
"methods": ["GET", "POST", "OPTIONS"]
|
||||
},
|
||||
"upstream": {
|
||||
"url": "http://hydra:4444",
|
||||
"strip_path_prefix": "/oidc"
|
||||
"strip_path": "/oidc"
|
||||
},
|
||||
"authenticators": [{ "handler": "noop" }],
|
||||
"authorizer": { "handler": "allow" },
|
||||
|
||||
@@ -1,501 +1,521 @@
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
container_name: baron_postgres
|
||||
environment:
|
||||
POSTGRES_USER: "${DB_USER:-baron}"
|
||||
POSTGRES_PASSWORD: "${DB_PASSWORD:-password}"
|
||||
POSTGRES_DB: "${DB_NAME:-baron_sso}"
|
||||
ports:
|
||||
- "${DB_PORT:-5432}:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- ./docker/init-metadata:/docker-entrypoint-initdb.d
|
||||
networks:
|
||||
- baron_net
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"pg_isready -U ${DB_USER:-baron} -d ${DB_NAME:-baron_sso}",
|
||||
]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
restart: always
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
container_name: baron_postgres
|
||||
environment:
|
||||
POSTGRES_USER: "${DB_USER:-baron}"
|
||||
POSTGRES_PASSWORD: "${DB_PASSWORD:-password}"
|
||||
POSTGRES_DB: "${DB_NAME:-baron_sso}"
|
||||
ports:
|
||||
- "${DB_PORT:-5432}:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- ./docker/init-metadata:/docker-entrypoint-initdb.d
|
||||
networks:
|
||||
- baron_net
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"pg_isready -U ${DB_USER:-baron} -d ${DB_NAME:-baron_sso}",
|
||||
]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
restart: always
|
||||
|
||||
clickhouse:
|
||||
image: clickhouse/clickhouse-server:latest
|
||||
container_name: baron_clickhouse
|
||||
restart: always
|
||||
volumes:
|
||||
- clickhouse_data:/var/lib/clickhouse
|
||||
environment:
|
||||
CLICKHOUSE_USER: "${CLICKHOUSE_USER:-baron}"
|
||||
CLICKHOUSE_PASSWORD: "${CLICKHOUSE_PASSWORD:-password}"
|
||||
networks:
|
||||
- baron_net
|
||||
healthcheck:
|
||||
test: ["CMD", "clickhouse-client", "--query", "SELECT 1"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
clickhouse:
|
||||
image: clickhouse/clickhouse-server:latest
|
||||
container_name: baron_clickhouse
|
||||
restart: always
|
||||
volumes:
|
||||
- clickhouse_data:/var/lib/clickhouse
|
||||
environment:
|
||||
CLICKHOUSE_USER: "${CLICKHOUSE_USER:-baron}"
|
||||
CLICKHOUSE_PASSWORD: "${CLICKHOUSE_PASSWORD:-password}"
|
||||
networks:
|
||||
- baron_net
|
||||
healthcheck:
|
||||
test: ["CMD", "clickhouse-client", "--query", "SELECT 1"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: baron_redis
|
||||
restart: always
|
||||
command: redis-server --port 6389
|
||||
ports:
|
||||
- "6389:6389"
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- baron_net
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-p", "6389", "ping"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: baron_redis
|
||||
restart: always
|
||||
command: redis-server --port 6389
|
||||
ports:
|
||||
- "6389:6389"
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- baron_net
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "-p", "6389", "ping"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
gateway:
|
||||
image: nginx:alpine
|
||||
container_name: baron_gateway
|
||||
restart: always
|
||||
ports:
|
||||
- "${USERFRONT_PORT:-5000}:5000"
|
||||
volumes:
|
||||
- ./gateway/nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
networks:
|
||||
- baron_net
|
||||
- public_net
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:5000/"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
gateway:
|
||||
image: nginx:alpine
|
||||
container_name: baron_gateway
|
||||
restart: always
|
||||
ports:
|
||||
- "${USERFRONT_PORT:-5000}:5000"
|
||||
volumes:
|
||||
- ./gateway/nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
networks:
|
||||
- baron_net
|
||||
- public_net
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:5000/"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
postgres_ory:
|
||||
image: postgres:${ORY_POSTGRES_TAG:-17-alpine}
|
||||
container_name: ory_postgres
|
||||
environment:
|
||||
- POSTGRES_USER=${ORY_POSTGRES_USER:-ory}
|
||||
- POSTGRES_PASSWORD=${ORY_POSTGRES_PASSWORD:-secret}
|
||||
- POSTGRES_DB=${ORY_POSTGRES_DB:-ory}
|
||||
volumes:
|
||||
- ./docker/ory/init-db:/docker-entrypoint-initdb.d
|
||||
- ory_postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- ory-net
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"pg_isready -U ${ORY_POSTGRES_USER:-ory} -d ${KRATOS_DB:-ory_kratos}",
|
||||
]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
postgres_ory:
|
||||
image: postgres:${ORY_POSTGRES_TAG:-17-alpine}
|
||||
container_name: ory_postgres
|
||||
environment:
|
||||
- POSTGRES_USER=${ORY_POSTGRES_USER:-ory}
|
||||
- POSTGRES_PASSWORD=${ORY_POSTGRES_PASSWORD:-secret}
|
||||
- POSTGRES_DB=${ORY_POSTGRES_DB:-ory}
|
||||
volumes:
|
||||
- ./docker/ory/init-db:/docker-entrypoint-initdb.d
|
||||
- ory_postgres_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- ory-net
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
"CMD-SHELL",
|
||||
"pg_isready -U ${ORY_POSTGRES_USER:-ory} -d ${KRATOS_DB:-ory_kratos}",
|
||||
]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
kratos-migrate:
|
||||
image: oryd/kratos:${KRATOS_VERSION:-v25.4.0}
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KRATOS_DB:-ory_kratos}?sslmode=disable&max_conns=20
|
||||
- KRATOS_SERVE_PUBLIC_BASE_URL=${KRATOS_BROWSER_URL:-http://localhost:4433}
|
||||
- KRATOS_SERVE_ADMIN_BASE_URL=${KRATOS_ADMIN_URL:-http://kratos:4434}
|
||||
- KRATOS_SELFSERVICE_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL:-http://localhost:5000}
|
||||
- KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=["${KRATOS_UI_URL:-http://localhost:5000}","${USERFRONT_URL:-http://localhost:5000}"]
|
||||
- KRATOS_SELFSERVICE_FLOWS_ERROR_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/error
|
||||
- KRATOS_SELFSERVICE_FLOWS_SETTINGS_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/error?error=settings_disabled
|
||||
- KRATOS_SELFSERVICE_FLOWS_RECOVERY_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/recovery
|
||||
- KRATOS_SELFSERVICE_FLOWS_VERIFICATION_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/verification
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGIN_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/login
|
||||
- KRATOS_SELFSERVICE_FLOWS_REGISTRATION_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/registration
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGOUT_AFTER_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL:-http://localhost:5000}/login
|
||||
volumes:
|
||||
- ./docker/ory/kratos:/etc/config/kratos
|
||||
command: migrate sql up -e -c /etc/config/kratos/kratos.yml --yes
|
||||
depends_on:
|
||||
postgres_ory:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- ory-net
|
||||
kratos-migrate:
|
||||
image: oryd/kratos:${KRATOS_VERSION:-v26.2.0}
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KRATOS_DB:-ory_kratos}?sslmode=disable&max_conns=20
|
||||
- KRATOS_SERVE_PUBLIC_BASE_URL=${KRATOS_BROWSER_URL}
|
||||
- KRATOS_SERVE_ADMIN_BASE_URL=${KRATOS_ADMIN_URL}
|
||||
- KRATOS_SELFSERVICE_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL}
|
||||
- KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=${KRATOS_ALLOWED_RETURN_URLS_JSON:-["${KRATOS_UI_URL}","${KRATOS_UI_URL}/","${USERFRONT_URL}","${USERFRONT_URL}/","${USERFRONT_URL}/ko","${USERFRONT_URL}/ko/","${USERFRONT_URL}/en","${USERFRONT_URL}/en/","${USERFRONT_URL}/auth/callback","${USERFRONT_URL}/ko/auth/callback","${USERFRONT_URL}/en/auth/callback","${ADMINFRONT_URL}/auth/callback","${DEVFRONT_URL}/auth/callback","${ORGFRONT_URL}/auth/callback"]}
|
||||
- KRATOS_SELFSERVICE_FLOWS_ERROR_UI_URL=${KRATOS_UI_URL}/error
|
||||
- KRATOS_SELFSERVICE_FLOWS_SETTINGS_UI_URL=${KRATOS_UI_URL}/error?error=settings_disabled
|
||||
- KRATOS_SELFSERVICE_FLOWS_RECOVERY_UI_URL=${KRATOS_UI_URL}/recovery
|
||||
- KRATOS_SELFSERVICE_FLOWS_VERIFICATION_UI_URL=${KRATOS_UI_URL}/verification
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGIN_UI_URL=${KRATOS_UI_URL}/login
|
||||
- KRATOS_SELFSERVICE_FLOWS_REGISTRATION_UI_URL=${KRATOS_UI_URL}/registration
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGOUT_AFTER_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL}/login
|
||||
volumes:
|
||||
- ./docker/ory/kratos:/etc/config/kratos
|
||||
command: migrate sql up -e -c /etc/config/kratos/kratos.yml --yes
|
||||
depends_on:
|
||||
postgres_ory:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- ory-net
|
||||
|
||||
kratos:
|
||||
image: oryd/kratos:${KRATOS_VERSION:-v25.4.0}
|
||||
container_name: ory_kratos
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KRATOS_DB:-ory_kratos}?sslmode=disable&max_conns=20
|
||||
- COOKIE_SECRET=${COOKIE_SECRET:-localcookie123}
|
||||
- KRATOS_SERVE_PUBLIC_BASE_URL=${KRATOS_BROWSER_URL:-http://localhost:4433}
|
||||
- KRATOS_SERVE_ADMIN_BASE_URL=${KRATOS_ADMIN_URL:-http://kratos:4434}
|
||||
- KRATOS_SELFSERVICE_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL:-http://localhost:5000}
|
||||
- KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=["${KRATOS_UI_URL:-http://localhost:5000}","${USERFRONT_URL:-http://localhost:5000}"]
|
||||
- KRATOS_SELFSERVICE_FLOWS_ERROR_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/error
|
||||
- KRATOS_SELFSERVICE_FLOWS_SETTINGS_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/error?error=settings_disabled
|
||||
- KRATOS_SELFSERVICE_FLOWS_RECOVERY_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/recovery
|
||||
- KRATOS_SELFSERVICE_FLOWS_VERIFICATION_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/verification
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGIN_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/login
|
||||
- KRATOS_SELFSERVICE_FLOWS_REGISTRATION_UI_URL=${KRATOS_UI_URL:-http://localhost:5000}/registration
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGOUT_AFTER_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL:-http://localhost:5000}/login
|
||||
volumes:
|
||||
- ./docker/ory/kratos:/etc/config/kratos
|
||||
command: serve -c /etc/config/kratos/kratos.yml --dev --watch-courier
|
||||
depends_on:
|
||||
kratos-migrate:
|
||||
condition: service_completed_successfully
|
||||
networks:
|
||||
- ory-net
|
||||
- kratosnet
|
||||
kratos:
|
||||
image: oryd/kratos:${KRATOS_VERSION:-v26.2.0}
|
||||
container_name: ory_kratos
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KRATOS_DB:-ory_kratos}?sslmode=disable&max_conns=20
|
||||
- COOKIE_SECRET=${COOKIE_SECRET:-localcookie123}
|
||||
- KRATOS_SERVE_PUBLIC_BASE_URL=${KRATOS_BROWSER_URL}
|
||||
- KRATOS_SERVE_ADMIN_BASE_URL=${KRATOS_ADMIN_URL}
|
||||
- KRATOS_SELFSERVICE_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL}
|
||||
- KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=${KRATOS_ALLOWED_RETURN_URLS_JSON:-["${KRATOS_UI_URL}","${KRATOS_UI_URL}/","${USERFRONT_URL}","${USERFRONT_URL}/","${USERFRONT_URL}/ko","${USERFRONT_URL}/ko/","${USERFRONT_URL}/en","${USERFRONT_URL}/en/","${USERFRONT_URL}/auth/callback","${USERFRONT_URL}/ko/auth/callback","${USERFRONT_URL}/en/auth/callback","${ADMINFRONT_URL}/auth/callback","${DEVFRONT_URL}/auth/callback","${ORGFRONT_URL}/auth/callback"]}
|
||||
- KRATOS_SELFSERVICE_FLOWS_ERROR_UI_URL=${KRATOS_UI_URL}/error
|
||||
- KRATOS_SELFSERVICE_FLOWS_SETTINGS_UI_URL=${KRATOS_UI_URL}/error?error=settings_disabled
|
||||
- KRATOS_SELFSERVICE_FLOWS_RECOVERY_UI_URL=${KRATOS_UI_URL}/recovery
|
||||
- KRATOS_SELFSERVICE_FLOWS_VERIFICATION_UI_URL=${KRATOS_UI_URL}/verification
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGIN_UI_URL=${KRATOS_UI_URL}/login
|
||||
- KRATOS_SELFSERVICE_FLOWS_REGISTRATION_UI_URL=${KRATOS_UI_URL}/registration
|
||||
- KRATOS_SELFSERVICE_FLOWS_LOGOUT_AFTER_DEFAULT_BROWSER_RETURN_URL=${KRATOS_UI_URL}/login
|
||||
volumes:
|
||||
- ./docker/ory/kratos:/etc/config/kratos
|
||||
command: serve -c /etc/config/kratos/kratos.yml --dev --watch-courier
|
||||
depends_on:
|
||||
kratos-migrate:
|
||||
condition: service_completed_successfully
|
||||
networks:
|
||||
- ory-net
|
||||
- kratosnet
|
||||
|
||||
hydra-migrate:
|
||||
image: oryd/hydra:${HYDRA_VERSION:-v25.4.0}
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${HYDRA_DB:-ory_hydra}?sslmode=disable&max_conns=20
|
||||
command: migrate sql up -e --yes
|
||||
depends_on:
|
||||
postgres_ory:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- ory-net
|
||||
hydra-migrate:
|
||||
image: oryd/hydra:${HYDRA_VERSION:-v26.2.0}
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${HYDRA_DB:-ory_hydra}?sslmode=disable&max_conns=20
|
||||
command: migrate sql up -e --yes
|
||||
depends_on:
|
||||
postgres_ory:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- ory-net
|
||||
|
||||
hydra:
|
||||
image: oryd/hydra:${HYDRA_VERSION:-v25.4.0}
|
||||
container_name: ory_hydra
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${HYDRA_DB:-ory_hydra}?sslmode=disable&max_conns=20
|
||||
- URLS_SELF_ISSUER=${USERFRONT_URL:-http://localhost:5000}/oidc
|
||||
- URLS_LOGIN=${USERFRONT_URL:-http://localhost:5000}/login
|
||||
- URLS_CONSENT=${USERFRONT_URL:-http://localhost:5000}/consent
|
||||
- SECRETS_SYSTEM=${ORY_POSTGRES_PASSWORD}
|
||||
volumes:
|
||||
- ./docker/ory/hydra:/etc/config/hydra
|
||||
command: serve -c /etc/config/hydra/hydra.yml all --dev
|
||||
depends_on:
|
||||
hydra-migrate:
|
||||
condition: service_completed_successfully
|
||||
networks:
|
||||
- ory-net
|
||||
- hydranet
|
||||
hydra:
|
||||
image: oryd/hydra:${HYDRA_VERSION:-v26.2.0}
|
||||
container_name: ory_hydra
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${HYDRA_DB:-ory_hydra}?sslmode=disable&max_conns=20
|
||||
- URLS_SELF_ISSUER=${HYDRA_PUBLIC_URL}
|
||||
- URLS_LOGIN=${HYDRA_LOGIN_URL:-${USERFRONT_URL}/login}
|
||||
- URLS_CONSENT=${HYDRA_CONSENT_URL:-${USERFRONT_URL}/consent}
|
||||
- URLS_ERROR=${HYDRA_ERROR_URL:-${USERFRONT_URL}/error}
|
||||
- SECRETS_SYSTEM=${ORY_POSTGRES_PASSWORD}
|
||||
volumes:
|
||||
- ./docker/ory/hydra:/etc/config/hydra
|
||||
command: serve -c /etc/config/hydra/hydra.yml all --dev
|
||||
depends_on:
|
||||
hydra-migrate:
|
||||
condition: service_completed_successfully
|
||||
networks:
|
||||
- ory-net
|
||||
- hydranet
|
||||
|
||||
keto-migrate:
|
||||
image: oryd/keto:${KETO_VERSION:-v25.4.0}
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KETO_DB:-ory_keto}?sslmode=disable&max_conns=20
|
||||
volumes:
|
||||
- ./docker/ory/keto:/etc/config/keto
|
||||
command: ["migrate", "up", "-c", "/etc/config/keto/keto.yml", "--yes"]
|
||||
depends_on:
|
||||
postgres_ory:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- ory-net
|
||||
keto-migrate:
|
||||
image: oryd/keto:${KETO_VERSION:-v26.2.0}
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KETO_DB:-ory_keto}?sslmode=disable&max_conns=20
|
||||
volumes:
|
||||
- ./docker/ory/keto:/etc/config/keto
|
||||
command: ["migrate", "up", "-c", "/etc/config/keto/keto.yml", "--yes"]
|
||||
depends_on:
|
||||
postgres_ory:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- ory-net
|
||||
|
||||
keto:
|
||||
image: oryd/keto:${KETO_VERSION:-v25.4.0}
|
||||
container_name: ory_keto
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KETO_DB:-ory_keto}?sslmode=disable&max_conns=20
|
||||
volumes:
|
||||
- ./docker/ory/keto:/etc/config/keto
|
||||
command: serve -c /etc/config/keto/keto.yml
|
||||
depends_on:
|
||||
keto-migrate:
|
||||
condition: service_completed_successfully
|
||||
networks:
|
||||
- ory-net
|
||||
keto:
|
||||
image: oryd/keto:${KETO_VERSION:-v26.2.0}
|
||||
container_name: ory_keto
|
||||
environment:
|
||||
- DSN=postgres://${ORY_POSTGRES_USER}:${ORY_POSTGRES_PASSWORD}@postgres_ory:5432/${KETO_DB:-ory_keto}?sslmode=disable&max_conns=20
|
||||
volumes:
|
||||
- ./docker/ory/keto:/etc/config/keto
|
||||
command: serve -c /etc/config/keto/keto.yml
|
||||
depends_on:
|
||||
keto-migrate:
|
||||
condition: service_completed_successfully
|
||||
networks:
|
||||
- ory-net
|
||||
|
||||
oathkeeper:
|
||||
image: oryd/oathkeeper:${OATHKEEPER_VERSION:-v0.40.6}
|
||||
container_name: oathkeeper
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
kratos:
|
||||
condition: service_started
|
||||
environment:
|
||||
- LOG_LEVEL=debug
|
||||
command: serve proxy --config /etc/config/oathkeeper/oathkeeper.yml
|
||||
volumes:
|
||||
- ./docker/ory/oathkeeper:/etc/config/oathkeeper
|
||||
- oathkeeper_logs:/var/log/oathkeeper
|
||||
networks:
|
||||
- ory-net
|
||||
- baron_net
|
||||
- public_net
|
||||
ports:
|
||||
- "4455:4455"
|
||||
- "4456:4456"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:4456/health/ready"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
oathkeeper_logs_init:
|
||||
image: alpine:latest
|
||||
command:
|
||||
[
|
||||
"sh",
|
||||
"-c",
|
||||
"mkdir -p /var/log/oathkeeper && chown -R ${OATHKEEPER_UID:-1001}:${OATHKEEPER_GID:-1001} /var/log/oathkeeper",
|
||||
]
|
||||
volumes:
|
||||
- oathkeeper_logs:/var/log/oathkeeper
|
||||
networks:
|
||||
- ory-net
|
||||
|
||||
ory_clickhouse:
|
||||
image: clickhouse/clickhouse-server:latest
|
||||
container_name: ory_clickhouse
|
||||
environment:
|
||||
- CLICKHOUSE_USER=${ORY_CLICKHOUSE_USER:-ory}
|
||||
- CLICKHOUSE_PASSWORD=${ORY_CLICKHOUSE_PASSWORD:-orypass}
|
||||
volumes:
|
||||
- ory_clickhouse_data:/var/lib/clickhouse
|
||||
- ./docker/ory/clickhouse:/docker-entrypoint-initdb.d
|
||||
networks:
|
||||
- ory-net
|
||||
oathkeeper:
|
||||
image: oryd/oathkeeper:${OATHKEEPER_VERSION:-v0.40.6}
|
||||
container_name: oathkeeper
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
oathkeeper_logs_init:
|
||||
condition: service_completed_successfully
|
||||
kratos:
|
||||
condition: service_started
|
||||
user: "${OATHKEEPER_UID:-1001}:${OATHKEEPER_GID:-1001}"
|
||||
environment:
|
||||
- APP_ENV=${APP_ENV:-stage}
|
||||
- LOG_LEVEL=debug
|
||||
- OATHKEEPER_INTROSPECT_CLIENT_ID=${OATHKEEPER_INTROSPECT_CLIENT_ID:-oathkeeper-introspect}
|
||||
- OATHKEEPER_INTROSPECT_CLIENT_SECRET=${OATHKEEPER_INTROSPECT_CLIENT_SECRET:-oathkeeper-secret}
|
||||
volumes:
|
||||
- ./docker/ory/oathkeeper:/etc/config/oathkeeper
|
||||
- oathkeeper_logs:/var/log/oathkeeper
|
||||
entrypoint: ["/etc/config/oathkeeper/entrypoint.sh"]
|
||||
networks:
|
||||
- ory-net
|
||||
- baron_net
|
||||
- public_net
|
||||
ports:
|
||||
- "4455:4455"
|
||||
- "4456:4456"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:4456/health/ready"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
ory_stack_check:
|
||||
image: alpine:latest
|
||||
container_name: ory_stack_check
|
||||
command: >
|
||||
/bin/sh -c "
|
||||
apk add --no-cache curl;
|
||||
echo 'Wait for services...';
|
||||
until curl -s http://kratos:4433/health/ready; do sleep 1; done;
|
||||
until curl -s http://hydra:4444/health/ready; do sleep 1; done;
|
||||
until curl -s http://keto:4466/health/ready; do sleep 1; done;
|
||||
echo 'Ory Stack is fully operational!';"
|
||||
depends_on:
|
||||
- kratos
|
||||
- hydra
|
||||
- keto
|
||||
networks:
|
||||
- ory-net
|
||||
ory_clickhouse:
|
||||
image: clickhouse/clickhouse-server:latest
|
||||
container_name: ory_clickhouse
|
||||
environment:
|
||||
- CLICKHOUSE_USER=${ORY_CLICKHOUSE_USER:-ory}
|
||||
- CLICKHOUSE_PASSWORD=${ORY_CLICKHOUSE_PASSWORD:-orypass}
|
||||
volumes:
|
||||
- ory_clickhouse_data:/var/lib/clickhouse
|
||||
- ./docker/ory/clickhouse:/docker-entrypoint-initdb.d
|
||||
networks:
|
||||
- ory-net
|
||||
|
||||
init-rp:
|
||||
image: alpine:latest
|
||||
env_file:
|
||||
- .env
|
||||
command:
|
||||
- /bin/sh
|
||||
- -ec
|
||||
- |
|
||||
apk add --no-cache curl tar
|
||||
HYDRA_CLI_VERSION="$${HYDRA_VERSION:-v26.2.0}"
|
||||
HYDRA_CLI_VERSION="$${HYDRA_CLI_VERSION%-distroless}"
|
||||
HYDRA_CLI_ARCHIVE_VERSION="$${HYDRA_CLI_VERSION#v}"
|
||||
curl -fsSLo /tmp/hydra.tar.gz "https://github.com/ory/hydra/releases/download/$${HYDRA_CLI_VERSION}/hydra_$${HYDRA_CLI_ARCHIVE_VERSION}-linux_64bit.tar.gz"
|
||||
tar -xzf /tmp/hydra.tar.gz -C /usr/local/bin hydra
|
||||
rm /tmp/hydra.tar.gz
|
||||
ory_stack_check:
|
||||
image: alpine:latest
|
||||
container_name: ory_stack_check
|
||||
command: >
|
||||
/bin/sh -c "
|
||||
apk add --no-cache curl;
|
||||
echo 'Wait for services...';
|
||||
until curl -s http://kratos:4433/health/ready; do sleep 1; done;
|
||||
until curl -s http://hydra:4444/health/ready; do sleep 1; done;
|
||||
until curl -s http://keto:4466/health/ready; do sleep 1; done;
|
||||
echo 'Ory Stack is fully operational!';"
|
||||
depends_on:
|
||||
- kratos
|
||||
- hydra
|
||||
- keto
|
||||
networks:
|
||||
- ory-net
|
||||
|
||||
# Function to create or update OAuth2 client (Idempotency)
|
||||
upsert_client() {
|
||||
ID=$$1
|
||||
shift
|
||||
if hydra get oauth2-client --endpoint http://hydra:4445 "$$ID" >/dev/null 2>&1; then
|
||||
echo "Updating existing client: $$ID"
|
||||
hydra update oauth2-client --endpoint http://hydra:4445 "$$ID" "$$@"
|
||||
else
|
||||
echo "Creating new client: $$ID"
|
||||
hydra create oauth2-client --endpoint http://hydra:4445 --id "$$ID" "$$@"
|
||||
fi
|
||||
}
|
||||
init-rp:
|
||||
image: alpine:latest
|
||||
env_file:
|
||||
- .env
|
||||
command:
|
||||
- /bin/sh
|
||||
- -ec
|
||||
- |
|
||||
apk add --no-cache curl tar
|
||||
HYDRA_CLI_VERSION="$${HYDRA_VERSION:-v26.2.0}"
|
||||
HYDRA_CLI_VERSION="$${HYDRA_CLI_VERSION%-distroless}"
|
||||
HYDRA_CLI_ARCHIVE_VERSION="$${HYDRA_CLI_VERSION#v}"
|
||||
curl -fsSLo /tmp/hydra.tar.gz "https://github.com/ory/hydra/releases/download/$${HYDRA_CLI_VERSION}/hydra_$${HYDRA_CLI_ARCHIVE_VERSION}-linux_64bit.tar.gz"
|
||||
tar -xzf /tmp/hydra.tar.gz -C /usr/local/bin hydra
|
||||
rm /tmp/hydra.tar.gz
|
||||
|
||||
upsert_client "adminfront" \
|
||||
--name "AdminFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri "$${ADMINFRONT_CALLBACK_URLS:-http://localhost:5173/auth/callback}"
|
||||
# Function to create or update OAuth2 client (Idempotency)
|
||||
upsert_client() {
|
||||
ID=$$1
|
||||
shift
|
||||
if hydra get oauth2-client --endpoint "$${HYDRA_ADMIN_URL}" "$$ID" >/dev/null 2>&1; then
|
||||
echo "Updating existing client: $$ID"
|
||||
hydra update oauth2-client --endpoint "$${HYDRA_ADMIN_URL}" "$$ID" "$$@"
|
||||
else
|
||||
echo "Creating new client: $$ID"
|
||||
hydra create oauth2-client --endpoint "$${HYDRA_ADMIN_URL}" --id "$$ID" "$$@"
|
||||
fi
|
||||
}
|
||||
|
||||
upsert_client "devfront" \
|
||||
--name "DevFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri "$${DEVFRONT_CALLBACK_URLS:-http://localhost:5174/auth/callback}"
|
||||
upsert_client "adminfront" \
|
||||
--name "AdminFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri "$${ADMINFRONT_CALLBACK_URLS:-$${ADMINFRONT_URL}/auth/callback}"
|
||||
|
||||
upsert_client "orgfront" \
|
||||
--name "OrgFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri "$${ORGFRONT_CALLBACK_URLS:-http://localhost:5175/auth/callback,http://172.16.10.176:5175/auth/callback, https://baron-orgchart.hmac.kr/auth/callback}"
|
||||
upsert_client "devfront" \
|
||||
--name "DevFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri "$${DEVFRONT_CALLBACK_URLS:-$${DEVFRONT_URL}/auth/callback}"
|
||||
|
||||
upsert_client "$${OATHKEEPER_INTROSPECT_CLIENT_ID:-oathkeeper-introspect}" \
|
||||
--secret "$${OATHKEEPER_INTROSPECT_CLIENT_SECRET:-oathkeeper-secret}" \
|
||||
--grant-type client_credentials \
|
||||
--response-type token \
|
||||
--scope openid,offline_access,profile,email
|
||||
depends_on:
|
||||
ory_stack_check:
|
||||
condition: service_completed_successfully
|
||||
networks:
|
||||
- hydranet
|
||||
upsert_client "orgfront" \
|
||||
--name "OrgFront" \
|
||||
--grant-type authorization_code,refresh_token \
|
||||
--response-type code \
|
||||
--scope openid,offline_access,profile,email \
|
||||
--token-endpoint-auth-method none \
|
||||
--redirect-uri "$${ORGFRONT_CALLBACK_URLS:-$${ORGFRONT_URL}/auth/callback}"
|
||||
|
||||
backend:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile
|
||||
container_name: baron_backend
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- APP_ENV=${APP_ENV:-development}
|
||||
- GO_ENV=${APP_ENV:-development}
|
||||
- COOKIE_SECRET=${COOKIE_SECRET}
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
- NAVER_CLOUD_ACCESS_KEY=${NAVER_CLOUD_ACCESS_KEY}
|
||||
- NAVER_CLOUD_SECRET_KEY=${NAVER_CLOUD_SECRET_KEY}
|
||||
- NAVER_CLOUD_SERVICE_ID=${NAVER_CLOUD_SERVICE_ID}
|
||||
- NAVER_SENDER_PHONE_NUMBER=${NAVER_SENDER_PHONE_NUMBER}
|
||||
- USERFRONT_URL=${USERFRONT_URL}
|
||||
- REDIS_ADDR=${REDIS_ADDR}
|
||||
- IDP_PROVIDER=${IDP_PROVIDER:-ory}
|
||||
- KRATOS_ADMIN_URL=${KRATOS_ADMIN_URL:-http://kratos:4434}
|
||||
- HYDRA_ADMIN_URL=${HYDRA_ADMIN_URL:-http://hydra:4445}
|
||||
- HYDRA_PUBLIC_URL=${HYDRA_PUBLIC_URL:-http://hydra:4444}
|
||||
- DB_HOST=postgres
|
||||
- CLICKHOUSE_HOST=clickhouse
|
||||
- CLICKHOUSE_PORT=${CLICKHOUSE_PORT_NATIVE:-9000}
|
||||
- CLICKHOUSE_USER=${CLICKHOUSE_USER:-baron}
|
||||
- CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD:-password}
|
||||
- SEED_TENANT_CSV_PATH=/app/seed-tenant.csv
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
oathkeeper:
|
||||
condition: service_healthy
|
||||
kratos:
|
||||
condition: service_started
|
||||
hydra:
|
||||
condition: service_started
|
||||
keto:
|
||||
condition: service_started
|
||||
infra_check:
|
||||
condition: service_started
|
||||
networks:
|
||||
- baron_net
|
||||
- ory-net
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
- ./adminfront/seed-tenant.csv:/app/seed-tenant.csv:ro
|
||||
command: ["go", "run", "./cmd/server"]
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
upsert_client "$${OATHKEEPER_INTROSPECT_CLIENT_ID:-oathkeeper-introspect}" \
|
||||
--secret "$${OATHKEEPER_INTROSPECT_CLIENT_SECRET:-oathkeeper-secret}" \
|
||||
--grant-type client_credentials \
|
||||
--response-type token \
|
||||
--scope openid,offline_access,profile,email
|
||||
depends_on:
|
||||
ory_stack_check:
|
||||
condition: service_completed_successfully
|
||||
networks:
|
||||
- hydranet
|
||||
|
||||
adminfront:
|
||||
build:
|
||||
context: ./adminfront
|
||||
dockerfile: Dockerfile
|
||||
container_name: baron_adminfront
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- APP_ENV=${APP_ENV:-development}
|
||||
- API_PROXY_TARGET=http://baron_backend:3000
|
||||
ports:
|
||||
- "${ADMINFRONT_PORT:-5173}:5173"
|
||||
volumes:
|
||||
- ./adminfront:/app
|
||||
- /app/node_modules
|
||||
networks:
|
||||
- baron_net
|
||||
backend:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile
|
||||
container_name: baron_backend
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- APP_ENV=${APP_ENV:-development}
|
||||
- GO_ENV=${APP_ENV:-development}
|
||||
- COOKIE_SECRET=${COOKIE_SECRET}
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
- NAVER_CLOUD_ACCESS_KEY=${NAVER_CLOUD_ACCESS_KEY}
|
||||
- NAVER_CLOUD_SECRET_KEY=${NAVER_CLOUD_SECRET_KEY}
|
||||
- NAVER_CLOUD_SERVICE_ID=${NAVER_CLOUD_SERVICE_ID}
|
||||
- NAVER_SENDER_PHONE_NUMBER=${NAVER_SENDER_PHONE_NUMBER}
|
||||
- USERFRONT_URL=${USERFRONT_URL}
|
||||
- REDIS_ADDR=${REDIS_ADDR}
|
||||
- IDP_PROVIDER=${IDP_PROVIDER:-ory}
|
||||
- KRATOS_ADMIN_URL=${KRATOS_ADMIN_URL:-http://kratos:4434}
|
||||
- HYDRA_ADMIN_URL=${HYDRA_ADMIN_URL:-http://hydra:4445}
|
||||
- HYDRA_PUBLIC_URL=${HYDRA_PUBLIC_URL}
|
||||
- DB_HOST=postgres
|
||||
- CLICKHOUSE_HOST=clickhouse
|
||||
- CLICKHOUSE_PORT=${CLICKHOUSE_PORT_NATIVE:-9000}
|
||||
- CLICKHOUSE_USER=${CLICKHOUSE_USER:-baron}
|
||||
- CLICKHOUSE_PASSWORD=${CLICKHOUSE_PASSWORD:-password}
|
||||
- SEED_TENANT_CSV_PATH=/app/seed-tenant.csv
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
oathkeeper:
|
||||
condition: service_healthy
|
||||
kratos:
|
||||
condition: service_started
|
||||
hydra:
|
||||
condition: service_started
|
||||
keto:
|
||||
condition: service_started
|
||||
infra_check:
|
||||
condition: service_started
|
||||
networks:
|
||||
- baron_net
|
||||
- ory-net
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
- ./adminfront/seed-tenant.csv:/app/seed-tenant.csv:ro
|
||||
command: ["go", "run", "./cmd/server"]
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
devfront:
|
||||
build:
|
||||
context: ./devfront
|
||||
dockerfile: Dockerfile
|
||||
container_name: baron_devfront
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- APP_ENV=${APP_ENV:-development}
|
||||
- API_PROXY_TARGET=http://baron_backend:3000
|
||||
ports:
|
||||
- "${DEVFRONT_PORT:-5174}:5173"
|
||||
volumes:
|
||||
- ./devfront:/app
|
||||
- /app/node_modules
|
||||
networks:
|
||||
- baron_net
|
||||
adminfront:
|
||||
build:
|
||||
context: ./adminfront
|
||||
dockerfile: Dockerfile
|
||||
container_name: baron_adminfront
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- APP_ENV=${APP_ENV:-development}
|
||||
- API_PROXY_TARGET=http://baron_backend:3000
|
||||
ports:
|
||||
- "${ADMINFRONT_PORT:-5173}:5173"
|
||||
volumes:
|
||||
- ./adminfront:/app
|
||||
- /app/node_modules
|
||||
networks:
|
||||
- baron_net
|
||||
|
||||
orgfront:
|
||||
build:
|
||||
context: ./orgfront
|
||||
dockerfile: Dockerfile
|
||||
container_name: baron_orgfront
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- APP_ENV=${APP_ENV:-development}
|
||||
- API_PROXY_TARGET=http://baron_backend:3000
|
||||
- USERFRONT_URL=${USERFRONT_URL}
|
||||
ports:
|
||||
- "${ORGFRONT_PORT:-5175}:5175"
|
||||
volumes:
|
||||
- ./orgfront:/app
|
||||
- /app/node_modules
|
||||
networks:
|
||||
- baron_net
|
||||
devfront:
|
||||
build:
|
||||
context: ./devfront
|
||||
dockerfile: Dockerfile
|
||||
container_name: baron_devfront
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- APP_ENV=${APP_ENV:-development}
|
||||
- API_PROXY_TARGET=http://baron_backend:3000
|
||||
ports:
|
||||
- "${DEVFRONT_PORT:-5174}:5173"
|
||||
volumes:
|
||||
- ./devfront:/app
|
||||
- /app/node_modules
|
||||
networks:
|
||||
- baron_net
|
||||
|
||||
userfront:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: userfront/Dockerfile
|
||||
container_name: baron_userfront
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- BACKEND_URL=${BACKEND_URL:-}
|
||||
- USERFRONT_URL=${USERFRONT_URL}
|
||||
- APP_ENV=${APP_ENV}
|
||||
networks:
|
||||
- baron_net
|
||||
- ory-net
|
||||
depends_on:
|
||||
backend:
|
||||
condition: service_healthy
|
||||
command: >
|
||||
/bin/sh -c "mkdir -p /usr/share/nginx/html/assets &&
|
||||
echo \"BACKEND_URL=$${BACKEND_URL}\" >> /usr/share/nginx/html/assets/.env &&
|
||||
echo \"USERFRONT_URL=$${USERFRONT_URL}\" >> /usr/share/nginx/html/assets/.env &&
|
||||
echo \"APP_ENV=$${APP_ENV}\" >> /usr/share/nginx/html/assets/.env &&
|
||||
cp /usr/share/nginx/html/assets/.env /usr/share/nginx/html/.env &&
|
||||
nginx -g 'daemon off;'"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:5000/"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
orgfront:
|
||||
build:
|
||||
context: ./orgfront
|
||||
dockerfile: Dockerfile
|
||||
container_name: baron_orgfront
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- APP_ENV=${APP_ENV:-development}
|
||||
- API_PROXY_TARGET=http://baron_backend:3000
|
||||
- USERFRONT_URL=${USERFRONT_URL}
|
||||
ports:
|
||||
- "${ORGFRONT_PORT:-5175}:5175"
|
||||
volumes:
|
||||
- ./orgfront:/app
|
||||
- /app/node_modules
|
||||
networks:
|
||||
- baron_net
|
||||
|
||||
infra_check:
|
||||
image: alpine
|
||||
command: ["echo", "Infrastructure assumed running"]
|
||||
networks:
|
||||
- baron_net
|
||||
userfront:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: userfront/Dockerfile
|
||||
container_name: baron_userfront
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- BACKEND_URL=${BACKEND_URL:-}
|
||||
- USERFRONT_URL=${USERFRONT_URL}
|
||||
- APP_ENV=${APP_ENV}
|
||||
networks:
|
||||
- baron_net
|
||||
- ory-net
|
||||
depends_on:
|
||||
backend:
|
||||
condition: service_healthy
|
||||
command: >
|
||||
/bin/sh -c "mkdir -p /usr/share/nginx/html/assets &&
|
||||
echo \"BACKEND_URL=$${BACKEND_URL}\" >> /usr/share/nginx/html/assets/.env &&
|
||||
echo \"USERFRONT_URL=$${USERFRONT_URL}\" >> /usr/share/nginx/html/assets/.env &&
|
||||
echo \"APP_ENV=$${APP_ENV}\" >> /usr/share/nginx/html/assets/.env &&
|
||||
cp /usr/share/nginx/html/assets/.env /usr/share/nginx/html/.env &&
|
||||
nginx -g 'daemon off;'"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:5000/"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
infra_check:
|
||||
image: alpine
|
||||
command: ["echo", "Infrastructure assumed running"]
|
||||
networks:
|
||||
- baron_net
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
clickhouse_data:
|
||||
redis_data:
|
||||
ory_postgres_data:
|
||||
ory_clickhouse_data:
|
||||
oathkeeper_logs:
|
||||
postgres_data:
|
||||
clickhouse_data:
|
||||
redis_data:
|
||||
ory_postgres_data:
|
||||
ory_clickhouse_data:
|
||||
oathkeeper_logs:
|
||||
|
||||
networks:
|
||||
baron_net:
|
||||
external: true
|
||||
name: baron_net
|
||||
public_net:
|
||||
external: true
|
||||
name: public_net
|
||||
ory-net:
|
||||
external: true
|
||||
name: ory-net
|
||||
hydranet:
|
||||
external: true
|
||||
name: hydranet
|
||||
kratosnet:
|
||||
external: true
|
||||
name: kratosnet
|
||||
baron_net:
|
||||
external: true
|
||||
name: baron_net
|
||||
public_net:
|
||||
external: true
|
||||
name: public_net
|
||||
ory-net:
|
||||
external: true
|
||||
name: ory-net
|
||||
hydranet:
|
||||
external: true
|
||||
name: hydranet
|
||||
kratosnet:
|
||||
external: true
|
||||
name: kratosnet
|
||||
|
||||
@@ -23,7 +23,7 @@ sequenceDiagram
|
||||
UF->>HY: 로그인 승인 요청
|
||||
HY->>User: 권한 동의(Consent) 화면 표시
|
||||
User->>HY: '허용' 클릭
|
||||
HY-->>DF: 인증 코드와 함께 리다이렉트 (/callback?code=...)
|
||||
HY-->>DF: 인증 코드와 함께 리다이렉트 (/auth/callback?code=...)
|
||||
DF->>HY: 토큰 교환 요청 (Code -> ID/Access Token)
|
||||
HY-->>DF: 토큰 발급
|
||||
Note over DF: [FIX] 백엔드 /api/me 호출 대신<br/>ID Token에서 프로필 정보 직접 추출
|
||||
@@ -46,7 +46,7 @@ sequenceDiagram
|
||||
* 사용자가 '허용'을 누르면 Hydra는 `devfront`가 신뢰할 수 있는 앱임을 기록합니다.
|
||||
|
||||
4. **인증 코드 전달 및 토큰 교환 (Callback)**:
|
||||
* Hydra는 사용자를 `devfront`의 콜백 페이지(`http://localhost:5174/callback?code=...`)로 보냅니다.
|
||||
* Hydra는 사용자를 `devfront`의 콜백 페이지(`http://localhost:5174/auth/callback?code=...`)로 보냅니다.
|
||||
* `devfront`는 이 코드를 Hydra의 토큰 엔드포인트로 보내 **ID Token**과 **Access Token**을 발급받습니다.
|
||||
|
||||
5. **사용자 정보 로드 (Profile Recovery)**:
|
||||
@@ -71,9 +71,9 @@ hydra clients create
|
||||
--response-types code
|
||||
--scope openid,offline_access,profile,email
|
||||
--token-endpoint-auth-method none \ # Public Client (PKCE 사용)
|
||||
--callbacks http://localhost:5174/callback;
|
||||
--callbacks http://localhost:5174/auth/callback;
|
||||
```
|
||||
이 설정으로 인해 `devfront`라는 ID의 클라이언트가 미리 존재하게 되며, `localhost:5174`로의 리다이렉션이 안전하게 허용됩니다.
|
||||
이 설정으로 인해 `devfront`라는 ID의 클라이언트가 미리 존재하게 되며, `localhost:5174/auth/callback`으로의 리다이렉션이 안전하게 허용됩니다.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
## 적용 범위
|
||||
- UserFront, AdminFront, DevFront의 로그인/콜백 경로
|
||||
- Ory Stack(Hydra/Kratos/Oathkeeper) 설정
|
||||
- `compose.ory.yaml`, `gateway/nginx.conf`, `docker/ory/oathkeeper/rules*.json`
|
||||
- `compose.ory.yaml`, `docker/compose.ory.yaml`, `docker/staging_pull_compose.template.yaml`
|
||||
- `gateway/nginx.conf`, `deploy/templates/gateway/nginx.conf`, `docker/ory/oathkeeper/rules*.json`
|
||||
- `Makefile` 기반 사전 검증/스모크 검증 단계
|
||||
|
||||
## 핵심 원칙
|
||||
@@ -27,8 +28,8 @@
|
||||
|
||||
2. `mapped_match`
|
||||
- Public URL과 Internal URL이 다르지만, 아래가 모두 성립
|
||||
- Gateway 라우팅 규칙 존재 (예: `/oidc` rewrite)
|
||||
- Oathkeeper `match`와 `upstream` 규칙 존재 (예: `strip_path_prefix=/oidc`)
|
||||
- Gateway 라우팅 규칙 존재: `/oidc` prefix를 제거하지 않고 Oathkeeper로 전달
|
||||
- Oathkeeper `match`와 `upstream` 규칙 존재: `/oidc/*` rule이 `strip_path=/oidc`로 Hydra에 전달
|
||||
- 최종 업스트림이 기대 서비스(Hydra/Kratos)로 연결
|
||||
|
||||
3. `unmapped_fail`
|
||||
@@ -42,6 +43,8 @@
|
||||
- `ADMINFRONT_CALLBACK_URLS`, `DEVFRONT_CALLBACK_URLS` URL 유효성/중복/경로 규약
|
||||
- Gateway `/oidc`, `/auth` 라우팅 규칙 존재 여부
|
||||
- Oathkeeper `rules*.json`의 Hydra/Kratos 매핑 규칙 존재 여부
|
||||
- staging pull/deploy template의 Oathkeeper entrypoint 사용 여부
|
||||
- `KRATOS_ALLOWED_RETURN_URLS_JSON`에 공개 도메인, locale path, callback/return path가 포함되는지 여부
|
||||
|
||||
2. 런타임 검증 (`make verify-oidc-config`)
|
||||
- OIDC Discovery endpoint 조회 가능 여부
|
||||
@@ -49,9 +52,38 @@
|
||||
- 필요 시 Gateway 경유 endpoint probe로 매핑 체인 확인
|
||||
|
||||
## 경로 규약
|
||||
- DevFront callback: `/callback`
|
||||
- DevFront callback: `/auth/callback`
|
||||
- AdminFront callback: `/auth/callback`
|
||||
- OrgFront callback: `/auth/callback`
|
||||
- UserFront OIDC 진입점: `/oidc/*` (Gateway 경유)
|
||||
- locale return path: `/ko`, `/en`, `/ko/auth/callback`, `/en/auth/callback`
|
||||
|
||||
## `/oidc` 책임 경계
|
||||
- Gateway는 `/oidc` prefix를 보존합니다.
|
||||
- Oathkeeper는 `/oidc/.well-known/*`, `/oidc/oauth2/*`, `/oidc/userinfo` rule에서 `strip_path=/oidc`를 적용합니다.
|
||||
- Hydra는 prefix가 제거된 내부 경로(`/.well-known/*`, `/oauth2/*`, `/userinfo`)를 받습니다.
|
||||
- 따라서 gateway template이나 staging pull compose에서 `rewrite ^/oidc`가 다시 들어가면 dev/stage/prod 간 책임 경계가 달라지므로 실패로 간주합니다.
|
||||
|
||||
## Oathkeeper rules 선택 정책
|
||||
- Oathkeeper는 직접 `command: serve proxy ...`로 시작하지 않고 `/etc/config/oathkeeper/entrypoint.sh`를 통해 시작합니다.
|
||||
- entrypoint는 `APP_ENV`에 따라 다음 파일을 선택하고 `/tmp/oathkeeper/rules.active.json`으로 복사합니다.
|
||||
- `stage|staging`: `rules.stage.json`
|
||||
- `production|prod`: `rules.prod.json`
|
||||
- 그 외: `rules.json`
|
||||
- `oathkeeper.yml`은 `file:///tmp/oathkeeper/rules.active.json`만 읽습니다.
|
||||
|
||||
## Kratos allowed return URL 정책
|
||||
- stage/prod에서는 `KRATOS_ALLOWED_RETURN_URLS_JSON`을 명시하는 것을 우선합니다.
|
||||
- 최소 포함 대상:
|
||||
- `KRATOS_UI_URL`, `KRATOS_UI_URL/`
|
||||
- `USERFRONT_URL`, `USERFRONT_URL/`
|
||||
- `USERFRONT_URL/ko`, `USERFRONT_URL/ko/`
|
||||
- `USERFRONT_URL/en`, `USERFRONT_URL/en/`
|
||||
- `USERFRONT_URL/auth/callback`
|
||||
- `USERFRONT_URL/ko/auth/callback`
|
||||
- `USERFRONT_URL/en/auth/callback`
|
||||
- `ADMINFRONT_CALLBACK_URLS`, `DEVFRONT_CALLBACK_URLS`, `ORGFRONT_CALLBACK_URLS`
|
||||
- private IP, legacy domain, comma-space가 포함된 URI 항목은 stage/prod 기본값으로 두지 않습니다.
|
||||
|
||||
## 운영 지침
|
||||
1. 환경별 URL은 동일할 필요가 없고, 매핑 체인이 검증 가능해야 합니다.
|
||||
@@ -65,3 +97,4 @@
|
||||
- #272
|
||||
- #274
|
||||
- #276
|
||||
- #710
|
||||
|
||||
@@ -33,12 +33,14 @@ Ory 구성은 **컨테이너 내부 통신 URL**과 **브라우저 접근 URL**
|
||||
### 내부 통신용 URL(컨테이너 네트워크)
|
||||
- `KRATOS_PUBLIC_URL=http://kratos:4433`
|
||||
- `KRATOS_ADMIN_URL=http://kratos:4434`
|
||||
- `HYDRA_PUBLIC_URL=http://hydra:4444`
|
||||
- `HYDRA_ADMIN_URL=http://hydra:4445`
|
||||
- Hydra public upstream은 Oathkeeper rule 내부에서 `http://hydra:4444`로 전달합니다.
|
||||
|
||||
### 브라우저 접근용 URL(외부 도메인/프록시)
|
||||
- `KRATOS_BROWSER_URL` : Kratos Public의 외부 URL
|
||||
- `KRATOS_BROWSER_URL` : Kratos Public의 외부 URL. 보통 `${OATHKEEPER_PUBLIC_URL}/auth`
|
||||
- `KRATOS_UI_URL` : UserFront의 외부 URL (Kratos UI 역할)
|
||||
- `HYDRA_PUBLIC_URL` : Hydra issuer/OIDC discovery의 외부 URL. 보통 `${OATHKEEPER_PUBLIC_URL}/oidc`
|
||||
- `VITE_OIDC_AUTHORITY` : 프론트엔드 OIDC authority. `HYDRA_PUBLIC_URL`과 같아야 합니다.
|
||||
|
||||
예시(로컬):
|
||||
```env
|
||||
@@ -48,8 +50,11 @@ KRATOS_UI_URL=http://localhost:5000
|
||||
|
||||
예시(리버스 프록시/도메인):
|
||||
```env
|
||||
KRATOS_BROWSER_URL=https://sso.example.com
|
||||
OATHKEEPER_PUBLIC_URL=https://sso.example.com
|
||||
KRATOS_BROWSER_URL=https://sso.example.com/auth
|
||||
KRATOS_UI_URL=https://sso.example.com
|
||||
HYDRA_PUBLIC_URL=https://sso.example.com/oidc
|
||||
VITE_OIDC_AUTHORITY=https://sso.example.com/oidc
|
||||
```
|
||||
|
||||
### 포트 노출 정책
|
||||
@@ -64,6 +69,7 @@ Kratos는 self-service UI URL을 설정값으로 사용합니다. **UserFront의
|
||||
- `KRATOS_SELFSERVICE_DEFAULT_BROWSER_RETURN_URL`
|
||||
- `KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS`
|
||||
- `KRATOS_SELFSERVICE_FLOWS_*_UI_URL`
|
||||
- `KRATOS_ALLOWED_RETURN_URLS_JSON`
|
||||
|
||||
compose에서 기본적으로 다음과 같이 오버라이드합니다:
|
||||
- `KRATOS_SELFSERVICE_FLOWS_LOGIN_UI_URL=${KRATOS_UI_URL}/login`
|
||||
@@ -72,18 +78,44 @@ compose에서 기본적으로 다음과 같이 오버라이드합니다:
|
||||
- `KRATOS_SELFSERVICE_FLOWS_RECOVERY_UI_URL=${KRATOS_UI_URL}/recovery`
|
||||
- `KRATOS_SELFSERVICE_FLOWS_VERIFICATION_UI_URL=${KRATOS_UI_URL}/verification`
|
||||
|
||||
## 5) 트러블슈팅
|
||||
### 5.1 로그인 클릭 시 동작 없음
|
||||
stage/prod에서는 `KRATOS_ALLOWED_RETURN_URLS_JSON`에 공개 도메인과 callback/locale 경로를 명시합니다.
|
||||
|
||||
필수 후보:
|
||||
- `${KRATOS_UI_URL}`, `${KRATOS_UI_URL}/`
|
||||
- `${USERFRONT_URL}`, `${USERFRONT_URL}/`
|
||||
- `${USERFRONT_URL}/ko`, `${USERFRONT_URL}/ko/`
|
||||
- `${USERFRONT_URL}/en`, `${USERFRONT_URL}/en/`
|
||||
- `${USERFRONT_URL}/auth/callback`
|
||||
- `${USERFRONT_URL}/ko/auth/callback`
|
||||
- `${USERFRONT_URL}/en/auth/callback`
|
||||
- `${ADMINFRONT_CALLBACK_URLS}`, `${DEVFRONT_CALLBACK_URLS}`, `${ORGFRONT_CALLBACK_URLS}`
|
||||
|
||||
## 5) `/oidc` Gateway/Oathkeeper 책임 경계
|
||||
Gateway는 `/oidc` prefix를 rewrite하지 않습니다. `/oidc/*` 요청은 prefix를 보존한 채 Oathkeeper로 전달하고, Oathkeeper rule이 `strip_path=/oidc`로 Hydra 내부 upstream(`http://hydra:4444`)에 전달합니다.
|
||||
|
||||
이 정책은 `gateway/nginx.conf`, `deploy/templates/gateway/nginx.conf`, `docker/ory/oathkeeper/rules*.json`, `docker/staging_pull_compose.template.yaml`에서 동일해야 합니다.
|
||||
|
||||
## 6) Oathkeeper active rules
|
||||
Oathkeeper는 `/etc/config/oathkeeper/entrypoint.sh`를 통해 시작해야 합니다. entrypoint는 `APP_ENV`에 따라 env별 rules 파일을 고르고 `/tmp/oathkeeper/rules.active.json`을 생성합니다.
|
||||
|
||||
- `APP_ENV=stage|staging`: `rules.stage.json`
|
||||
- `APP_ENV=production|prod`: `rules.prod.json`
|
||||
- 그 외: `rules.json`
|
||||
|
||||
`docker/ory/oathkeeper/oathkeeper.yml`은 `file:///tmp/oathkeeper/rules.active.json`을 읽습니다. compose나 배포 템플릿이 entrypoint를 우회해 `oathkeeper serve proxy`를 직접 실행하면 active rules 생성이 누락될 수 있습니다.
|
||||
|
||||
## 7) 트러블슈팅
|
||||
### 7.1 로그인 클릭 시 동작 없음
|
||||
- 원인: Kratos 기동 실패(설정 파싱 실패 등) 또는 브라우저용 URL이 내부 도메인(`kratos:...`)으로 설정됨
|
||||
- 확인:
|
||||
- `docker logs ory_kratos`에서 config 오류 여부 확인
|
||||
- 브라우저 네트워크 탭에서 `/self-service/login/browser` 응답 확인(302 Location 헤더)
|
||||
|
||||
### 5.2 kratos.yml에 ${...} 환경 변수 치환 실패
|
||||
### 7.2 kratos.yml에 ${...} 환경 변수 치환 실패
|
||||
- Kratos 설정 파일은 `${ENV}` 치환을 지원하지 않음
|
||||
- 해결: compose 환경 변수로 `KRATOS_SELFSERVICE_*`, `KRATOS_SERVE_*` 오버라이드 사용
|
||||
|
||||
## 6) 네트워크 접근 테스트
|
||||
## 8) 네트워크 접근 테스트
|
||||
아래 스크립트는 **ory-net에서 Admin 포트 접근 가능** / **baron_net(Frontend 영역)에서 접근 불가**를 검증합니다.
|
||||
|
||||
```bash
|
||||
@@ -101,7 +133,7 @@ docker run --rm --network baron_net curlimages/curl:8.10.1 -fsS http://hydra:444
|
||||
docker run --rm --network baron_net curlimages/curl:8.10.1 -fsS http://kratos:4434/health/ready
|
||||
```
|
||||
|
||||
## 7) 참고 파일
|
||||
## 9) 참고 파일
|
||||
- `compose.ory.yaml`
|
||||
- `docker/ory/kratos/kratos.yml`
|
||||
- `.env.sample`
|
||||
|
||||
@@ -61,7 +61,6 @@ server {
|
||||
|
||||
# Hydra Public API
|
||||
location /oidc {
|
||||
rewrite ^/oidc/(.*)$ /$1 break;
|
||||
proxy_pass $oathkeeper_upstream;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
@@ -16,11 +16,12 @@ fi
|
||||
USERFRONT_URL="${USERFRONT_URL:-http://localhost:5000}"
|
||||
OATHKEEPER_PUBLIC_URL="${OATHKEEPER_PUBLIC_URL:-$USERFRONT_URL}"
|
||||
HYDRA_PUBLIC_URL="${HYDRA_PUBLIC_URL:-${OATHKEEPER_PUBLIC_URL%/}/oidc}"
|
||||
HYDRA_ADMIN_URL="${HYDRA_ADMIN_URL:-http://hydra:4445}"
|
||||
KRATOS_UI_URL="${KRATOS_UI_URL:-http://localhost:5000}"
|
||||
ADMINFRONT_URL="${ADMINFRONT_URL:-https://sadmin.hmac.kr}"
|
||||
DEVFRONT_URL="${DEVFRONT_URL:-https://sdev.hmac.kr}"
|
||||
ADMINFRONT_CALLBACK_URLS="${ADMINFRONT_CALLBACK_URLS:-http://172.16.10.176:5173/auth/callback}"
|
||||
DEVFRONT_CALLBACK_URLS="${DEVFRONT_CALLBACK_URLS:-http://172.16.10.176:5174/auth/callback}"
|
||||
ADMINFRONT_CALLBACK_URLS="${ADMINFRONT_CALLBACK_URLS:-${ADMINFRONT_URL%/}/auth/callback}"
|
||||
DEVFRONT_CALLBACK_URLS="${DEVFRONT_CALLBACK_URLS:-${DEVFRONT_URL%/}/auth/callback}"
|
||||
KRATOS_ALLOWED_RETURN_URLS_EXTRA="${KRATOS_ALLOWED_RETURN_URLS_EXTRA:-}"
|
||||
|
||||
declare -a WARNINGS=()
|
||||
@@ -258,13 +259,10 @@ validate_gateway_mapping() {
|
||||
if ! grep -Eq 'location /oidc' "$ROOT_DIR/gateway/nginx.conf"; then
|
||||
mode="unmapped_fail"
|
||||
fi
|
||||
if ! grep -Eq 'rewrite \^/oidc/\(\.\*\)\$ /\$1 break;' "$ROOT_DIR/gateway/nginx.conf"; then
|
||||
if ! grep -Eq '"url": "<\.\*>://<(\.\*|\[\^/\]\+)>/oidc/oauth2/<\.\*>"' "$ROOT_DIR/docker/ory/oathkeeper/rules.json"; then
|
||||
mode="unmapped_fail"
|
||||
fi
|
||||
if ! grep -Eq '"url": "<\.\*>://<\.\*>/oidc/oauth2/<\.\*>"' "$ROOT_DIR/docker/ory/oathkeeper/rules.json"; then
|
||||
mode="unmapped_fail"
|
||||
fi
|
||||
if ! grep -Eq '"strip_path_prefix": "/oidc"' "$ROOT_DIR/docker/ory/oathkeeper/rules.json"; then
|
||||
if ! grep -Eq '"strip_path(_prefix)?": "/oidc"' "$ROOT_DIR/docker/ory/oathkeeper/rules.json"; then
|
||||
mode="unmapped_fail"
|
||||
fi
|
||||
fi
|
||||
@@ -358,10 +356,10 @@ verify_runtime_hydra_clients() {
|
||||
fi
|
||||
|
||||
local admin_info dev_info
|
||||
if ! admin_info="$(docker exec ory_hydra hydra get oauth2-client --endpoint http://hydra:4445 adminfront 2>/dev/null)"; then
|
||||
if ! admin_info="$(docker exec ory_hydra hydra get oauth2-client --endpoint "$HYDRA_ADMIN_URL" adminfront 2>/dev/null)"; then
|
||||
fail "failed to read hydra client 'adminfront' from running container"
|
||||
fi
|
||||
if ! dev_info="$(docker exec ory_hydra hydra get oauth2-client --endpoint http://hydra:4445 devfront 2>/dev/null)"; then
|
||||
if ! dev_info="$(docker exec ory_hydra hydra get oauth2-client --endpoint "$HYDRA_ADMIN_URL" devfront 2>/dev/null)"; then
|
||||
fail "failed to read hydra client 'devfront' from running container"
|
||||
fi
|
||||
|
||||
@@ -382,6 +380,7 @@ run_validation() {
|
||||
validate_dotenv_line_safety "BACKEND_URL"
|
||||
validate_dotenv_line_safety "OATHKEEPER_PUBLIC_URL"
|
||||
validate_dotenv_line_safety "HYDRA_PUBLIC_URL"
|
||||
validate_dotenv_line_safety "HYDRA_ADMIN_URL"
|
||||
validate_dotenv_line_safety "KRATOS_BROWSER_URL"
|
||||
validate_dotenv_line_safety "KRATOS_UI_URL"
|
||||
validate_dotenv_line_safety "ADMINFRONT_URL"
|
||||
|
||||
@@ -3,6 +3,19 @@ set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
dry_run_default_dev="$(
|
||||
make --dry-run --always-make -C "$repo_root" dev 2>&1
|
||||
)"
|
||||
|
||||
default_app_up_line="$(
|
||||
grep -E "docker compose .* -f docker-compose.yaml up .*backend.*adminfront.*devfront.*orgfront.*userfront" <<<"$dry_run_default_dev" | tail -1
|
||||
)"
|
||||
|
||||
if [[ -z "$default_app_up_line" ]]; then
|
||||
echo "make dev must include orgfront in the default development app services." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dry_run_dev="$(
|
||||
make --dry-run --always-make -C "$repo_root" dev DEV_SERVICES="backend adminfront" 2>&1
|
||||
)"
|
||||
@@ -45,10 +58,32 @@ if ! grep -q "Ensuring Ory stack" <<<"$dry_run_up_dev"; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dry_run_up_app="$(
|
||||
make --dry-run --always-make -C "$repo_root" up-app 2>&1
|
||||
)"
|
||||
|
||||
if ! grep -q "Starting App stack (backend/userfront/adminfront/devfront/orgfront)" <<<"$dry_run_up_app"; then
|
||||
echo "make up-app must announce orgfront as part of the app stack." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dry_run_up_all="$(
|
||||
make --dry-run --always-make -C "$repo_root" up-all 2>&1
|
||||
)"
|
||||
|
||||
if ! dry_run_up="$(
|
||||
make --dry-run --always-make -C "$repo_root" up 2>&1
|
||||
)"; then
|
||||
echo "make up must be available as the default full-stack startup target." >&2
|
||||
echo "$dry_run_up" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q "Starting ALL stacks (infra + ory + app)" <<<"$dry_run_up"; then
|
||||
echo "make up must delegate to the full-stack startup flow." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q "Ensuring Docker networks" <<<"$dry_run_up_all"; then
|
||||
echo "make up-all must ensure external Docker networks before compose up." >&2
|
||||
exit 1
|
||||
|
||||
@@ -10,6 +10,26 @@ docker_config="$(
|
||||
docker compose --env-file "$repo_root/.env" -f "$repo_root/docker/compose.ory.yaml" config
|
||||
)"
|
||||
|
||||
override_env="$(mktemp)"
|
||||
cp "$repo_root/.env" "$override_env"
|
||||
cat >> "$override_env" <<'EOF'
|
||||
USERFRONT_URL=https://compose-policy.example.test/sso
|
||||
HYDRA_PUBLIC_URL=https://compose-policy.example.test/sso/oidc
|
||||
KRATOS_UI_URL=https://compose-policy.example.test/ui
|
||||
KRATOS_BROWSER_URL=https://compose-policy.example.test/auth
|
||||
ADMINFRONT_CALLBACK_URLS=https://compose-policy.example.test/admin/callback
|
||||
DEVFRONT_CALLBACK_URLS=https://compose-policy.example.test/dev/callback
|
||||
ORGFRONT_CALLBACK_URLS=https://compose-policy.example.test/org/callback
|
||||
EOF
|
||||
trap 'rm -f "$override_env"' EXIT
|
||||
|
||||
override_config="$(
|
||||
docker compose --env-file "$override_env" -f "$repo_root/compose.ory.yaml" config
|
||||
)"
|
||||
override_docker_config="$(
|
||||
docker compose --env-file "$override_env" -f "$repo_root/docker/compose.ory.yaml" config
|
||||
)"
|
||||
|
||||
for service in kratos hydra keto oathkeeper; do
|
||||
version_key="$(tr '[:lower:]' '[:upper:]' <<<"$service")_VERSION"
|
||||
expected_version="$(grep -E "^${version_key}=" "$repo_root/.env" | cut -d= -f2-)"
|
||||
@@ -28,6 +48,40 @@ if grep -q "oryd/hydra:v25.4.0" <<<"$root_config"; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for compose_file in "$repo_root/compose.ory.yaml" "$repo_root/docker/compose.ory.yaml"; do
|
||||
if grep -Eq 'redirect-uri .*:-.*https?://' "$compose_file"; then
|
||||
echo "ERROR: $compose_file must not hard-code external redirect URI fallbacks; use .env variables." >&2
|
||||
exit 1
|
||||
fi
|
||||
if grep -Eq 'KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=.*https?://localhost' "$compose_file"; then
|
||||
echo "ERROR: $compose_file must not hard-code Kratos allowed return URL fallbacks; use .env variables." >&2
|
||||
exit 1
|
||||
fi
|
||||
if awk 'in_block && /^ [A-Za-z0-9_-]+:/ { exit } /^ init-rp:/ { in_block=1 } in_block { print }' "$compose_file" | grep -q -- '--endpoint http://hydra:4445'; then
|
||||
echo "ERROR: $compose_file init-rp must use HYDRA_ADMIN_URL instead of hard-coded Hydra admin endpoint." >&2
|
||||
exit 1
|
||||
fi
|
||||
if awk 'in_block && /^ [A-Za-z0-9_-]+:/ { exit } /^[[:space:]]+oathkeeper:/ { in_block=1 } in_block { print }' "$compose_file" | grep -q "command: serve proxy --config /etc/config/oathkeeper/oathkeeper.yml"; then
|
||||
echo "ERROR: $compose_file Oathkeeper must use entrypoint.sh instead of bypassing rules.active.json generation." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
for expected_url in \
|
||||
"https://compose-policy.example.test/sso/oidc" \
|
||||
"https://compose-policy.example.test/sso/login" \
|
||||
"https://compose-policy.example.test/sso/consent" \
|
||||
"https://compose-policy.example.test/sso/error" \
|
||||
"https://compose-policy.example.test/admin/callback" \
|
||||
"https://compose-policy.example.test/dev/callback" \
|
||||
"https://compose-policy.example.test/org/callback"
|
||||
do
|
||||
if ! grep -q "$expected_url" <<<"$override_config$override_docker_config"; then
|
||||
echo "ERROR: Ory compose config must render env override URL: $expected_url" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
root_init_rp="$(
|
||||
awk 'in_block && /^ [A-Za-z0-9_-]+:/ { exit } /^ init-rp:/ { in_block=1 } in_block { print }' "$repo_root/compose.ory.yaml"
|
||||
)"
|
||||
@@ -53,3 +107,159 @@ if grep -q "releases/download/v25.4.0" "$repo_root/docker/staging_pull_compose.t
|
||||
echo "ERROR: staging pull compose must not download a hard-coded Hydra v25.4.0 CLI." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
staging_pull_template="$repo_root/docker/staging_pull_compose.template.yaml"
|
||||
|
||||
if ! grep -q 'entrypoint: \["/etc/config/oathkeeper/entrypoint.sh"\]' "$staging_pull_template"; then
|
||||
echo "ERROR: staging pull Oathkeeper must use the env-aware entrypoint." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep -q "command: serve proxy --config /etc/config/oathkeeper/oathkeeper.yml" "$staging_pull_template"; then
|
||||
echo "ERROR: staging pull Oathkeeper must not bypass entrypoint.sh with a direct command." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q "URLS_SELF_ISSUER=\${HYDRA_PUBLIC_URL}" "$staging_pull_template"; then
|
||||
echo "ERROR: staging pull Hydra issuer must use HYDRA_PUBLIC_URL." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep -Eq '(KRATOS_(SERVE|SELFSERVICE|UI|BROWSER|PUBLIC|ADMIN).*:-http://localhost|URLS_.*:-http://localhost)' "$staging_pull_template"; then
|
||||
echo "ERROR: staging pull Ory browser URLs must not fall back to localhost." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q 'KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=${KRATOS_ALLOWED_RETURN_URLS_JSON' "$staging_pull_template"; then
|
||||
echo "ERROR: staging pull Kratos allowed_return_urls must be driven by KRATOS_ALLOWED_RETURN_URLS_JSON." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for return_path in '/ko' '/en' '/auth/callback' '/ko/auth/callback' '/en/auth/callback'; do
|
||||
if ! grep -q "$return_path" "$staging_pull_template" "$repo_root/deploy/templates/.env.template" "$repo_root/.gitea/workflows/staging_code_pull.yml"; then
|
||||
echo "ERROR: staging/prod allowed_return_urls must include locale/callback path: $return_path" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if grep -Eq 'ORGFRONT_CALLBACK_URLS=.*(172\.16\.10\.176|baron-orgchart\.hmac\.kr|, https?://)' "$staging_pull_template" "$repo_root/.gitea/workflows/staging_code_pull.yml"; then
|
||||
echo "ERROR: staging pull OrgFront callbacks must not keep private IP, legacy orgchart domain, or comma-space URI entries." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep -q "rewrite \\^/oidc" "$repo_root/gateway/nginx.conf"; then
|
||||
echo "ERROR: gateway must preserve the /oidc prefix and let Oathkeeper strip it." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for rules_file in \
|
||||
"$repo_root/docker/ory/oathkeeper/rules.json" \
|
||||
"$repo_root/docker/ory/oathkeeper/rules.stage.json" \
|
||||
"$repo_root/docker/ory/oathkeeper/rules.prod.json"
|
||||
do
|
||||
for rule_id in hydra-well-known hydra-well-known-oidc hydra-oauth2 hydra-oauth2-oidc hydra-userinfo hydra-userinfo-oidc; do
|
||||
if ! grep -q "\"id\": \"$rule_id\"" "$rules_file"; then
|
||||
echo "ERROR: Oathkeeper rules must expose Hydra public route in $rules_file: $rule_id" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
for prefixed_rule in hydra-well-known-oidc hydra-oauth2-oidc hydra-userinfo-oidc; do
|
||||
if ! awk -v id="\"id\": \"$prefixed_rule\"" '
|
||||
$0 ~ id { in_rule = 1 }
|
||||
in_rule && /strip_path/ && /\/oidc/ { found = 1 }
|
||||
in_rule && /^ }[,]?$/ { in_rule = 0 }
|
||||
END { exit found ? 0 : 1 }
|
||||
' "$rules_file"; then
|
||||
echo "ERROR: prefixed Oathkeeper route must strip /oidc in $rules_file: $prefixed_rule" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
for wildcard_rules_file in \
|
||||
"$repo_root/docker/ory/oathkeeper/rules.json" \
|
||||
"$repo_root/docker/ory/oathkeeper/rules.stage.json"
|
||||
do
|
||||
if grep -q "<\\.\\*>://<\\.\\*>/" "$wildcard_rules_file"; then
|
||||
echo "ERROR: wildcard Oathkeeper host must not swallow path segments in $wildcard_rules_file." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
deploy_template="$repo_root/deploy/templates/docker-compose.yaml"
|
||||
deploy_env_template="$repo_root/deploy/templates/.env.template"
|
||||
deploy_gateway_template="$repo_root/deploy/templates/gateway/nginx.conf"
|
||||
deploy_kratos_template="$repo_root/deploy/templates/ory/kratos/kratos.yml"
|
||||
deploy_oathkeeper_rules_template="$repo_root/deploy/templates/ory/oathkeeper/rules.json"
|
||||
|
||||
for required_template in \
|
||||
"$repo_root/deploy/templates/orgfront/vite.config.ts" \
|
||||
"$repo_root/deploy/templates/orgfront/auth.ts" \
|
||||
"$repo_root/docker/ory/init-db/01_create_dbs.sh" \
|
||||
"$repo_root/docker/ory/hydra/hydra.yml" \
|
||||
"$repo_root/docker/ory/keto/keto.yml" \
|
||||
"$repo_root/docker/ory/oathkeeper/entrypoint.sh" \
|
||||
"$repo_root/docker/ory/oathkeeper/oathkeeper.yml"
|
||||
do
|
||||
if [[ ! -f "$required_template" ]]; then
|
||||
echo "ERROR: deploy instance generation requires missing source file: $required_template" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if grep -Eq "oryd/(kratos|hydra|keto|oathkeeper):v25\\.4\\.0" "$deploy_template"; then
|
||||
echo "ERROR: deploy template Ory stack must not hard-code v25.4.0 images." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for prod_sensitive_file in \
|
||||
"$repo_root/docker/ory/oathkeeper/rules.prod.json" \
|
||||
"$repo_root/docker/ory/kratos/kratos.yml" \
|
||||
"$repo_root/deploy/templates/ory/kratos/kratos.yml"
|
||||
do
|
||||
if grep -q "app\\.brsw\\.kr" "$prod_sensitive_file"; then
|
||||
echo "ERROR: Ory production-sensitive config must not hard-code app.brsw.kr: $prod_sensitive_file" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
for service in kratos-migrate kratos hydra-migrate hydra keto-migrate keto oathkeeper_logs_init oathkeeper; do
|
||||
if ! grep -q "^ $service:" "$deploy_template"; then
|
||||
echo "ERROR: deploy template Ory stack must include service: $service" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
for version_key in KRATOS_VERSION HYDRA_VERSION KETO_VERSION OATHKEEPER_VERSION; do
|
||||
if ! grep -q "^$version_key=v26\\.2\\.0$" "$deploy_env_template"; then
|
||||
echo "ERROR: deploy env template must define $version_key=v26.2.0." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if ! grep -q 'entrypoint: \["/etc/config/oathkeeper/entrypoint.sh"\]' "$deploy_template"; then
|
||||
echo "ERROR: deploy template Oathkeeper must use the env-aware entrypoint." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if grep -q "rewrite \\^/oidc" "$deploy_gateway_template"; then
|
||||
echo "ERROR: deploy template gateway must preserve the /oidc prefix." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q '^version: v26.2.0$' "$deploy_kratos_template"; then
|
||||
echo "ERROR: deploy Kratos template config version must match v26.2.0." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for rule_id in hydra-well-known hydra-well-known-oidc hydra-oauth2 hydra-oauth2-oidc hydra-userinfo hydra-userinfo-oidc; do
|
||||
if ! grep -q "\"id\": \"$rule_id\"" "$deploy_oathkeeper_rules_template"; then
|
||||
echo "ERROR: deploy Oathkeeper rules must expose Hydra public route: $rule_id" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if ! grep -q '"strip_path": "/oidc"' "$deploy_oathkeeper_rules_template"; then
|
||||
echo "ERROR: deploy Oathkeeper prefixed routes must strip /oidc with strip_path." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user