Workload

Workload (워크로드)

이 문서는 Airflow에서 워크로드를 안전하게 보호하도록 구성하는 방법을 설명해요. Task 실행 시 Unix 사용자로 가장(impersonation)하는 기능과, 워크로드 격리(isolation)의 현재 상태 및 한계를 다룹니다.

출처: 문서

본문

이 문서에서는 Airflow를 구성해 워크로드를 안전하게 보호하는 방법을 설명해요.

가장 (Impersonation)

Airflow는 Task의 run_as_user 파라미터(사용자 이름을 받음)에 따라 Task 인스턴스를 실행할 때 Unix 사용자로 가장하는 기능이 있어요.

참고: 가장이 동작하려면 하위 태스크가 sudo -u로 실행되고 파일 권한이 변경되므로 Airflow에 sudo가 필요해요. 또한 해당 Unix 사용자가 워커에 존재해야 해요. Airflow가 airflow 사용자로 실행 중이라고 가정할 때, 이를 달성하기 위한 간단한 sudoers 파일 항목은 다음과 같아요. 즉 Airflow 사용자는 root 사용자처럼 신뢰받고 취급되어야 한다는 뜻이에요.

airflow ALL=(ALL) NOPASSWD: ALL

가장을 사용하는 하위 태스크는 여전히 같은 폴더에 로그를 남기지만, 로그 파일의 권한이 해당 Unix 사용자만 쓸 수 있도록 변경돼요.

기본 가장 (Default Impersonation)

가장을 사용하지 않는 Task가 sudo 권한으로 실행되는 것을 방지하려면, run_as_user가 설정되지 않았을 때 기본으로 가장할 사용자를 설정하는 core:default_impersonation config를 지정할 수 있어요.

[core]
default_impersonation = airflow

가장이 다루지 않는 것

가장은 Task **실행(execution)**에 적용돼요. DAG 파일 **파싱(parsing)**에는 적용되지 않아요.

run_as_user는 DAG 또는 Task에 설정할 수 있으므로 default_impersonation을 덮어써요. Airflow는 DAG 파일을 파싱할 때까지 어떤 사용자로 전환해야 하는지 알 수 없으며, DAG 파일 파싱은 모듈 수준 코드를 실행해요. 따라서 그 코드는 어떤 sudo -u가 발생하기 전에 워커 자신의 Unix 사용자로 실행돼요. 파일은 전환 후 두 번째로 가장된 사용자로서 파싱돼요.

run_as_userdefault_impersonation은 Task가 한번 실행되면 무엇을 하는지 제약해요. 둘 다 DAG 파일 자체를 격리하지 않으며, 설정을 워커가 파싱 전에 읽을 수 있는 곳으로 옮기지 않는 한 그렇게 만들 수도 없어요. 모듈 수준 DAG 코드도 격리해야 한다면, 공유 워커 안에서 가상에 의존하기보다 워커를 격리하세요 — 예를 들어 신뢰할 수 없는 DAG 작성자의 워크로드를 별도 워커에서 실행하는 식으로 말이죠.

이것이 전반적인 신뢰 경계에 어떻게 맞는지는 Airflow 보안 모델을 참고하세요.

워크로드 격리와 현재 한계

이 섹션은 Apache Airflow의 워크로드 격리 현재 상태를 설명해요. 마련된 보호 조치, 알려진 한계, 계획된 개선 사항을 포함해요.

전체 보안 모델과 배포 강화 지침은 Airflow 보안 모델을 참고하세요. 워커와 내부 컴포넌트가 사용하는 JWT 인증 흐름에 대한 자세한 내용은 JWT 토큰 인증을 참고하세요.

워커 프로세스 메모리 보호 (Linux)

Linux에서 supervisor 프로세스는 Task 프로세스를 포크하기 전에 supervise_task() 시작 시 prctl(PR_SET_DUMPABLE, 0)을 호출해요. 이 플래그는 포크된 자식에게 상속돼요. 프로세스를 non-dumpable로 표시하면 같은 UID의 형제 프로세스가 /proc/<pid>/mem, /proc/<pid>/environ, /proc/<pid>/maps를 읽지 못하게 하고, ptrace(PTRACE_ATTACH)도 차단해요. 각 supervisor가 메모리에 고유한 JWT 토큰을 보관하므로 이는 매우 중요해요 — 이 보호가 없다면 같은 Unix 사용자로 실행되는 악성 Task 프로세스가 형제 supervisor 프로세스의 토큰을 훔칠 수 있어요.

