1
0
forked from baron/baron-sso

ory stack 설정 검사 추가. make 명령으로 실행 필요.

This commit is contained in:
Lectom C Han
2026-02-19 16:09:06 +09:00
parent 65c45c7571
commit 3025be52d5
5 changed files with 156 additions and 53 deletions

View File

@@ -111,12 +111,12 @@ HYDRA_ADMIN_URL=http://hydra:4445
HYDRA_PUBLIC_URL=${OATHKEEPER_PUBLIC_URL}/oidc
# OIDC 클라이언트 callback (콤마 구분)
ADMINFRONT_CALLBACK_URLS=http://localhost:5173/auth/callback
DEVFRONT_CALLBACK_URLS=http://localhost:5174/callback
ADMINFRONT_CALLBACK_URLS=http://localhost:5173/auth/callback,https://sso.hmac.kr/auth/callback
DEVFRONT_CALLBACK_URLS=http://localhost:5174/callback,https://sso.hmac.kr/devfront/callback
# Kratos allowed_return_urls 확장 목록 (콤마 구분, 선택)
# 기본값은 KRATOS_UI_URL, USERFRONT_URL, 각 callback URL을 자동 포함합니다.
KRATOS_ALLOWED_RETURN_URLS_EXTRA=
KRATOS_ALLOWED_RETURN_URLS_EXTRA=[]
# Oathkeeper JWKS (내부 통신용)
JWKS_URL=http://oathkeeper:4456/.well-known/jwks.json

View File

@@ -12,11 +12,11 @@ COMPOSE_ORY := compose.ory.yaml
COMPOSE_APP := docker-compose.yaml
AUTH_CONFIG_ENV := .generated/auth-config.env
COMPOSE_ENV_FILES :=
COMPOSE_CLI_ENV_ARGS :=
ifneq (,$(wildcard ./.env))
COMPOSE_ENV_FILES += --env-file .env
COMPOSE_CLI_ENV_ARGS += --env-file .env
endif
COMPOSE_ENV_FILES += --env-file $(AUTH_CONFIG_ENV)
COMPOSE_CLI_ENV_ARGS += --env-file $(AUTH_CONFIG_ENV)
# --- 인증 설정 빌드/검증 ---
build-auth-config:
@@ -36,7 +36,7 @@ verify-auth-config: validate-auth-config
# 주의: --remove-orphan 사용 금지 (다른 스택이 orphan으로 판단되어 종료될 수 있음)
up-all: validate-auth-config
@echo "Starting ALL stacks (infra + ory + app)..."
docker compose $(COMPOSE_ENV_FILES) -f $(COMPOSE_INFRA) -f $(COMPOSE_ORY) -f $(COMPOSE_APP) up -d
docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_INFRA) -f $(COMPOSE_ORY) -f $(COMPOSE_APP) up -d
# --- 개별 스택 실행 ---
up-infra:
@@ -45,15 +45,15 @@ up-infra:
up-ory: validate-auth-config
@echo "Starting Ory stack (kratos/hydra/keto/oathkeeper)..."
docker compose $(COMPOSE_ENV_FILES) -f $(COMPOSE_ORY) up -d
docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_ORY) up -d
up-app: validate-auth-config
@echo "Starting App stack (backend/userfront/adminfront/devfront)..."
docker compose $(COMPOSE_ENV_FILES) -f $(COMPOSE_APP) up -d
docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_APP) up -d
up-backend: validate-auth-config
@echo "Starting Backend only..."
docker compose $(COMPOSE_ENV_FILES) -f $(COMPOSE_APP) up -d backend
docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_APP) up -d backend
up-dev: up-infra up-ory
@echo "Dev stack is up (infra + ory)."

View File

