GitHub Actions 실행 보호 GA: 누가 어떤 이벤트로 워크플로를 실행할지 잠근다

GitHub Actions는 코드를 검사하고, 사이트를 배포하고, 패키지를 공개하는 자동화 엔진입니다. 편리함의 반대편에는 하나의 질문이 있습니다.

저장소에 코드를 쓸 수 있는 사람과, 권한이 있는 워크플로를 실행할 수 있는 사람을 반드시 같게 봐야 할까?

GitHub는 2026년 9월 17일 Workflow execution protections for GitHub Actions를 정식 출시했습니다. 이제 GitHub Enterprise·조직·저장소 수준에서 워크플로를 실행할 수 있는 주체(actor)와 이벤트(event)를 허용목록으로 제한할 수 있습니다. 공개 프리뷰에서 제공하던 기능에 더해 워크플로 파일별 적용 범위, 정책 인사이트, REST API가 추가됐습니다.

이번 변화의 핵심은 YAML 파일 하나를 잘 작성하는 데서 끝나지 않습니다. 누가 무엇을 실행할 수 있는지라는 제어면(control plane)을 저장소 밖의 정책으로 분리해, 잘못 작성된 워크플로 한 개가 전체 공급망의 경계가 되는 상황을 줄이는 데 의미가 있습니다.

이 글은 GitHub의 2026년 9월 17일 출시 공지와 Actions 정책·보안 문서를 교차 확인해 작성했습니다. 조직 요금제와 저장소 가시성에 따른 제공 범위, 정책 UI와 REST API는 실제 계정에서 최신 문서를 다시 확인해야 합니다.


1. 정식 출시에서 달라진 점

실행 보호는 워크플로가 실행되기 전에 두 가지를 확인합니다.

정책 축 확인하는 질문 예시
Actor 규칙 누가 실행을 시작했는가? 특정 팀, 저장소 역할, GitHub App, Dependabot
Event 규칙 어떤 사건이 실행을 요청했는가? push, pull_request, pull_request_target, workflow_dispatch

정책을 적용하면 “쓰기 권한이 있으니 모든 자동화를 실행할 수 있다”는 기본값을 세분화할 수 있습니다. GitHub 문서에 따르면 기본적으로 저장소에 쓰기 권한이 있는 사용자는 워크플로를 실행할 수 있지만, actor 규칙으로 코드 기여 권한과 CI 실행 권한을 분리할 수 있습니다. 이벤트 규칙으로는 수동 실행이나 포크 기반 풀 리퀘스트처럼 위험도가 다른 진입점을 별도로 다룰 수 있습니다.

GA에서 특히 실무적인 변화는 세 가지입니다.

  1. 워크플로 파일 타기팅
    저장소 전체가 아니라 특정 경로의 파일에만 정책을 적용합니다. 예를 들어 배포용 deploy.yml은 릴리스 팀만 실행하게 하고, 읽기 전용 테스트는 더 넓게 열어 둘 수 있습니다.

  2. 정책 인사이트
    평가 모드에서 실제 실행을 막기 전에 어떤 실행이 제한 대상인지 확인할 수 있습니다. 정책을 바로 강제해 기존 배포를 깨뜨리는 대신, 관측하고 조정한 뒤 시행할 수 있습니다. 평가 모드는 GitHub Enterprise Cloud에서 제공되는 기능이므로 계정 유형을 확인해야 합니다.

  3. REST API
    엔터프라이즈·조직·저장소 범위의 정책을 코드와 거버넌스 도구로 관리할 수 있습니다. 수백 개 저장소에 같은 규칙을 적용하거나, 보안 검토 이력과 정책 변경을 함께 관리할 때 의미가 큽니다.


2. 왜 “실행할 수 있는 사람”이 보안 경계인가

