8.4.4 규칙 정의 (Ingress/Egress Rules)

앞서 우리는 네트워크 폴리시(Network Policy)가 Ingress (수신)와 Egress (송신)라는 두 가지 주요 타입으로 나뉘어 파드(Pod)로 들어오거나 나가는 트래픽을 제어한다는 것을 배웠습니다. 이제 한 걸음 더 나아가, 이 Ingress 규칙과 Egress 규칙 내에서 구체적으로 어떤 조건의 트래픽을 허용할 것인지를 어떻게 정의하는지 자세히 살펴보겠습니다. 마치 우리가 방화벽 규칙을 설정할 때, “어떤 출발지에서 오는”, “어떤 목적지로 향하는”, “어떤 서비스 포트를 사용하는” 트래픽을 허용하거나 차단할지를 명시하는 것과 같습니다.

네트워크 폴리시 명세(spec) 내의 ingress (배열) 또는 egress (배열) 필드 아래에는 하나 이상의 규칙(rule) 객체들을 정의할 수 있습니다. 각 규칙 객체는 “이러한 조건을 만족하는 트래픽은 허용한다”는 의미를 가지며, 주로 트래픽의 출발지/목적지를 지정하는 부분(from 또는 to 필드)과 허용할 포트를 지정하는 부분(ports 필드)으로 구성됩니다. 만약 특정 파드에 대해 네트워크 폴리시가 적용되었는데, 들어오거나 나가는 트래픽이 이 규칙들 중 어느 하나에도 해당하지 않는다면, 그 트래픽은 기본적으로 차단됩니다 (단, policyTypes 설정에 따라 해당 방향의 트래픽이 제어 대상일 경우).

이제 이 규칙 정의의 핵심 요소들을 하나씩 자세히 알아보겠습니다.

8.4.4.1 podSelector, namespaceSelector, ipBlock 활용

