클라우드

GitHub Actions와 OIDC, 액세스 키 없이 AWS에 배포하는 원리

GitHub Actions에서 OIDC를 쓰면 저장소에 AWS 액세스 키를 두지 않고도 배포할 수 있다.
대신 AWS가 어떤 저장소의 어떤 작업을 믿을지 역할의 신뢰 조건에 적어야 하고, 옛 키는 따로 찾아 지워야 한다.

이 글의 목차액세스 키는 지울 때까지 유효하다5
  1. 액세스 키는 지울 때까지 유효하다
  2. 저장해 둔 키 대신 그때그때 받는 토큰
  3. 누구를 믿을지는 신뢰 정책에 적는다
  4. 옛 키는 저절로 사라지지 않는다
  5. 옮긴 뒤에 마무리하는 일

GitHub Actions는 저장소에 적어 둔 워크플로에 따라 빌드와 배포 같은 작업을 자동으로 돌려 주는 GitHub의 기능이다.
이것으로 AWS에 배포하는 튜토리얼은 대개 이렇게 시작한다.

AWS에서 IAM 사용자를 만들고, 액세스 키를 발급받고, 그 값을 저장소의 비밀 값(Secrets) 칸에 넣는다.

이렇게 해도 배포는 문제없이 돌아간다.
그런데 AWS는 액세스 키 같은 장기 자격 증명 대신 IAM 역할 같은 임시 자격 증명을 쓰라고 권한다.
그 이유는 액세스 키라는 자격 증명의 성질에 있다.

액세스 키는 지울 때까지 유효하다

IAM 사용자는 AWS 계정 안에 만드는 신원이고, 액세스 키는 그 사용자에게 붙는 장기 자격 증명이다.
액세스 키 ID와 비밀 액세스 키 두 부분으로 이뤄지고, 둘을 함께 써서 AWS API 요청에 서명한다.

장기라는 말 그대로 정해진 만료가 없다.
비활성화하거나 지우기 전까지 계속 유효하다.
그래서 액세스 키를 남에게 넘기면 계정에 대한 영구적인 접근을 내줄 수도 있다.

보관 기간에 따른 키 통제 범위 만료 없는 키는 복사본이 남은 모든 자리에서 직접 폐기하기 전까지 계속 유효하다. 개념 도해 보관 기간에 따른 키 통제 범위 키 복사 경로 ① 키 발급 ② 비밀 값 저장 ③ 복사 자동 만료 없음 실행 환경 다른 도구 개인 기록 시간에 따른 통제 상태 유효 복사 범위 시간 관리 경계 발급 저장 첫 복사 추가 복사 복사본 파악 불가 폐기 전까지 유효 만료 없는 키는 복사본이 남은 모든 자리에서 직접 폐기하기 전까지 계속 유효하다. SOSHIN · DEV NOTES
만료 없는 액세스 키는 복사될수록 어디에 몇 개가 남았는지 파악하기 어려워진다.

문제는 복사본이다.
저장소의 비밀 값에 넣은 키는 배포 작업이 돌 때마다 실행 환경에 풀린다.
다른 도구에 옮겨 적기도 하고, 시험해 보려고 개인 컴퓨터에 두기도 한다.

복사본이 어디에 몇 개 있는지 셀 수 없게 되면, 그중 하나가 새어 나가도 알아채기 어렵다.

키를 주기적으로 바꾸는 방법이 있기는 하다.
새 키를 만들어 쓰는 곳을 모두 바꾸고, 옛 키가 더 쓰이지 않는지 확인한 뒤 비활성화하고 지운다.
키가 쓰이는 곳을 다 알아야 할 수 있는 일이다.

저장해 둔 키 대신 그때그때 받는 토큰

OIDC(OpenID Connect)⁠는 한 서비스가 서명해서 발급한 신원 정보를 다른 서비스가 검증하도록 정한 표준이다.
신원 정보를 담은 토큰은 JWT라는 형식으로 오간다.

GitHub Actions도 이 표준을 지원하고, AWS를 비롯한 클라우드 업체의 공식 로그인 액션이 이 방식으로 자격 증명을 받아 온다.

흐름은 이렇다.
워크플로의 작업(job)⁠이 돌 때마다 GitHub의 OIDC 공급자가 그 작업만을 위한 토큰을 새로 만든다.
토큰에는 어느 저장소의 어느 브랜치에서, 어떤 워크플로로 돌았는지 같은 정보가 클레임이라는 항목으로 적혀 있다.

