콘텐츠로 이동

캡스톤 · 면접 노트 (M0–M6 + 심화 M7–M11을 졸업한 뒤)

7개 코어 모듈(M0–M6)을 직접 재구현했다면, 이제 보여줄 것을 만든다. 아래를 채우면 그대로 포트폴리오 요약이자 면접 답변이 된다. 각 모듈 3칸: 무엇을 재구현했나 / 막는 것 / 막지 하는 것(정직하게 — 한계를 아는 것이 실력이다). 앵커 한 줄은 시작점일 뿐, 네 말로 다시 써라. M7–M9는 심화(재조명)다: 새 통제가 아니라 기존 스택을 형식검증(M7)·측정(M8)·침해가정 렌즈(M9)로 재조명하므로, "무엇을 만들었나"보다 "무엇을 증명/측정했나"로 말하는 게 정확하다. M10(GitOps 무결성·reconciler-TCB 이전)·M11(BPF-LSM exec 허용목록)은 새 통제 표면을 더한다.

채우는 법: 각 모듈 README의 구두 문답(접힌 답안)을 보지 말고 먼저 말로 답한 뒤, 여기 옮겨라.


M0 · Cedar 인가 (ABAC + RBAC)

  • 재구현: 빈 정책에서 owner/한도/역할/동결 인가를 Cedar로 작성, 11/11.
  • 막는 것: 권한 없는 조회·초과/음수 이체·동결 계좌 이체 (per-request 인가).
  • 못 막는 것(정직): 앵커 — Deny는 default-deny로 공짜로 맞을 수 있다(통과≠증명); 경계값 없으면 뮤턴트가 산다.

M1 · 쉬프트레프트 (checkov)

  • 재구현: 하든드 안 된 워크로드의 16개 결함을 수정, Failed 0.
  • 막는 것: 배포 전에 잘못된 securityContext/권한/리소스 누락을 정적으로.
  • 못 막는 것: 앵커 — 스캐너는 매니페스트만 본다(런타임 행동은 못 봄); 스킵 남발은 위험을 가린다.

M2 · 신원 (admission CEL)

  • 재구현: 라벨↔SA 일관성 VAP의 CEL, 위조 DENY/정합 ADMIT 5/5.
  • 막는 것: label≠SA 위조(kubectl run --labels app=api → default SA → 거부).
  • 못 막는 것: 앵커 — 자기일관 위조(app:api+api-sa)는 못 막는다 → SA-use 게이트·SPIFFE가 닫는다.

M3 · 네트워크 (Cilium L3/L7/egress)

  • 재구현: default-deny에서 최소권한 홉(web→api→db) + L7, 7/7.
  • 막는 것: 횡이동·우회 경로·egress 비콘/유출(인터넷·메타데이터·apiserver).
  • 못 막는 것: 앵커 — 위치로 신뢰하지 않음이 핵심; 과차단도 결함(가용성).

M4 · 런타임 (Tetragon eBPF)

  • 재구현: data tier 셸 exec만 골라 SIGKILL, id=0 + sh=137 — 선택적 프리미티브(selector 문법).
  • 막는 것: 침해 후(post-exploit) 데이터 티어에서 나이브 셸 실행.
  • 못 막는 것(정직): 앵커 — 선택적 룰은 renamed-binary(/tmp/x sh)·execveat·fd-exec로 우회되고(matchBinaries는 호출자 매칭), 셸 없는 nc/python·다른 tier·노드 루트는 범위 밖. 그래서 shipped 기본은 zero-exec(execve+execveat 전부 Sigkill — id도 137; M8 측정·ADR 0001)이고 M4는 그 출발점이다(ED2/ED3=CONFIGURED/NOT_COVERED).

M5 · 암호화 (전송 + 저장)

  • 재구현: ET1(크로스노드 WireGuard) 채점 + capture-wg/etcd 직접 실행·해석.
  • 막는 것: 노드 간 도청(전송), 디스크/백업 유출(저장 etcd AES-CBC).
  • 못 막는 것: 앵커 — 평문0은 보강 증거지 결정적 아님(캡슐화); 사용 중(in-use) 암호화는 범위 밖.

