AWS Cloud School 13기 116일차

Forever 김·2026년 6월 18일

AWS Cloud School

목록 보기
106/116

2026-06-18

Today

EKS CI/CD를 종이 위에서 한 바퀴 다 돌린 날. 클러스터가 실제로 떴는지 확인하는 데서 시작해 IRSA → Jenkins 파이프라인 → ArgoCD/GitOps까지 설계가 이어졌다.

  • dev-eks 실측 — 구축담당이 EKS 모듈을 dev에 apply. dev-eks ACTIVE, OIDC provider 등록 확인. IAM에 OIDC provider 2개 공존(EKS·GHA). 모듈엔 IRSA 역할이 하나도 없어서 그건 내 몫으로 확정. 단 클러스터 access entry에 내가 빠져 있어 kubectl은 403(apply한 영우님만 admin).
  • jenkins-tf-runner IRSA 설계 — 신뢰정책·권한정책·permission boundary 3종 실값 확정. iam:CreateRole을 주되 boundary 없이는 못 만들게 막고, 그 boundary를 떼지도 못하게 해서 권한 상승을 2겹으로 차단.
  • Jenkins Terraform 파이프라인 §3 완성 — Checkout부터 Slack까지. checkov는 soft→baseline→hard로 단계 강화. 승인은 ECS처럼 자동으로 가되, 사람 게이트를 뺀 자리를 파괴-변경 가드(CI jq)와 prevent_destroy로 메움.
  • ArgoCD/GitOps 설계 — 구축담당이 ArgoCD·LBC·App-of-Apps를 이미 깔아둔 걸 확인. 토폴로지는 클러스터별(B), 멀티환경은 Kustomize overlay로 확정. 첫 컴포넌트로 External Secrets를 잡음.
  • 블루/그린 ALB 분석 — 구축담당이 ALB 가중 TG로 ECS↔EKS 전환 블루그린을 깔아둠. 여기서 "ALB=마이그레이션 / Istio=버전 카나리" 2층을 구분한 게 핵심. Istio 카나리 선택이 더 맞다는 근거가 됐다.
  • 산출물 — 설계서 2개(EKS CI/CD ①Terraform파이프라인 ②GitOps, 번호 시리즈로 통일) + 블로그 9·10편(humanize 완료) + 메모리·타임라인·MOC 등 문서 전수 갱신.

Notes

오늘 흐름 한 줄 정리

"EKS가 실제로 떴다 → 그 위에 내 IRSA·CI/CD·GitOps를 설계" 로 정리된다. 설계는 거의 완성, 실제 apply·검증만 남았다(access entry 등록·부트스트랩 의존).

구축담당과 맞춰야 할 경계

설계하다 보니 내 영역과 구축담당 영역이 겹치는 지점이 드러났다.

  • IRSA 소유권 — 구축담당이 LBC IRSA를 직접 만들었다. LBC는 부트스트랩이라 예외로 두되, 나머지(ESO·Rollouts·앱·jenkins-runner)는 내가 설계하는 걸로 합의 필요.
  • permission boundary 팀 규약 — LBC 역할엔 boundary가 없다. 나만 boundary 쓰면 우회 경로가 남으니 팀 IRSA에 규약을 맞춰야 한다.
  • state 분리 — 구축담당은 IRSA를 dev 루트 state에 인라인 중. 나는 dev/irsa.tfstate로 분리하려 했는데, 마찰을 줄이려면 합류가 실용적일 수도. 재고 중.
  • ALB weight 소유권 — 전환 중 리스너 weight를 누가 옮기고, terraform ignore_changes를 언제 켤지.

Learned

IRSA (IAM Roles for Service Accounts)

  • EKS에서 Pod 단위로 AWS IAM 권한을 부여하는 메커니즘
  • 기존 문제: EC2 노드에 IAM Role 부여 → 노드 내 모든 Pod가 동일 권한 (최소 권한 원칙 위반)
  • 해결: Kubernetes ServiceAccount ↔ IAM Role 1:1 매핑
  • 동작 흐름: OIDC Provider → Trust Policy 조건 매칭 → STS AssumeRoleWithWebIdentity → 임시 자격증명 발급
  • ECS Task Role과 대응 관계:
    • ECS: Task Definition에 Task Role 지정 (Task 단위)
    • EKS: ServiceAccount에 IAM Role annotation (Pod 단위)
  • 장점: 최소 권한 원칙 / STS 임시 토큰(자동 로테이션) / CloudTrail 감사 추적 가능

