0. Contents


1. Overview

Kukie우리 계정고객 AWS 계정고객이 가진 것WEBKukie 웹팀 설정 → 클러스터 연결APIKukie 서버역할 kukie-dev-member (IRSA)DB: 계정 · ExternalId · 리전 · 이름AGENT에이전트kubectl 실행자격증명은 받아 쓰고 버림CFNCloudFormation 스택kukie-access 템플릿 (공개 S3)IAMIAM 역할KukieAccess-<ExternalId>신뢰: Kukie 서버 + ExternalIdEKSEKS 클러스터접근 항목: KukieAccessEdit · namespace kukie-demoAPI 서버 (공개 엔드포인트)1스택 만들기 (고객이 클릭)역할 생성2AssumeRole + ExternalId15분 세션3목록 · 자기 등록415분 토큰5kubectl (네임스페이스 안만)
① 고객은 스택만 만들고 키를 넘기지 않는다 ② ExternalId 를 붙여 역할을 잠깐 빌린다 ③ 그 역할로 EKS 에 자기 이름표를 붙인다 ④⑤ 매 명령마다 새 토큰

Kukie 의 역할과 기존 연결 방식

  • 팀이 고른 쿠버네티스 클러스터에 kubectl 을 대신 실행해 준다
  • 지금까지 클러스터를 맡기는 방법은 kubeconfig 파일 하나였다
    • 파일 안에 그 클러스터의 자격증명이 들어 있다
    • Kukie 는 그것을 암호화해 보관했다

이번 편: AWS 계정 연결

  • 고객은 AWS 콘솔에서 스택을 한 번 만든다
  • Kukie 는 그 스택이 만든 역할을 필요할 때만 잠깐 빌린다

설계 원칙 세 가지

  • 영구 키를 받지 않는다 — Kukie 가 저장하는 것은 계정 번호, ExternalId, 리전, 클러스터 이름뿐이다
  • 할 수 있는 일은 고객 역할이 정한다 — 그 역할의 권한은 공개된 템플릿 한 장에 적혀 있다
  • 모든 접근은 짧게 산다 — 역할 세션도, kubectl 토큰도 15분이다

장별 내용

  • 2장: 고객 계정에 남는 두 조각
  • 3장: 남의 계정에 들어가는 신뢰
  • 4·5장: 역할의 권한과 리뷰가 찾은 우회
  • 6장: 토큰의 수명
  • 7장: 등록 전 주소 검사
  • 고객이 계정 번호를 적지 않아도 되게 만든 스택 알림은 다음 편(08편)에서 다룬다

2. Two Pieces — 출입증과 이름표

고객 AWS 계정Kukie 서버역할 kukie-dev-member+ 팀의 ExternalId① 출입증 = IAM 역할KukieAccess-<ExternalId>계정에 하나 · 고객 스택이 만듦kukie-demo이름표가 허락한 네임스페이스kube-system닿지 않음② 이름표 = 접근 항목클러스터마다 하나Kukie 가 [연결] 때 붙임EKS 클러스터 B자기 이름표가 따로 있다EKS 클러스터 AIAM 역할
출입증(①)이 없으면 계정에 못 들어오고, 이름표(②)가 없으면 그 클러스터 안에서 아무것도 못 한다

연결 후 고객 계정에 남는 두 가지

IAM출입증IAM 역할 — 건물(계정)에 들어오는 허가EKS이름표접근 항목 — 방(클러스터) 문 앞 명단고객 AWS 계정× 1계정에 하나EKS AEKS B클러스터마다이름KukieAccess-<ExternalId>이름역할 이름 그대로 붙음누가 만드나고객 — 스택 생성누가 만드나Kukie 서버 — [연결] 때하는 일Kukie 가 계정에 들어옴하는 일고른 네임스페이스만 편집없애는 법고객이 스택 삭제없애는 법Kukie 에서 클러스터 삭제+
둘 다 있어야 Kukie 가 일할 수 있다 — 출입증만 있으면 계정에는 들어오지만 클러스터 안에서 아무것도 못 하고, 이름표만 남으면 쓸 사람이 없다

접근 항목(access entry)

  • EKS 가 2023년 말에 내놓은 방식이다
  • aws-auth ConfigMap 대신 EKS API 로 “누가 이 클러스터에 들어오나” 를 관리한다
  • 항목에 접근 정책(access policy)을 붙여 권한을 정한다
    • Kukie 는 AWS 관리형 AmazonEKSEditPolicy 를 네임스페이스 범위로만 붙인다
  • 클러스터 인증 모드가 ConfigMap 전용이면 항목을 만들 수 없다 → 등록 단계에서 거절한다