이 보호는 민감한 설정을 구성 파일보다 환경 변수로 전달하는 것이 더 안전한 이유 중 하나예요: 환경 변수는 프로세스 자신(과 root)만 읽을 수 있는 반면, 디스크의 구성 파일은 같은 사용자로 실행되는 파일시스템 접근 권한이 있는 모든 프로세스가 읽을 수 있기 때문이에요.

Note

이 보호는 Linux 전용이에요. Linux가 아닌 플랫폼에서는 _make_process_nondumpable() 호출이 no-op이에요. Linux가 아닌 플랫폼에서 Airflow를 실행하는 배포 관리자(Deployment Managers)는 대체 격리 조치를 구현해야 해요.

워크로드 간 격리 부재 (No cross-workload isolation)

모든 워커 워크로드는 같은 서명 키, audience, issuer를 공유하는 토큰으로 같은 Execution API에 인증해요. ti:self 스코프 적용이 워커가 다른 task instance의 특정 엔드포인트(예: heartbeat, 상태 전이)에 접근하는 것을 방지하지만, 토큰은 개별 Task에 스코프되지 않은 connection, variable, XCom 같은 공유 리소스에 대한 접근을 부여해요.

Execution API의 팀 수준 격리 부재 (실험적 multi-team 기능)

실험적 multi-team 기능([core] multi_team)은 팀 간 UI 수준 및 REST API 수준 RBAC 격리를 제공하지만, 아직 Task 수준 격리를 보장하지 않아요. Execution API 수준에서는 팀 기반 접근 경계가 강제되지 않아요. 한 팀의 Task는 다른 팀의 Task와 같은 connection, variable, XCom에 접근할 수 있어요. 모든 워크로드는 팀 할당과 관계없이 같은 JWT 서명 키와 audience를 공유해요.

배포 수준에서 추가 강화 조치를 구현하지 않은 배포에서는, 한 팀의 Task가 다른 팀에 속한 리소스에 접근할 수 있어요(Airflow 보안 모델 참고). 팀 간 분리를 보장하도록 구성하려면 배포 관리자가 구성과 배포 보안에 대한 깊은 이해가 필요해요. Task 수준 팀 격리는 향후 Airflow 버전에서 개선될 예정이에요.

Dag File Processor와 Triggerer가 잠재적으로 JWT를 우회하고 데이터베이스에 접근

JWT 토큰 인증에 설명된 대로, 기본 배포는 모든 팀에 대해 단일 Dag File Processor와 단일 Triggerer를 실행해요. 둘 다 프로세스 내 전송(in-process transport)을 통해 JWT 인증을 잠재적으로 우회해요. multi-team 격리를 위해 배포 관리자는 팀별로 별도 인스턴스를 실행해야 하지만, 그렇더라도 각 인스턴스가 잠재적으로 데이터베이스에 직접 접근할 수 있어요. 이러한 컴포넌트에서 코드가 실행되는 DAG 작성자는 — 배포 관리자가 각 인스턴스에 제공되는 데이터베이스 자격 증명과 구성을 제한하지 않는 한 — 다른 팀에 속한 데이터나 JWT 서명 키 구성을 포함해 데이터베이스에 직접 접근할 수 있어요.

계획된 개선 사항 (Planned improvements)

향후 Airflow 버전은 다음으로 이러한 한계를 해결할 예정이에요:

  • 특정 리소스(connection, variable)와 팀에 묶인 더 세분화된 토큰 스코프.
  • Execution API에서 팀 기반 격리 강제.
  • 팀별 Dag File Processor 및 Triggerer 인스턴스에 대한 내장 지원.
  • Dag File Processor와 Triggerer에서 사용자 제출 코드의 샌드박싱 개선.
  • multi-team 기능에 대한 완전한 Task 수준 격리.

더 알아보기 (Learn more)