0. Contents


1. Overview

stateOIDC역할·경계Account Foundation관리자가 직접 적용 · 거의 안 바뀐다노드NATEKSPR 댓글 /apply 로 로봇이 적용ArgoCDLBCESORLDArgoCD + 공통 설비처음 한 번만 관리자가 Terraform 으로webmemberagentredisAppskukie-manifest 를 ArgoCD 가 배포
층과 층 사이를 오가는 것은 권한이다 — 이번 편은 그 권한의 상한을 정하는 이야기다

01편에서 남은 문제

  • 01편에서 Terraform 을 PR 댓글로 적용하는 로봇을 만들었다
  • 리뷰를 거친 main 코드만 apply 명찰을 빌릴 수 있게 했다
  • 하지만 그 명찰 자체가 너무 크면 소용이 없다
  • EKS 를 만드는 로봇은 IAM 역할도 만들어야 한다
    • 역할을 만들 수 있는 로봇은 마음만 먹으면 자기에게 관리자 권한을 줄 수 있다

이번 편: 권한의 상한

  • 이 편은 그 상한을 정하는 이야기다
  • 2장: 로봇은 키를 보관하지 않고 그때그때 빌린다
  • 3장: 로봇이 만드는 역할에는 넘을 수 없는 경계를 씌운다
  • 4장: 권한을 넓히는 일과 그 권한으로 만드는 일은 두 PR 로 나눈다
  • 5장: 클러스터 출입증이 실제로 무엇인지 들여다본다

2. OIDC — 저장된 키가 없다

키 대신 임시 자격증명

  • GitHub Actions 가 AWS 에 들어갈 때 장기 액세스 키를 쓰지 않는다
  • 실행마다 GitHub 이 “이 레포의 이 브랜치에서 돌고 있다” 는 OIDC 토큰을 발급한다
  • AWS 가 그걸 확인한 뒤 1시간짜리 임시 자격증명을 준다
  • GitHub 에 털릴 AWS 키가 애초에 없다
GitHubAWSrunner명찰을 차고 일한다① 증명서 · 레포 · 브랜치STSapply 역할명찰 규칙② 조건 확인 · main?③ 임시 키 1시간EKSEC2IAM④ runner 가 그 키로 terraform apply① 증명서: 레포 ID · 브랜치② STS: 규칙 확인 · main 만 apply③ runner 가 1시간짜리 키를 받는다④ runner 가 그 키로 AWS 를 바꾼다명찰을 차는 건 runner역할은 AWS 에 있는 규칙일 뿐
키를 보관하지 않고 그때그때 빌린다 — 받은 키는 runner 가 들고, 작업이 끝나면 버려진다

신뢰 조건: 레포 ID

  • 신뢰 조건에는 레포 이름이 아니라 바뀌지 않는 레포 ID 를 넣었다
  • 레포 이름을 바꾸거나 같은 이름으로 새 레포를 만들어도 → 역할을 빌릴 수 없다

3. Permissions Boundary — 만들 수는 있어도 넘을 수는 없다

문제: 역할을 만드는 역할

  • EKS 를 만드는 apply 역할은 IAM 역할도 만들어야 한다
    • 클러스터 역할, 노드 역할, IRSA 역할이 필요하기 때문이다
  • 역할을 만들 수 있는 역할은 위험하다 — 관리자 권한을 가진 역할을 만들어 자기가 쓰면 끝이다

permissions boundary 의 뜻

  • 역할이 가질 수 있는 최대 권한이다
  • 정책에 무엇을 적든 boundary 밖은 효력이 없다(7장)