출입증과 이름표의 차이

  • 한 계정의 클러스터 둘을 연결하면
    • 출입증: 하나를 같이 쓴다
    • 이름표: 둘이다
  • Kukie 에서 클러스터 하나를 지울 때
    • 출입증은 건드리지 않는다
    • 그 클러스터의 이름표만 뗀다
  • 같은 EKS 를 네임스페이스만 달리해 두 번 연결했다면
    • 이름표가 한 장이다
    • 떼는 대신 지운 네임스페이스만 범위에서 뺀다

3. Trust — ExternalId 와 혼동된 대리인

누가무엇을 요청하나어디서 판정되나팀 A정상 연결계정 1111 연결역할 KukieAccess-extAExternalId = extA고객 역할 신뢰 정책주체 kukie-dev-member ✓ExternalId extA ✓통과팀 BA 의 계정 번호를 앎계정 1111 연결역할 KukieAccess-extBExternalId = extBKukie 서버ExternalId 는 요청한 팀 것만1111 에 그 역할이 없음거부외부 공격자자기 AWS 자격AssumeRole 직접KukieAccess-extAExternalId = extA고객 역할 신뢰 정책주체가 kukie-dev-member 가 아님역할 이름을 알아도 소용없음거부서버 역할 탈취가정AssumeRole1111 의 관리자 역할ExternalId 없이Kukie 권한 경계대상은 KukieAccess-* 만ExternalId 필수거부역할 이름의 ExternalId 는 비밀이 아니다 — 막는 것은 '누가 맡느냐(신뢰 주체)'와 '어느 팀의 값을 붙이느냐(서버)'의 조합
1111 · extA · extB 는 설명용 값. 서버 역할을 빼앗긴 경우에도 KukieAccess 범위 안의 일은 남는다 (8장)

문제: 혼동된 대리인(confused deputy)

  • 여러 고객을 대신해 일하는 서비스는 모든 고객의 역할을 맡을 권한이 있다
  • 그래서 팀 B 가 팀 A 의 계정 번호를 대면, 서비스가 A 의 역할을 대신 맡아 버릴 수 있다
  • AWS 가 권하는 해법: 서드파티 역할의 신뢰 정책에 서비스 주체 + ExternalId 조건을 함께 건다

Kukie 의 ExternalId

  • 팀마다 하나 만든다
  • 형식: kukie- + 무작위 16자리 hex
  • 서버가 만들어 보여 줄 뿐, 팀이 고를 수 없다
  • 고객 템플릿은 이 값을 역할 이름과 신뢰 조건에 함께 쓴다
RoleName:
  Fn::Sub: "KukieAccess-${ExternalId}"
AssumeRolePolicyDocument:
  Statement:
    - Effect: Allow
      Principal:
        AWS: "arn:aws:iam::<Kukie 계정>:role/kukie-dev-member"
      Action: "sts:AssumeRole"
      Condition:
        StringEquals:
          "sts:ExternalId":
            Ref: ExternalId

차단 원리

  • 서버는 역할을 맡을 때 요청한 팀의 ExternalId 로만 역할 이름과 ExternalId 값을 만든다
  • 팀 B 가 A 의 계정 번호를 넣어도
    • 서버가 찾는 것은 그 계정의 KukieAccess-<B 의 값> 이다
    • A 는 그런 역할을 만든 적이 없다 → 실패
  • ExternalId 가 역할 이름에 그대로 들어가 비밀이 아니어도 괜찮다
    • 막는 것은 “누가 맡느냐(신뢰 주체)” + “어느 팀의 값을 붙이느냐(서버)” 의 조합이다
    • 외부 공격자는 값을 알아도 주체가 될 수 없다

Kukie 쪽 권한 경계 — 배포 역할들이 공유하는 권한 경계에 문장 하나를 더했다

