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_credentialsgrant 으로 자동 발급 + 캐시 + 만료 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 failed | Keycloak URL 오타 / DNS | GEND_KEYCLOAK_TOKEN_URL 명시 |
m2m grant returned 401 | client_secret 오류 / 클라이언트 disabled | Vault 값 + Keycloak 콘솔 재확인 |
intel sensor: no API token resolved warning | env 자체가 미주입 | secretRef 적용 확인 + Pod 재시작 |
token 정상 but /api/v1/intel/sources 가 403 | service-account 에 admin role 미부여 | step 1 재확인 |