네트워크 폴리시 규칙에서 가장 중요한 부분 중 하나는 **어떤 네트워크 엔드포인트로부터의 트래픽을 허용할지(ingress 규칙의 from 필드), 또는 어떤 네트워크 엔드포인트로의 트래픽을 허용할지(egress 규칙의 to 필드)**를 명확히 지정하는 것입니다. 쿠버네티스는 이를 위해 podSelector, namespaceSelector, 그리고 ipBlock이라는 세 가지 강력한 메커니즘을 제공합니다. 이들은 서로 조합하여 사용될 수도 있으며 (논리적 OR 관계로 동작), 매우 유연하고 정교한 방식으로 트래픽의 소스 또는 대상을 선택할 수 있게 해줍니다.

  • podSelector (파드 셀렉터):이 필드는 특정 레이블(label)을 가진 파드들을 트래픽의 소스(from 내부) 또는 대상(to 내부)으로 지정할 때 사용됩니다. 레이블 셀렉터 문법을 사용하여 matchLabels (정확히 일치하는 레이블) 또는 matchExpressions (더 복잡한 표현식)를 통해 원하는 파드 그룹을 선택할 수 있습니다.
    • ingress 규칙의 from 필드 내 podSelector: 여기에 정의된 레이블 셀렉터와 일치하는 레이블을 가진 파드들로부터 들어오는 트래픽을 허용합니다. 예를 들어, from: [{podSelector: {matchLabels: {role: frontend}}}] 라고 정의하면, role: frontend 레이블을 가진 파드들로부터 오는 연결만 허용합니다. 이때, 이 podSelector는 해당 네트워크 폴리시가 정의된 동일한 네임스페이스 내의 파드들만을 대상으로 합니다. 다른 네임스페이스의 파드를 지정하려면 namespaceSelector와 함께 사용해야 합니다.
    • egress 규칙의 to 필드 내 podSelector: 여기에 정의된 레이블 셀렉터와 일치하는 레이블을 가진 파드들로 나가는 트래픽을 허용합니다. 예를 들어, to: [{podSelector: {matchLabels: {app: database}}}] 라고 정의하면, app: database 레이블을 가진 파드들로의 연결만 허용합니다. 마찬가지로 동일 네임스페이스 내의 파드를 대상으로 합니다.

    podSelector는 마이크로서비스 아키텍처에서 특정 서비스 간의 통신을 명시적으로 허용하는 데 매우 유용합니다. 예를 들어, “프론트엔드 파드는 백엔드 API 파드하고만 통신할 수 있다”와 같은 규칙을 쉽게 구현할 수 있습니다.

  • namespaceSelector (네임스페이스 셀렉터):이 필드는 특정 레이블을 가진 네임스페이스(Namespace)에 속한 모든 파드들을 트래픽의 소스(from 내부) 또는 대상(to 내부)으로 지정할 때 사용됩니다. podSelector와 마찬가지로 matchLabels 또는 matchExpressions를 사용하여 원하는 네임스페이스 그룹을 선택할 수 있습니다.
    • ingress 규칙의 from 필드 내 namespaceSelector: 여기에 정의된 레이블 셀렉터와 일치하는 레이블을 가진 네임스페이스에 속한 모든 파드들로부터 들어오는 트래픽을 허용합니다. 예를 들어, from: [{namespaceSelector: {matchLabels: {project: monitoring}}}] 라고 정의하면, project: monitoring 레이블을 가진 네임스페이스 내의 모든 파드들로부터 오는 연결을 허용합니다.
    • egress 규칙의 to 필드 내 namespaceSelector: 여기에 정의된 레이블 셀렉터와 일치하는 레이블을 가진 네임스페이스에 속한 모든 파드들로 나가는 트래픽을 허용합니다. 예를 들어, to: [{namespaceSelector: {matchLabels: {environment: shared-services}}}] 라고 정의하면, environment: shared-services 레이블을 가진 네임스페이스 내의 모든 파드들로의 연결을 허용합니다.

    namespaceSelector는 멀티테넌트 환경이나 여러 팀이 공동으로 사용하는 클러스터에서 네임스페이스 단위로 네트워크 격리 및 접근 제어를 설정하는 데 매우 효과적입니다. 예를 들어, “A팀의 네임스페이스는 B팀의 네임스페이스에 있는 특정 서비스에만 접근할 수 있다”와 같은 정책을 구현할 수 있습니다.

    podSelector와 namespaceSelector의 조합:

    from 또는 to 필드 내에서 podSelector와 namespaceSelector를 함께 사용할 수도 있습니다. 이 경우, 지정된 namespaceSelector와 일치하는 네임스페이스에 있으면서, 동시에 지정된 podSelector와 일치하는 레이블을 가진 파드들이 트래픽의 소스 또는 대상이 됩니다. 이는 더 세밀한 접근 제어를 가능하게 합니다. 예를 들어, “모니터링 네임스페이스(namespaceSelector)에 있는 프로메테우스 서버 파드(podSelector)로부터만” 트래픽을 허용하도록 설정할 수 있습니다.

  • ipBlock (IP 블록):이 필드는 특정 IP 주소 범위(CIDR – Classless Inter-Domain Routing 형식) 또는 특정 IP 주소를 트래픽의 소스(from 내부) 또는 대상(to 내부)으로 지정할 때 사용됩니다. 이는 주로 쿠버네티스 클러스터 외부의 네트워크(예: 온프레미스 데이터센터, 다른 VPC, 인터넷상의 특정 IP)와의 통신을 제어하거나, 클러스터 내부의 특정 노드 IP 또는 서비스 IP 대역과의 통신을 명시적으로 허용/차단할 때 유용합니다.
    • ingress 규칙의 from 필드 내 ipBlock: 여기에 정의된 CIDR 범위에서 오는 트래픽을 허용합니다.
      클립보드에 복사
    • egress 규칙의 to 필드 내 ipBlock: 여기에 정의된 CIDR 범위로 나가는 트래픽을 허용합니다.
      클립보드에 복사
      (위 0.0.0.0/0에 대한 except 설정은 “인터넷으로만 나가고, 클러스터 내부 사설망으로는 나가지 못하게” 하는 일반적인 패턴입니다. 단, 클러스터 내부 파드 IP 대역이나 서비스 IP 대역이 이 사설망 범위에 포함된다면 의도치 않게 내부 통신까지 차단될 수 있으므로 주의해야 합니다. 보통은 클러스터 내부 통신은 podSelector나 namespaceSelector로 명시적으로 허용하고, 외부 인터넷 접근은 ipBlock으로 별도 관리하는 것이 좋습니다.)

ipBlock을 사용하면, 예를 들어 “사무실 고정 IP에서만 관리자 파드에 접근 허용” 또는 “애플리케이션 파드가 특정 외부 결제 게이트웨이 API 서버 IP로만 HTTPS 요청 가능”과 같은 정책을 구현할 수 있습니다.