작업은 이 토큰을 AWS에 내민다.
AWS는 GitHub의 토큰 발급 주소를 신뢰할 공급자로 미리 등록해 두고, 그 공급자가 공개한 키로 토큰의 서명을 확인한다.

서명이 맞고 토큰의 내용이 미리 적어 둔 조건과도 맞으면, AWS의 보안 토큰 서비스(STS)⁠가 그 작업에 IAM 역할의 임시 자격 증명을 내준다.
역할은 장기 자격 증명이 붙어 있지 않은 신원이라, 맡을 때마다 임시 자격 증명을 받는다.

임시 자격 증명은 몇 분에서 몇 시간 사이로 정한 시간이 지나면 만료되고, 그 뒤로 AWS는 이 자격 증명으로 온 요청을 받아 주지 않는다.
새어 나가더라도 쓸 수 있는 시간에 끝이 있다.

새어 나간 자격 증명은 언제까지 쓰일까

배포 작업 하나에서 자격 증명 두 개가 함께 새어 나갔다고 가정한다. 하나는 저장소 비밀 값에 넣어 둔 액세스 키이고, 다른 하나는 그 작업이 OIDC로 받은 임시 자격 증명이다.

저장소 비밀 값의 액세스 키

요청을 받아 줌

만료 시각 없음

이 작업이 받은 임시 자격 증명

요청을 받아 줌

발급 1시간 뒤 만료

임시 자격 증명은 정한 시간이 지나면 만료되어, 새어 나간 복사본으로 보낸 요청도 그 뒤로는 거부된다. 액세스 키는 만료 시각이 없어 30일이 지나도 요청이 받아들여지고, 비활성화한 뒤에야 거부된다.

임시 자격 증명의 기간은 STS 기본값인 1시간으로 두었다. 역할의 세션을 만료 전에 취소하는 방법과 권한 정책에 따른 거부는 다루지 않는다.

누구를 믿을지는 신뢰 정책에 적는다

역할에는 정책이 두 종류 붙는다.
그 역할로 무엇을 할 수 있는지 정하는 권한 정책, 그리고 누가 그 역할을 맡을 수 있는지 정하는 신뢰 정책이다.

OIDC를 쓸 때 공들여 적어야 하는 것은 신뢰 정책의 조건이다.
GitHub가 발급하는 수많은 토큰 가운데 어떤 것을 받아 줄지 여기서 정한다.

GitHub의 AWS용 OIDC 설정 문서는 신뢰하지 않는 저장소가 클라우드의 접근 토큰을 받아 가지 못하도록 조건을 적어도 하나는 반드시 정하라고 한다.
보통 저장소와 브랜치, 또는 배포 환경 이름을 조건으로 적는다.

이 조건은 토큰의 sub 항목과 대조된다.
sub⁠에는 어느 저장소의 어느 브랜치에서 돈 작업인지가 repo:OWNER/REPO:ref:refs/heads/main 같은 모양으로 적힌다.
OWNER는 저장소 소유자, REPO는 저장소 이름이다.

2026년 7월 15일 이후에 만든 저장소는 이 값의 소유자와 저장소 이름 뒤에 숫자 ID가 함께 붙는다.
지워진 이름을 다른 사람이 다시 쓰면 같은 값이 만들어질 수 있어서다.
신뢰 조건은 내 저장소가 쓰는 형식에 맞춰 적는다.

그런데 AWS 콘솔에서 GitHub용 역할을 만들 때 조직 이름은 꼭 적어야 하지만, 저장소와 브랜치 칸은 비워 두면 아무 값에나 맞는 와일드카드가 들어간다.

조직 이름만 적고 넘어가면 그 조직의 어느 저장소, 어느 브랜치에서 돈 작업이든 이 역할을 맡을 수 있다.
조직의 누군가 새로 만든 시험용 저장소의 워크플로도 마찬가지다.

