0. Contents


1. Overview

앱 레포develop 머지Actions굽기 · pushECRdigest PRkukie-manifestenvs/devArgoCD읽기 · 비교 · 적용K8s API검사 · 저장컨트롤러LBC · ESO · RLDAWSALB · Secret04편 — 이미지가 창고까지이번 편 — 창고 다음부터
ArgoCD 는 굽지 않는다 — Git 에 적힌 상태를 클러스터에 맞추는 구간만 맡고, 그 뒤는 컨트롤러가 이어받는다

이전 편과 이번 편

  • 03편에서 ArgoCD 를 설치했다
  • 04편에서 앱 이미지가 ECR 까지 가는 길을 만들었다
  • 이번 편: 그 사이에 놓인 ArgoCD 가 실제로 무엇을 하는지

ArgoCD 가 하는 일

  • 이미지를 굽지 않는다
  • Git 에 적힌 쿠버네티스 YAML 을 읽어서 클러스터의 상태와 비교하고, 다르면 맞춘다 — 그게 전부다
  • ALB 를 만들거나 Secrets Manager 에서 값을 꺼내는 일은 다른 컨트롤러가 한다
    • ArgoCD 가 넣은 객체를 읽은 컨트롤러다

진행 상황(2026-10-15 기준)

  • 끝난 단계: 설치, 저장소 자격증명, 플랫폼 GitOps
  • 앱 저장소 연결: 코드만 병합된 채 저장소 등록을 기다린다(9장 그림)

2. Source of Truth — ArgoCD가 읽는 두 저장소

kukie-infraargocd/dev/platformkukie-manifestenvs/devrootkukie-dev-platformLBCESOReloaderkukie-dev-apps수동 동기화webmemberagentredisroot 가 만든다kukie-platform클러스터 전체 · CRD · RBACkukie-appskukie-manifest 만 · kukie-dev 만 · 6종류
지시서는 두 권 — 플랫폼은 넓은 울타리에서 자동으로, 앱은 좁은 울타리에서 아직 수동으로

ArgoCD 가 읽는 지시서 두 권

kukie-infra
경로
argocd/dev/platform
담긴 것
공통 컨트롤러, namespace, 앱 연결 정의
읽는 Application
kukie-dev-platform (root)
프로젝트
kukie-platform
kukie-manifest
경로
envs/dev
담긴 것
web, member, agent, redis, Ingress
읽는 Application
kukie-dev-apps
프로젝트
kukie-apps

root Application 과 kukie-dev-apps

  • root Application 은 kukie-infra 를 읽고 그 안의 Application 들을 만든다(App of Apps, 03편 3.2)
  • 이번에 그 목록에 kukie-dev-apps 가 하나 더 들어갔다
  • kukie-manifest 를 보는 것은 이 Application 뿐이다

앱용 Application 의 위치: kukie-infra

  • 이유는 쓰기 권한이다
  • Application 을 쓸 수 있는 사람은 어느 프로젝트에 넣을지도 고를 수 있다(위키 5.4)
  • kukie-manifest 는 앱 CI 봇이 쓰는 저장소다
    • 거기에 Application 을 두면 봇이 클러스터 전체 권한의 kukie-platform 을 고를 수 있다
  • 그래서 앱 쪽 Application 과 그 울타리(kukie-apps)는 사람이 리뷰하는 kukie-infra 에만 있다

두 프로젝트의 차이

kukie-platform
읽는 저장소
kukie-infra, 컨트롤러 차트 저장소 3곳
배포 위치
argocd, kube-system, external-secrets, kukie-dev
클러스터 범위 리소스
전부 (CRD, ClusterRole 등)
namespace 리소스
제한 없음
kukie-apps
읽는 저장소
kukie-manifest 하나
배포 위치
kukie-dev 하나
클러스터 범위 리소스
없음
namespace 리소스
Deployment, Service, ConfigMap, Ingress, ExternalSecret, SecretStore

3. Repository Access — 비공개 저장소 읽기 자격증명