워크플로 파일은 저장소 안에 있지만 실행 결과는 저장소 밖으로 영향을 줍니다. 작업은 토큰, 시크릿, 패키지 레지스트리, 배포 환경, 자체 호스팅 러너와 연결될 수 있습니다. 공격자가 워크플로를 실행시키거나 실행 가능한 경로를 오용하면 단순한 테스트 실패가 아니라 다음 문제가 생깁니다.

  • GITHUB_TOKEN으로 브랜치·릴리스·이슈를 변경
  • 클라우드 자격 증명이나 패키지 레지스트리 토큰 유출
  • 자체 호스팅 러너에 악성 파일을 남기거나 내부망으로 이동
  • 캐시·아티팩트·배포 결과를 오염
  • 자동 게시·배포 작업을 이용해 신뢰받는 산출물에 악성 코드를 섞음

특히 pull_request_target은 주의해야 합니다. GitHub 문서에 따르면 이 이벤트는 기본 저장소의 GITHUB_TOKEN과 저장소·조직 시크릿에 접근할 수 있는 높은 신뢰 컨텍스트에서 실행됩니다. 워크플로가 포크의 코드를 체크아웃한 뒤 빌드나 테스트로 실행하면, 공격자가 만든 Makefile, 의존성, 설정 파일이 그 권한으로 동작하는 이른바 pwn request가 될 수 있습니다.

중요한 구분은 “포크 풀 리퀘스트를 받는 것”과 “포크 코드를 비밀과 함께 실행하는 것”이 다르다는 점입니다. pull_request는 포크 실행에서 토큰과 시크릿을 제한하는 기본 보호가 있지만, pull_request_target은 자동화에 필요한 특권을 제공하는 대신 워크플로 설계자가 신뢰 경계를 직접 지켜야 합니다.


3. 공개 저장소에 적용되는 새로운 기본값

GitHub는 정식 출시와 함께 공개 저장소의 pull_request_target에 대한 기본 이벤트 정책도 예고했습니다.

  • 이미 적용 가능한 이벤트 정책이 없는 공개 저장소를 대상으로 합니다.
  • 현재는 평가 모드라 실행은 계속되지만, 정책 인사이트에서 향후 차단 대상을 볼 수 있습니다.
  • GitHub가 안내한 시행일은 2026년 11월 2일입니다.
  • 비공개·내부 저장소에는 이 기본 정책이 적용되지 않습니다.
  • pull_request_target이 반드시 필요한 저장소는 이벤트 정책에서 명시적으로 허용할 수 있습니다.

따라서 “11월 2일에 갑자기 CI가 고장 난다”기보다, 지금부터 평가 결과를 읽고 두 가지 중 하나를 선택해야 합니다.

  1. 시크릿이 필요하지 않은 일반 검증은 pull_request로 옮긴다.
  2. 특권 이벤트가 정말 필요한 경우에만 해당 워크플로를 파일 단위로 허용하고, 포크 코드를 실행하지 않는지 다시 검토한다.

정책을 허용한다고 해서 안전해지는 것이 아닙니다. 허용은 예외를 문서화하는 행위이며, 위험한 체크아웃과 명령 실행을 없애는 설계 검토가 뒤따라야 합니다.


4. 이 블로그 저장소에 대입해 보기

현재 이 사이트의 .github/workflows/indexnow.yml은 main에 게시 관련 파일이 반영될 때 Jekyll을 빌드하고, 생성된 사이트맵 URL을 IndexNow에 알립니다. 워크플로에는 permissions: contents: read가 선언되어 있어, 게시 알림 작업에 필요한 최소한의 콘텐츠 읽기 권한만 요청합니다.

이 구조에서 실행 보호 정책을 검토할 때는 다음처럼 생각할 수 있습니다.

점검 대상 이 저장소에서의 질문
실행 주체 게시 커밋을 만드는 관리자·자동화 계정만 실행자로 허용할 것인가?
이벤트 push와 필요한 workflow_dispatch만 허용할 것인가?
파일 범위 게시·배포 워크플로만 별도 정책으로 더 강하게 보호할 것인가?
권한 사이트 빌드와 IndexNow 알림에 쓰기 토큰이 정말 필요한가?
실패 대응 정책으로 차단된 실행을 누가 확인하고 재실행할 것인가?