{
  Sid      = "AssumeCustomerAccess", Effect = "Allow", Action = ["sts:AssumeRole"]
  Resource = ["arn:aws:iam::*:role/KukieAccess-*"]
  Condition = {
    ArnEquals = { "aws:PrincipalArn" = "arn:aws:iam::<Kukie 계정>:role/kukie-dev-member" }
    Null      = { "sts:ExternalId" = "false" }
  }
}
  • 대상은 KukieAccess-* 이름의 역할뿐이다
  • ExternalId 를 빼고 부르면 거부된다
  • 서버 역할을 빼앗겨도 고객 계정의 다른 역할로 건너갈 수 없다(그림의 넷째 줄)
  • 한계: 고객 역할의 신뢰 정책은 Kukie 의 권한 경계로 줄일 수 없다
    • 남의 계정에 들어가는 실제 문은 고객 역할의 조건이다
    • 우리 쪽 경계는 그 문 앞까지 가는 길을 좁힐 뿐이다

4. Template Policy — 역할이 할 수 있는 일

요청실제 API 값판정한 문장EKS 목록·정보 보기eks:ListClusters · DescribeClusterListClusters자기 자신을 접근 항목으로 등록CreateAccessEntry principal=자기 · STANDARDAddSelfOnly다른 주체를 등록CreateAccessEntry principal=다른 역할AddSelfOnly (조건 불일치)그룹을 붙여 등록kubernetesGroups=[system:masters]AddSelfOnly (Null 조건)kukie-demo 에 EditAmazonEKSEditPolicy · namespace [kukie-demo]EditAllowedNamespacesOnlyClusterAdmin 연결AmazonEKSClusterAdminPolicyEditAllowedNamespacesOnly클러스터 전체 범위accessScope=clusterEditAllowedNamespacesOnly시스템 네임스페이스namespace [kube-system]NoSystemNamespaces패턴으로 넓히기namespace [k*]NoNamespacePatterns (5장)자기 항목 지우기DeleteAccessEntry principal=자기ManageSelfOnly
허용 넷(초록)은 모두 '역할 자기 자신'과 '고른 네임스페이스'로 묶여 있다. 문장 이름은 템플릿 kukie-access-v1.yaml 의 Sid

템플릿 보관 위치와 규칙

  • 공개 S3 버킷에 둔다 — CloudFormation 빠른 생성 링크가 S3 의 템플릿만 읽기 때문이다
  • 템플릿이 고객 계정 안에서 Kukie 가 할 수 있는 일을 정한다 → 한 번 게시한 버전은 고치지 않는다
  • 버전마다 내용 md5 를 코드에 고정한다
    • 파일이 바뀌면 plan 이 “새 버전으로 추가하라” 며 실패한다

역할의 권한

  • EKS 에만 있다
  • 쓰기는 전부 “역할 자기 자신” 으로 묶었다
- Sid: AddSelfOnly
  Effect: Allow
  Action: "eks:CreateAccessEntry"
  Resource: "*"
  Condition:
    StringEquals:
      "eks:principalArn":
        Fn::Sub: "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/KukieAccess-${ExternalId}"
      "eks:accessEntryType": "STANDARD"
    "Null":
      "eks:kubernetesGroups": "true"
      "eks:username": "true"
- Sid: EditAllowedNamespacesOnly
  Effect: Allow
  Action: "eks:AssociateAccessPolicy"
  Resource: "*"
  Condition:
    StringEquals:
      "eks:principalArn": # 위와 같은 자기 자신
      "eks:policyArn": "arn:aws:eks::aws:cluster-access-policy/AmazonEKSEditPolicy"
      "eks:accessScope": "namespace"
    "ForAllValues:StringLike":
      "eks:namespaces":
        Ref: AllowedNamespaces
    "Null":
      "eks:namespaces": "false"

조건별 차단 대상

  • 그룹·사용자 이름 금지
    • 그룹을 붙일 수 있으면 system:masters 처럼 클러스터에 이미 있는 관리자 바인딩에 올라탈 수 있다
    • 그룹과 사용자 이름 키가 아예 없어야(Null = true) 만들 수 있다
  • 네임스페이스 키 필수
    • ForAllValues 는 키가 비어 있으면 참이 된다
    • 그래서 Null = false 를 함께 건다(06편 5.2 와 같은 함정)
  • kube-* 는 항상 거부
    • AllowedNamespaces 를 무엇으로 고르든 시스템 네임스페이스는 별도 Deny 문장으로 막는다

리뷰는 마지막 줄이 “항상” 이 아니라는 것을 찾아냈다 → 5장


5. Namespace Pattern — k* 가 연 kube-system