@@ -155,13 +155,43 @@ Kratos가 사용자 SoT이며 Hydra는 순수 OIDC 토큰 엔진입니다. 비
```bash
cp .env.sample .env
```
2. **IDP 우선순위와 Ory 엔드포인트를 지정**합니다. 기본값은 Ory 입니다
```
IDP_PROVIDER=ory
KRATOS_ADMIN_URL=http://kratos:4434
HYDRA_ADMIN_URL=http://hydra:4445
HYDRA_PUBLIC_URL=http://hydra:4444
```
2. `.env`를 작성합니다. (아래 작성 규칙 필수)
### `.env` 작성 규칙 (중요)
- `KEY=value` 한 줄만 사용하고, **값 뒤에 같은 줄 주석을 붙이지 않습니다.**
- 주석이 필요하면 반드시 **윗줄에 별도 주석 라인**으로 작성합니다.
- URL 값 끝에 공백이 들어가면 Hydra/Kratos 기동 실패로 이어질 수 있습니다.
잘못된 예:
```env
USERFRONT_URL=https://sso.example.com # 이렇게 같은 줄 주석 금지
```
올바른 예:
```env
# UserFront 공개 URL
USERFRONT_URL=https://sso.example.com
```
### `.env` 핵심 변수 가이드
- `IDP_PROVIDER`: 기본 `ory`
- `USERFRONT_URL`: 브라우저 기준 공개 도메인 (예: `https://sso.example.com`)
- `OATHKEEPER_PUBLIC_URL`: 보통 `${USERFRONT_URL}`
- `HYDRA_PUBLIC_URL`: 보통 `${OATHKEEPER_PUBLIC_URL}/oidc`
- `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`)
- 주의: 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`
### `.env` 작성 후 권장 점검
```bash
make validate-auth-config
```
위 검증은 callback/allowed_return_urls/게이트웨이 매핑 규칙을 점검하고 `.generated/auth-config.env`를 생성합니다.
### 전체 스택 실행 (Running the Stack)
@@ -207,6 +237,15 @@ make verify-auth-config
- 게이트웨이 경유 환경은 URL 문자열 완전일치 대신 매핑 유효성(`direct_match` / `mapped_match`) 기준으로 검증합니다.
- 관련 정책 문서: `docs/oidc_redirect_mapping_validation_policy.md`
### 권장 실행 순서
```bash
cp .env.sample .env
# .env 편집
make validate-auth-config
make up-dev
make up-app
```
직접 Compose를 사용하려면 다음처럼 env 파일을 함께 주입하세요.
```bash
docker compose --env-file .env --env-file .generated/auth-config.env -f compose.infra.yaml -f compose.ory.yaml up -d

View File