EKS·EC2역할 6개apply 역할✕sts:AssumeRole✕경계 없는 역할✕생성자 관리자보라 상자: permissions boundary이 안에서만 효력이 있다초록: 허용 — EKS·EC2·정해진 역할만든 역할에도 같은 경계를 강제빨강: 거부 — 경계 밖자기 역할 빌리기 · 경계 떼기클러스터 관리자 되기 · 기존 VPC
역할을 만들 수 있는 역할이라도 상자 밖으로는 못 나간다 — 거부 규칙 28개를 변이 테스트로 고정했다
할 수 있음이름이 정해진 역할 6개만 만든다cluster · node · cni · alb · secrets · nat만든 역할에 boundary 를 반드시 붙인다안 붙이면 생성 자체가 거부할 수 없음✕boundary 떼기명시적 거부✕sts:AssumeRole자기가 만든 역할 빌리기✕클러스터 생성자 관리자 권한값을 빼도 거부 (기본값이 true)✕정해진 사람 밖의 출입증허용 목록 — 4장✕기존 VPC · DB 수정CloudFormation 소유 표시로막지 못하는 길 하나노드 launch template 을 바꾸면Secret 을 읽는 Pod 의 노드에서 코드 실행→ 리뷰와 댓글 승인으로 막는다변이 28개 — 정책을 넓히거나 거부 문장을 빼면 terraform test 가 실패한다
만들 수 있는 것은 이름으로 묶고, 넘으면 안 되는 것은 명시적 거부로 막는다

한계: launch template 을 통한 우회

  • 이 역할은 노드의 launch template 을 바꿀 수 있다
  • 그러면 비밀 값을 읽는 Pod 가 도는 노드에서 코드를 실행할 수 있다 → 간접적으로 Secret 에 닿는다
  • IAM 조건으로는 이 경로를 다 막지 못한다
  • 그래서 main 에 병합할 수 있는 사람은 개발환경 Secret 에 닿을 수 있다고 본다
    • 그 경로는 리뷰와 댓글 승인으로 막는다

4. Two-Step Change — 경비실 명단과 출입증

관리자 추가에 필요한 PR 두 개

  • 두 번째 관리자를 클러스터에 추가할 때 PR 이 두 개 필요했다
  • 처음에는 같은 일을 두 번 하는 것처럼 보였다
  • 등장인물을 나눠 보면 왜 둘인지 보인다
관리자AWS 관리자 권한GitHub runner/apply 때만 뜨는 VMinfra apply 역할 (AWS)규칙집출입증을 줄 수 있는 사람관리자 A · 관리자 B · 노드EKS 출입 명부관리자 A — 관리자관리자 B — 관리자① foundation 적용 — 규칙집에 B 를 적는다② /apply — runner 가 역할을 빌린다규칙 안에서만 B 를 적는다
규칙집(①)은 사람이 직접 고치고, 출입증(②)은 로봇이 규칙 안에서만 만든다

명단 두 개: 경비실 명단과 출입증

  • 경비실 벽에 붙은 명단: 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 사용자는 관리자” 라는 한 줄을 적는 것이다
  • 사용자 손에 새로 주어지는 것은 없다
노트북AWS 키는 여기만토큰 15분① IP 허용관리자 /32 만② 신원 확인토큰 → IAM 사용자③ 출입 명부관리자 정책 연결클러스터 안주황: 내가 가진 것AWS 키 → 칠 때마다 토큰파랑: 클러스터가 가진 것①과 ③을 관리자 추가 PR 이 바꾼다출입증은 내 손이 아니라클러스터 명부에 있는 한 줄
kubectl 한 번이 세 관문을 지난다 — 진짜 열쇠는 노트북의 AWS 키다

API 접근 제한: 관리자 IP

  • EKS 의 API 는 인터넷에 열려 있지만 관리자 공인 IP /32 만 허용했다
  • 이 값은 코드에도 그림에도 적지 않는다
    • GitHub Actions Secret 에 두었다가 plan 단계에서 TF_VAR_admin_cidrs 로 넘긴다
  • 다만 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장의 근거다.
→ GitHub Docs — OpenID Connect
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 역할이 만드는 역할에 경계를 강제한 근거다.
→ AWS IAM User Guide — Permissions boundaries for IAM entities
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장의 "출입증은 명부의 한 줄" 의 근거다.
→ Amazon EKS User Guide — Grant IAM users access to Kubernetes with EKS access entries