M6 · 프런티어 (agent-ABAC + ReBAC)

  • 재구현: AI 에이전트 위임을 Cedar 교집합 + ASI08 위임깊이 cap·홉별 클램프·출처 게이트(17/17) + OpenFGA 관계그래프(11/11)로.
  • 막는 것: confused-deputy — 과잉권한 에이전트가 저권한 대행사용자 데이터에 닿는 것.
  • 못 막는 것(정직): 앵커 — 라이브 에이전트 런타임/게이트웨이가 아니라 위임 인가 정책의 단위테스트; 교집합은 비소유 데이터 한정(owner override).

M7 · 형식 검증 (cross-layer, z3)

  • 재구현: Cilium L7 엣지 × Cedar PDP의 교차계층 일관성을 z3 유한도메인 체크로 — SHADOWED(ViewAuditLog: Cedar permit인데 L7이 경로 드롭=죽은 규칙) / UNGATED(L7 도달가능한데 PDP 게이트 부재). 세 입력 모두 진짜 아티팩트에서 유도(cedarpy 실평가·netpol 전사·main.py AST 워크).
  • 막는 것: 어느 단일 층 테스트도 못 잡는 연접 결함 — 특히 UNGATED(라우트가 authorize()를 떨어뜨린 사일런트 인가우회=BOLA의 전제). --ungate-transfer로 발화시켜 exit 1, CI 게이트가 살아있음을 증명.
  • 못 막는 것(정직): 앵커 — 도메인이 action 3개라 z3는 파이썬 컴프리헨션과 바이트 동일(기법 시연이지 unbounded 검증 아님 — 진짜 심볼릭은 cedar-policy-symcc). per-action 일관성만 봄 → L7정규식↔FastAPI 라우트 불일치·context의존 permit(amount=−1)은 범위 밖. SHADOWED는 버그가 아니라 명시화(warning/exit 0); 판정은 사람 몫.

M8 · 런타임 kill 경계 (detection ≠ prevention)

  • 재구현: M4 선택적 셸-kill의 경계를 라이브로 측정verify-runtime-scope로 Phase1 선택적(id=0/sh=137) → Phase2 zero-exec(id=137, 이름·arg0 무관·execveat 포함)의 델타를 보이고 shipped 기본으로 복원. 메트릭은 불변(82.5%): 통제 가감이 아니라 증거를 정직하게 진화.
  • 막는 것: execve+Sigkill은 pre-image-load(셸이 첫 명령 전에 죽음)라 prevention-grade. zero-exec는 데이터 티어의 모든 exec를 두 진입점(sys_execve+sys_execveat) 후킹으로 죽여 renamed-binary·fd-exec까지 닫음.
  • 못 막는 것(정직): 앵커 — write()는 동기 process-kill이어도 커널이 이미 바이트를 씀(detection-grade, prevention엔 Sigkill+Override 필요). io_uring(IORING_OP_READ)은 기본 syscall 정책에 blind — "Tetragon이 우회됐다"가 아니라 LSM/KRSI가 해법. zero-exec는 tier: data 한정(web/api는 정상 exec 있어 NOT_COVERED, 과잉차단도 결함). restart-tolerance는 이미지가 아니라 Tetragon 부착-창 덕(fragile).

