배포 하드닝 - 컴포넌트별 민감정보 분리와 향후 개선 방향
Apache Airflow Official Documentation (in-repo snapshot) — Apache Software Foundation security/security_model.rst - "Deployment hardening for improved isolation" 섹션, 컴포넌트별 민감정보 표와 mermaid 다이어그램 (약 546-827행)
이 모듈을 다 읽으면
- 환경 변수가 설정 파일보다 안전한 이유를 prctl(PR_SET_DUMPABLE) 메커니즘으로 설명할 수 있다
- API Server, Scheduler, Dag File Processor, Triggerer, Worker 각각이 필요로 하는 민감 값의 종류를 구분할 수 있다
- 비대칭 키 JWT 서명이 대칭 키 대비 어떤 보안 이점을 제공하는지 설명할 수 있다
더 강한 격리가 필요한 Deployment Manager는 Airflow가 기본으로 강제하지 않는 배포 수준 하드닝 조치를 취할 수 있다: Dag 코드 리뷰, 컴포넌트별 최소 권한 민감정보 배포, 환경 변수를 통한 안전한 설정 전달, 비대칭 키 JWT 서명, 네트워크 레벨 격리가 핵심 축이다.
코드 리뷰와 컴포넌트별 최소 권한 원칙
더 강한 격리가 필요한 Deployment Manager는 Dag 번들에 제출되는 모든 Dag에 대한 리뷰 프로세스를 도입할 수 있다 - Dag 파일 배포 전 pull request 리뷰 요구, 의심스러운 패턴(직접 DB 접근 시도, 환경 변수 읽기, 설정 모듈 import 등)을 탐지하는 정적 분석, 위험한 코드를 표시하는 자동 린팅 규칙 등이다.
또한 모든 설정 파라미터를 모든 컴포넌트에 공유하지 않아야 한다. 구체적으로: JWT 서명 키(``[api_auth] jwt_secret`` 또는 ``jwt_private_key_path``)는 토큰을 생성해야 하는 컴포넌트(Scheduler/Executor, API Server)와 검증해야 하는 컴포넌트(API Server)에만 제공되어야 하며, 워커는 서명 키에 접근할 필요가 없다 - 발급받은 토큰만 있으면 된다. 외부 시스템용 Connection 자격증명(Secrets Manager 경유)은 워커에게 자격증명을 서빙하는 API Server에만 제공되어야 하며, Scheduler·Dag File Processor·Triggerer에는 직접 제공하지 않아야 한다(다만 이는 외부 시스템 인증이 필요한 Deadline Alerts나 트리거 기능 일부를 제한할 수 있다). 데이터베이스 연결 문자열은 직접 DB 접근이 필요한 컴포넌트(API Server, Scheduler, Dag File Processor, Triggerer)에만 제공되어야 하며 워커에는 제공하지 않는다.
핵심 포인트
- Dag 제출에 대한 PR 리뷰, 정적 분석, 자동 린팅으로 위험 패턴을 사전에 걸러낼 수 있다
- JWT 서명 키는 Scheduler/Executor·API Server에만 필요하고 워커는 필요 없다
- Connection 자격증명은 API Server에만 필요하며, Scheduler/DFP/Triggerer에 직접 주면 필요 이상의 권한 확산이 된다
- DB 연결 문자열은 API Server/Scheduler/DFP/Triggerer에만 필요하고 워커에는 불필요하다
환경 변수 vs 설정 파일: prctl(PR_SET_DUMPABLE)
더 높은 보안을 위해서는 민감한 설정 값을 설정 파일이 아니라 환경 변수로 전달하는 것이 낫다. 환경 변수는 Airflow 워커 프로세스에서 내장된 보호 덕분에 설정 파일보다 태생적으로 안전하다: 리눅스에서 supervisor 프로세스는 태스크 프로세스를 fork하기 전에 ``prctl(PR_SET_DUMPABLE, 0)``을 호출하고, 이 플래그는 fork된 자식에 상속된다. 이렇게 부모와 자식 모두를 non-dumpable로 표시하면, 같은 UID의 형제 프로세스가 ``/proc/<pid>/environ``, ``/proc/<pid>/mem``을 읽거나 ``ptrace``로 attach하는 것을 막는다. 반면 디스크의 설정 파일은 동일 Unix 사용자로 실행되는 어떤 프로세스든 읽을 수 있다. 환경 변수는 또한 개별 프로세스나 컨테이너 단위로 스코핑할 수 있어 어떤 컴포넌트가 어떤 시크릿에 접근하는지 제한하기 더 쉽다.
잘 하드닝된 배포에서 각 컴포넌트가 필요로 하는 민감 값의 클래스는 다음과 같다(최소 권한인 Worker(초록)에서 최대 권한인 API Server(파랑)로 갈수록 필요한 시크릿이 늘어난다): Worker는 Fernet 키, 워커 시크릿 백엔드 자격증명, 원격 로그 핸들러 kwargs만 필요하고 DB 연결이나 JWT 서명 키는 전혀 필요 없다. Triggerer/Dag File Processor는 DB 연결, Fernet 키, non-worker 시크릿 백엔드 자격증명이 필요하다(Triggerer는 추가로 원격 로그 핸들러 kwargs도 필요). Scheduler는 여기에 더해 JWT 서명 키와 원격 로그 핸들러 kwargs까지 필요하다. API Server는 DB 연결, JWT 서명 키, Fernet 키까지 전부 필요한 유일한 컴포넌트다.
핵심 민감 설정 변수 예시로는 ``AIRFLOW__API_AUTH__JWT_SECRET``(API Server, Scheduler 필요), ``AIRFLOW__CORE__FERNET_KEY``(API Server/Scheduler/Workers/DFP/Triggerer 모두 필요), ``AIRFLOW__DATABASE__SQL_ALCHEMY_CONN``(API Server/Scheduler/DFP/Triggerer 필요, Workers 불필요), ``AIRFLOW__SECRETS__BACKEND_KWARGS``(Scheduler/DFP/Triggerer, non-worker 모드), ``AIRFLOW__WORKERS__SECRETS_BACKEND_KWARGS``(Workers 전용)가 있다. Provider별 민감 변수(celery broker URL, keycloak client secret, opensearch 자격증명 등)도 해당 기능이 활성화된 컴포넌트에만 설정해야 한다. 참고로 ``AIRFLOW__API_AUTH__JWT_PRIVATE_KEY_PATH``는 시크릿 '값' 자체가 아니라 파일 경로이기 때문에 config.yml에서 sensitive로 표시되지 않지만, 그 경로가 가리키는 파일에 대한 접근은 토큰을 생성하는 Scheduler와 검증하는 API Server로 제한해야 한다.
핵심 포인트
- prctl(PR_SET_DUMPABLE, 0)은 supervisor가 태스크 프로세스를 fork하기 전에 호출하며 자식에 상속되어 /proc 경유 자격증명 절취와 ptrace attach를 막는다
- 설정 파일은 동일 Unix 사용자의 어떤 프로세스든 읽을 수 있어 환경 변수보다 근본적으로 덜 안전하다
- Worker는 최소 권한(Fernet 키, 워커 전용 시크릿 백엔드, 로그 핸들러 kwargs)만 필요하고, API Server는 DB 연결·JWT 서명 키·Fernet 키를 모두 필요로 하는 유일한 컴포넌트다
- jwt_private_key_path는 값 자체가 아니라 경로이므로 sensitive로 표시되지 않지만, 그 파일 접근은 Scheduler/API Server로 제한해야 한다
비대칭 키 JWT 서명, 네트워크 격리, 향후 계획
비대칭 키(``[api_auth] jwt_private_key_path``와 JWKS 엔드포인트)를 사용하는 것이 대칭 키보다 더 안전하다: 서명에 쓰이는 개인 키는 Scheduler/Executor로 제한할 수 있고, API Server는 검증을 위해 (JWKS를 통한) 공개 키만 있으면 되며, 워커는 설령 JWKS 엔드포인트에 접근할 수 있더라도 개인 키가 없으므로 토큰을 위조할 수 없다.
네트워크 정책, VPC 등으로 어떤 컴포넌트가 서로 통신할 수 있는지 제한하는 것도 중요하다 - 예를 들어 워커는 Execution API 엔드포인트에만 도달할 수 있어야 하며, 메타데이터 DB나 내부 서비스에 직접 도달할 수 없어야 한다. Unix 사용자 레벨 격리가 구현되어 있다면, Dag File Processor와 Triggerer의 자식 프로세스도 이상적으로는 메타데이터 DB에 대한 네트워크 접근이 없어야 한다.
향후 Airflow는 두 가지 방향으로 이 한계를 해결할 계획이다: 전략적(장기) 접근은 Dag File Processor와 Triggerer가 오늘날 워커가 Execution API를 쓰는 것처럼 API Server를 통해서만 메타데이터 DB와 통신하도록 바꾸는 것으로, 이는 이 컴포넌트들이 애초에 DB 자격증명을 가질 필요를 없애 배포 수준 조치가 아닌 설계 자체로 보안을 확보한다. 전술적(단기) 접근은 Dag File Processor/Triggerer 자식 프로세스에 대한 네이티브 Unix 사용자 임퍼스네이션 지원으로, Dag Author 코드가 부모의 자격증명이나 DB에 접근할 수 없는 별도의 저권한 사용자로 실행되게 하는 것이다.
핵심 포인트
- 비대칭 키 JWT는 개인 키를 Scheduler/Executor로 제한하고 API Server는 공개 키(JWKS)만 필요로 해, 워커가 JWKS에 접근해도 토큰을 위조할 수 없다
- 네트워크 정책으로 워커는 Execution API에만 도달하게 하고 메타데이터 DB나 내부 서비스에는 직접 도달하지 못하게 해야 한다
- 장기적으로는 DFP/Triggerer도 API Server 경유로 DB와 통신하게 바꿔 애초에 DB 자격증명 필요성을 없애는 것이 목표다
- 단기적으로는 DFP/Triggerer 자식 프로세스에 대한 Unix 사용자 임퍼스네이션 지원이 계획되어 있다