요청 eks:namespaces = ["k*"]고객이 스택에서 AllowedNamespaces = k* 를 고른 경우 (템플릿 패턴상 유효한 값)IAM정책 평가 — 값을 글자로 비교Allow EditAllowedNamespacesOnly"k*" StringLike k*고객 값 k* 를 패턴으로 → 글자 k* 는 맞음맞음Deny NoSystemNamespaces"k*" StringLike kube-*글자 k* 는 kube- 로 시작하지 않음안 맞음결과 허용거부 문장이 적용되지 않으니 Allow 가 남는다EKS범위 적용 — 값을 패턴으로 해석k* 에 맞는 네임스페이스kube-system범위 안kube-public범위 안kube-node-lease범위 안kafka범위 안kukie-demo범위 안default밖payments밖kube-* 은 항상 거부라던 경계가 이 경로로 열린다같은 글자다른 해석고친 뒤 Deny NoNamespacePatternsForAnyValue:StringLike eks:namespaces ["*${*}*", "*${?}*"]${*} 는 IAM 정책에서 '글자 그대로의 *'. 값 안에 * 나 ? 가 있으면 무엇이든 거부 → 정확한 이름만 등록된다IAM 평가기 확인: kukie-demo 허용 · kukie-* · k* · kukie-? · kube-system 명시 거부"k*" 거부
IAM 조건은 값을 문자열로만 본다. 그 값을 받는 서비스가 패턴으로 해석하면, 정책은 글자 * 자체를 따로 막아야 한다

AllowedNamespaces 형식

  • AllowedNamespaces 형식: “이름, 또는 끝에만 * 를 붙인 접두사” (^[a-z0-9][-a-z0-9]*\*?$)
  • 고객이 k* 를 고르는 것은 형식상 문제가 없다
  • 그 상태에서 eks:namespaces = ["k*"] 로 Edit 를 연결하면 이렇게 된다
  1. 허용 문장: 요청 값 "k*" 를 정책 값 k* 와 StringLike 로 비교한다. 패턴은 정책 쪽에만 있고, 요청 값 "k*" 는 그냥 글자 두 개다. k 로 시작하니 맞는다
  2. 거부 문장: 요청 값 "k*" 를 kube-* 와 비교한다. 글자 k* 는 kube- 로 시작하지 않으니 맞지 않는다. 거부가 적용되지 않는다
  3. EKS: 네임스페이스 범위에 dev-* 같은 와일드카드를 그대로 받는다. k* 를 패턴으로 풀어 kube-system 까지 범위에 넣는다

원인: 문자열 비교와 패턴 해석의 차이

  • IAM 조건은 요청 값을 문자열로만 본다
  • 그 값을 받는 서비스(EKS)는 패턴으로 해석한다
  • 그래서 정책이 막았다고 믿은 범위와 실제 범위가 갈라진다

수정: 글자 *·? 거부 — 값 안에 글자 그대로의 * 나 ? 가 있으면 무조건 거부한다

- Sid: NoNamespacePatterns
  Effect: Deny
  Action: "eks:AssociateAccessPolicy"
  Resource: "*"
  Condition:
    "ForAnyValue:StringLike":
      "eks:namespaces":
        - "*${*}*"
        - "*${?}*"
  • IAM 정책 값에서 * 와 ? 는 와일드카드다
    • 글자 자체를 찾으려면 정책 변수 문법 ${*}, ${?} 를 쓴다
  • 결과
    • 접두사 패턴은 스택의 허용 범위(AllowedNamespaces)에만 남는다
    • 실제 연결은 정확한 네임스페이스 이름으로만 이뤄진다
  • 게시 전에 IAM 평가기(simulate-custom-policy)로 확인했다
요청 eks:namespaces결과근거
kukie-demo허용허용 범위 안, 정확한 이름
kukie-*명시적 거부NoNamespacePatterns
k*명시적 거부NoNamespacePatterns
kukie-?명시적 거부NoNamespacePatterns
kube-system명시적 거부NoSystemNamespaces
default암묵적 거부허용 범위 밖

서버의 이중 확인

  • 등록 요청의 네임스페이스가 DNS 라벨 형식이 아니거나 kube- 로 시작하면 AWS 를 부르기 전에 거절한다
  • 템플릿은 게시하면 고칠 수 없다 → 이 문장은 v1 을 내기 전 리뷰에서 들어갔다

6. Short-lived Access — 15분 세션과 토큰