@@ -198,40 +198,40 @@ services:
# 기본 RP (Admin Front 등) 자동 등록 컨테이너
init-rp:
image: oryd/hydra:${HYDRA_VERSION:-v25.4.0}
environment:
- HYDRA_ADMIN_URL=http://hydra:4445
- OATHKEEPER_INTROSPECT_CLIENT_ID=${OATHKEEPER_INTROSPECT_CLIENT_ID:-oathkeeper-introspect}
- OATHKEEPER_INTROSPECT_CLIENT_SECRET=${OATHKEEPER_INTROSPECT_CLIENT_SECRET:-oathkeeper-secret}
- ADMINFRONT_CALLBACK_URLS=${ADMINFRONT_CALLBACK_URLS:-http://localhost:5173/auth/callback}
- DEVFRONT_CALLBACK_URLS=${DEVFRONT_CALLBACK_URLS:-http://localhost:5174/callback}
command: |
hydra clients create \
--endpoint http://hydra:4445 \
--id adminfront \
--secret admin-secret \
--grant-types authorization_code,refresh_token \
--response-types code \
--scope openid,offline_access,profile,email \
--callbacks "$ADMINFRONT_CALLBACK_URLS";
image: oryd/hydra:v25.4.0
entrypoint: ["/bin/sh"]
command:
- -ec
- |
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 ${OATHKEEPER_INTROSPECT_CLIENT_ID:-oathkeeper-introspect} >/dev/null 2>&1 || true
hydra clients create \
--endpoint http://hydra:4445 \
--id devfront \
--grant-types authorization_code,refresh_token \
--response-types code \
hydra create oauth2-client \
--endpoint http://hydra:4445 \
--id adminfront \
--secret admin-secret \
--grant-type authorization_code,refresh_token \
--response-type code \
--scope openid,offline_access,profile,email \
--redirect-uri ${ADMINFRONT_CALLBACK_URLS:-http://localhost:5173/auth/callback}
hydra create oauth2-client \
--endpoint http://hydra:4445 \
--id devfront \
--grant-type authorization_code,refresh_token \
--response-type code \
--scope openid,offline_access,profile,email \
--token-endpoint-auth-method none \
--response-types code \
--callbacks "$DEVFRONT_CALLBACK_URLS";
--redirect-uri ${DEVFRONT_CALLBACK_URLS:-http://localhost:5174/callback}
hydra clients create \
--endpoint http://hydra:4445 \
--id "$OATHKEEPER_INTROSPECT_CLIENT_ID" \
--secret "$OATHKEEPER_INTROSPECT_CLIENT_SECRET" \
--grant-types client_credentials \
--response-types token \
--scope openid,offline_access,profile,email;
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
depends_on:
ory_stack_check:
condition: service_completed_successfully

View File

@@ -32,6 +32,24 @@ warn() {
WARNINGS+=("$1")
}
validate_dotenv_line_safety() {
local key="$1"
local env_file="$ROOT_DIR/.env"
[[ -f "$env_file" ]] || return 0
local raw_line
raw_line="$(grep -E "^${key}=" "$env_file" | tail -n 1 || true)"
[[ -n "$raw_line" ]] || return 0
if [[ "$raw_line" == *" #"* ]]; then
fail ".env line for $key contains inline comment. Use comment-only line above the key."
fi
if [[ "$raw_line" =~ [[:space:]]+$ ]]; then
fail ".env line for $key has trailing whitespace."
fi
}
trim() {
local value="$1"
value="${value#"${value%%[![:space:]]*}"}"
@@ -50,6 +68,38 @@ csv_to_lines() {
done
}
list_to_lines() {
local raw="$1"
raw="$(trim "$raw")"
if [[ -z "$raw" || "$raw" == "[]" ]]; then
return 0
fi
if [[ "$raw" =~ ^\[(.*)\]$ ]]; then
local inner="${BASH_REMATCH[1]}"
inner="$(trim "$inner")"
if [[ -z "$inner" ]]; then
return 0
fi
printf '%s\n' "$inner" | tr ',' '\n' | while IFS= read -r token; do
local item
item="$(trim "$token")"
item="${item#\"}"
item="${item%\"}"
item="${item#\'}"
item="${item%\'}"
item="$(trim "$item")"
if [[ -n "$item" ]]; then
printf '%s\n' "$item"
fi
done
return 0
fi
csv_to_lines "$raw"
}
is_http_url() {
local url="$1"
[[ "$url" =~ ^https?://[^[:space:]]+$ ]]
@@ -144,7 +194,7 @@ collect_values() {
while IFS= read -r item; do
EXTRA_ALLOWED_RETURNS+=("$item")
done < <(csv_to_lines "$KRATOS_ALLOWED_RETURN_URLS_EXTRA")
done < <(list_to_lines "$KRATOS_ALLOWED_RETURN_URLS_EXTRA")
}
validate_urls() {
@@ -169,8 +219,13 @@ validate_callback_group() {
local has_path=0
for url in "${urls[@]}"; do
validate_urls "$group_name entry" "$url"
local canonical
canonical="$(canonicalize_url "$url")"
if [[ "$url" != "$canonical" ]]; then
fail "$group_name entry must not end with trailing slash: $url"
fi
local path
path="$(url_path "$url")"
path="$(url_path "$canonical")"
if [[ -n "$path" && "$path" != "/" ]]; then
has_path=1
fi
@@ -283,9 +338,9 @@ EOF
validate_compose_wiring() {
grep -Eq 'KRATOS_SELFSERVICE_ALLOWED_RETURN_URLS=\$\{KRATOS_ALLOWED_RETURN_URLS_JSON' "$ROOT_DIR/compose.ory.yaml" \
|| fail "compose.ory.yaml is not wired to KRATOS_ALLOWED_RETURN_URLS_JSON"
grep -Eq 'ADMINFRONT_CALLBACK_URLS=\$\{ADMINFRONT_CALLBACK_URLS' "$ROOT_DIR/compose.ory.yaml" \
grep -Eq 'ADMINFRONT_CALLBACK_URLS' "$ROOT_DIR/compose.ory.yaml" \
|| fail "compose.ory.yaml is not wired to ADMINFRONT_CALLBACK_URLS"
grep -Eq 'DEVFRONT_CALLBACK_URLS=\$\{DEVFRONT_CALLBACK_URLS' "$ROOT_DIR/compose.ory.yaml" \
grep -Eq 'DEVFRONT_CALLBACK_URLS' "$ROOT_DIR/compose.ory.yaml" \
|| fail "compose.ory.yaml is not wired to DEVFRONT_CALLBACK_URLS"
}
@@ -301,10 +356,10 @@ verify_runtime_hydra_clients() {
fi
local admin_info dev_info
if ! admin_info="$(docker exec ory_hydra hydra clients get --endpoint http://hydra:4445 adminfront 2>/dev/null)"; then
if ! admin_info="$(docker exec ory_hydra hydra get oauth2-client --endpoint http://hydra:4445 adminfront 2>/dev/null)"; then
fail "failed to read hydra client 'adminfront' from running container"
fi
if ! dev_info="$(docker exec ory_hydra hydra clients get --endpoint http://hydra:4445 devfront 2>/dev/null)"; then
if ! dev_info="$(docker exec ory_hydra hydra get oauth2-client --endpoint http://hydra:4445 devfront 2>/dev/null)"; then
fail "failed to read hydra client 'devfront' from running container"
fi
@@ -321,6 +376,15 @@ verify_runtime_hydra_clients() {
}
run_validation() {
validate_dotenv_line_safety "USERFRONT_URL"
validate_dotenv_line_safety "BACKEND_URL"
validate_dotenv_line_safety "OATHKEEPER_PUBLIC_URL"
validate_dotenv_line_safety "HYDRA_PUBLIC_URL"
validate_dotenv_line_safety "KRATOS_BROWSER_URL"
validate_dotenv_line_safety "KRATOS_UI_URL"
validate_dotenv_line_safety "ADMINFRONT_CALLBACK_URLS"
validate_dotenv_line_safety "DEVFRONT_CALLBACK_URLS"
collect_values
validate_callback_group "ADMINFRONT_CALLBACK_URLS" "/auth/callback" "${ADMIN_CALLBACKS[@]}"
validate_callback_group "DEVFRONT_CALLBACK_URLS" "/callback" "${DEV_CALLBACKS[@]}"