[CKS] Minimize Microservice Vulnerabilities (7) - Implementing Resource Quotas in Kubernetes

Kubernetes에서 mTLS와 Service Mesh(Istio)를 통해 Pod 간 통신을 암호화하고, Namespace, RBAC, 네트워크 정책으로 멀티 테넌트 환경을 안전하게 격리 및 관리하는 방법을 소개합니다.

[CKS] Minimize Microservice Vulnerabilities (7) - Implementing Resource Quotas in Kubernetes
Photo by Aoi / Unsplash

개요

CKS 자격증을 위해 아래 내용을 정리했습니다.

One way SSL vs Mutual SSL

mTLS와 단방향 SSL을 확인합니다.

One way SSL흐름

단방향은 서버의 진위 여부를 확인하기 위한 이메일, SNS 같은 인터넷 기반 서비스에 사용됩니다.

  1. 서버의 공개 인증서를 확인
  2. CA(인증 기관)이 신뢰할 수 있는지 인증서를 검증
  3. 공개 인증서를 사용하여 대칭키 암호화하여 전송
  4. 서버는 자체 개인 키로 대칭키 복호화해서 사용

최근에는 ECDHE(Diffie-Hellman) 방식으로 세션 키 생성합니다. → 동일한 세션키를 독립적으로 계산

→ 서버 개인 키가 유출되어도 세션 복호화 불가능 (임시 비밀값)

mTLS 흐름

사람이 자격 증명을 입력하지 않습니다. 상호 정당한 요청, 서버인지 검증하는 방식입니다.

  1. 클라이언트가 서버 공개 인증서 요청
  2. 서버는 자신의 인증서 전송 + 클라이언트 인증서 요청
  3. 클라이언트는 CA 공개 키를 사용하여 인증서 검증
  4. 인증된다면 클라이언트는 자신의 인증서 + 공개 키 기반 대칭키 전송
  5. 서버도 CA를 활용하여 클라이언트 인증서 검증

상호 인증이 완료된다면 대칭 키(TLS v1.3 세션키)를 사용하여 통신

특징 단방향 SSL 상호 TLS
인증서 확인 클라이언트는 서버의 인증서만 확인합니다. 클라이언트 및 서버 인증서 모두 검증됩니다.
일반적인 사용 사례 웹 서비스(온라인 뱅킹, 이메일, 소셜 미디어) 자동화된 시스템 간 통신(B2B 데이터 공유)
보안 수준 안전한 통신; 사용자 인증은 별도로 처리됩니다. 상호 인증을 통한 보안 강화

mTLS 기반 Pod간 암호화 구현

Kubernetes로 연결된 수 많은 노드의 파드는 서로 끊임없이 통신합니다.

하지만 파드 간 통신은 암호화되지 않아 민감한 데이터가 노출될 수 있습니다.

mTLS로 파드 간 통신을 인증하고 데이터 유출, 무단 접근 위험을 줄이는 방법을 확인합니다.

Pod 간 mTLS 작동 방식

기본적인 mTLS 동작과 동일합니다.

  1. 인증서 요청: Pod A는 Pod B의 인증서를 요청하여 통신 시작
  2. 인증서 교환: Pod B는 자체 인증서를 응답으로 보내고 동시에 Pod A의 인증서 요청
  3. 인증서 유효성 검사 및 키 교환: Pod A는 Pod B의 인증서를 검증. 자체 공개 인증서와 대칭 암호화 키 전송
  4. 안전한 통신: Pod B가 Pod A의 인증서를 검증하면 이후 모든 통신을 암호화하기 위해 대칭 키 사용

Cluster 전체 암호화 관리하기

수백 개의 파드가 여러 노드에 걸쳐있다면 통신을 관리하기 위한 방법이 필요합니다

MySQL같은 애플리케이션은 내장 암호화를 제공하지만 클러스터 전체에 적용하기 위한 일관성은 부족합니다.

전반에 암호화 통신을 적용하기 위해선 Service Mesh를 사용할 수 있습니다.

mTLS용 Service Mesh