신뢰 조건에 따른 자격 증명 발급 서명이 맞는 토큰이라도 신뢰 조건이 조직까지만 적혀 있으면, 같은 조직의 다른 저장소 작업도 임시 자격 증명을 받는다. 개념 도해 신뢰 조건에 따른 자격 증명 발급 토큰 교환 경로 ① 배포 작업 GitHub Actions ② 토큰 발급 GitHub OIDC 공급자 ③ 서명 · 조건 확인 AWS STS ④ 임시 자격 증명 만료 시각 있음 sub · 저장소와 브랜치 신뢰 정책 조건과 대조 신뢰 조건별 발급 결과 내 저장소 · main 브랜치 같은 조직의 시험 저장소 다른 조직의 저장소 조직만 적은 조건 저장소 · 브랜치 칸 비움 발급 의도 밖 발급 거부 저장소 · 브랜치 조건 배포할 저장소와 브랜치 지정 발급 거부 거부 서명이 맞는 토큰이라도 신뢰 조건이 조직까지만 적혀 있으면, 같은 조직의 다른 저장소 작업도 임시 자격 증명을 받는다. SOSHIN · DEV NOTES
STS는 토큰의 sub 값을 신뢰 정책의 조건과 대조한다. 조건이 넓으면 서명이 맞는 다른 저장소의 토큰도 통과한다.

AWS의 OIDC 역할 생성 문서도 조건에 조직이나 저장소를 특정하지 않으면, 통제 밖에 있는 조직이나 저장소의 GitHub Actions까지 역할을 맡을 수 있다고 경고한다.

IAM이 저장 단계에서 막아 주는 것은 조건이 아예 없거나 값이 와일드카드 하나뿐인 경우다.
조직 전체를 허용하는 조건은 그대로 저장된다.

옛 키는 저절로 사라지지 않는다

전환 단계에 따른 유효 자격 증명 경로 새 경로를 검증한 뒤 옛 키를 모두 폐기해야 기존 접근 경로가 닫힌다. 개념 도해 전환 단계에 따른 유효 자격 증명 경로 자격 증명 선택 경로 ① 배포 시작 ② 자격 증명 검색 옛 키 없음 옛 키 남음 ③ OIDC 교환 단기 자격 증명 같은 작업 ③ 고정 키 선택 계속 유효 같은 작업 전환 단계별 열린 경로 유효 경로 전환 단계 목표 · 단일 경로 옛 키 경로 전환 전 OIDC 경로 옛 키 경로 OIDC 적용 OIDC 경로 옛 키 폐기 옛 경로 열림 새 경로를 검증한 뒤 옛 키를 모두 폐기해야 기존 접근 경로가 닫힌다. SOSHIN · DEV NOTES
OIDC 경로를 여는 일과 옛 키 경로를 닫는 일은 별개다. 옛 키를 폐기하기 전까지는 두 경로가 함께 열려 있다.

OIDC로 옮기고 나면 배포가 잘 돈다.
잘 도니까 다 끝난 것 같지만 옛 액세스 키는 그대로 있다.
저장소의 비밀 값에, 다른 도구의 설정에, 누군가의 컴퓨터에 남아 있을 수 있다.

옛 키가 워크플로의 환경 변수로 계속 들어가고 있다면 배포 도구가 OIDC로 받은 자격 증명 대신 그 키를 쓸 수도 있다.
AWS SDK는 자격 증명을 정해진 순서로 찾다가 처음 찾은 것을 쓰기 때문이다.

그래서 배포가 성공했다는 것만으로는 어느 자격 증명이 쓰였는지 알 수 없다.
확인할 곳은 AWS 계정의 API 호출을 기록하는 CloudTrail⁠이다.

CloudTrail 기록의 사용자 정보를 보면 IAM 사용자의 키로 온 요청인지, 역할을 맡아 받은 임시 자격 증명으로 온 요청인지 구별된다.

옮긴 뒤에 마무리하는 일

배포 역할은 배포 대상마다 따로 만들고, 신뢰 조건에는 저장소와 브랜치까지 적는다.
운영 배포에 GitHub의 배포 환경을 쓴다면 그 환경에 보호 규칙을 걸어 두라고 AWS도 권한다.

권한 정책에는 배포에 필요한 동작만 넣는다.
토큰 교환에 성공한 작업이 AWS에서 할 수 있는 일은 이 정책이 정한다.

옛 키는 확인하고 지운다.
키의 마지막 사용 정보로는 쓰이지 않는 것 같아도 곧바로 지우지 않고, 먼저 비활성화한다.
며칠 지켜봐서 문제가 없으면 그때 지운다.

소신을 상징하는 까마귀 목판화 일러스트
작성자소신 · Soshin

웹과 서버를 만들고, 개발하며 배운 것들을 글로 남깁니다.

좌우로 움직여 보세요