본문 바로가기
Kubernetes/PKOS

[5주차-1] 쿠버네티스 클러스터에 Polaris 적용하기

by isn`t 2023. 4. 8.

*본 게시글의 내용은 개인 학습내용과 더불어 가시다님의 노션 페이지와 스터디 자료인 '24단계 실습으로 정복하는 쿠버네티스 도서' 를 기반으로 작성하였습니다.

Polaris

쿠버네티스 클러스터의 구성과 보안 상태를 분석하여 보안 취약점과 성능 이슈에 대한 식별 및 평가하는 오픈소스 도구이다. 다양한 룰셋을 지원하며, 룰셋을 커스터마이징 하여 평가 항목에 추가하는 방식도 가능하다. 분석한 보안 상태와 성능 이슈를 시각화한 자료를 함께 제공하기 때문에 관리자가 보완이 필요한 부분을 가시적으로 확인하는데 도움을 주는 툴이다.

폴라리스는 3가지 모드로 실행 가능하다.

  • Dashboard : 코드로 정의한 정책(policy as code)을 따라 쿠버네티스 리소스의 유효성을 검증하고, 어떤 보완 작업이 필요한지 보여준다.
  • Admission Controller : 정책을 위반하는 워크로드는 강제로 수정하거나 생성을 막는다.
  • CLI Tool : 코드화 한 정책(policy as code)을 CI/CD 파이프라인에 추가하여 yaml파일을 테스트한다. 통과하지 못한 yaml파일은 반영되지 않는다.

평가 기준 및 조치방법

Polaris의 공식 도큐먼트가 사용자에게 있어 꽤나 친절하다는 느낌을 받은 부분이다.

보안, 성능효율, 사이트 안정성에 대하여 3개 카테고리로 분류한 기준을 설명하고 있으며, 분석 항목에 대한 danger/warning 기준과, Admission Controller의 차단 기준을 표에서 설명한다.
페이지 하단에서는 이러한 차단 기준이 어떤 배경에 의해 설정되었는지 소개하고 있다.

다만 각 매니페스트에 대한 예시를 제공하지 않는 점이 아쉬웠는데
나는 Polaris로 분석한 결과를 아래 표를 기준으로 먼저 살펴보고, 실제 조치 과정에서는 아래 세 개의 레퍼런스를 가장 많이 참조했다.

1. 쿠버네티스 공식문서
2. bridgecrew의 kubernetes policy
3. polaris github의 check/*.yaml 파일 내용들

Security

Security checks 메뉴얼 링크

Efficiency

Efficiency check 메뉴얼 링크

Reliability

Reliability check 메뉴얼 링크

Dashboard 모드

설치 및 사용

  • helm으로 배포
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
  • 로컬에 docker로 배포
docker run -d -p8080:8080 -v ~/.kube/config:/opt/app/config:ro  quay.io/fairwinds/polaris:1.2 polaris dashboard --kubeconfig /opt/app/config

대시보드는 반드시 쿠버네티스 클러스터가 아닌, 로컬에 구성하여 kubeconfig 파일을 기반으로 클러스터에 연결할 수도 있다.

실제로 쿠버네티스 밖의 환경에서 별도로 대시보드를 실행할 수 있는지 궁금하기도 해서 일부러 쿠버네티스 클러스터와 완전히 분리된 로컬 환경에서 docker로 실행해보았다.

kOps로 구성한 실습 환경인데, 아직 아무런 사용하지 않은 설치 직후의 최초 분석 결과는 위와 같다. 분석 결과는 분석에 사용된 룰셋에 따라 달라지기 떄문에 조직 내에서 분석 대상에 대한 리스트업과 평가 기준을 세워 사용하는 편이 좋을 것 같다.

네임스페이스별로 배포된 각 리소스에 대한 세밀한 분석결과도 제공한다.

aws-node(vpc cni)의 분석 결과를 보면, 심각도에 따라 조치가 필요한 항목을 보여준다. 하나의 파드가 여러 컨테이너를 품고 있는 단위인 만큼, 각 컨테이너별로 분석이 이루어지며 컨테이너 레벨의 분석 결과와 파드 레벨의 분석 결과를 분리해서 확인할 수 있다.

기본적으로 30개 이상의 미리 세팅된 룰셋들이 존재하며, 평가된 항목들을 보면 쿠버네티스 리소스 생성시 안정적인 서비스 운영을 위해 적용을 권장하는 항목들이 주를 이루고 있기 때문에 필수 항목만 체크하려고 한다면 사전 정의된 룰셋만으로도 충분한 효과를 볼 수 있을 것 같다.

  • 호스트 네트워크대역 공유
  • 컨테이너에 부여된 권한
  • CPU/Mem limit&request
  • Readiness , Liveness Prove 설정
  • 이미지 태그 명시

물론 호스트 네트워크 대역의 사용이나, 운영상의 목적으로 CPU/Memory 자원에 대한 limit & request를 설정하지 않는 경우도 있기 때문에 모든 항목을 맹목적으로 따를 필요는 없어 보인다.

이 중 CPU limits should be set 항목 옆의 ? 버튼을 클릭하면 세부 조치 항목과 이 항목이 조치되어야 하는 이유를 함께 가이드하고 있는데, 이러한 배경이 함께 제공된다는 점은 매우 매력적이다.

조치

테스트로 nginx파드와 argocd를 추가로 배포하고 확인해보았다. 대시보드를 새로고침하면 새로이 배포한 리소스들이 바로 반영되고, 분석이 이루어진다.

nginx 파드의 분석 결과에서 조치가 필요한 항목 중 일부 항목에 대한 조치를 해보고, 어떻게 반영되는지 확인해보겠다.
기존 배포는 아래와 같이 했다.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80

조치 후의 매니페스트는 아래와 같다.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    imagePullPolicy: Always
    ports:
    - containerPort: 80
    securityContext:
      readOnlyRootFilesystem: true
      runAsNonRoot: true
    resources:
      requests:
        cpu: 100m
        memory: 100Mi
      limits:
        cpu: 100m
        memory: 100Mi
    readinessProbe:
      exec:
        command: ["ls", "/usr/share/nginx/html/index.html"]
    livenessProbe:
      exec:
        command: ["ls", "/usr/share/nginx/html/index.html"]
      initialDelaySeconds: 5
      periodSeconds: 3
      failureThreshold: 3

아래의 항목들을 조치하여 매니페스트에 반영하였다.

  • image 태그 반영 : image: nginx:1.14.2
  • cpu limit : limits.cpu : 100m
  • cpu request : request.cpu : 100m
  • mem limit : limits.memory : 100Mi
  • mem request reqeust.memory : 100Mi
  • livenessprove : command: ["ls", "/usr/share/nginx/html/index.html"]
  • image pull policy를 Always로 적용 : imagePullPolicy: Always
  • 컨테이너를 루트로 실행하지 않도록 함 : runAsNonRoot: true
  • 파일시스템 리드온리로 변경 : readOnlyRootFilesystem: true

조치 결과

대시보드는 룰셋의 평가 기준에 벗어난다고 해서 쿠버네티스 리소스의 생성을 차단하거나, 강제로 수정시키는 등의 동작은 하지 않고, 평가 결과와 조치 내용에 대한 View만 제공한다.

Admission Controller 모드

Polarlist Admission Controller 모드는 Admission Controller로 Built-In PodSecurity Admission Controller가 아닌 Polarlis를 사용하여 개발자 또는 관리자가 새로운 워크로드를 쿠버네티스 클러스터에 배포하려고 할 때, 분석 항목을 만족하는지 확인하고 만족하지 않는 경우 배포를 차단하는 방식으로 동작한다.

설치

helm upgrade --install polaris fairwinds-stable/polaris --namespace demo --create-namespace --set webhook.enable=true --set dashboard.enable=false

Admission Contrller를 활성화하고, 대시보드를 비활성화 한다. 설치에 성공하면 아래와 같은 메세지가 표시된다.

NAME: polaris
LAST DEPLOYED: Sat Apr  8 14:48:54 2023
NAMESPACE: demo
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
** Please be patient while the chart is being deployed **

Enjoy Polaris and smooth sailing!
The webhook is now running. Any resources that violate Polaris policy will be rejected

테스트를 위해 nginx 파드를 조치 전 기준으로 재배포해보았더니, Polaris 에 의해 배포가 차단되고 조치가 필요한 항목이 출력되었다.

Error from server (
Polaris prevented this deployment due to configuration problems:
- Container nginx: Privilege escalation should not be allowed
- Container nginx: Should not be allowed to run as root
- Container nginx: Image tag should be specified
): error when creating "pod.yaml": admission webhook "polaris.fairwinds.com" denied the request: 
Polaris prevented this deployment due to configuration problems:
- Container nginx: Privilege escalation should not be allowed
- Container nginx: Should not be allowed to run as root
- Container nginx: Image tag should be specified

이번에는 앞서 조치를 완료했던 매니페스트로 nginx를 배포해보았는데, 이번에도 배포가 실패하고 에러가 출력되었다.
Dashboard에서는 분명 모든 조치가 완료된 것으로 표시되었는데, Dashboard의 평가 기준과 Admission Controller 모드의 평가 기준이 다른 듯 보인다.

Error from server (
Polaris prevented this deployment due to configuration problems:
- Container nginx: Privilege escalation should not be allowed
): error when creating "pod.yaml": admission webhook "polaris.fairwinds.com" denied the request: 
Polaris prevented this deployment due to configuration problems:
- Container nginx: Privilege escalation should not be allowed

아래와 같이 Security Context를 추가하여 조치하였고, 파드 생성에 성공했다.

...
    securityContext:
      readOnlyRootFilesystem: true
      runAsNonRoot: true
      allowPrivilegeEscalation: false
      privileged: false
...

$kubectl apply -f pod.yaml 
pod/nginx created

폴라리스 공식 문서에 따르면, 아직까지는 부적절한 워크로드의 생성 자체를 reject 시킬수만 있고, 대시보드처럼 단순 경고는 불가능하다고 한다.

심각도 분류는 danger와 Warning, success(ignore)으로 나누어지는데, Warning인 항목은 Admission Controller에 의한 검사를 통과하며, danger일 때만 차단이 발생한다.

Polaris CLI

폴라리스의 마지막 동작 모드로 CLI를 사용하는 방법이 있다. 로컬에서 작업한 yaml파일을 polaris cli를 이용하여 분석하는 방법이다. 커맨드라인으로 동작하기 때문에 CI/CD 파이프라인에 녹여서 사용이 가능한 것으로 소개하고 있다.

다만 이번에 사용해본 바로는 조치 결과를 출력해주는 것 외에, 배포를 차단하여 수정을 강제하는 효과를 볼 수 있을지는 모르겠다. 오히려 Admission Controller 모드를 사용하고 알림을 설정해서 받아보는 편이 더 좋을 수 있겠다는 생각이 들었다.

설치

curl -L "https://github.com/FairwindsOps/polaris/releases/download/7.4.1/polaris_linux_amd64.tar.gz" > polaris.tar.gz

tar -xvf polaris.tar.gz

sudo mv polaris /usr/local/bin/

중간에 7.4.1이 현 시점 최신 버전이고, 내 로컬은 리눅스 환경이기 때문에 linux_amd64 로 설치하였다. 업데이트 현황과 로컬 환경에 따라 수정하여 설치할 수 있으며, polaris github에서 릴리즈 버전과 환경별 바이너리 다운로드가 가능하다.

다시 pod의 매니페스트 파일을 조치 전 기준으로 변경하고, polaris cli를 사용해보았다. 현재 pod.yaml 파일은 ~/polaris_test/ 경로에 있어 path를 지정하였다.

polaris audit --audit-path ./polaris_test/ --format=pretty
Polaris audited Path ./polaris_test/ at 2023-04-08T15:19:24+09:00
    Nodes: 0 | Namespaces: 0 | Controllers: 1
    Final score: 45

Pod nginx
    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 nginx
    readinessProbeMissing                😬 Warning
        Reliability - Readiness probe should be configured
    cpuLimitsMissing                     😬 Warning
        Efficiency - CPU limits should be set
    dangerousCapabilities                🎉 Success
        Security - Container does not have any dangerous capabilities
    hostPortSet                          🎉 Success
        Security - Host port is not configured
    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
    pullPolicyNotAlways                  😬 Warning
        Reliability - Image pull policy should be "Always"
    privilegeEscalationAllowed           ❌ Danger
        Security - Privilege escalation should not be allowed
    runAsPrivileged                      🎉 Success
        Security - Not running as privileged
    cpuRequestsMissing                   😬 Warning
        Efficiency - CPU requests should be set
    insecureCapabilities                 😬 Warning
        Security - Container should not have insecure capabilities
    livenessProbeMissing                 😬 Warning
        Reliability - Liveness probe should be configured
    memoryRequestsMissing                😬 Warning
        Efficiency - Memory requests should be set
    notReadOnlyRootFilesystem            😬 Warning
        Security - Filesystem should be read only
    runAsRootAllowed                     ❌ Danger
        Security - Should not be allowed to run as root
    sensitiveContainerEnvVar             🎉 Success
        Security - The container does not set potentially sensitive environment variables
    tagNotSpecified                      ❌ Danger
        Reliability - Image tag should be specified



Want more? Automate Polaris for free with Fairwinds Insights!
🚀 https://fairwinds.com/insights-signup/polaris 🚀

마찬가지로 조치 후 다시 검사를 실행.

polaris audit --audit-path ./polaris_test/ --format=pretty  --only-show-failed-tests
Polaris audited Path ./polaris_test/ at 2023-04-08T16:40:17+09:00
    Nodes: 0 | Namespaces: 0 | Controllers: 1
    Final score: 89

Pod nginx
    topologySpreadConstraint             😬 Warning
        Reliability - Pod should be configured with a valid topology spread constraint
  Container nginx
    insecureCapabilities                 😬 Warning
        Security - Container should not have insecure capabilities
    linuxHardening                       😬 Warning
        Security - Use one of AppArmor, Seccomp, SELinux, or dropping Linux Capabilities to restrict containers using unwanted privileges
    hostPortSet                          😬 Warning
        Security - Host port should not be configure

danger 항목은 모두 조치되었고, warning 항목에서 몇 가지 경고를 보여준다.

위와 같이 단일 디렉토리나, 매니페스트 파일에 대하여 검사를 수행할 수도 있지만 클러스터 전체애 대한 수행도 가능하다. 이미 실행중인 워크로드에 대해서도 분석이 이루어지며, kubeconfig 파일에 설정된 클러스터를 기준으로 동작한다.

polaris audit --format=pretty

커맨드를 실행하면 먼저 기존 워크로드를 읽어들인다.

polaris audit --format=pretty
INFO[0000] Loading nodes                                
INFO[0000] Loading namespaces                           
INFO[0000] Loading pods                                 
INFO[0000] Setting up restmapper                        
INFO[0000] Loading networking.k8s.io/Ingress            
INFO[0000] Loading rbac.authorization.k8s.io/RoleBinding 
INFO[0000] Loading rbac.authorization.k8s.io/ClusterRole 
INFO[0000] Loading /ConfigMap                           
INFO[0000] Loading policy/PodDisruptionBudget           
INFO[0000] Loading rbac.authorization.k8s.io/Role       
INFO[0000] Loading ServiceAccount                       
INFO[0000] Loading networking.k8s.io/NetworkPolicy      
INFO[0000] Loading rbac.authorization.k8s.io/ClusterRoleBinding 
INFO[0000] Loading controllers                          
INFO[0000] Done loading Kubernetes resource

그리고 아래와 같이 네임스페이스별, 워크로드별로 분석한 결과를 보여주는데, 클러스터 내의 모든 워크로드를 분석한 결과를 출력하다보니 내용이 꽤 길기 때문에 output을 파일로 써서 천천히 살펴보는 편이 좋았다.

$ polaris audit --format=pretty > result.txt
$ head result.txt -n 30

---

Polaris audited Cluster https://api.ilikebigmac.link at 2023-04-08T15:25:54+09:00
    Nodes: 3 | Namespaces: 7 | Controllers: 26
    Final score: 83

Role system::leader-locking-kube-controller-manager in namespace kube-system
    rolePodExecAttach                    🎉 Success
        Security - The Role does not allow pods/exec or pods/attach

Role cert-manager-cainjector:leaderelection in namespace kube-system
    rolePodExecAttach                    🎉 Success
        Security - The Role does not allow pods/exec or pods/attach

...

--only-show-failed-tests 옵션을 추가하면 실패한 항목만 출력할 수 있는데, 어떤 항목에 대한 평가가 이루어졌는지보다는 실패한 항목만을 찾아 조치하고자 하는 경우에 사용하면 좋을 것 같다. 내용을 거의 다 날려버려서 사용자에게 폴라리스가 분석한 결과와 평가 항목에 대한 내용을 전달하고자 하는 경우에는 쓰지 않는게 좋을 것 같음.

$ polaris audit --audit-path ./polaris_test/ --format=pretty  -c config.yaml --only-show-failed-tests

Polaris audited Path ./polaris_test/ at 2023-04-08T16:24:12+09:00
    Nodes: 0 | Namespaces: 0 | Controllers: 1
    Final score: 88

Pod nginx
    topologySpreadConstraint             😬 Warning
        Reliability - Pod should be configured with a valid topology spread constraint
  Container nginx
    hostPortSet                          😬 Warning
        Security - Host port should not be configured
    linuxHardening                       😬 Warning
        Security - Use one of AppArmor, Seccomp, SELinux, or dropping Linux Capabilities to restrict containers using unwanted privileges
    insecureCapabilities                 😬 Warning
        Security - Container should not have insecure capabilities



Want more? Automate Polaris for free with Fairwinds Insights!
🚀 https://fairwinds.com/insights-signup/polaris 🚀 

Customizing

기본적으로 설정된 Polaris의 룰셋들은 미리 설정된 config.yaml 파일 내에 정의되어 있다.
사용자는 이 config.yaml 을 변경하여 아래와 같이 폴라리스를 커스텀 할 수 있다.

  • check를 켜고 끌 수 있음
  • 각 평가 항목에 대한 심각도 수준 조정(danger/warning)
  • 새로운 custom check 추가
  • 특정 룰에서 특정 워크로드에 대한 예외 추가

테스트에서는 privilegeEscalationAllowed의 심각도 수준을 변경해보려고 한다.

config.yaml의 아래 privilegeEscalationAllowed: dangerprivilegeEscalationAllowed: warning 으로 변경한 뒤, pod.yaml의 내용에서 privilegeEscalationAllowed 설정을 제거해보았다.

  • 기존
  • privilegeEscalationAllowed ❌ Danger Security - Privilege escalation should not be allowed
  • 변경 후
  • privilegeEscalationAllowed 😬 Warning Security - Privilege escalation should not be allowed ...

 

  • ignore 적용 후
Polaris audited Path ./polaris_test/ at 2023-04-08T16:46:32+09:00
    Nodes: 0 | Namespaces: 0 | Controllers: 1
    Final score: 88

Pod nginx
    topologySpreadConstraint             😬 Warning
        Reliability - Pod should be configured with a valid topology spread constraint
  Container nginx
    linuxHardening                       😬 Warning
        Security - Use one of AppArmor, Seccomp, SELinux, or dropping Linux Capabilities to restrict containers using unwanted privileges
    insecureCapabilities                 😬 Warning
        Security - Container should not have insecure capabilities
    hostPortSet                          😬 Warning
        Security - Host port should not be configured



Want more? Automate Polaris for free with Fairwinds Insights!
🚀 https://fairwinds.com/insights-signup/polaris 🚀 

warning에서 ignore로 변경했더니, 아예 평가 항목에서 사라져버렸다. Success로 표기되는 개념이 아닌 평가 항목에서의 완전 배제를 ignore로 설정할 수 있는 것으로 보인다.

마치며

쿠버네티스 클러스터와 워크로드에 대한 보안/성능 분석 툴의 사용은 이번 스터디 주제로 다루면서 처음 경험해보았다.
사용 전에는 이러한 툴의 적용으로 인해서 개발 및 배포 프로세스가 지연될 가능성에 대한 고려가 필요해 보였고, 때문에 속도를 중시하면서 어느정도의 유연한 운영을 원하는 경우 사용이 어렵지 않을까 하는 생각이었는데 지금까지 핸즈온 해본 바로는 최초 설정시에 기준만 잘 잡아둔다면 오히려 안정성 있는 워크로드 구성을 가속화 할 수 있겠다는 느낌을 받았다.

다만 이 역시 초기 적용시에는 클러스터를 관리하는 인원간에 각 분석 항목에 대한 합의와 함께 개발 조직과 협업하여 일정 기간 베타테스트가 선행된다면 좋을 것 같다.

최근에 타 팀에서 아직 쿠버네티스와 인프라 레벨의 AWS 설정에 대한 도메인이 부족한 상태에서, 모 플랫폼을 PoC하기 위하여 production 데이터를 끌어다 EKS 기반으로 워크로드를 올렸다가 일부 데이터와 함께 플랫폼의 admin 정보가 노출되었던 사례가 있었다. 다행히 조치가 빠르게 이루어져서 보안 사고로 이어지지는 않았지만.

쿠버네티스의 운영도 결국 사람이 한다. Polaris 의 도입과 함께 추가로 check 룰셋을 조직의 환경에 맞게 커스터마이징 해서 사용한다면, 미처 놓칠 수 있는 보안 취약점이나 서비스 안정성을 위해 반드시 추가되어야 하는 설정값들이 빠져 서비스 장애가 발생할 수 있는 경우의 수를 현저히 낮출 수 있을 것으로 기대한다.

Ref

  1. https://github.com/FairwindsOps/polaris
  2. https://polaris.docs.fairwinds.com/checks/security/
  3. https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/
  4. https://coffeewhale.com/kubernetes/admission-control/2021/04/28/opa1/
  5. https://docs.bridgecrew.io/docs/kubernetes-policy-index
  6. https://www.fairwinds.com/blog