0분5분10분15분20분25분30분35분kubectl 요청STS 세션EKS 토큰세션 1 · AssumeRole세션 2 · AssumeRole세션 3 · AssumeRole남은 시간 5분 미만 → 새로 빌림5분 넘게 남음 → 그대로 씀토큰은 요청마다 새로 서명 (presigned STS GetCallerIdentity). 진한 조각이 실제로 쓰는 몇 초, 옅은 막대가 받아 주는 15분DB 에 남는 것계정 · ExternalId · 리전 · 이름 (암호화). 키·토큰 없음고객이 스택을 지우면다음 AssumeRole 이 실패 — 길어야 세션 남은 시간만큼
세션은 서버 메모리에만, 토큰은 에이전트가 명령 하나에 쓰고 버린다

명령마다 새 접속 정보

  1. 고객 역할을 AssumeRole 로 빌린다. 세션 길이는 900초, AssumeRole 이 허용하는 최솟값이다
  2. 빌린 세션은 메모리에 두고, 만료까지 5분 넘게 남았으면 다시 쓴다. 토큰을 받은 직후 세션이 끝나 명령이 끊기지 않게 하는 여유다
  3. 그 세션으로 EKS 토큰을 서명한다. aws eks get-token 과 같은 방식으로, STS GetCallerIdentity 요청을 미리 서명한 URL 에 x-k8s-aws-id: <클러스터 이름> 헤더를 묶어 base64url 로 감싸고 k8s-aws-v1. 을 붙인다. EKS 는 이 토큰을 15분 동안 받아 준다
  4. 에이전트는 토큰을 명령 하나에 쓰고 버린다

저장 범위

  • DB 에는 계정 번호, ExternalId, 리전, 클러스터 이름만 암호화해 둔다
  • 키도 토큰도 저장하지 않는다

연결 해제: 스택 삭제

  • 고객이 스택을 지우면 역할이 사라진다
  • 다음 AssumeRole 부터 실패하고, Kukie 에서는 AWS_ROLE_NOT_ASSUMABLE 로 보인다

한계: 15분 넘는 명령

  • 오래 걸리는 명령(logs -f, watch)은 15분을 넘기면 끊길 수 있다
  • 지금 Kukie 의 명령은 대부분 몇 초 안에 끝난다
  • 길게 지켜보는 기능을 넣을 때는 토큰을 중간에 갈아 끼워야 한다

7. Private Address — 등록 전 주소 검사

kukie-dev VPC 10.42.0.0/16APIKukie 서버주소 검사 후 등록EKSkukie-dev우리 서비스DBAuroraRedis · 메타데이터 등VPC 밖 · 인터넷EKSkukie-hosting다른 VPC · 공개 엔드포인트EKS고객 클러스터다른 계정공인 IP 로 풀림 → 통과kukie-dev 주소→ 10.42.20.48내부 IP → 거부kubeconfig 에내부 주소→ 거부 (SSRF)검사 규칙· 이름을 직접 풀어 본다 (DNS)· 사설 · 루프백 · 링크로컬 · 메타데이터 대역이면 거부· kubeconfig 등록과 AWS 등록 모두 같은 검사· 개발 때만 KUKIE_ALLOW_LOCAL_CLUSTER 로 끔
같은 EKS 주소도 묻는 곳에 따라 답이 다르다 — 서버와 같은 VPC 의 클러스터만 내부 IP 로 보인다

위험: 사용자 입력 주소(SSRF)

  • kubeconfig 로 등록할 때 클러스터 주소는 사용자가 적는다
  • 그대로 믿으면, 누군가 10.42.x.x 처럼 Kukie 내부망 주소를 클러스터라며 등록할 수 있다
  • 그러면 에이전트가 내부망으로 요청을 보내게 된다

등록 전 주소 검사

  • 서버가 등록 전에 이름을 직접 풀어 본다
  • 아래로 풀리면 거절한다
    • 사설 대역(10/8, 172.16/12, 192.168/16)
    • 루프백
    • 링크로컬(인스턴스 메타데이터가 있는 169.254/16)
    • 문서·예약 대역
  • 로컬 개발 때만 KUKIE_ALLOW_LOCAL_CLUSTER 로 끈다

AWS 연결에도 같은 검사

  • 주소가 DescribeCluster 응답에서 와도 이름을 풀어 본다
  • 실제로 걸린 때: 우리 계정을 고객처럼 시험하며 후보 목록에서 kukie-dev 를 골랐을 때
    • “사설 주소로 풀리는 이름은 등록할 수 없습니다 … → 10.42.20.48”