from 또는 to 필드의 동작:

ingress 규칙의 from 배열이나 egress 규칙의 to 배열 내에 여러 개의 항목(예: 여러 개의 podSelector, namespaceSelector, ipBlock 항목)이 정의되어 있다면, 이들은 논리적 OR 관계로 평가됩니다. 즉, 들어오거나 나가는 트래픽이 이 항목들 중 어느 하나라도 만족하면 해당 소스 또는 대상으로 간주되어 규칙의 다음 단계(포트 검사)로 진행됩니다.

만약 from (Ingress 규칙의 경우) 또는 to (Egress 규칙의 경우) 필드가 아예 생략되거나 빈 배열 []로 주어지면, 이는 모든 소스 또는 모든 대상을 의미합니다. 즉, 특정 소스나 대상을 제한하지 않겠다는 뜻입니다. (단, 이 경우에도 ports 필드에 의해 포트 제한은 적용될 수 있습니다.)

8.4.4.2 포트 지정

네트워크 폴리시 규칙에서 트래픽의 출발지/목적지를 지정하는 것만큼이나 중요한 것은 어떤 네트워크 포트를 통해 통신을 허용할 것인지를 명시하는 것입니다. 아무리 신뢰할 수 있는 소스로부터 온 요청이라 할지라도, 예상치 못한 포트로의 접근은 보안 위협이 될 수 있습니다. 따라서 네트워크 폴리시는 ports 필드를 통해 허용할 프로토콜과 포트 번호를 세밀하게 제어할 수 있도록 지원합니다.

ports 필드는 ingress 규칙 또는 egress 규칙의 각 항목(from 또는 to 항목과 같은 레벨) 내에 정의되며, 허용할 포트들의 목록을 배열 형태로 가집니다. 각 포트 항목은 다음과 같은 하위 필드들로 구성됩니다.

  • protocol 필드 (선택 사항):허용할 네트워크 프로토콜을 지정합니다. 유효한 값은 TCP, UDP, SCTP 입니다. 만약 이 필드가 생략되면 기본값으로 TCP가 사용됩니다.
  • port 필드 (필수):허용할 포트 번호를 지정합니다. 이 값은 정수형 포트 번호 (예: 80, 443, 5432) 또는 파드 명세에 정의된 **명명된 포트(named port)**의 이름 (예: http, mysql-port)일 수 있습니다.
    • 정수형 포트 번호: 특정 포트 번호로의 트래픽만 명시적으로 허용합니다.
    • 명명된 포트: 파드 템플릿의 컨테이너 포트 정의 시 name 필드를 사용하여 포트에 이름을 부여할 수 있습니다 (예: name: web-port, containerPort: 8080). 네트워크 폴리시에서 이 web-port라는 이름을 port 필드에 지정하면, 실제 포트 번호가 변경되더라도 폴리시를 수정할 필요 없이 유연하게 대응할 수 있다는 장점이 있습니다.

포트 지정 예시:

다음은 ports 필드를 사용하여 다양한 방식으로 포트를 지정하는 예시입니다.

클립보드에 복사

ports 필드의 동작:

  • 만약 ports 필드가 아예 생략되거나 빈 배열 []로 주어지면, 해당 from 또는 to 조건에 맞는 소스/대상과의 모든 포트 및 모든 프로토콜에 대한 통신이 허용됩니다. 이는 매우 관대한 설정이므로, 정말로 모든 포트를 열어두어야 하는 경우가 아니라면 필요한 포트만 명시적으로 지정하는 것이 보안상 권장됩니다.
  • 만약 ports 필드가 정의되어 있지만, 들어오거나 나가는 트래픽이 해당 ports 목록에 명시된 프로토콜과 포트 조합과 일치하지 않는다면, 그 트래픽은 차단됩니다 (해당 from/to 조건은 만족했더라도).

이처럼 네트워크 폴리시 규칙 내에서 podSelector, namespaceSelector, ipBlock을 조합하여 트래픽의 소스/대상을 정교하게 선택하고, ports 필드를 통해 허용할 프로토콜과 포트를 명확히 지정함으로써, 우리는 쿠버네티스 클러스터 내에서 매우 세밀하고 강력한 네트워크 접근 제어 정책을 구현할 수 있습니다. 이는 “최소 권한의 원칙”을 네트워크 레벨에서 실현하고, 애플리케이션의 보안 경계를 효과적으로 방어하는 데 핵심적인 역할을 합니다.