Security - NetworkPolicy

2026. 1. 2. 20:27·CKA

이 글은 Kubernetes에서 NetworkPolicy(네트워크 정책) 를 설계/적용하기 위해 필요한 흐름을 “기본 개념 → 최소 요구사항 정의 → 정책 작성(deny-by-default + allowlist) → 네임스페이스/IP 확장 → egress 확장 → 규칙 조합(AND/OR) 주의점 → 적용/검증” 순서로 정리합니다.


1) Ingress / Egress: “요청 방향”만 보면 된다

3티어 예시로 시작합니다.

  • 사용자 → Web 서버(80)
  • Web 서버 → API 서버(5000)
  • API 서버 → DB 서버(3306)

여기서 Ingress/Egress는 ‘해당 컴포넌트 기준으로 요청이 들어오고 나가는 방향’ 입니다.

  • Web 서버 관점
    • 사용자 → Web(80) : Ingress
    • Web → API(5000) : Egress
  • API 서버 관점
    • Web → API(5000) : Ingress
    • API → DB(3306) : Egress
  • DB 서버 관점
    • API → DB(3306) : Ingress

중요한 포인트:

  • 정책 설계 시에는 “요청이 시작되는 방향(실선)”을 기준으로 생각합니다.
  • 응답 트래픽(점선)은 보통 별도로 신경 쓰지 않습니다. (대부분의 CNI 구현에서 연결 추적 기반으로 응답은 자동 허용되는 형태로 동작)

2) Kubernetes 기본 네트워킹 전제: Pod 간 통신은 기본 허용(allow-all)

Kubernetes는 일반적으로 클러스터 내부 Pod/Service 간 통신이 기본적으로 가능한 네트워크 모델을 전제로 합니다.

그래서 정책을 만들지 않으면 보통:

  • Web Pod → DB Pod 직접 통신도 가능
  • “원래 막고 싶었던” 경로가 열려있는 상태가 됩니다.

3) NetworkPolicy가 필요한 상황: “DB는 API만 허용” 같은 요구사항

이제 심화 요구사항을 명확히 잡아봅니다.

요구사항(정확히)

  • 목표: DB Pod 보호
  • DB Pod의 3306 포트는 API Pod에서 오는 트래픽만 허용
  • 그 외(Web Pod 포함) 어떤 Pod도 DB:3306에 접근 못 하게 차단

범위 정리(중요)

  • Web Pod나 API Pod의 다른 포트, 외부 트래픽 등은 “이번 요구사항에서는 신경 쓰지 않는다”라고 가정
  • 즉, 핵심은 DB Pod 인그레스(3306)만 통제입니다.

4) 첫 단계: “DB Pod에 대한 기본 차단”부터 만든다

NetworkPolicy는 “방화벽처럼” 동작시키려면 보통 deny-by-default 를 먼저 만들고, 그 다음 allowlist를 추가합니다.

4.1 DB Pod에 레이블 부여

DB Pod가 role=db 라벨을 갖도록 합니다.

kubectl label pod db-pod role=db

API Pod에도 라벨을 붙입니다.

kubectl label pod api-pod role=api

4.2 DB Pod에 대해 Ingress 기본 차단(deny) 만들기

policyTypes: [Ingress]를 선언하고, ingress: []로 비워두면 “인그레스 전부 차단” 효과를 만들 수 있습니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-policy-deny-ingress
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  ingress: []

이 시점에 DB Pod는:

  • 어디서든 들어오는 연결이 차단됩니다(= DB 접근이 전부 막힘)
  • ingress: [] 는 비어있으므로 전부 차단이며 아래는 허용을 해주는 하나의 정책이 있는것이라 전부 허용을 의미
    ingress:
    - {} 

5) 두 번째 단계: “API Pod만 DB:3306 인그레스 허용” 규칙 추가

이제 요구사항을 만족시키기 위한 allow 규칙을 넣습니다.

핵심은 DB Pod 관점:

  • API Pod에서 DB로 들어오는 트래픽(Ingress) 만 열면 됩니다.
  • 응답 트래픽을 위해 별도의 룰은 보통 필요 없습니다.

5.1 최종 형태(deny-by-default + allow API on 3306)

아래 정책 하나로도 “선택된 DB Pod의 인그레스는 allowlist만 허용”이 됩니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: api
    ports:
    - protocol: TCP
      port: 3306

이제 DB Pod는:

  • role=api 라벨을 가진 Pod에서 오는 TCP/3306만 허용
  • Web Pod(예: role=web)에서 DB로 직접 붙는 트래픽은 차단

