slack

SSH에서 REST로: Slack EMR 데이터 파이프라인의 보안 주도 현대화 (새 탭에서 열림)

Slack은 700개가 넘는 EMR 데이터 파이프라인을 직접 SSH로 실행하던 구조에서 REST 기반 작업 제출 방식으로 전환했다. SSH는 보안 공격 표면, 키 관리, 장애 복구, 작업 관측성 측면에서 한계가 있었고 Spark on Kubernetes와 AWS 계정 분리 같은 현대화도 가로막았다. Slack은 YARN REST API와 YARN Distributed Shell을 활용해 8개 데이터 리전의 작업을 중단 없이 마이그레이션하고 SSH를 완전히 제거했다.

SSH 기반 파이프라인의 확산

  • 2017년경 Airflow가 EMR 마스터 노드에 SSH로 접속해 명령을 실행하는 방식으로 데이터 파이프라인을 구축했다.
  • 단순한 SSHOperator 패턴이 확산되면서 다음과 같은 작업까지 SSH로 실행됐다.
    • Spark 및 MapReduce 작업
    • AWS CLI 명령
    • 사용자 정의 Python 스크립트
  • 2024년에는 700개 이상의 운영 작업이 SSH 기반으로 실행되고 있었다.
  • 검색 인덱싱, 분석, 비즈니스 인텔리전스 등 핵심 데이터 처리도 이 구조에 의존했다.

SSH의 보안 및 운영상 문제

  • 보안 위험
    • 오케스트레이션 워커가 EMR 클러스터에 직접 SSH 접속해야 해 공격 표면이 커졌다.
    • SSH 키를 여러 워커에 배포하고 주기적으로 교체해야 했다.
    • 세밀한 감사 추적을 위해 여러 시스템의 로그를 상호 연관해야 했다.
    • 보안 그룹과 사용자 권한 설정이 복잡해졌다.
  • 운영 장애
    • 작업이 EMR 마스터 노드에서 직접 실행되어 리소스 경쟁이 발생했다.
    • Kubernetes Pod가 재시작되면 SSH 연결이 끊겨 작업이 실패했다.
    • 연결이 끊긴 뒤에도 작업이 계속 실행되는 ‘좀비 작업’이 남을 수 있었다.
    • 연결 단절 후 작업의 성공·실패 상태를 안정적으로 확인하기 어려웠다.
  • 인프라 현대화 차단
    • Spark on Kubernetes와 EMR on EKS 도입을 시작할 수 없었다.
    • 메인 AWS 계정의 EMR 클러스터를 자식 계정으로 이전하는 Whitecastle 프로젝트가 지연됐다.
    • 신뢰할 수 있는 작업 모니터링과 관측성을 구현하기 어려웠다.

REST 기반 작업 제출의 장점

  • SSH는 클라이언트와 서버 사이의 상태ful 연결을 유지해야 한다.
  • REST 방식에서는 작업의 생명주기를 서버가 관리한다.
    • POST: 작업을 제출하고 작업 ID를 받음
    • GET: 작업 ID로 실행·완료·실패 상태를 조회
    • DELETE: 필요할 때 작업을 취소
  • Airflow나 Kubernetes Pod가 재시작되어도 작업 자체는 서버에서 계속 실행될 수 있다.
  • 클라이언트가 작업 상태를 다시 조회할 수 있어 연결 단절에 강하다.
  • 작업 취소, 리소스 관리, 로그 확인 등도 실행 엔진의 표준 기능으로 처리할 수 있다.

YARN Distributed Shell을 활용한 해결책

  • Spark는 Livy REST API, Hive는 HiveServer2를 사용할 수 있어 상대적으로 이전이 쉬웠다.
  • 반면 MapReduce와 aws s3 sync, hadoop distcp 같은 300개 이상의 임의 CLI 작업은 바로 사용할 REST API가 없었다.
  • 검토한 대안은 다음과 같았다.
    • 원격 명령 실행용 커스텀 래퍼 서비스
    • Ansible이나 Salt 같은 원격 실행 프레임워크
    • YARN에 새로운 작업 유형을 직접 개발
  • 이러한 방법은 별도 보안 계층과 운영 인프라를 구축·유지해야 해 복잡도가 높았다.
  • YARN의 Distributed Shell은 임의의 셸 스크립트를 YARN 컨테이너에서 실행할 수 있도록 했다.
    • 기존 YARN REST API를 그대로 사용
    • YARN의 인증·인가 체계 활용
    • 별도 보안 서비스 불필요
    • 오픈소스 표준 기반
    • 컨테이너 리소스와 작업 생명주기 관리 지원

Distributed Shell의 실행 흐름

  • 실행할 셸 스크립트를 S3에 업로드한다.
    • 예: s3://bucket/command.sh
    • 스크립트는 aws s3 sync 같은 임의 명령을 포함할 수 있다.
  • YARN REST 요청에 Distributed Shell의 ApplicationMaster와 스크립트 위치를 지정한다.
  • YARN이 컨테이너를 할당하고 S3에서 스크립트를 내려받아 실행한다.
  • 실행 과정에서 YARN이 다음을 담당한다.
    • 메모리와 vCore 등 리소스 제한
    • 컨테이너 격리
    • 재시도와 장애 복구
    • 정상적인 작업 취소
    • YARN UI를 통한 로그 및 상태 확인

마이그레이션의 의미

  • YARN Distributed Shell을 통해 REST API가 없던 CLI·MapReduce 작업까지 동일한 실행 모델로 통합할 수 있었다.
  • 작업 제출과 실행을 SSH 연결에서 분리해 클라이언트 재시작과 네트워크 단절에 대한 안정성을 높였다.
  • 700개 이상의 작업을 8개 데이터 리전에 걸쳐 중단 없이 이전하면서 SSH 의존성을 제거했다.
  • 결과적으로 보안 강화뿐 아니라 Kubernetes 기반 실행 환경, AWS 계정 분리, 표준화된 모니터링으로 나아갈 기반을 마련했다.

실용적으로는 원격 서버에 직접 접속해 명령을 실행하기보다, 작업 ID·상태 조회·취소를 제공하는 서버 측 실행 모델을 사용하는 것이 바람직하다. 특히 기존 작업이 단순 CLI 스크립트라면 복잡한 신규 실행 서비스를 만들기 전에 YARN Distributed Shell처럼 기존 플랫폼의 표준 기능을 우선 검토할 수 있다.