자동 게시를 도입할 때는 글을 생성하는 워크플로와 배포·알림 워크플로를 한 덩어리로 만들지 않는 편이 좋습니다. 생성 작업은 외부 자료와 모델 응답을 다루고, 배포 작업은 main에 반영된 검토 결과만 사용하도록 분리하면 각각의 actor·event·권한을 좁힐 수 있습니다.

이 글을 추가하는 현재 커밋처럼 신뢰된 main 반영이 push를 일으키는 구조라면, 정책을 바꾸기 전에 “누가 이 브랜치에 쓰는가”와 “어떤 자동화가 실제로 실행되는가”를 로그로 확인해야 합니다. 정책을 적용하는 일 자체가 워크플로 트리거를 바꾸는 것은 아니며, 기존 자동화의 실행 주체와 이벤트를 먼저 목록화하는 것이 안전합니다.


5. 단계별 도입 절차

1단계: 트리거와 권한을 목록화한다

모든 .github/workflows/*.yml에서 on 아래의 이벤트를 추출하고, 각 작업의 permissions, 시크릿, 환경 보호, 러너 유형을 기록합니다. 특히 다음 이벤트를 별도로 표시합니다.

  • workflow_dispatch: 수동 실행 입력값과 실행자를 확인
  • pull_request_target: 특권 컨텍스트인지 확인
  • workflow_run: 앞선 실행의 아티팩트를 신뢰하는지 확인
  • push와 배포 브랜치: 누가 커밋을 만들 수 있는지 확인

2단계: 평가 모드에서 오탐을 찾는다

정책 인사이트에서 “실제로 차단될 실행”과 “차단될 뻔한 실행”을 구분합니다. 배포·릴리스 담당자가 아닌 사람이 실행하는 테스트까지 막히는지, Dependabot·GitHub App 같은 봇이 누락되는지 확인합니다. 이 단계에서는 편의보다 누락 없는 관측이 목표입니다.

3단계: 위험도가 높은 파일부터 범위를 좁힌다

프로덕션 배포, 패키지 공개, 클라우드 인프라 변경을 수행하는 파일은 actor와 event를 가장 좁게 잡습니다. 일반적인 린트·문서 검사처럼 시크릿과 쓰기 토큰이 필요 없는 작업은 별도 정책이나 읽기 전용 권한으로 분리할 수 있습니다.

4단계: 정책과 YAML을 함께 리뷰한다

실행 보호는 중앙 정책이지만, 워크플로 파일을 안전하게 만드는 작업을 대신하지 않습니다. GitHub는 GITHUB_TOKEN에 필요한 최소 권한만 부여하고, 필요하지 않으면 시크릿을 전달하지 말 것을 권고합니다. 외부 액션은 커밋 SHA 고정, 환경 승인, 브랜치 보호, 아티팩트 검증과 함께 검토해야 합니다.

5단계: 강제 후 인사이트를 운영 지표로 만든다

정책으로 차단된 실행 수, 허용 예외 수, 실패한 배포 수를 보안·플랫폼 팀의 운영 지표로 기록합니다. 예외를 무기한 허용하지 말고 담당자와 만료일을 붙여야 합니다. 정책이 너무 넓어 모든 실행을 통과시키거나 너무 좁아 개발자가 우회 계정을 만드는 상황 모두 실패 신호입니다.


6. 실행 보호만으로 해결되지 않는 한계

정책은 실행 전 관문입니다. 통과한 워크플로 안에서 일어나는 모든 보안 문제를 해결하지는 않습니다.

첫째, 신뢰된 actor가 악성 변경을 커밋하면 정책은 그대로 실행을 허용할 수 있습니다. .github/workflows에 CODEOWNERS 리뷰와 브랜치 보호를 두고, 배포 환경에는 승인 단계를 추가해야 합니다.

둘째, 허용된 이벤트에서도 토큰 권한이 넓으면 피해 범위가 커집니다. GitHub 문서의 권고처럼 기본은 콘텐츠 읽기 중심으로 두고, 쓰기가 필요한 job에만 세분화된 permissions를 부여해야 합니다.

셋째, 서드파티 액션과 의존성의 무결성은 별도 문제입니다. 실행자를 제한해도 태그가 이동한 액션이나 오염된 아티팩트를 가져오면 공급망 위험이 남습니다. 액션을 신뢰할 수 있는 커밋 SHA에 고정하고, 의존성·아티팩트의 출처와 해시를 검증해야 합니다.

넷째, 자체 호스팅 러너는 실행 보호와 독립적으로 격리해야 합니다. 러너에 장기 자격 증명을 남기지 않고, 작업 사이에 재사용되지 않는 환경과 내부망 차단을 검토해야 합니다.

정리하면 실행 보호는 다음 방어층 중 하나입니다.

코드 리뷰·브랜치 보호
    ↓
실행 주체·이벤트 허용목록
    ↓
최소 권한 토큰·시크릿 분리
    ↓
액션·의존성·아티팩트 무결성 검증
    ↓
격리된 러너·환경 승인·감사 로그

한 층이 다른 층을 대체하지 않습니다.


7. 교육과 실무에서 얻는 교훈

이번 기능은 DevOps 수업에서 “워크플로가 실행된다”를 넘어 실행 권한도 설계 대상이라는 사실을 실습하기 좋습니다.

실습 1: 같은 YAML, 다른 정책

동일한 build.yml에 push와 workflow_dispatch를 두고, actor·event 허용목록을 바꿔 실행 결과가 어떻게 달라지는지 비교합니다. 정책이 코드를 수정하지 않고도 실행 경계를 바꾼다는 점을 확인할 수 있습니다.

실습 2: pwn request 재현 대신 안전한 정적 분석

실제 시크릿을 사용하지 않고, pull_request_target에서 포크 ref를 체크아웃하는 위험한 패턴을 정적 검색합니다. “코드를 실행하지 않고 파일만 검사하기”, “시크릿이 필요 없으면 pull_request 사용하기” 같은 대안을 설계합니다.

실습 3: 최소 권한 표 만들기

각 job이 필요한 API 범위를 표로 만들고 contents: read, pull-requests: write, id-token: write처럼 요구 권한을 최소화합니다. 기능이 동작한다는 이유만으로 write-all을 주지 않는 습관을 익힙니다.

학생과 실무자 모두에게 중요한 결론은 “보안은 마지막 단계의 스캐너”가 아니라는 점입니다. 어떤 커밋이 어떤 이벤트로 어떤 권한을 가진 실행을 시작하는지 모델링하는 순간부터 공급망 보안이 시작됩니다.


결론

GitHub Actions 실행 보호의 GA는 새로운 스캐너를 추가한 소식이 아니라, 워크플로 실행을 정책으로 통제하는 층을 정식 기능으로 끌어올린 변화입니다. actor와 event 허용목록, 워크플로 파일별 타기팅, 평가 인사이트, REST API를 조합하면 저장소마다 흩어진 예외를 조직의 규칙으로 관리할 수 있습니다.

가장 먼저 할 일은 모든 실행을 막는 것이 아닙니다. pull_request_target과 workflow_dispatch처럼 영향이 큰 이벤트를 찾아 평가 모드에서 실제 사용 현황을 확인하고, 배포·릴리스 워크플로를 가장 좁은 actor와 권한으로 옮기는 것입니다. 2026년 11월 2일 공개 저장소의 pull_request_target 기본 정책 시행 전에 이 검토를 끝내면, 보안을 강화하면서도 필요한 자동화는 유지할 수 있습니다.


참고 자료

GitHub Actions 정책과 기본값은 계정 유형·저장소 가시성·조직 설정에 따라 달라질 수 있습니다. 실제 적용 전에는 정책 인사이트, 최신 GitHub 문서, 조직의 브랜치·환경 보호 규칙을 함께 확인하세요.