6) 네임스페이스가 여러 개면? namespaceSelector로 “특정 네임스페이스의 API만 허용”

문제 상황:

  • dev/test/prod 네임스페이스가 있고
  • 각 네임스페이스에 role=api Pod가 존재
  • 지금 정책은 “같은 네임스페이스(default) 내 role=api”만 매칭하지만, 설계에 따라 “네임스페이스 경계도 포함해서” 명확히 하고 싶을 수 있습니다.

요구사항 예:

  • prod 네임스페이스의 API Pod만 DB에 접근 허용

6.1 먼저 네임스페이스에 라벨을 붙인다

예: prod 네임스페이스에 env=prod

kubectl label namespace prod env=prod

6.2 podSelector + namespaceSelector를 함께 사용(AND)

같은 from 항목 안에 podSelector와 namespaceSelector를 같이 넣으면 둘 다 만족해야(AND) 허용됩니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-policy-prod-api-only
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes: ["Ingress"]
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: api
      namespaceSelector:
        matchLabels:
          env: prod
    ports:
    - protocol: TCP
      port: 3306

이 의미는:

  • env=prod 네임스페이스 안에 있으면서
  • role=api 라벨인 Pod만
  • DB:3306 인그레스 허용

6.3 namespaceSelector만 있고 podSelector가 없으면?

from에 namespaceSelector만 두면:

  • 해당 네임스페이스의 모든 Pod가 DB로 접근 가능해집니다.

7) 클러스터 외부(백업 서버 등)에서 DB 접근을 허용하려면? ipBlock 사용

상황:

  • 쿠버네티스 클러스터 외부에 백업 서버가 있고
  • 이 서버가 DB Pod에 접근해야 함
  • 이 서버는 Pod가 아니므로 podSelector/namespaceSelector로 표현 불가

이때는 ipBlock을 사용합니다.

예: 백업 서버 IP가 192.168.5.1 이면:

ingress:
- from:
  - ipBlock:
      cidr: 192.168.5.1/32
  ports:
  - protocol: TCP
    port: 3306

ipBlock.cidr는 범위를 지정할 수 있고, 필요하면 except로 일부 IP를 제외할 수도 있습니다.


8) 규칙 조합에서 가장 많이 실수하는 부분: AND / OR, 그리고 “대시(-)” 위치

NetworkPolicy는 “YAML 리스트 구조” 때문에 작은 차이가 의미를 크게 바꿉니다.

8.1 OR 동작(여러 from 항목)

from 아래에 -가 여러 개면 OR 입니다.

from:
- podSelector: { ... }   # 조건 A
- ipBlock: { ... }       # 조건 B

→ A 또는 B면 허용

8.2 AND 동작(한 항목 안에 selector를 같이 넣는 경우)

한 - 항목 안에 podSelector와 namespaceSelector를 같이 넣으면 AND 입니다.

from:
- podSelector: { ... }
  namespaceSelector: { ... }

→ podSelector도 맞고 namespaceSelector도 맞아야 허용

8.3 “대시(-)를 하나 더 쳤을 뿐인데” 정책이 완전히 달라지는 예

아래처럼 분리하면 두 개가 별도 규칙(OR)이 됩니다.

from:
- podSelector:
    matchLabels:
      role: api
- namespaceSelector:
    matchLabels:
      env: prod

이 경우 의미는:

  • role=api 인 Pod(네임스페이스 무관)도 허용될 수 있고
  • env=prod 네임스페이스의 모든 Pod도 허용될 수 있음

요구사항이 “prod의 api만”이었다면 완전히 다른 결과가 됩니다.


9) Egress까지 필요해지는 순간: “DB가 외부 백업 서버로 Push”해야 한다면

지금까지는 DB Pod로 “들어오는 것(ingress)”만 다뤘습니다.
하지만 DB Pod가 외부로 나가는 트래픽이 필요한 경우가 있습니다.

예:

  • DB Pod 안에 백업 에이전트가 있어서
  • 백업 서버로 데이터를 푸시(egress) 한다

이때는 Egress 정책이 필요합니다.

9.1 egress를 정책 타입에 추가하고 egress 규칙 정의

예: DB Pod가 192.168.5.1 백업 서버의 80 포트로 나가는 것을 허용

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-policy-with-egress
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes: ["Ingress", "Egress"]
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: api
    ports:
    - protocol: TCP
      port: 3306

  egress:
  - to:
    - ipBlock:
        cidr: 192.168.5.1/32
    ports:
    - protocol: TCP
      port: 80

