0. Contents
1. Overview
층과 층 사이를 오가는 것은 권한이다 — 이번 편은 그 권한의 상한을 정하는 이야기다
01편에서 남은 문제
- 01편에서 Terraform 을 PR 댓글로 적용하는 로봇을 만들었다
- 리뷰를 거친 main 코드만 apply 명찰을 빌릴 수 있게 했다
- 하지만 그 명찰 자체가 너무 크면 소용이 없다
- EKS 를 만드는 로봇은 IAM 역할도 만들어야 한다
- 역할을 만들 수 있는 로봇은 마음만 먹으면 자기에게 관리자 권한을 줄 수 있다
이번 편: 권한의 상한
- 이 편은 그 상한을 정하는 이야기다
- 2장: 로봇은 키를 보관하지 않고 그때그때 빌린다
- 3장: 로봇이 만드는 역할에는 넘을 수 없는 경계를 씌운다
- 4장: 권한을 넓히는 일과 그 권한으로 만드는 일은 두 PR 로 나눈다
- 5장: 클러스터 출입증이 실제로 무엇인지 들여다본다
2. OIDC — 저장된 키가 없다
키 대신 임시 자격증명
- GitHub Actions 가 AWS 에 들어갈 때 장기 액세스 키를 쓰지 않는다
- 실행마다 GitHub 이 “이 레포의 이 브랜치에서 돌고 있다” 는 OIDC 토큰을 발급한다
- AWS 가 그걸 확인한 뒤 1시간짜리 임시 자격증명을 준다
- GitHub 에 털릴 AWS 키가 애초에 없다
키를 보관하지 않고 그때그때 빌린다 — 받은 키는 runner 가 들고, 작업이 끝나면 버려진다
신뢰 조건: 레포 ID
- 신뢰 조건에는 레포 이름이 아니라 바뀌지 않는 레포 ID 를 넣었다
- 레포 이름을 바꾸거나 같은 이름으로 새 레포를 만들어도 → 역할을 빌릴 수 없다
3. Permissions Boundary — 만들 수는 있어도 넘을 수는 없다
문제: 역할을 만드는 역할
- EKS 를 만드는 apply 역할은 IAM 역할도 만들어야 한다
- 클러스터 역할, 노드 역할, IRSA 역할이 필요하기 때문이다
- 역할을 만들 수 있는 역할은 위험하다 — 관리자 권한을 가진 역할을 만들어 자기가 쓰면 끝이다
permissions boundary 의 뜻
- 역할이 가질 수 있는 최대 권한이다
- 정책에 무엇을 적든 boundary 밖은 효력이 없다(7장)
역할을 만들 수 있는 역할이라도 상자 밖으로는 못 나간다 — 거부 규칙 28개를 변이 테스트로 고정했다
만들 수 있는 것은 이름으로 묶고, 넘으면 안 되는 것은 명시적 거부로 막는다
한계: launch template 을 통한 우회
- 이 역할은 노드의 launch template 을 바꿀 수 있다
- 그러면 비밀 값을 읽는 Pod 가 도는 노드에서 코드를 실행할 수 있다 → 간접적으로 Secret 에 닿는다
- IAM 조건으로는 이 경로를 다 막지 못한다
- 그래서 main 에 병합할 수 있는 사람은 개발환경 Secret 에 닿을 수 있다고 본다
- 그 경로는 리뷰와 댓글 승인으로 막는다
4. Two-Step Change — 경비실 명단과 출입증
관리자 추가에 필요한 PR 두 개
- 두 번째 관리자를 클러스터에 추가할 때 PR 이 두 개 필요했다
- 처음에는 같은 일을 두 번 하는 것처럼 보였다
- 등장인물을 나눠 보면 왜 둘인지 보인다
규칙집(①)은 사람이 직접 고치고, 출입증(②)은 로봇이 규칙 안에서만 만든다
명단 두 개: 경비실 명단과 출입증
- 경비실 벽에 붙은 명단: AWS IAM 정책 안에 있는 “출입증을 줘도 되는 사람” 목록
- 손에 쥔 출입증: EKS 클러스터에 실제로 등록된 출입 항목
# ① github-actions-foundation — 경비실 명단 (관리자가 로컬에서 적용)
infra_access_entry_principals = [
"arn:aws:iam::<account>:user/<admin-a>",
"arn:aws:iam::<account>:user/<admin-b>", # ★ 추가
"arn:aws:iam::<account>:role/kukie-dev-node",
]
# ② dev/eks-platform — 출입증 (PR 댓글 /apply 로 로봇이 적용)
resource "aws_eks_access_entry" "admin" {
for_each = toset(["<admin-a>", "<admin-b>"]) # ★ 추가
principal_arn = "arn:aws:iam::<account>:user/${each.key}"
}
적용 순서와 적용 주체
- ①이 없는 상태로 ②를
/apply하면- 로봇이 AWS 에 “B 출입증 만들어 줘” 를 보낸다
- IAM 이 로봇의 규칙집을 보고 거부한다
- ①은 권한 자체를 바꾼다 → 댓글 배포 대상에서 뺐다
- 관리자가 plan 을 눈으로 보고 직접 적용한다
- 이번 ①의 plan: 정책 한 줄 추가, 변경 1
실무 팁: moved 블록
for_each로 바꾸면 기존 항목의 주소가admin에서admin["<admin-a>"]로 바뀐다- Terraform 은 이걸 삭제 후 생성으로 읽는다 → 그 사이 기존 관리자가 잠깐 잘린다
moved블록으로 주소만 옮기면 plan 에서 삭제가 사라진다
moved {
from = aws_eks_access_entry.admin
to = aws_eks_access_entry.admin["<admin-a>"]
}
5. Access Entry — 출입증은 명부의 한 줄이다
출입증의 실체: 명부의 한 줄
- 출입증이라고 부르지만 토큰도 비밀키도 아니다
- 클러스터 쪽 명부에 “이 IAM 사용자는 관리자” 라는 한 줄을 적는 것이다
- 사용자 손에 새로 주어지는 것은 없다
kubectl 한 번이 세 관문을 지난다 — 진짜 열쇠는 노트북의 AWS 키다
API 접근 제한: 관리자 IP
- EKS 의 API 는 인터넷에 열려 있지만 관리자 공인 IP
/32만 허용했다 - 이 값은 코드에도 그림에도 적지 않는다
- GitHub Actions Secret 에 두었다가 plan 단계에서
TF_VAR_admin_cidrs로 넘긴다
- GitHub Actions Secret 에 두었다가 plan 단계에서
- 다만 plan 과 state 에는 남는다 → 비밀이라기보다는 공개하지 않는 값이다
apply 역할과 클러스터 내부
- 같은 이유로, EKS 를 만든 apply 역할은 클러스터 안에 들어가지 못한다
- 클러스터 생성 API 는 AWS 쪽 일이다
- 클러스터 안의 일은 출입 명부를 통과해야 한다
- 03편의 ArgoCD 설치가 로봇이 아니라 사람 몫이 되는 이유다
6. Discussion
반복된 모양: 허가와 생성의 분리
- 이 편에서 같은 모양이 여러 번 반복됐다 — 권한을 바꾸는 일과 그 권한으로 무언가를 만드는 일을 떼어 놓는 것
- 나타난 곳
- ECR 을 앱별로 나눌 때
- EKS 를 등록할 때
- 관리자를 추가할 때
- 모니터링 저장소를 준비할 때
- 매번 foundation 이 먼저 허가를 넓히고, 그다음 root 가 그 안에서 만들었다
- PR 이 두 개로 늘어나는 대신 → 로봇이 할 수 있는 일의 상한은 항상 사람이 정한다
IAM 조건 밖에 남은 길
- IAM 조건으로 다 막지 못하는 길도 있다
- 노드 설정을 바꿔 비밀 값에 간접적으로 닿는 길 → 리뷰와 댓글 승인으로 막는다
- main 에 병합할 수 있는 사람은 개발환경 Secret 에 닿을 수 있다고 보고, 그 권한을 줄 사람을 고른다
핵심 메시지
OIDC
키를 보관하지 않는다. 작업 하나 동안만 빌린다
경계
역할을 만들 수 있어도, 만든 역할도 상자 밖으로는 못 나간다
두 단계
허가(경비실 명단)는 사람이, 생성(출입증)은 로봇이 허가 안에서
출입증
사용자에게 주는 물건이 아니라 클러스터 명부의 한 줄
남은 길
IAM 으로 못 막는 경로는 리뷰와 승인으로
리뷰와 기록 없이는 아무것도 바뀌지 않게 하려면, 결국 누가 무엇을 쓸 수 있는지를 하나씩 정하게 된다. 레포, 역할, 경계, 출입 명부는 모두 같은 질문에 대한 서로 다른 층의 답이다. 다음 편은 이 권한 위에 EKS 를 세 번 만에 세우고, ArgoCD 를 들이는 이야기다.
7. References
GitHub Actions 가 장기 키 없이 클라우드에 들어가는 방식은 GitHub 의 OIDC 문서에 정리되어 있다.
"With OIDC, your cloud provider issues a short-lived access token that is only valid for a single job, and then automatically expires."
[해석] "OIDC 를 쓰면 클라우드 제공자가 작업 하나에만 유효한 짧은 수명의 액세스 토큰을 발급하고, 그 토큰은 자동으로 만료된다." — 2장의 근거다.
permissions boundary 가 무엇을 제한하는지는 IAM 사용 설명서에 있다.
"An entity's permissions boundary allows it to perform only the actions that are allowed by both its identity-based policies and its permissions boundaries."
[해석] "엔터티의 권한 경계는 자격 증명 기반 정책과 권한 경계 양쪽이 모두 허용한 작업만 수행하게 한다." — 3장에서 apply 역할이 만드는 역할에 경계를 강제한 근거다.
EKS 출입 항목이 무엇인지는 EKS 사용 설명서의 개요 첫 문단에 있다.
"Fundamentally, an EKS access entry associates a set of Kubernetes permissions with an IAM identity, such as an IAM role."
[해석] "근본적으로 EKS 출입 항목은 쿠버네티스 권한 묶음을 IAM 역할 같은 IAM 자격 증명에 연결한다." — 5장의 "출입증은 명부의 한 줄" 의 근거다.