kukie-dev 만 걸린 이유

  • EKS 엔드포인트 이름은 하나지만, 사설 접근이 켜진 클러스터는
    • 같은 VPC 안에서 물으면 내부 IP
    • 밖에서 물으면 공인 IP 로 답한다
  • Kukie 서버는 kukie-dev VPC 안에서 돈다 → kukie-dev 이름만 내부 IP 로 보였다
  • 다른 VPC 의 kukie-hosting, 다른 계정의 고객 클러스터는 공인 IP 로 풀려 통과한다

예외를 두지 않은 이유

  • “AWS 가 준 EKS 주소면 내부 IP 라도 믿는다” 는 예외를 둘 수도 있었다
  • 하지만 걸리는 것은 Kukie 가 사는 클러스터 하나뿐이고, 그 클러스터는 애초에 고객용 연결 대상이 아니다

8. Discussion

남은 위험

  • 서버 역할과 DB 를 함께 잃는 경우
    • DB 의 ExternalId + 서버 역할이 있으면, 연결된 모든 고객 클러스터에서 그 고객이 고른 네임스페이스의 Edit 권한 안의 일을 할 수 있다
    • 한 고객의 경계 밖으로는 못 나가지만, 고객 수만큼 범위가 넓다
    • 서버 역할을 맡을 수 있는 것은 kukie-dev 네임스페이스의 ServiceAccount 하나뿐이다(IRSA)
  • 같은 계정을 고객으로 쓸 때
    • 기본 허용 범위 kukie-* 가 Kukie 자신의 네임스페이스 kukie-dev 와 겹친다
    • 시험용 스택은 AllowedNamespaces = kukie-demo 로 좁혔다
    • 실제 고객 계정에는 Kukie 서비스가 없으므로 해당하지 않는다
  • 템플릿은 v1 그대로
    • 한 번 게시한 템플릿은 고치지 않는다
    • 권한을 바꾸려면 새 버전을 내고 고객이 스택을 업데이트해야 한다

핵심 메시지

  • 남의 계정에 들어가는 문은 그쪽 역할의 신뢰 조건이다
    • 우리 쪽에서는 “어느 팀의 ExternalId 를 붙이느냐” 를 서버가 정하게 해 대리인 혼동을 막는다
  • IAM 은 문자열로, 받는 서비스는 패턴으로 — 그 사이에 틈이 생긴다
    • 글자 * 자체를 막아 정확한 값만 통과시킨다
  • 접근은 짧고 좁게
    • 영구 키 대신 15분 세션과 15분 토큰
    • 클러스터마다 붙였다 떼는 이름표

9. References

여러 고객을 대신하는 서비스가 고객 역할을 맡을 때 생기는 혼동된 대리인 문제와, 신뢰 정책의 ExternalId 조건으로 막는 방법. 3장의 근거다.
→ AWS IAM — The confused deputy problem
서드파티에 계정 접근을 줄 때 ExternalId 를 서비스가 만들어 고객별로 다르게 쓰라는 권고.
→ AWS IAM — Access to AWS accounts owned by third parties
EKS 접근 항목과 인증 모드(API, API_AND_CONFIG_MAP, CONFIG_MAP). 2장의 이름표가 이것이다.
→ Amazon EKS — Grant IAM users access to Kubernetes with EKS access entries
접근 정책과 범위. 네임스페이스 범위가 와일드카드 패턴을 받는다는 점이 5장 우회의 출발점이다.
→ Amazon EKS — Associate access policies with access entries
정책 값에서 글자 그대로의 * · ? · $ 를 쓰는 특수 문자 ${*} · ${?} · ${$}. 5장의 NoNamespacePatterns 가 이것을 쓴다.
→ AWS IAM — IAM policy elements: Variables and tags
ForAllValues · ForAnyValue 와 키가 없을 때의 동작. 4장의 Null 조건을 함께 거는 이유다.
→ AWS IAM — Single-valued vs. multivalued context keys
EKS 토큰 형식(미리 서명한 STS GetCallerIdentity, x-k8s-aws-id 헤더, k8s-aws-v1 접두사). 6장의 토큰 서명이 이 방식을 따른다.
→ kubernetes-sigs — aws-iam-authenticator
AssumeRole 의 DurationSeconds 범위(최소 900초).
→ AWS STS — AssumeRole