Checkov

  • IaC 정적 분석 보안 스캐너 (오픈소스, Bridgecrew/Palo Alto Networks)
  • Terraform·CloudFormation·K8s·Helm·Dockerfile 등 멀티 프레임워크 지원
  • 배포 전 보안 취약점 탐지 (Shift-Left Security)
  • 탐지 예시: 과도한 IAM 권한, 열린 SG, 암호화 미적용, 로깅 누락
  • 각 검사 항목에 CKV ID 부여 (예: CKV_AWS_18 = S3 access logging 누락)
  • CI/CD 파이프라인(GitHub Actions)에 통합하여 PR 시 자동 스캔 가능
  • tfsec 대비 장점: 멀티 프레임워크 지원, Python으로 커스텀 정책 작성

Application Auto Scaling이 desiredCount 하한을 강제한다

  • ECS 서비스에 Auto Scaling(min=1)이 걸리면 UpdateService desiredCount=0으로 내려도 "min 위반"으로 즉시 1로 복원 → dev 야간종료가 무력화됐던 원인.
  • 해결: stop 시 RegisterScalableTarget으로 Min=0/Max=0부터 내린 뒤 desired=0. start는 Min1/Max2 복원.
  • 검증: aws application-autoscaling describe-scalable-targets의 MinCapacity(0이면 정상).

CI/CD IAM 역할 난립이 왜 위험한가

  • 안 쓰는 CodePipeline/CodeBuild 실험 역할이 쌓이면 공격표면↑(강권한 유휴 역할 assume 가능)·최소권한 위배·감사 추적 혼탁.
  • 정리: Access Advisor last-used로 미사용 확인 후 백업·삭제.

AUTH_DEV_MASTER = 인증 우회 (편의 기능의 양날)

  • enabled=true면 특정 code(DEV_MASTER)로 OAuth를 건너뛰고 JWT 발급. 우회코드가 공개·고정값이면 백도어가 됨.
  • 완화: 우회코드 난수화 + Secrets Manager 이관(제거 대신).

Jenkins vs GitHub Actions

  • 상호배타 아님(공존 가능). GHA=SaaS·OIDC 키리스·제로인프라 / Jenkins=셀프호스팅·플러그인 방대·운영(패치)책임.
  • 선택 기준: 클라우드네이티브·키리스면 GHA, 엔터프라이즈 표준·복잡 파이프라인이면 Jenkins.

EKS CI/CD = AWS 권장 2레이어

  • AWS 권장: CI 도구가 빌드/검증 → GitOps(ArgoCD/Flux)가 "배포 단계". CI에서 kubectl apply보다 GitOps(풀·드리프트감지·감사) 권장.
  • 분리 원칙: "IAM/인프라는 terraform(CI), K8s 오브젝트는 GitOps".

GitHub Actions OIDC ≠ EKS IRSA OIDC

  • 둘 다 키리스지만 issuer가 다름: GHA=token.actions.githubusercontent.com(sub=repo:org/repo), EKS=oidc.eks...(sub=system:serviceaccount:ns:sa).
  • issuer가 달라 GHA용을 IRSA에 재사용 불가. 전환 후 계정에 OIDC provider 2개 공존.

Jenkins on EKS 부트스트랩 (닭-달걀)

  • Jenkins가 Terraform으로 EKS를 만드는데 정작 Jenkins는 그 EKS 위에 산다 → 자기 클러스터를 못 만듦.
  • 해결: 최초 클러스터는 수동/로컬 apply(부트스트랩), 이후 day-2 변경만 Jenkins.

IRSA = 신뢰정책 + 권한정책 (의존성 분리)

  • 신뢰정책(누가 assume = OIDC): 클러스터 필요 → 나중. 권한정책(무엇 가능): 클러스터 무관 → 미리 설계 가능.
  • 덕분에 클러스터 전에 권한정책·Jenkinsfile·agent 이미지를 선제 준비(반응형 접근).

CI/CD Validate 단계 (Terraform PR 게이트)

  • GitHub Actions에서 Terraform 코드 PR 시 배포 전 자동 검증하는 단계
  • 실행 도구 4가지: terraform fmt -check(포맷) → terraform validate(문법) → tflint(린트) → checkov(보안)
  • 앞 3개는 pass/fail 명확(자동), checkov만 결정 필요 (false positive, 심각도 다양)
  • 결정 포인트: soft-fail(경고만) vs hard-fail-on CRITICAL,HIGH(심각한 것만 블로킹) vs 전체 hard-fail
  • skip 정책: .checkov.yml 또는 인라인 #checkov:skip=CKV_ID:사유로 의도적 예외 관리
  • 베이스라인(--create-baseline): 지금 있는 위반을 동결하고 신규 위반만 실패시킴 → 레거시 부채를 다 못 고쳐도 "더 나빠지지 않기"를 즉시 강제
  • 점진 강화 패턴: 보안 게이트는 soft(관측) → baseline(신규 차단) → hard-fail-on HIGH(심각도 차단) 순으로 올린다. 처음부터 전체 차단하면 우회·skip 남발로 무력화됨 (WAF Count→Block과 동일 원리)