읽기 자격증명의 필요

  • 두 저장소 모두 비공개다
  • ArgoCD 가 3분마다 Git 을 확인하려면 읽기 자격증명이 필요하다

3.1 Token Choice — PAT에서 GitHub App으로

처음 절차: 개인 fine-grained token

  • 처음 README 절차(2026-10-14, #35): kukie-infra 하나에 Contents 읽기만 준 개인 fine-grained token
  • 그보다 앞선 문서(2026-09-22, #5): “토큰 또는 SSH key” 로 열어 두었다
  • 왜 PAT 로 좁혔는지는 커밋에도 PR 에도 남아 있지 않았다
개인 PAT
소유
만든 사람 계정
만료
최대 1년
사람이 빠지면
끊김
저장소 2개
토큰 하나
저장소 주소
HTTPS
Deploy Key
소유
저장소
만료
없음
사람이 빠지면
상관없음
저장소 2개
키 2개
저장소 주소
git@ 로 바꿔야 함
조직 GitHub App
소유
조직
만료
없음 (ArgoCD 가 1시간 토큰을 스스로 받음)
사람이 빠지면
상관없음
저장소 2개
앱 하나
저장소 주소
HTTPS

#46: 조직 소유 GitHub App 으로 전환

  • 2026-10-15 의 #46 이 조직 소유 GitHub App 으로 바꿨다
  • 이유
    • 개인 계정에 묶이지 않는다
    • 만료 갱신이 없다
    • 주소가 HTTPS 그대로라 root Application 과 sourceRepos 를 고칠 필요가 없다
  • 처음으로 이유가 적힌 결정이다

자격증명 보관 위치

  • ArgoCD 화면에서 등록했다
  • 결과는 argocd namespace 의 repository Secret 하나다
  • Terraform 변수나 Git 에는 넣지 않는다 → 넣으면 state 에 private key 가 남는다

3.2 Two Apps — 쓰기 앱과 읽기 앱의 분리

앱 레포 CIserver · agent · webkukie-manifestkukie-infraArgoCD클러스터 안manifest-bot · 쓰기argocd-dev · 읽기열쇠: 각 레포 Actions Secretdurokukie 조직 저장소열쇠: argocd namespace Secret
앱은 조직 소유, 설치는 저장소별 허락 — 쓰는 열쇠는 CI 에, 읽는 열쇠만 클러스터에 둔다

기존 앱 kukie-manifest-bot 과의 분리

  • 조직에는 앱이 이미 하나 있었다 — 2026-09-26 에 만든 kukie-manifest-bot
  • 둘을 합치지 않은 이유: 권한과 열쇠가 놓이는 자리
kukie-manifest-bot
쓰는 쪽
앱 레포 3곳의 CI
권한
Contents·Pull requests 쓰기
설치 저장소
kukie-manifest
열쇠 위치
각 레포 Actions Secret, 잡이 돌 때만 사용
durokukie-argocd-dev
쓰는 쪽
ArgoCD
권한
Contents·Metadata 읽기
설치 저장소
kukie-infra, kukie-manifest
열쇠 위치
클러스터 Secret, 항상 존재

클러스터에 두는 열쇠: 읽기 전용

  • ArgoCD 가 쓰기 앱의 열쇠를 들면
    • 클러스터에서 그 열쇠가 샐 때 kukie-manifest 를 고쳐 아무 이미지나 배포할 수 있다
  • 그래서 항상 클러스터에 놓여 있는 열쇠는 읽기만 하게 했다

앱과 설치의 구분

  • 앱은 조직에 속하고, 설치는 저장소별 허락이다
  • kukie-manifest 를 읽게 하는 일은 새 앱을 만드는 게 아니었다
    • durokukie-argocd-dev 의 설치 범위에 저장소 하나를 더하는 일이었다

4. Sync Loop — 감지와 비교와 적용

4.1 Interval — 3분 주기의 확인

Git main새 커밋repo-serverYAML 렌더링controller클러스터와 비교K8s API적용↺ 120초 + 최대 60초SyncedGit 과 같으면 아무것도 안 한다OutOfSync · 자동플랫폼 — 바로 맞춘다 (prune · selfHeal)OutOfSync · 수동kukie-dev-apps — 차이만 보여 준다
감지 → 렌더링 → 비교 → 적용 — 다른 점은 마지막 화살표를 자동으로 긋느냐 뿐이다

확인 주기와 실제 반영 시간

  • 읽기 · 렌더링 · 비교 · 적용의 반복과 확인 주기(최대 3분)는 위키 1절과 9.1에 있다
  • 이 클러스터는 주기를 기본값 그대로 두었다
  • 플랫폼 쪽 렌더링은 Helm 차트다
  • #40 을 병합하고 root Application 이 새 커밋을 읽기까지 실제로 약 1분 반이 걸렸다

GitOps 켜기: root Application 하나

  • 이 클러스터에서 “GitOps 를 켰다” 는 건 enable_gitops = true 로 root Application 하나를 만든 일이다
  • 켜진 시점을 알려 주는 기록(2026-10-15 14:59 KST)
    • Helm 릴리스 argocd-apps 의 revision 이 1에서 2로 바뀐 기록
    • 같은 시각에 생긴 Application 4개

4.2 Auto and Manual — 플랫폼과 앱의 동기화 방식

OutOfSync 이후: 플랫폼과 앱의 차이

  • Synced · OutOfSync 와 수동 · 자동 동기화의 뜻은 위키 4.2 · 9.1에 있다
  • 이 클러스터는 OutOfSync 다음을 플랫폼과 앱에서 다르게 둔다
root, LBC, ESO, Reloader
동기화
자동 (prune, selfHeal)
OutOfSync 다음
바로 Git 대로 맞춘다. 클러스터에서 손으로 바꾼 것도 되돌린다
kukie-dev-apps
동기화
수동
OutOfSync 다음
차이만 보여 준다

앱 쪽 수동 동기화의 이유: 순서

  • member 이미지는 아직 ECR 에 없고, Secret 값도 비어 있다
  • 자동으로 두면 연결하는 순간 이미지 받기에 실패하는 Pod 가 생긴다
  • 수동이면 ArgoCD 가 kukie-manifest 를 읽고 렌더링까지는 한다
    • 저장소 연결과 YAML 이 맞는지를 배포 없이 먼저 볼 수 있다
  • kukie-manifest 는 비공개라 kukie-infra 의 CI 가 렌더링해 볼 수 없는 저장소이기도 하다
# argocd/dev/platform/templates/kukie-apps.yaml
spec:
  project: kukie-apps
  source:
    repoURL: https://github.com/durokukie/kukie-manifest.git
    targetRevision: main
    path: envs/dev
  syncPolicy:                       # automated 없음 — 읽고 비교만
    syncOptions: [RespectIgnoreDifferences=true]

병합 직후 상태: ComparisonError

  • 병합 직후 kukie-dev-apps 는 ComparisonError 였다
  • 원인: ArgoCD 에 kukie-manifest 저장소가 아직 등록되지 않아 authentication required 를 받았다
  • 등록하면 OutOfSync 로 바뀌고 만들 객체 목록이 보인다
  • 자동 동기화는 member digest, Secret 값, DB 허용이 끝난 뒤 별도 PR 로 켠다

4.3 Sync Wave — 생성 순서

NamespacePod Security정책 2wave -2 · 검문소namespace 레이블 · admission policyAppProject kukie-appswave -1 · 울타리앱이 쓸 프로젝트LBCESOReloaderkukie-dev-appswave 0 · Application컨트롤러 3 + 앱 1
아래 층부터 선다 — 앱 울타리와 검문소가 앱보다 먼저 있어야 한다

같은 커밋 안의 생성 순서

  • 같은 커밋 안에서도 순서가 있다
  • argocd.argoproj.io/sync-wave 주석이 작은 것부터 만든다
-2
객체
Namespace kukie-dev, admission policy 2개와 연결
먼저 있어야 하는 이유
앱 Pod 와 Ingress 가 들어오기 전에 검사가 서 있어야 한다
-1
객체
AppProject kukie-apps
먼저 있어야 하는 이유
Application 이 고를 울타리가 먼저 있어야 한다
0
객체
Application 4개

클러스터의 실제 생성 순서

  • #40 병합 뒤 클러스터에도 이 순서로 생겼다
  • 검사는 7장에서 다룬다

5. Downstream Controllers — ArgoCD 이후의 컨트롤러

IngressLBCALBAWS 로드밸런서ExternalSecretESOSecretSecrets Manager 값ConfigMap 변경ReloaderPod 재시작DeploymentArgoCD 가 넣는 것컨트롤러결과
ArgoCD 의 일은 쿠버네티스 객체까지 — ALB 와 Secret 은 그 객체를 읽은 컨트롤러가 만든다

객체를 넣은 뒤: 컨트롤러 셋

  • ArgoCD 는 객체를 넣는 데까지 한다
  • 실제 일은 그 객체를 읽는 컨트롤러가 한다(위키 8절)
  • 이 클러스터에서 그 일을 맡는 건 03편 3.3 에서 세운 컨트롤러 셋이다
Ingress
읽는 컨트롤러
AWS Load Balancer Controller
만들어지는 것
AWS 의 ALB
ExternalSecret
읽는 컨트롤러
External Secrets Operator
만들어지는 것
Secrets Manager 값이 담긴 쿠버네티스 Secret
ConfigMap·Secret 변경
읽는 컨트롤러
Reloader
만들어지는 것
그 값을 쓰는 Deployment 재시작

Ingress 담당: LB Controller

  • 이 클러스터에서 Ingress(ingressClassName: alb)를 읽는 건 LB Controller 다
  • Ingress 의 기본 개념은 K8sPatterns.13 5.3 에 있다

ALB 의 자리와 수명

  • ALB 는 Pod 위에서 돌지 않는다
    • AWS 가 운영하는 장비가 private subnet 에 자리를 잡는다
    • target-type: ip 라서 노드를 거치지 않고 Pod IP 로 바로 요청을 보낸다
  • Pod 가 바뀌면 LB Controller 가 대상 목록을 고친다
  • ArgoCD 는 ALB 가 있는지도 모른다
  • 다만 ArgoCD 가 Ingress 를 지우면 LB Controller 가 ALB 를 지운다 → 결과적으로 ALB 의 수명은 Git 을 따라간다

6. Ownership Boundary — 관리 범위의 세 층

subnet asubnet c보안 그룹IAM 역할LBCinternal ALBIngressArgoCDTerraform — 땅과 담장subnet · 보안 그룹 · IAM · PR 승인 후 /applyLB Controller — 건물Ingress 를 보고 ALB 를 짓고 고치고 허문다ArgoCD — 주문서Git 의 Ingress 를 클러스터에 넣는다
주문서는 땅을 고르지 않는다 — 이름과 태그로 Terraform 이 만든 자리를 가리킬 뿐이다

Ingress 를 따라 나뉘는 관리 주체 셋

땅과 담장
무엇
subnet, 보안 그룹, IAM 역할
관리
Terraform
바꾸는 방법
PR, plan, /apply
건물
무엇
ALB
관리
LB Controller
바꾸는 방법
Ingress 를 따라 자동
주문서
무엇
Ingress
관리
ArgoCD
바꾸는 방법
Git 병합

subnet: 고르지 않고 가리키기

  • subnet 은 ArgoCD 가 관리하지 않는다
  • 주문서는 땅을 고르지 않고 가리킬 뿐이다
  • 가리키는 방법은 ID 가 아니라 이름과 태그다
보안 그룹
Ingress 에 적힌 것
이름 kukie-dev-internal-alb
LB Controller 가 찾는 방법
Name 태그가 그 이름인 보안 그룹
subnet
Ingress 에 적힌 것
없음
LB Controller 가 찾는 방법
kubernetes.io/role/internal-elb 태그가 붙은 subnet

Terraform 출력 자동 전달 없음

  • Terraform 출력을 manifest 로 자동으로 넘기는 장치는 없다
    • 보안 그룹 ID 는 다시 만들면 바뀐다
    • 값을 넘기려면 Terraform 쪽에 kukie-manifest 쓰기 권한이 생긴다
  • 이름과 태그가 약속 역할을 한다
  • 대신 이름을 바꾸면 세 곳을 같이 바꿔야 한다 — Terraform, manifest, admission policy

ingress_annotations 출력 정리

  • Terraform 의 ingress_annotations 출력은 원래 보안 그룹 ID 와 subnet ID 목록을 안내했다
    • Ingress 를 처음 쓰는 사람이 보라고 만든 메모였다
    • 실제 manifest 는 처음부터 이름과 자동 탐색을 썼다
  • 7장의 정책이 들어오면서 이 메모대로 쓴 Ingress 는 거부되게 됐다 → 출력을 이름과 자동 탐색으로 맞췄다
  • 리소스는 바뀌지 않아 plan 은 생성 0 · 변경 0 · 삭제 0 이었다

7. Admission Guard — 클러스터 입구의 검사

ArgoCD동기화Pod Securitybaselineadmission policyinternal ALB 만저장etcdprivileged · hostPathinternet-facing✕✕
ArgoCD 가 넣어도 API 서버가 거른다 — 앱 저장소가 바꿀 수 없는 namespace 와 클러스터 범위 객체에 규칙을 둔다

허용 목록의 빈칸: 종류만 본다

  • kukie-apps 의 허용 목록은 종류만 본다 — Deployment 는 허용, ClusterRole 은 금지
  • 허용된 Deployment 안에 무엇을 적었는지는 보지 않는다
  • #40 의 리뷰가 이 빈칸을 두 번 짚었다

검사 위치: API 서버 입구

  • ArgoCD 가 보낸 객체는 쿠버네티스 API 서버를 지나 저장된다 → 검사는 그 입구에 둔다
  • 규칙이 붙는 곳은 namespace 레이블과 클러스터 범위 객체다
    • kukie-apps 로는 건드릴 수 없다
    • 바꾸려면 kukie-infra 에 PR 을 내야 한다

7.1 Pod Security — 위험 설정과 baseline

위험 설정: 격리에 낸 구멍

  • 컨테이너는 노드의 디스크, 네트워크, 다른 프로세스와 격리돼 있다
  • 위험 설정은 그 격리에 스스로 구멍을 내는 설정이다
  • 노드 하나를 뚫으면 그 노드의 모든 Pod 와 노드 IAM 권한까지 넘어간다

Pod Security Admission 켜기

  • 쿠버네티스에 들어 있는 검사다
  • namespace 레이블 한 줄로 켠다
# argocd/dev/platform/templates/namespace.yaml
metadata:
  name: kukie-dev
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/enforce-version: latest
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/audit: restricted

baseline 의 정해진 거부 항목

privileged
거부하는 값
true
뚫리는 것
노드 관리자 권한
hostNetwork, hostPID, hostIPC
거부하는 값
true
뚫리는 것
노드의 네트워크, 프로세스, 공유 메모리
volumes[].hostPath
거부하는 값
사용
뚫리는 것
노드 디스크
hostPort
거부하는 값
0 이 아닌 값
뚫리는 것
노드 포트
capabilities.add
거부하는 값
기본 목록 밖 (SYS_ADMIN 등)
뚫리는 것
사실상 관리자 권한
seccomp, AppArmor
거부하는 값
Unconfined
뚫리는 것
커널 보안 필터
procMount, sysctls
거부하는 값
기본값 밖
뚫리는 것
커널 설정

baseline 이 보지 않는 것

  • 이 값들을 적지 않으면 기본값이 안전한 쪽이라 그냥 통과한다
  • 이미지, 환경변수, 메모리 같은 설정은 보지 않는다
  • 지금 manifest 의 앱 넷은 이 항목을 하나도 쓰지 않는다

수준 결정: 실제 클러스터에 dry-run

  • 수준은 실제 클러스터에 물어보고 정했다
  • kubectl label --dry-run=server
    • 레이블을 바꾸지 않는다
    • 바꾸면 기존 Pod 중 무엇이 걸리는지만 돌려준다
  • 결과
    • baseline: 경고가 없었다
    • restricted: kukie-dev 의 Reloader 가 allowPrivilegeEscalation != false, unrestricted capabilities 로 걸렸다
  • 그래서 강제는 baseline, restricted 는 경고와 감사 기록만 남긴다

거부 시점: Pod 를 만드는 순간

  • 검사는 Pod 에 걸린다
  • Deployment 는 경고만 받고 들어간다
  • 그 Deployment 가 Pod 를 만들려는 순간 거부되어 FailedCreate 이벤트가 남는다
  • 노드 권한이 정말 필요한 도구(노드 지표 수집기 같은 것)는 kukie-dev 가 아니라 kukie-infra 가 관리하는 별도 namespace 에 둔다

7.2 Internal ALB — Ingress와 Service 제한

두 번째 빈칸: 로드밸런서

  • kukie-apps 가 허용한 Ingress 와 Service 는 LB Controller 가 AWS 로드밸런서로 만든다
  • “CloudFront 만 들어오는 internal ALB” 라는 경계는 manifest 의 주석 한 줄이었다
  • 쓰기 권한이 새면 그 줄을 internet-facing 으로 바꿔 인터넷에 바로 열린 ALB 를 만들 수 있었다

차단 수단: ValidatingAdmissionPolicy

  • 쿠버네티스 1.30 부터 기본 기능이다
  • 웹훅 서버 없이 CEL 식으로 규칙을 적는다
  • Ingress 와 Service 는 필드가 달라 정책을 둘로 나눴다
    • 한 정책에 섞으면 서로 없는 필드를 참조한다는 타입 경고가 남는다
# argocd/dev/platform/templates/kukie-dev-admission.yaml (요약)
validations:   # kukie-dev-ingress-internal-alb
  - expression: "has(object.spec.ingressClassName) && object.spec.ingressClassName == 'alb'"
  - expression: "variables.annotations[?'alb.ingress.kubernetes.io/scheme'].orValue('') == 'internal'"
  - expression: "variables.annotations[?'alb.ingress.kubernetes.io/security-groups'].orValue('') == 'kukie-dev-internal-alb'"
  - expression: "!['alb.ingress.kubernetes.io/subnets', 'alb.ingress.kubernetes.io/customer-owned-ipv4-pool',
                   'kubernetes.io/ingress.class'].exists(key, key in variables.annotations)"
validations:   # kukie-dev-no-load-balancer-service
  - expression: "!has(object.spec.type) || object.spec.type != 'LoadBalancer'"

정책 연결과 CI 검사

  • 두 정책 모두 failurePolicy: Fail, 연결은 validationActions: [Deny] 다
  • kukie-dev namespace 에만 붙는다
  • 정책 두 개와 Deny 연결, namespace 레이블이 빠지면 kukie-infra 의 check-gitops.rb 가 PR 을 실패시킨다

7.3 Verification — kind 클러스터 검증

manifest Ingress통과ClusterIP Service통과다른 namespace통과internet-facing거부다른 보안 그룹거부다른 class거부옛 class 주석거부subnet 지정거부LoadBalancer Svc거부통과 3 · 거부 6Kubernetes 1.36 · server dry-run
지금 manifest 는 그대로 통과하고, 주석 한 줄로 바깥에 여는 시도는 모두 막힌다

kind 클러스터 시험: 아홉 가지 요청

  • 실제 클러스터에 넣기 전에 로컬 kind 클러스터(Kubernetes 1.36.1)에 같은 정책을 넣었다
  • server dry-run 으로 아홉 가지를 보냈다
    • 통과: 지금 manifest 의 Ingress, ClusterIP Service, 다른 namespace 의 internet-facing Ingress
    • 거부: internet-facing, 다른 보안 그룹, 다른 ingress class, 옛 kubernetes.io/ingress.class 주석, subnet 직접 지정, LoadBalancer Service
  • 처음 한 정책에 Ingress 와 Service 를 섞었을 때 남던 타입 경고는 둘로 나눈 뒤 사라졌다
  • 시험이 끝난 뒤 kind 클러스터는 지웠다

실제 클러스터 반영

  • #40 병합 뒤 실제 클러스터에도 레이블과 정책 두 개, 연결 두 개가 생겼다
  • kukie-dev 의 Reloader 는 그대로 Running 이었다

8. Operator View — 관리 화면 접속 경로

내 PCport-forwardAWS IAM누구인가EKS API 서버허용 IP · 관리자 명단argocd-server웹 화면① 토큰② 터널③ admin 로그인ArgoCD 자체 계정kukie-dev 클러스터
건물 출입은 AWS 계정으로, 방 안 열쇠는 ArgoCD 계정으로 — 두 번의 확인

화면과 API 담당: argocd-server

  • ArgoCD Pod 넷의 역할은 위키 2절에 있다
  • 그중 화면과 API 를 내는 건 argocd-server 다

접속 방법: kubectl port-forward

  • argocd-server 는 ClusterIP 라 클러스터 밖에서 들어올 주소가 없다
  • 화면은 kubectl port-forward 로 본다
kubectl -n argocd port-forward svc/argocd-server 8080:443

port-forward 통로의 경로

  • 이 명령은 내 PC 의 8080 포트와 Pod 사이에 통로를 만든다
  • 통로는 이미 열려 있는 EKS API 연결 안을 지난다
  • 그래서 그 연결에 들어갈 수 있는 사람만 화면을 볼 수 있다
① 신원
어디서
AWS IAM
무엇을
kubectl 이 AWS 프로필로 받은 토큰 — "이 요청은 IAM 사용자 누구"
② 입장
어디서
EKS API 서버
무엇을
접속 IP 가 허용 목록에 있는지, 그 IAM 사용자가 access entry 관리자 명단에 있는지
③ 로그인
어디서
ArgoCD
무엇을
ArgoCD 자체 계정 admin

EKS 의 신원: AWS 신원 그대로

  • EKS 는 클러스터 계정을 따로 만들지 않고 AWS 신원을 쓴다
  • ①② 는 건물 출입증이고, ③ 은 그 건물 안 방 하나의 열쇠다
  • 관리자 명단과 IP 허용 목록은 02편 5장의 access entry 와 같은 것이다

Pod 쪽 포트가 8080 인 이유

  • 출력 Forwarding from 127.0.0.1:8080 -> 8080 에서 Pod 쪽은 443 이 아니라 8080 이다
  • 서비스의 443 이 Pod 의 8080 으로 이어진다
  • kubectl 은 서비스를 거치지 않고 Pod 포트에 바로 붙는다

9. Discussion

설치10-14자격증명GitHub AppGitOps10-15플랫폼 앱Synced앱 저장소등록 대기자동 동기화조건 대기완료 4 · 남은 단계 2
플랫폼은 Git 이 바로 클러스터가 되고, 앱은 아직 읽기와 비교까지만

작업 대부분: ArgoCD 바깥의 일

  • ArgoCD 를 붙이는 일은 대부분 ArgoCD 바깥의 일이었다
    • 저장소를 읽을 자격증명(3장)
    • 무엇을 어느 울타리에 넣을지(2장)
    • 넣은 뒤 누가 이어받는지(5, 6장)
    • 넣기 전에 누가 거르는지(7장)
  • ArgoCD 자체의 설정은 Application 하나에 동기화 방식 한 줄이었다

리뷰가 찾은 세 가지와 닫은 방법

  • 모두 “종류는 막았는데 내용은 열려 있다” 는 같은 모양이었다
    • 허용된 Deployment 안의 privileged
    • 허용된 Ingress 안의 internet-facing
    • 새 검사와 어긋난 Terraform 출력
  • 앞의 둘: 앱 저장소가 바꿀 수 없는 자리에 규칙을 두는 것으로 닫았다
  • 마지막: 메모를 실제 방식에 맞추는 것으로 닫았다

남은 일: 앱 쪽

  • ArgoCD 에 kukie-manifest 저장소 등록
  • member 이미지와 digest PR 자동화
  • kukie-dev/member Secret 값
  • DB 5432 허용
  • member 의 SES 발송용 IRSA 역할
  • 다 끝나면 kukie-dev-apps 에 자동 동기화 한 줄을 더한다

핵심 메시지

두 저장소
플랫폼은 kukie-infra 에서 자동으로, 앱은 kukie-manifest 에서 아직 수동으로
읽기 앱
조직 소유 GitHub App. 클러스터에 놓이는 열쇠는 읽기만 한다
동기화
감지, 렌더링, 비교, 적용. 자동과 수동의 차이는 마지막 단계뿐
이어받는 컨트롤러
ArgoCD 는 객체까지. ALB 와 Secret 은 컨트롤러가 만든다
입구 검사
종류는 프로젝트가, 내용은 API 서버가 거른다

ArgoCD 는 Git 과 클러스터를 맞추는 일만 한다. 굽기는 앞에서, ALB 와 Secret 은 뒤에서 다른 것이 한다. 앱이 쓸 수 있는 자리와 규칙이 놓이는 자리를 나눴다. 규칙은 리뷰를 거치는 저장소에만 있다. 다음 편은 앱 쪽 — 자동 동기화를 켜기 전에 채워야 할 이미지, Secret, DB 다.


10. References

Argo CD 가 Git 을 얼마나 자주 확인하는지는 FAQ 에 있다.
"By default, Argo CD checks (polls) Git repositories every 3 minutes to detect changes."
[해석] "기본으로 Argo CD 는 변경을 찾으려고 3분마다 Git 저장소를 확인(폴링)한다." — 4.1 의 확인 주기 근거다. 같은 문서에 120초와 최대 60초 흔들림으로 나뉜다고 적혀 있다.
→ Argo CD FAQ
프로젝트가 무엇을 제한하는지는 Projects 문서 첫머리에 세 줄로 있다.
"restrict what kinds of objects may or may not be deployed (e.g. RBAC, CRDs, DaemonSets, NetworkPolicy etc...)"
[해석] "어떤 종류의 객체를 배포할 수 있는지 제한한다." — 2장 kukie-apps 의 허용 목록이 종류까지만 막는 근거다. 그 안의 내용은 7장에서 따로 거른다.
→ Argo CD — Projects
baseline 수준의 성격은 Pod Security Standards 의 개요 표에 있다.
"Minimally restrictive policy which prevents known privilege escalations. Allows the default (minimally specified) Pod configuration."
[해석] "알려진 권한 상승을 막는 최소한의 정책. 기본(최소로 적은) Pod 설정은 허용한다." — 7.1 에서 지금 앱이 고칠 것 없이 통과한 이유다.
→ Kubernetes — Pod Security Standards
ValidatingAdmissionPolicy 가 무엇인지는 쿠버네티스 문서 첫 문단에 있다.
"Validating admission policies offer a declarative, in-process alternative to validating admission webhooks."
[해석] "검증 admission policy 는 검증 웹훅을 대신하는, 선언형이고 API 서버 안에서 도는 방법이다." — 7.2 에서 웹훅 서버를 따로 두지 않은 근거다.
→ Kubernetes — Validating Admission Policy
LB Controller 가 internal ALB 의 subnet 을 고르는 방법은 subnet 탐색 문서에 있다.
"For internal load balancers, the controller looks for private subnets with following tags:"
[해석] "internal 로드밸런서는 아래 태그가 붙은 private subnet 을 찾는다." — 6장에서 Ingress 에 subnet 을 적지 않고 kubernetes.io/role/internal-elb 태그에 맡긴 근거다.
→ AWS Load Balancer Controller — Subnet auto-discovery
EKS 가 AWS 신원으로 클러스터 권한을 주는 방식은 access entry 문서 개요에 있다.
"Fundamentally, an EKS access entry associates a set of Kubernetes permissions with an IAM identity, such as an IAM role."
[해석] "EKS access entry 는 쿠버네티스 권한 묶음을 IAM 신원에 연결한다." — 8장 ② 단계의 관리자 명단이다.
→ Amazon EKS — Access entries