이번에 쿠버네티스 스터디의 마지막 5장의 내용을 작성해보고자한다.
보안에는 다양한 툴들이 등장하고 있는데 특히 이번에 배운 polaris라는 오픈소스를 처음 접하고 많은 관심이 생겨서 이 부분에 대해서 좀 더 자세히 적어보고자 한다.
1. Polaris란 무엇인가
polaris는 쿠버네티스 클러스터의 구성 및 보안 설정과 관련된 문제를 자동을 검사하고 보고서를 생성하는 오픈소스 툴이다. 다양한 검사 항목과 보안 권장 사항을 지원해서 운영자가 좀 더 손쉽고 정확하게 보안 진단을 할 수 있다.
- 깃허브 : (https://github.com/FairwindsOps/polaris/tree/v5.0.1)
- DOCS : (https://polaris.docs.fairwinds.com/)
2. Polaris의 기능
polaris를 동작시키는 방법은 총 3가지가 있다.
첫째는 대시보드를 통한 방식이다. 가장 가시적이고 가장 간편하기 때문에 초보가 사용하기 좋고 기본적으로 운영자가 운영상태 보고서를 받는 느낌으로 사용할 수 있다.
둘째는 adminssion controller를 활용하는 방식이다. 컨트롤러를 통해 작동하기 때문에 정해진 룰에 따른 자동화가 가능하다.
셋째는 CLI를 활용하는 방식이다. 좀 더 전문가용으로 로컬 YAML 파일과 같은 작업을 좀 더 빠르고 대규모로 적용이 가능하다.
3. Polaris 설치
3.1 대시보드 형
3.1.1 설치
helm을 통해서 polaris 대시보드를 설치해보자.
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm upgrade --install polaris fairwinds-stable/polaris --namespace polaris --create-namespace
kubectl port-forward --namespace polaris svc/polaris-dashboard 8080:80
3.1.2 Overview
설치한 대시보드에 접속하면 아래와 같은 페이지가 나오는데, 한눈에 아주 잘 보이고 깔끔한 UI가 등장한다.
현재 페이지는 cluster에 대한 overview로 warning checks와 Dangerous Checks를 기준으로 심각도를 확인할 수 있는데 warning은 경고 수준이지만 Dangerous의 경우는 되도록 조치를 반드시 해야한다.
3.1.3 Categories
Categories 색션에서는 아래 3가지 섹션에 대해서 표시한다.
Result by Catagory
- Efficiency (효율성) : 쿠버네티스 클러스터의 워크로드에 대한 리소스 요청 및 제한에 대한 구성으로 CPU나 메모리에 대한 요청이나 제한 값에 대한 부분을 확인한다. 특히 쿠버네티스 클러스터의 경우 많은 자원이 컨테이너로 가상화 동작하기 때문에 적당한 조율이 반드시 필요하다.
https://polaris.docs.fairwinds.com/checks/efficiency/
- Reliability (신뢰성) : 워크로드가 항상 사용 가능하고 올바른 이미지를 실행하는지 확인하는 지표이다.
https://polaris.docs.fairwinds.com/checks/reliability/
- Security (보안성) : 엑세스 수준 제한 등 기본적인 보안 검토하는 지표이다.
https://polaris.docs.fairwinds.com/checks/security/
3.1.4 filter
대시보드에서는 Namespace 필터를 통해서 조금 더 간편하게 클러스터에 대한 지표를 확인할 수 있다.
대부분 회사에서 네임스페이스를 통해서 서비스 부서 혹은 애플리케이션을 구분하고 있기 때문에 네임스페이스를 통해서 나눠주는 것은 상당히 쉽게 파악할 수 있도록 도와준다.
3.2 Admission Controller 활용하기
3.2.1 설치
명확한 설치를 위해서는 CA 인증서가 필요하다. helm의 set옵션을 통해서 여러가지 변형이 가능하다.
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm upgrade --install polaris fairwinds-stable/polaris --namespace polaris --create-namespace \
--set webhook.enable=true --set dashboard.enable=true
3.2.2 특징
취약했던 mario.yaml을 실행하려고 했더니, polaris가 막으면서 Danger의 내용을 표시하였다.
이미지 태그 없음, privilege escalation 없음을 해결하거나 허가하고 싶으면 웹훅을 통해 허가하라는 내용을 이야기한다.
즉, 워크로드에서 취약한 yaml이 발견되면 일단 STOP을 시켜주는 것이다.
다만, 취약의 조건은 현재는 Danger부분만 해당된다.
kubectl apply -f mario.yaml
service/mario created
Error from server (
Polaris prevented this deployment due to configuration problems:
- Container mario: Image tag should be specified
- Container mario: Privilege escalation should not be allowed
): error when creating "mario.yaml": admission webhook "polaris.fairwinds.com" denied the request:
Polaris prevented this deployment due to configuration problems:
- Container mario: Image tag should be specified
- Container mario: Privilege escalation should not be allowed
3.3 Polaris CLI 활용하기
CLI의 경우 쿠버네티스 매니페스트 파일을 감시하는데 사용된다. CI/CD에서도 적용할 수 있는데 yaml파일에 대한 검사 결과에서 polaris 점수가 설정 값보다 못미치거나 Dangerous Check가 발생하는 경우 CI/CD를 중단시킬 수 있다.
3.3.1 설치(리눅스 기준)
wget https://github.com/FairwindsOps/polaris/releases/download/7.4.1/polaris_linux_amd64.tar.gz
tar -zxvf polaris_linux_amd64.tar.gz
mv polaris /usr/local/bin/
3.3.2 audit
이런식의 audit 명령어를 통해서 현재 경로에 있는 yaml 파일을 점검할 수 있다.
polaris audit --audit-path . --format=pretty
예를들어 지금 마리오 게임을 배포하는 yaml이 있는데 이것을 검사해보자.
apiVersion: apps/v1
kind: Deployment
metadata:
name: mario
labels:
app: mario
spec:
replicas: 1
selector:
matchLabels:
app: mario
template:
metadata:
labels:
app: mario
spec:
containers:
- name: mario
image: pengbai/docker-supermario
---
apiVersion: v1
kind: Service
metadata:
name: mario
spec:
selector:
app: mario
ports:
- port: 80
protocol: TCP
targetPort: 8080
type: LoadBalancer
검사결과를 다음과 같이 정말 예쁘게 표현해준다. 총 점수는 43점인데, Danger 한 것들을 좀 살펴볼 필요가 있다.
Polaris audited Path ./ at 2023-04-09T08:15:43+09:00
Nodes: 0 | Namespaces: 0 | Controllers: 1
Final score: 43
Deployment mario
deploymentMissingReplicas 😬 Warning
Reliability - Only one replica is scheduled
hostIPCSet 🎉 Success
Security - Host IPC is not configured
hostNetworkSet 🎉 Success
Security - Host network is not configured
hostPIDSet 🎉 Success
Security - Host PID is not configured
topologySpreadConstraint 😬 Warning
Reliability - Pod should be configured with a valid topology spread constraint
Container mario
linuxHardening 😬 Warning
Security - Use one of AppArmor, Seccomp, SELinux, or dropping Linux Capabilities to restrict containers using unwanted privileges
memoryLimitsMissing 😬 Warning
Efficiency - Memory limits should be set
tagNotSpecified ❌ Danger
Reliability - Image tag should be specified
pullPolicyNotAlways 😬 Warning
Reliability - Image pull policy should be "Always"
readinessProbeMissing 😬 Warning
Reliability - Readiness probe should be configured
sensitiveContainerEnvVar 🎉 Success
Security - The container does not set potentially sensitive environment variables
runAsRootAllowed ❌ Danger
Security - Should not be allowed to run as root
cpuLimitsMissing 😬 Warning
Efficiency - CPU limits should be set
hostPortSet 🎉 Success
Security - Host port is not configured
memoryRequestsMissing 😬 Warning
Efficiency - Memory requests should be set
livenessProbeMissing 😬 Warning
Reliability - Liveness probe should be configured
notReadOnlyRootFilesystem 😬 Warning
Security - Filesystem should be read only
privilegeEscalationAllowed ❌ Danger
Security - Privilege escalation should not be allowed
runAsPrivileged 🎉 Success
Security - Not running as privileged
cpuRequestsMissing 😬 Warning
Efficiency - CPU requests should be set
dangerousCapabilities 🎉 Success
Security - Container does not have any dangerous capabilities
insecureCapabilities 😬 Warning
Security - Container should not have insecure capabilities
Service mario
성공한 것을 제외하고 경고,위험만 보고싶다면 아래 명령어도 가능하다.
polaris audit --audit-path . --format=pretty --only-show-failed-tests
여기서 특히 위험한 Danger 부분만 해결해보자.
1. tagNotSpecified
해당 위험은 컨테이너의 이미지의 버전이 명시되지 않은 경우이다. 이 경우 대부분 latest 이미지를 다운받게 되는데, 이 이미지가 취약점이 발견되거나 혹은 잘못 업로드 되는 순간 문제가 발생할 수 있기 때문에 특정 버전을 명시할 것을 권고하고 있다.
따라서 기존의 docker-supermario에서 docker-supermario:v1.2.0 이라는 임의의 버전을 붙였다.
(아쉽지만 이 이미지가 실제로는 latest버전만 존재하기 때문에.. 실습을 위해서 임의의 버전을 적었다.)
spec:
containers:
- name: mario
image: pengbai/docker-supermario:v1.2.0
2. runAsRootAllowed
이 위험은 컨테이너가 루트로 동작하는 것을 말하는데, 대부분의 컨테이너는 정해진 루틴대로만 진행하기 때문에 루트 권한이 필요없다. 루트 권한을 악의적인 사용자가 탈취하여 사용할 경우 해당 컨테이너를 통해 다른 컨테이너에 잘못된 명령을 실행하거나 클러스터 혹은 그 서비스 자체의 장애를 유발할 수 있기 때문에 위험하다. 따라서 spec.containers.securityContext를 추가하여 runAsNonRoot를 true로 설정하여 root 권한으로 동작하지 않도록 제한한다.
securityContext:
runAsNonRoot: true
3. allowPrivilegeEscalation
이 위험은 권한 상승에 대한 내용을 제한하는 것으로 위의 runAsNonRoot 형태와 비슷하게 작성한다.
securityContext:
allowPrivilegeEscalation: false
이렇게 하면 권한 점수가 일정부분 상승한 것을 확인할 수 있다. 하지만 그렇게 높진 않다. warning이 많다보니.
그래도 Danger부분은 제거됨을 확인할 수 있다.
Polaris audited Path . at 2023-04-09T08:40:00+09:00
Nodes: 0 | Namespaces: 0 | Controllers: 1
Final score: 56
Deployment mario
deploymentMissingReplicas 😬 Warning
Reliability - Only one replica is scheduled
topologySpreadConstraint 😬 Warning
Reliability - Pod should be configured with a valid topology spread constraint
Container mario
cpuRequestsMissing 😬 Warning
Efficiency - CPU requests should be set
livenessProbeMissing 😬 Warning
Reliability - Liveness probe should be configured
memoryRequestsMissing 😬 Warning
Efficiency - Memory requests should be set
readinessProbeMissing 😬 Warning
Reliability - Readiness probe should be configured
linuxHardening 😬 Warning
Security - Use one of AppArmor, Seccomp, SELinux, or dropping Linux Capabilities to restrict containers using unwanted privileges
notReadOnlyRootFilesystem 😬 Warning
Security - Filesystem should be read only
insecureCapabilities 😬 Warning
Security - Container should not have insecure capabilities
memoryLimitsMissing 😬 Warning
Efficiency - Memory limits should be set
cpuLimitsMissing 😬 Warning
Efficiency - CPU limits should be set
pullPolicyNotAlways 😬 Warning
Reliability - Image pull policy should be "Always"
3.3.3 CLI 커스터마이징
저렇게 모든 정보 출력 필요없이 사내에서 딱 필요한 정보들만 확인하고, 필터를 걸고자 한다면 아래와 같이 checks 에 대한 항목과 그 수준을 나열하면 된다.
checks:
tagNotSpecified: ignore
runAsRootAllowed: danger
pullPolicyNotAlways: warning
--config 옵션을 통해서 위의 내용을 적용해보자.
polaris audit --audit-path . --config config.yaml --format pretty
출력값은 다음과 같은데, tag에 대한내용은 ignore되어 표시되지 않고, runAsRootAllowed, pullpolicyNotAlways만 식별해서 표시하였다.
Polaris audited Path . at 2023-04-09T09:26:41+09:00
Nodes: 0 | Namespaces: 0 | Controllers: 1
Final score: 0
Deployment mario
Container mario
pullPolicyNotAlways 😬 Warning
Reliability - Image pull policy should be "Always"
runAsRootAllowed ❌ Danger
Security - Should not be allowed to run as root
Service mario
이상으로 polaris를 사용해보았는데, 실제로 현업에서 적용하기 좋은 가시적인 부분이 많아서 좋았다.
특히 대시보드를 통해서 전반적인 운영관리를 한눈에 파악하고, CLI를 통해 적용될 yaml에 대한 검사를 수행해 운영에 쉽게 적용가능하고 도움도 많이 될 것으로 생각된다.