Kubernetes/Certificates

[CKS] Minimize Microservice Vulnerabilities

Operation CWAL 2021. 5. 3. 23:18

Secret 데이터 암호화

ETCD에 Secret을 저장할 때, API서버에서 Encryption/Decryption을 수행하는 기능에 대해 다룬다. 내용이 꽤 있으므로, 따로 정리해놓은 페이지를 참고하기 바란다.

 

ETCD Encryption

Kubernetes Secret 일반적으로 K8s 환경에서 Password, Access Token와 같이 보안에 민감한 데이터를 Secret 리소스로 관리한다. 다음은 간단한 Secret을 생성하는 예시이다. kubectl create secret generic secre..

cwal.tistory.com

 

Container Runtime Sandbox

Container는 Host와 Kernel을 공유하도록 설계되어있다. 예를 들어, 다음 명령어를 Container에서 수행하는 것과 Host에서 수행할 때의 결과는 동일하다.

uname -r	#현재 커널 버전

문제는 해커가 Pod의 root 권한을 획득했을 때, Host 커널 접근이 가능하다는 점이다. 이를 막기 위해, Pod의 커널을 Host로부터 분리하는 Sandbox가 필요하며, 대표적으로 VM 방식의 Katacontainer 그리고 제한된 system call만 제공하는 gVisor가 있다. CKS 시험은 gVisor를 Container Runtime Sandbox로 사용하는 방법에 대해 알고 있는지 확인한다.

출처 - https://gvisor.dev/docs

gVisor

Container를 위한 사용자 영역 kernel로 다음과 같은 특징을 갖는다.

  • 별도의 레이어를 통해 Kernel과 Container App 분리
  • 하이퍼바이저/VM을 사용하지 않음
  • 제한된 기능의 커널 syscall을 시뮬레이션
  • 사용자 영역(User-space)에서 실행됨
  • OCI 표준을 따르는 컨테이너 런타임 'runsc' 제공

 

자세한 내용은 아래 링크를 참고하기 바란다.

 

What is gVisor?

gVisor is an application kernel, written in Go, that implements a substantial portion of the Linux system call interface. It provides an additional layer of isolation between running applications and the host operating system. gVisor includes an Open Conta

gvisor.dev

 

gVisor를 K8s RuntimeClass로 사용하기 위해선 다음과 같은 설정이 필요하다.

 

1. 모든 Node에 gVisor를 설치한다. CKS 시험환경에선 이미 설치되어 있으니, 생략 가능하다.

2. 아래와 같이 RuntimeClass를 정의한다.

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: gvisor
handler: runsc

3. Pod 정의시, runtimeClassName 항목을 다음과 같이 추가한다.

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  runtimeClassName: gvisor
  # ...

 

 

Runtime Class

FEATURE STATE: Kubernetes v1.20 [stable] This page describes the RuntimeClass resource and runtime selection mechanism. RuntimeClass is a feature for selecting the container runtime configuration. The container runtime configuration is used to run a Pod's

kubernetes.io

 

OS Level Security Domain

Container의 User/Group 설정

UID=1000, GID=3000인 User를 기본으로 사용하는 Pod은 다음과 같이 정의할 수 있다.

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
  containers:
  - name: sec-ctx-demo
    image: busybox
    command: [ "sh", "-c", "sleep 1h" ]

Container 내부에서 다음 명령어를 사용하여, 현재 사용자의 uid와 gid를 확인 가능하다.

id

Container의 Non-Root 강제

Container에서 root user를 사용할 수 없도록, 다음과 같이 정의할 수 있다.

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsNonRoot: true
  containers:
  - name: sec-ctx-demo
    image: busybox
    command: [ "sh", "-c", "sleep 1h" ]

주의할 점으로, Container Image의 기본 사용자가 이미 root로 설정되어 있다면 다음과 같이 Pod을 생성할 수 없다.

Privileged Container

Container 내부에서 root 사용자로 접근하더라도, Host의 root와 동일한 권한은 주어지지 않는다. 예를 들어, 컨테이너 내부에서 시스템 시간이나 hostname을 변경하는 것은 허용하지 않는다. 하지만 다음과 같이 securityContext 항목을 설정하면 Host의 root의 모든 권한을 컨테이너에서 사용 가능하다.

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    privileged: false
  containers:
  - name: sec-ctx-demo
    image: busybox
    command: [ "sh", "-c", "sleep 1h" ]

 

이외에도 자식 프로세스가 부모 프로세스의 권한을 넘어설 수 없게 강제하는 기능도 제공하며, 다음과 같이 설정한다.

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  containers:
  - name: sec-ctx-demo
    image: busybox
    command: [ "sh", "-c", "sleep 1h" ]
    securityContext:
      allowPrivilegeEscalation: false

이 설정이 적용되었는지 확인하기 위해선, 컨테이너 내부에서 'cat /proc/1/status' 명령어 실행 후 'NoNewPrivs' 값이 1인지 보면 된다.

PodSecurityPolicy

PodSecurityPolicy는 API서버의 Admission Controller 중 하나로, 생성 요청이 들어온 Pod의 SecurityContext가 미리 지정한 조건을 준수하는지 확인 후 승인 또는 거부하는 역할을 담당한다.

 

이 기능을 사용하기 위해선, 다음과 같이 설정을 진행한다.

 

1. API 서버 Manifest 파일(/etc/kubernetes/manifests/kube-apiserver.yaml)에 다음 내용을 추가한다.

#...
spec:
  containers:
  - command:
    # ...
    - --enable-admission-plugins=NodeRestriction,PodSecurityPolicy
    # ...
#...

 

2. PodSecurityPolicy 리소스를 추가한다. 아래 예시는 'allowPrivilegeEscalation: true'를 강제하는 정책이다.

apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: default
spec:
  allowPrivilegeEscalation: false
  privileged: false  # Don't allow privileged pods!
  # The rest fills in some required fields.
  seLinux:
    rule: RunAsAny
  supplementalGroups:
    rule: RunAsAny
  runAsUser:
    rule: RunAsAny
  fsGroup:
    rule: RunAsAny
  volumes:
  - '*'

 

3 default 네임스페이스의 기본 ServiceAccount인 'default'가 PodSecurityPolicy 리소스를 사용할 수 있도록 아래와 같이 RBAC을 추가한다.

kubectl create role psp-access --verb=use --resource=podsecuritypolicies
kubectl create rolebinding psp-access --role=psp-access --serviceaccount=default:default

 

위 Policy를 적용하면, 'allowPrivilegeEscalation: true'로 설정된 Pod은 더 이상 'default' 네임스페이스에 생성할 수 없다.

mTLS

출제 영역에 포함된다고 하나, 명확한 예시가 없다. Istio와 같이 별도의 Service Mesh가 없다면 매뉴얼 방식으로 구현하기엔 상당히 까다로울 것으로 예상된다.

그 외엔, Sidecar Proxy에서 iptables 사용을 위해 'NET_ADMIN' capability를 Pod 또는 Container에 추가하는 정도의 문제가 나오지 않을까라는 생각이 든다.

'Kubernetes > Certificates' 카테고리의 다른 글

[CKS] Supply Chain Security  (0) 2021.05.16
[CKS] Runtime Security  (0) 2021.05.08
[CKS] System Hardening  (0) 2021.05.02
[CKS] Cluster Hardening  (0) 2021.05.01
[CKS] Cluster Setup  (0) 2021.04.30