주의:

  • policyTypes에 Egress를 넣는 순간, 해당 Pod는 egress도 “allowlist 기반”으로 바뀌는 형태가 될 수 있습니다.
  • 실무에서는 DNS(53) 같은 기본 통신이 막혀 장애가 나기도 하므로, egress 차단을 시작할 땐 “필수 목적지(DNS 등)”도 같이 열어줘야 합니다.

10) 적용/확인 커맨드

정책 적용:

kubectl apply -f db-policy.yaml
kubectl get netpol -n default
kubectl describe netpol db-policy -n default

접속 테스트(예시):

  • Web Pod에서 DB로 접속 시도 → 실패해야 정상
  • API Pod에서 DB로 접속 시도 → 성공해야 정상

(테스트 도구는 환경에 따라 nc, curl, mysql 클라이언트 등 사용)


11) 마지막으로 꼭 기억할 것: “CNI가 NetworkPolicy를 집행해야 실제로 막힌다”

NetworkPolicy 오브젝트는 Kubernetes API에 “생성”할 수 있지만,
실제 패킷 차단/허용(enforcement)은 CNI 플러그인 구현이 지원해야 동작합니다.

  • 정책을 만들었는데도 전혀 막히지 않으면: CNI가 NetworkPolicy를 지원하는지 먼저 확인합니다.

요약

  • Ingress/Egress는 “요청 방향” 관점으로 이해하면 설계가 쉬워진다.
  • Kubernetes 기본은 allow-all에 가까워서, DB 같은 핵심 컴포넌트는 NetworkPolicy로 보호해야 한다.
  • 추천 접근:
    1. DB Pod를 selector로 고른다
    2. Ingress/Egress를 deny-by-default로 만든다(필요한 방향만)
    3. API Pod만 3306 허용 같은 allowlist 규칙을 추가한다
  • podSelector, namespaceSelector, ipBlock을 조합할 때 AND/OR와 “대시(-) 위치”가 의미를 크게 바꾼다.
  • Egress가 필요하면 policyTypes에 Egress를 추가하고 egress.to 규칙을 설계한다.
  • CNI가 NetworkPolicy enforcement를 지원해야 실제로 적용된다.

 

 

Practice Test: https://uklabs.kodekloud.com/topic/practice-test-network-policies-2/

'CKA' 카테고리의 다른 글

Security - Custom Resource Definition  (0) 2026.01.02
Security - Context & 네임스페이스 전환을 빠르게 하는 도구  (0) 2026.01.02
Security - 도커 보안 기초 + 쿠버네티스의 Security Context  (0) 2026.01.02
Security - Secret of Docker Registry  (0) 2026.01.02
Security - Service Account  (0) 2026.01.02
'CKA' 카테고리의 다른 글
  • Security - Custom Resource Definition
  • Security - Context & 네임스페이스 전환을 빠르게 하는 도구
  • Security - 도커 보안 기초 + 쿠버네티스의 Security Context
  • Security - Secret of Docker Registry
5jyan5
5jyan5
  • 5jyan5
    jyan
    5jyan5
  • 전체
    오늘
    어제
    • 분류 전체보기 (243)
      • 김영한의 스프링 핵심 원리(기본편) (8)
      • 김영한의 스프링 핵심 원리 - 고급편 (11)
      • 김영한의 스프링 MVC 1편 (1)
      • 김영한의 스프링 DB 1편 (3)
      • 김영한의 스프링 MVC 2편 (3)
      • 김영한의 ORM 표준 JPA 프로그래밍(기본편) (9)
      • 김영한의 스프링 부트와 JPA 활용2 (2)
      • 김영한의 실전 자바 - 중급 1편 (1)
      • 김영한의 실전 자바 - 고급 1편 (9)
      • 김영한의 실전 자바 - 고급 2편 (9)
      • Readable Code: 읽기 좋은 코드를 작성.. (2)
      • 김영한의 실전 자바 - 고급 3편 (9)
      • CKA (119)
      • 개발 (37)
      • 경제 (4)
      • 리뷰 (1)
      • 정보 (2)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      빈 후처리기
      락
      hibernate5module
      reentarantlock
      양방향 맵핑
      Thread
      WAS
      버퍼
      Target
      김영한
      @args
      고급
      jdk 동적 프록시
      프록시
      gesingleresult
      @within
      조회 성능 최적화
      프록시 팩토리
      typequery
      @discriminatorvalue
      페치 조인
      스레드
      log trace
      jpq
      자바
      @discriminatorcolumn
      requset scope
      단방향 맵핑
      cglib
      JPQL
    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.2
    5jyan5
    Security - NetworkPolicy
    상단으로

    티스토리툴바