본문으로 건너뛰기

Intel Dagster Sensor M2M 자격증명 운영자 가이드

intel_source_cron_sensor 가 gend-api 의 POST /api/v1/intel/sources/{id}/run 을 자동 호출하려면 인증된 JWT 가 필요합니다. 본 가이드는 Keycloak service-account 클라이언트 + Vault secret + dagster-daemon env 주입 절차를 정리합니다 (Issue #1407).

왜 필요한가

  • Sensor 는 daemon Pod 에서 매 분 호출 — 정적 토큰은 만료/rotation 문제
  • API 라우터가 모두 JWT 인증 강제 (workspace 격리, audit log)
  • 따라서 client_credentials grant 으로 자동 발급 + 캐시 + 만료 60s 전 자동 refresh

1. Keycloak service-account 클라이언트 등록

gend realm 에 confidential 클라이언트 gend-dagster-sensor 생성 (kcadm 또는 admin REST):

# kcadm
kcadm.sh create clients -r gend -s clientId=gend-dagster-sensor \
-s clientAuthenticatorType=client-secret -s publicClient=false \
-s serviceAccountsEnabled=true -s standardFlowEnabled=false \
-s directAccessGrantsEnabled=false

# service account 사용자에 admin role 매핑
kcadm.sh add-roles -r gend --uusername service-account-gend-dagster-sensor \
--rolename admin

보안 강화: admin 대신 read-only role 신설 (intel_collector_runner) 도 가능. 현재 sensor 는 GET sources + POST run 만 호출하므로 좁은 권한도 OK.

client_secret 확인:

kcadm.sh get clients/<client-uuid>/client-secret -r gend --fields value

2. Vault 에 secret 저장

vault kv put secret/gend/intel-dagster-sensor \
GEND_DAGSTER_CLIENT_ID="gend-dagster-sensor" \
GEND_DAGSTER_CLIENT_SECRET="<above value>"

3. ExternalSecret 적용

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: intel-dagster-credentials
namespace: gend
spec:
refreshInterval: 1m
secretStoreRef: { name: vault-backend, kind: ClusterSecretStore }
target: { name: intel-dagster-credentials, creationPolicy: Owner }
data:
- secretKey: GEND_DAGSTER_CLIENT_ID
remoteRef: { key: gend/intel-dagster-sensor, property: GEND_DAGSTER_CLIENT_ID }
- secretKey: GEND_DAGSTER_CLIENT_SECRET
remoteRef: { key: gend/intel-dagster-sensor, property: GEND_DAGSTER_CLIENT_SECRET }

infra/external-secrets/ 아래 파일로 저장 + kubectl apply.

4. dagster-daemon envFrom 추가

infra/helm/dagster/values.yaml 의 daemon section 에:

dagsterDaemon:
envFrom:
- secretRef:
name: intel-dagster-credentials
optional: true

또는 직접 deployment 패치:

kubectl --context aks-genos-prod set env deploy/dagster-daemon -n gend \
--from secret/intel-dagster-credentials

5. 검증

# 1) Pod env 확인
POD=$(kubectl get pod -n gend -l app.kubernetes.io/component=dagster-daemon -o name | head -1 | cut -d/ -f2)
kubectl exec -n gend "$POD" -c dagster-daemon -- bash -c 'env | grep DAGSTER_CLIENT' | sed 's/=.*=\(...\)/=***\1/'

# 2) Sensor 로그
kubectl logs -n gend deploy/dagster-daemon -c dagster-daemon --tail=50 | grep -E "intel_source|m2m token"

# 3) IntelSource last_run_at 갱신
kubectl exec -n gend deploy/gend-api -c gend-api -- python3 -c "
import asyncio
from gend_api.db.session import async_session
from sqlalchemy import text
async def m():
async with async_session() as db:
r = await db.execute(text('SELECT name, last_run_at FROM intel_sources ORDER BY last_run_at DESC NULLS LAST'))
for row in r.fetchall(): print(row)
asyncio.run(m())
"

5분 안에 last_run_at 가 cron tick 마다 갱신되고, intel_filings/intel_articles/intel_ohlcv_daily 의 row 가 증가합니다.

Fallback 옵션 (긴급 운영)

긴급 시 GEND_API_TOKEN 환경변수에 정적 JWT 를 박을 수도 있음 (sensor 가 우선 검사):

kubectl create secret generic intel-dagster-static-token \
--from-literal=GEND_API_TOKEN="<paste-jwt>"
kubectl set env deploy/dagster-daemon -n gend --from secret/intel-dagster-static-token

단 JWT 만료 (보통 5분) 시 sensor 가 다시 401 — M2M 경로가 진짜 해결책.

Troubleshooting

증상원인조치
m2m token request failedKeycloak URL 오타 / DNSGEND_KEYCLOAK_TOKEN_URL 명시
m2m grant returned 401client_secret 오류 / 클라이언트 disabledVault 값 + Keycloak 콘솔 재확인
intel sensor: no API token resolved warningenv 자체가 미주입secretRef 적용 확인 + Pod 재시작
token 정상 but /api/v1/intel/sources 가 403service-account 에 admin role 미부여step 1 재확인