Istio , Linkerd 같은 도구로 네트워크 수준에서 mTLS를 활성화하여 일관된 암호화를 보장할 수 있습니다.

  • 애플리케이션 코드에서 암호화 분리 가능
  • 통신 암호화 정책에 대한 중앙 집중식 관리
  • 이기종 애플리케이션 간 일관된 구성 및 보안 제공

SideCar 기반의 Istio 가 널리 사용되고 있습니다.

Istio 작동 방식

Notion Image

Sidecar로 동작하며 통신을 자동으로 가로채서 암호화하여 전송합니다.

2가지 암호화를 제공합니다.

  • Permissive (Opportunistic) Mode
    • 가능한 경우 트래픽을 암호화
    • 외부 서비스 or mTLS를 지원하지 않는다면 비암호화된 통신을 수행
  • Strict (Enforced) Mode
    • 모든 트래픽은 반드시 mTLS로 구성
    • 보안성이 높지만 모든 서비스가 mTLS를 지원해야함

Multi Tenancy in Kubernetes

Kubernetes에서 멀티 테넌시를 구성하는 방법을 확인합니다.

멀티 테넌시 구성은 격리, 보안, 효율적인 리소스 관리를 보장하며 동일한 인프라를 공유하며 테넌트간의 보안과 무결성을 유지하는데 도움을 줍니다.

이는 특히 SaaS 환경에서 매우 중요합니다.

Kubernetes Tenant

Notion Image
Notion Image

Kubernetes 안티 패턴 중 하나로 애플리케이션 별도의 클러스터를 구성하는 것이 있습니다.

각기 다른 리소스, 보안 정책을 가진 클러스터 여러 개를 관리하는건 상당한 복잡성과 운영 오버헤드를 일으킵니다.

  • 공통 인프라 내 격리된 환경을 구성하는데 집중해야합니다
    • 컴퓨팅, 스토리지, 네트워킹을 효율적이고 안전하게 공유해야하는 클라우드 환경에서 크게 유효합니다.

강력한 격리는 필요합니다. 무단 데이터 접근, 리소스 경합 등으로 시스템의 안정성에 치명적일 수 있습니다.

멀티 테넌트를 구성하긴 매우 어렵습니다.

  • 테넌트간 데이터 유출
  • 테넌트의 리소스 경합 방지
  • 보안 정책, 접근 제어, 리소스 할당 관리부터 규제 요건 준수와 개인정보 보호

하지만 Kubernetes 환경을 사용하면 단일 클러스터를 공유하며 리소스 활용도를 극대화하고 하드웨어 및 운영 비용을 모두 절감할 수 있습니다.

혜택 설명
비용 효율성 별도의 클러스터가 필요 없어지므로 하드웨어 및 운영 비용이 절감됩니다.
향상된 리소스 사용 여러 테넌트 간에 컴퓨팅, 스토리지 및 네트워크 리소스를 더욱 효율적으로 활용할 수 있습니다.
간소화된 관리 중앙 집중식 제어는 운영 관리, 모니터링 및 문제 해결을 간소화합니다.
강력한 보안 네임스페이스, RBAC, 네트워크 정책과 같은 격리 메커니즘은 간섭 및 데이터 유출을 방지합니다.

Kubernetes의 Multi Tenant 유형

Kubernetes의 멀티 테넌트 유형으로 Multi-Team Tenancy , Multi-Customer Tenancy

Multi-Team Tenancy

Notion Image

단일 클러스터 내 팀 혹은 프로젝트 단위로 리소스를 관리하고 격리합니다. 서로 다른 내부 그룹으로 분리되어 공통 인프라를 공유합니다.

  • 역할 기반 접근 제어(RBAC)
  • Namespace 할당량 구성

내부팀 간 공정한 리소스 할당과 보안을 보장하는 것이 중요합니다.

Multi-Customer Tenancy

Notion Image

단일 클러스터 내 여러 외부 고객혹은 클라이언트를 위한 애플리케이션 호스팅해서 분리하는 방식입니다.

