LabHub

KCSA — 쿠버네티스 보안 어소시에이트 · 클라우드 네이티브 보안 개요 · 이론

4C — 바깥 계층은 안쪽 계층을 구해 주지 못한다

LabHub 에서 이어서 보기

한 줄 요약

Cloud → Cluster → Container → Code. 이 네 겹은 바깥이 안쪽을 감싸지만 대신해 주지는 않습니다.
클라우드 방화벽이 완벽해도 코드에 인가 검사가 없으면 정상 사용자가 남의 데이터를 봅니다.

왜 이게 필요했나

"보안을 강화하자"는 말은 아무 방향도 가리키지 않습니다. 방화벽을 더 조일지, RBAC 을 손볼지,
이미지를 스캔할지, 코드 리뷰를 늘릴지 — 전부 보안이지만 막는 위협이 완전히 다릅니다.

4C 모델은 이 혼란을 정리합니다. 각 계층이 무엇을 막을 수 있고 무엇은 원리적으로 못 막는지
분명히 해 주기 때문입니다.

어떻게 동작하나

네 겹과 각자의 관할

| 계층 | 통제 수단 | 여기서 막을 수 있는 것 | 여기서는 못 막는 것 |
| --- | --- | --- | --- |
| Cloud/인프라 | 네트워크 경계, IAM, 노드 OS, 물리 보안 | 인터넷에서 apiserver·etcd 로 직접 붙는 것 | 정당한 자격증명을 가진 내부자 |
| Cluster | 인증/인가(RBAC), 어드미션, 네트워크 정책, 감사 로그 | 권한 없는 API 호출, 위험한 파드 스펙 | 권한 안에서 벌어지는 오남용 |
| Container | 이미지 출처·스캔, 최소 권한 실행, 읽기 전용 루트 | 취약한 베이스 이미지, 루트 실행 | 애플리케이션 로직 결함 |
| Code | 인가 검사, 입력 검증, 시크릿 취급, 의존성 관리 | IDOR, 인젝션, 하드코딩된 키 | 위 계층의 설정 실수 |

왜 바깥이 안쪽을 못 구하나

세 가지 이유입니다.

첫째, 바깥 계층은 요청의 의미를 모릅니다. 클라우드 방화벽은 "누가 어디로 TCP 를 열었나"까지만
봅니다. 정당한 로그인 사용자가 GET /v1/orders/10422 를 호출하는 것이 자기 주문인지 남의 주문인지
방화벽은 판단할 근거가 없습니다. 그 판단에 필요한 정보는 데이터베이스에 있기 때문입니다.

둘째, 안쪽 계층의 결함은 바깥 계층에서 정상 트래픽으로 보입니다. IDOR 공격의 요청은 인증도
통과하고 응답 코드도 200 입니다. 실패한 요청이 하나도 없으니 알람도 울리지 않습니다.

셋째, 계층은 서로의 가정에 기대고 있습니다. 컨테이너를 아무리 최소 권한으로 돌려도 노드가
장악되면 그 노드의 모든 컨테이너가 함께 넘어갑니다. 반대로 노드가 튼튼해도 코드가 자격증명을
로그로 덤프하면 그 값은 로그 인덱스로 흘러갑니다.

그래서 어떻게 쓰는가

4C 는 "다 하자"가 아니라 "이 위협은 어느 계층에서 막아야 가장 싸고 확실한가" 를 묻는 도구입니다.

현장에서 만나는 모습

저자의 홈랩에서 4C 의 계층 의존성이 그대로 드러난 사건이 있었습니다.
DHCP 갱신으로 컨트롤 플레인 노드의 IP 가 .111 에서 .120 으로 바뀌자 클러스터 전체가 멈췄습니다.
IP 주소 할당이라는 Cloud/인프라 계층의 사건 하나가 Cluster 계층을 통째로 무력화한 것입니다.

더 정확히 말하면 인증서가 문제였습니다. apiserver.crt 의 Subject Alternative Name 에 .111
있고 .120 이 없었습니다. TLS 신뢰가 IP 에 묶여 있었기 때문에, **인프라 계층에서 주소 하나가
바뀐 것이 클러스터 계층의 신원 체계를 깨뜨렸습니다.**

같은 클러스터를 7 노드로 키운 뒤에도 비슷한 교훈이 나왔습니다. etcd 멤버 3 개로 쿼럼을 확보했지만
controlPlaneEndpoint 가 cp-1 의 물리 IP 로 박혀 있어서, cp-1 이 죽으면 데이터는 안전한데
아무도 접속할 수 없었습니다. "데이터 가용성과 접근 가용성은 별개" — 이것도 계층이 서로를
대신해 주지 못한다는 같은 이야기입니다.

이어서 읽을 것

이어지는 읽을거리에서 각 계층의 공격 표면을 구체적인 진입점 목록으로 펼칩니다.
다음 모듈부터는 Cluster 계층으로 내려가 apiserver·etcd·kubelet 을 하나씩 뜯어봅니다.