SCM (Source Code Management)

  • 소스 코드 관리 시스템 = Git + 호스팅 플랫폼 통칭 (GitHub, GitLab, Bitbucket, CodeCommit 등)
  • CI/CD에서 "SCM에서 코드 받아오는 단계" = actions/checkout 또는 git clone (첫 단계, 설계 결정 불필요)
  • VCS(Version Control System)와 거의 동의어로 혼용됨 (VCS=도구 자체, SCM=플랫폼 포괄)

Jenkins 동작 원리

  • Controller-Agent 구조: Controller(중앙)가 스케줄링·UI·큐 관리, Agent(워커)가 실제 빌드 실행
  • Executor = Agent 내 동시 실행 슬롯 수
  • 실행 흐름: 트리거 → 빌드 큐 등록 → label 매칭으로 Agent 할당 → Jenkinsfile 실행 → 결과 리포트
  • Agent 연결: SSH(전통) / JNLP(Agent→Controller 역접속) / Kubernetes Plugin(Pod 동적 생성·삭제)
  • EKS 위 Jenkins: Controller Pod만 상주, 빌드 시 Agent Pod 동적 생성 → 끝나면 삭제 (비용 절감)
  • 확장: Plugin 기반 (1,800+개), 설정은 Jenkinsfile(Groovy) + UI
  • GHA 대비: 셀프호스팅(운영 부담↑) 대신 플러그인·커스터마이징 자유도 높음

Terraform 자동 적용의 파괴적 변경 가드 (CI vs terraform)

  • terraform은 시키면 지운다 — "위험하니 막기"는 terraform 밖에서 따로 넣어야 함.
  • CI 가드: terraform show -json으로 plan을 떠 change.actionsdelete 든 리소스를 jq로 세고, 있으면 파이프라인이 exit 1로 차단. 차단 주체 = CI(파이프라인), terraform 아님. (policy as code — OPA/conftest/Sentinel로 확장)
  • lifecycle { prevent_destroy = true }: terraform-native 최후 방어선. 박아둔 리소스를 지우는 plan이면 terraform core가 직접 거부. 핵심 리소스(RDS·state 버킷)에만, 삭제만 막음.
  • 실무 = 둘 다(넓게 CI + 깊게 terraform).
  • replace = ["delete","create"]: in-place 불가 변경은 지우고 새로 만듦(무중단 아님, 데이터 손실 위험) → 가드 핵심 대상.

terraform plan 파일 저장 + stale 거부

  • 인자 없는 terraform apply는 그 자리서 plan을 재계산 → 검토한 것과 다른 게 적용될 수 있음.
  • plan -out=tfplanapply tfplan = 저장한 계획만 적용. 그새 state가 바뀌면 "stale" 거부(오래된 계획이 최신 인프라 덮어쓰기 방지).

Jenkins 승인 게이트 실무 패턴

  • 사람 승인(input)은 agent none으로 — pod 안 잡고 대기(유휴비용·controller 재시작 시 input 유실 방지). "승인 구간은 executor 점유 금지"가 정석.
  • stash/unstash = 같은 빌드의 stage 간 파일 전달(Plan pod → Apply pod로 tfplan). 빌드 내 전달이라 아티팩트와 다름.
  • submitter로 승인자 제한(GHA Environments Required reviewers 대응). 직무 분리 = 작성자 ≠ 승인자.

GitOps

  • Git을 단일 진실 원천(SSOT)으로 삼아, Git 상태 = 클러스터 실제 상태가 되도록 자동 동기화하는 운영 모델
  • 핵심 4원칙: 선언적 / Git=SSOT / 자동 적용 / 드리프트 감지·자가 복구
  • Pull 모델: 클러스터 내부의 Agent(ArgoCD/Flux)가 Git을 감시 → 변경 감지 시 sync (CI에 클러스터 credential 불필요)
  • Push(전통 CI/CD)와 차이: CI가 kubectl apply 직접 실행 vs GitOps Agent가 내부에서 당겨옴
  • 실무 분리: CI = 빌드·테스트·이미지 push까지 / 배포 = GitOps 도구 담당
  • 대표 도구: ArgoCD(UI·멀티클러스터·RBAC), Flux(CLI·가벼움·이미지 자동 업데이트)
  • 장점: 보안(credential 노출 없음) / 감사(Git 커밋=배포 이력) / 롤백(git revert) / 드리프트 자동 복구

Prompt(회고)

  • 오늘부터 우리 프로젝트는 EKS로 진입을 시작했다. ECS 때처럼 내가 담당한 부분인 CI/CD 설계를 했다. 일단 ECS와 달리 ArgoCD와 Jenkins를 사용하려고 한다. 왜냐하면 일단 채용공고에 나오는 기술을 해봐야하지 않나 생각으로 한다.
  • ECS와 달리 많은 Learning Curve가 필요한 부분인 만큼 더 시간을 할애해서 잘해봐야겠다.
profile
나를 한줄로

0개의 댓글