M9 · 침해 가정 (블래스트 반경 봉쇄)

  • 재구현: web 파드 제로데이 RCE를 가정하고 grade.sh로 봉쇄 경계를 라이브 측정 — 횡이동(L3 000/L7 403)·유출(egress→인터넷·메타데이터·apiserver 000)·권한상승(SA 권한0 can-i=no)·데이터티어 도달 시 exec 137. 익스플로잇은 안 돌림; probe-web이 web과 동일 Cilium 신원이라 네트워크-정책 등가.
  • 막는 것: 제로데이를 막는 정책은 없다(미지엔 시그니처가 없음) → 현실적 답은 시그니처 없이 작동하는 봉쇄: default-deny·SA 권한0·zero-exec가 기본 금지로 횡이동·유출·권한상승 경로 자체를 닫음. break-and-fix로 egress 한 줄 열면 BREACH로 뒤집힘을 확인.
  • 못 막는 것(정직): 앵커 — 봉쇄는 피해를 줄이지 없애지 않는다. 같은 티어 내부 피해(web이 합법적으로 하는 것), 위조 가능한 데모 X-User(JWT enforce 전), 허용 egress(DNS)의 covert 채널, io_uring 회피, 노드 루트·하이퍼바이저 탈출·공급망은 전부 잔여.

M10 · GitOps 무결성 (reconciler = 새 신원-TCB)

  • 재구현: ArgoCD 아래에서 같은 통제(M2 admission·M3 netpol)를 다른 actor(reconciler)로 다시 측정 — drift를 일부러 내고 자동교정 윈도우를 재고, admission과의 교착(fighting controllers)·reconciler SA 권한 경계를 라이브로 본다. 무클러스터 절반은 항상 CI 게이트(check-reconciler-rbac.py·check-sync-wave-order.py).
  • 막는 것: GitOps는 새 통제를 추가하지 않고 신원-TCB를 이전한다(B7→B8): "누가 파드를 만드나"(RBAC)가 "누가 머지하나 + reconciler SA가 무엇을 적용·사칭할 수 있나"가 된다. drift 자동교정이 수동 변조를 known-good으로 되돌리고, sync-wave 순서가 통제 적용 순서를 강제한다.
  • 못 막는 것(정직): 앵커 — 교정은 탐지 후라 drift 윈도우 동안은 열려 있다(prevention 아님). reconciler SA가 과대권한이면 그 자체가 새 단일 침해점이고, Git 머지 권한·서명되지 않은 매니페스트는 이 랩 밖. GitOps는 무결성·복원이지 런타임 차단이 아니다.

M11 · BPF-LSM exec 허용목록 (적재-이미지 신원)

  • 재구현: M4·M8이 이름만 대고 못 막은 잔여(exec 허용목록)를 실제로 구현 — BPF-LSM bprm_check_security 훅으로 적재되는 이미지(linux_binprm->file)의 신원을 봐서 nginx만 허용, 주입 셸은 Sigkill. 대부분의 kind/Docker 커널엔 lsm=에 bpf가 없어 grade.sh가 정직하게 SKIP(FAIL 아님) — ED3 NOT_COVERED·헤드라인 불변.
  • 막는 것: arg0(matchArgs)는 rename으로 우회되고 matchBinaries는 caller를 봐 거꾸로 작동한다(nginx-RCE 셸은 caller=nginx라 통과). 적재-이미지 신원만이 정직한 허용목록의 유일한 훅 — syscall 표면("어떤 호출이 일어났나")이 아니라 커널 연산("어떤 이미지가 적재되나")을 본다.
  • 못 막는 것(정직): 앵커 — BPF-LSM이 없는 커널(이 repo가 닿는 모든 환경)에선 집행 자체가 불가라 ED3는 라이브 미검증으로 정직히 NOT_COVERED. 정적 채점(grade.py)은 메커니즘이 맞는지만 보지 라이브 차단을 증명하지 않는다 — "정답=메커니즘"의 한계.

한 문단 요약 (이력서/포트폴리오용)

예: "금융 망분리 완화(MLS) 보상통제 스택의 7개 통제(인가·스캔·신원·네트워크·런타임·암호화·에이전트 위임)를 빈 파일에서 직접 재구현하고, 각 repo의 실행 가능한 채점기로 검증했다. 각 통제가 막는 것과 막지 못하는 것을 정직하게 구분할 수 있다." — 네 경험으로 다시 써라.