엄격한 보안 구성으로 데이터와 애플리케이션 격리해야하는 SaaS에서 구성합니다.

  • 고객이 클러스터에 접근할 수 없도록 GDPR, HIPAA 같은 규제 표준 준수와 보안 프로토콜이 필수

주요 차이점

  • Focus
    • Multi Team → 내부 팀 관리
    • Multi Customer → 외부 고객을 위한 애플리케이션 및 데이터 관리
  • Isolation and Security
    • Kubernetes Namespace 기반 격리
      • Multi Customer는 엄격한 규제 요건을 요구 → 더 높은 보안 조치 + 분리 구성이 필요
  • Access Control
    • kubectl , GitOps Controller 같은 도구로 클러스터 직접 엑세스
    • 외부 고객은 직접 엑세스 불가능하며 클러스터는 백그라운드 실행(Customer 관점)

Kubernetes Namespace, Pod, Node 격리 수준

Notion Image

적절한 리소스 격리가 없다면 파드 간 지나친 간섭이 발생할 수 있습니다.

Namespace로 쿠버네티스 클러스터를 논리적인 섹션으로 나눌 수 있습니다. 이를 통해 각 팀이나 프로젝트가 리소스를 독립적으로 구성, 관리해야합니다.

  • Control Plane Isolation
    • Namespace, RBAC 같은 접근 제어 메커니즘으로 구현
  • Data Plane Isolation
    • 네트워크 정책, 스토리지 격리 및 노드 격리를 통해 관리

Namespace Isolation

Notion Image

건물에 비유하면 쉬운데 층 수를 나누어 팀끼리 간섭하지 않고 공용 인프라를 사용할 수 있게 구성합니다.

Namespace RBAC은 카드 키와 같이 역할, 부서, 회사에 따라 서로 다른 수준의 접근 권한을 부여합니다.

Pod Isolation

Notion Image

파드는 개별 작업 공간과 유사합니다. 공용 도구를 통해 서로 협업하지만 리소스 할당과 관리를 위해 독립적인 리소스를 갖습니다.

Network Isolation

Notion Image

각 팀, 파드 간의 통신을 제한합니다. 허용된 파드만 상호 작용하여 내부 네트워크 보안과 외부 네트워크에 노출을 최소화합니다.

Node Isolation

Notion Image

하나의 층에서 엑세스를 제어하는 것과 유사합니다.

Node가 물리적인 Floor라면 Namespace는 논리적인 Floor를 구성합니다.

Hard Isolation vs. Soft Isolation

Hard Isolation

Notion Image
  • 각 테넌트에게 물리적인 인프라를 전용 제공
    • 컴퓨팅, 스토리지, 네트워킹 리소스를 공유하지 않고 완전히 격리

Soft Isolation

Notion Image
  • 테넌트가 기본 인프라를 공유하며 논리적으로 구별 됨(Namespace)
    • 리소스 할당량 제한으로 단일 테넌트가 리소스를 과도하게 사용할 수 있음.

ControlPlane Isolation

ControlPlane 격리는 Namespace, RBAC, Resource Quotas를 통해 구현됩니다.

Namespace

Namespace로 격리하여 다른 Namespace 간의 리소스와 격리합니다. Namespace 접근 제어는 개별 Namespace 역할 기반 접근 제어, 네트워크 정책을 포함합니다.

kubectl create namespace namespaceA
kubectl create namespace namespaceB

**Authorization and Access Control(**RBAC)

Notion Image

적절한 접근제한으로 팀이나 다른 워크로드에 부적절하게 접근하거나 수정하는 것을 방지합니다.

최소 권한 원칙으로 각 팀이 필요한 Namespace, Resource에만 접근해야합니다.

  • 적절한 Service Account, User Account를 구성하여 역할을 지정합니다.
    • 각 역할은 최소 권한으로 구성됩니다.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: development
  name: developer-role
rules:
  - apiGroups: [""]
    resources: ["pods", "services"]
    verbs: ["get", "list", "watch", "create", "update", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: developer-rolebinding
  namespace: development
subjects:
  - kind: User
    name: pranjal
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: developer-role
  apiGroup: rbac.authorization.k8s.io

Resource Quotas

Kubernetes에서 Pod Resource quota objects 메커니즘을 다시 확인합니다.

CKA에서 정리했던 내용으로 CPU, 메모리 등 제어하는 방법을 확인합니다.

Namespace Reosurce Quotas

apiVersion: v1
kind: ResourceQuota
metadata:
  name: cpu-memory-quota
  namespace: namespace_a
spec:
  hard:
    requests.cpu: "4"
    requests.memory: 16Gi
    limits.cpu: "8"
    limits.memory: 32Gi

Pod Resource Quotas

apiVersion: v1
kind: Pod
metadata:
  name: resource-limited-pod
  namespace: namespace_a
spec:
  containers:
  - name: resource-limited-container
    image: nginx
    resources:
      requests:
        cpu: "250m"
        memory: "64Mi"
      limits:
        cpu: "500m"
        memory: "128Mi"

Data Plane Isolation

네트워크 정책, 스토리지 격리 및 노드 격리를 통해 관리하는 방법을 알아봅니다.

  • 네트워크: Pod 간 트래픽을 제어하여 승인된 통신만 수행
  • 스토리지 격리: 스토리지 무단 엑세스를 방지하여 테넌트간 영향 제거
  • Taints & Tolerations: 허용 조건을 설정하여 부적절한 노드에 실행되는 걸 방지

Data Plane Isolation Network

네트워크 정책을 서술합니다. 파드 간 네트워크 트래픽 흐름을 제어하는 규칙을 설정할 수 있습니다. Namespace가 논리적 격리(이름 구분, 리소스 그룹화)라면 네트워크 정책은 네트워크 트래픽간 명확한 구분을 의미합니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-tenant-a-to-tenant-b
  namespace: tenant_a
spec:
  podSelector:
    matchLabels:
      app: backend
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          tenant: tenant_b
  ports:
  - protocol: TCP
    port: 8080

네트워크 정책을 사용하여 테넌트간 통신을 제어하고 보호합니다.

  • Pod Selector, Namespace Selector
  • Port, Protocol

Data Plane Isolation Storage

고성능, 표준 스토리지에 따라 Storage Class를 분리하는 것을 권장합니다.

각 테넌트가 자기에게 할당된 스토리지 종류만 사용하게 제한합니다.(noisy neighbor)

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: high-performance
provisioner: kubernetes.io/aws-ebs
parameters:
  type: io1                          # AWS io1 disks support high IOPS
  iopsPerGB: "50"                    # Specify high IOPS per GB
  fsType: ext4
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: Immediate
  1. Storage Class 먼저 정의 (관리자가 미리 만들어둠)
  2. PVC 생성 (파드가 필요한 스토리지 요청)
  3. PV 자동 생성 (Storage Class가 PVC를 보고 PV를 동적으로 생성)

Node Pools & TaintsTolerations for Isolation

접근 방식을 설정해 특정 노드를 개별 테넌트에 전용 할당이 가능합니다.

noisy neighbor로 알려진 워크로드 간섭문제를 해결할 수 있습니다.

  • Taints/Tolerations 노드 격리는 특정 테넌트의 예약된 노드에 승인되지 않은 파드 스케줄링 방지

Taints를 적용

  • NoSchedule: taint를 tolerate 하지 못한다면 스케줄링 금지
kubectl taint nodes nodeA customer=customerA:NoSchedule

Toleration

  • Exist: Key 값이 있는 경우 키를 가진 모든 노드 가능. Key가 없다면 모든 노드에 Taints 관계없이 가능
  • Eqaul: Key, Value가 정확한 곳에서만 Taints에서 허용
apiVersion: v1
kind: Pod
metadata:
  name: customer-a-pod
  namespace: customer_a
spec:
  containers:
  - name: customer-a-container
    image: nginx
  tolerations:
  - key: "customer"
    operator: "Equal"
    value: "customerA"
    effect: "NoSchedule"