카이도스의 Tech Blog
PKOS 7주차 - 보안 본문
쿠버네티스 공부는 ‘24단계 실습으로 정복하는 쿠버네티스 책을 기준으로 진행.
kubescape
- 소개 및 사용 : 보안 권고 사항 기반 현재 쿠버네티스 클러스터(YAML, Helm chart)의 취약점을 점검
kubescape?
kubescape는 DevOps를 위한 kubernetes용 보안 플랫폼이다. NSA/CISA의 ‘쿠버네티스 보안강화지침(kubernetest hadrdening guidance)’에 맞게 안전하게 배포되었는지 테스트하는 도구로 단일 yaml파일부터 클러스터 단위의 테스트를 수행한다. 또한 그 결과로 JSON 형태의 출력을 하여 이를 기반으로 CI를 비롯한 다른 시스템의 연동이 용이하다.
쿠버네티스 보안강화지침의 주요 내용
- 취약점 또는 잘못된 구성을 찾기 위해 컨테이너와 포드 스캔하기
- 최소한의 권한으로 컨테이너와 포드 실행하기
- 네트워크를 분리하여 발생할 수 있는 데미지를 제어하기
- 방화벽을 사용해서 필요없는 네트웍 연결을 제한하고, 암호화하기
- 강력한 인증 및 권한관리를 통해서 사용자 및 관리자의 접근을 제한하고, 공격 표면(Attack Surface)을 한정시키기.
- 관리자가 활동을 모니터링하고, 잠재적인 위험 동작에 대해 경고할 수 있도록 Log Auditing 사용하기
- 정기적으로 모든 k8s 설정을 검토하고, Vulnerability 스캔을 사용해서 위험 방지및 보안 패치가 적용되었는지 확인하기
kubescape의 핵심가치
- 쿠버네티스 상에서 잘못된 설정정보나 취약점을 감지
- 이를 수치화해서 위험정도를 체크하고 과거의 수치들을 기반으로 경향도 파악
- 실시간 설정변경파악
- 특정 기준(NSA, Mitre, Devops best practice)을 준수하도록 프레임 워크들 제공하고 사용자화도 할수 있음
- 예외관리를 통해 무분별한 알람발생 제어
- 다양한 devops 도구들고 연동 (Jenkins, CircleCI, Github workflows, Gitlab, Prometheus, Slack,…)
- 사용하기 쉬운 cli 제공과 유연한 결과출력 조정 (json, junit xml..)
- 쿠버네티스의 상태와 정책의 준수를 보여주는 ui
- 복구지원 - 장애지정과 원인을 알려주고 자원 선택시 crd에서 문제를 일이킨 지점으로 이동
- 이미지 스캔 - 취약점을 보여주는데 편리하게 정령이나 필터등 가능
- RBAC 생성지원 - 시각화 지원을 통해 클러스터에 추가되는 rbac의 복잡도를 줄여줌
내부동작
- OPA 엔진을 기반으로 하고 있고 ARMO의 조작도구를 사용한다.
- ARMO가 개발한 rego snippet 들을 실행하여 스캔을 수행
- 다양한 기준을 얼마나 준수하고 있는지 파악
링크 - https://devocean.sk.com/blog/techBoardDetail.do?ID=164199
polaris
소개 및 설치 : 오픈소스 보안 점검 도구, Polaris is an open source policy engine for Kubernetes that validates and remediates resource configuration - helm
- 여기에는 30개 이상의 기본 제공 구성 정책과 JSON 스키마로 사용자 지정 정책을 구축하는 기능이 포함됩니다.
- 명령줄에서 실행하거나 변형 웹후크로 실행될 때 Polaris는 정책 기준에 따라 문제를 자동으로 해결할 수 있습니다.
실습환경 구성
kops 인스턴스 t3.small & 노드 t3.xlarge (vCPU 4, Memory 16GiB) 배포 및 kops 인스턴스(t3.small)에 SSH 접속
# 배포 완료 후 접속
# EC2 instance profiles 에 IAM Policy 추가(attach)
aws iam attach-role-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy --role-name masters.$KOPS_CLUSTER_NAME
aws iam attach-role-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy --role-name nodes.$KOPS_CLUSTER_NAME
aws iam attach-role-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AllowExternalDNSUpdates --role-name masters.$KOPS_CLUSTER_NAME
aws iam attach-role-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AllowExternalDNSUpdates --role-name nodes.$KOPS_CLUSTER_NAME
EC2 IAM Role & 메타데이터
워커 노드 1대 EC2 메타데이터 보안 제거 ⇒ 적용 및 재생성 5분 시간 소요
#
kops edit ig nodes-ap-northeast-2a
---
# 아래 3줄 제거
spec:
instanceMetadata:
httpPutResponseHopLimit: 1
httpTokens: required
---
# 업데이트 적용 : 노드1대 롤링업데이트
kops update cluster --yes && echo && sleep 3 && kops rolling-update cluster --yes
파드에서 EC2 메타데이터 사용 가능 확인
# netshoot-pod 생성
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: netshoot-pod
spec:
replicas: 2
selector:
matchLabels:
app: netshoot-pod
template:
metadata:
labels:
app: netshoot-pod
spec:
containers:
- name: netshoot-pod
image: nicolaka/netshoot
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
# 파드 이름 변수 지정
PODNAME1=$(kubectl get pod -l app=netshoot-pod -o jsonpath={.items[0].metadata.name})
PODNAME2=$(kubectl get pod -l app=netshoot-pod -o jsonpath={.items[1].metadata.name})
# EC2 메타데이터 정보 확인
kubectl exec -it $PODNAME1 -- curl 169.254.169.254 ;echo
kubectl exec -it $PODNAME2 -- curl 169.254.169.254 ;echo
# 파드1에서 EC2 메타데이터 정보 확인
kubectl exec -it $PODNAME1 -- curl 169.254.169.254/latest ;echo
kubectl exec -it $PODNAME1 -- curl 169.254.169.254/latest/meta-data/iam/security-credentials/ ;echo
kubectl exec -it $PODNAME1 -- curl 169.254.169.254/latest/meta-data/iam/security-credentials/nodes.$KOPS_CLUSTER_NAME | jq
# 파드2에서 EC2 메타데이터 정보 확인
kubectl exec -it $PODNAME2 -- curl 169.254.169.254/latest ;echo
kubectl exec -it $PODNAME2 -- curl 169.254.169.254/latest/meta-data/iam/security-credentials/ ;echo
kubectl exec -it $PODNAME2 -- curl 169.254.169.254/latest/meta-data/iam/security-credentials/nodes.$KOPS_CLUSTER_NAME | jq
파드(컨테이너) 탈취 후 EC2 메타데이터의 IAM Role 토큰 정보를 활용해 python boto3를 통해 SDK로 AWS 서비스 강제 사용 - boto3
# boto3 사용을 위한 파드 생성
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: boto3-pod
spec:
replicas: 2
selector:
matchLabels:
app: boto3
template:
metadata:
labels:
app: boto3
spec:
containers:
- name: boto3
image: jpbarto/boto3
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
# 파드 이름 변수 지정
PODNAME1=$(kubectl get pod -l app=boto3 -o jsonpath={.items[0].metadata.name})
PODNAME2=$(kubectl get pod -l app=boto3 -o jsonpath={.items[1].metadata.name})
# 파드1에서 boto3 사용
kubectl exec -it $PODNAME1 -- sh
------------
cat <<EOF> ec2.py
import boto3
ec2 = boto3.client('ec2', region_name = 'ap-northeast-2')
response = ec2.describe_instances()
print(response)
EOF
python ec2.py # aws ec2 describe-vpcs
exit
------------
# 파드2에서 boto3 사용
kubectl exec -it $PODNAME2 -- sh
------------
cat <<EOF> ec2.py
import boto3
ec2 = boto3.client('ec2', region_name = 'ap-northeast-2')
response = ec2.describe_instances()
print(response)
EOF
python ec2.py # aws ec2 describe-vpcs
exit
------------
# Pod2에서 성공!!
# 실습 완료 후 삭제
kubectl delete deploy boto3-pod
kubescape
# 설치
curl -s https://raw.githubusercontent.com/kubescape/kubescape/master/install.sh | /bin/bash
# Download all artifacts and save them in the default path (~/.kubescape)
kubescape download artifacts
tree ~/.kubescape/
cat ~/.kubescape/attack-tracks.json | jq
# 제공하는 보안 프레임워크 확인
kubescape list frameworks --format json | jq '.[]'
"AllControls"
"ArmoBest"
"DevOpsBest"
"MITRE"
"NSA"
"cis-eks-t1.2.0"
"cis-v1.23-t1.0.1"
# 제공하는 통제 정책 확인
kubescape list controls
# 모니터링
watch kubectl get pod -A
# 클러스터 스캔
# Deploy Kubescape host-sensor daemonset in the scanned cluster. Deleting it right after we collecting the data.
# Required to collect valuable data from cluster nodes for certain controls.
# Yaml file: https://github.com/kubescape/kubescape/blob/master/core/pkg/hostsensorutils/hostsensor.yaml
kubescape scan --help
kubescape scan --enable-host-scan --verbose
+----------+-------------------------------------------------------+------------------+---------------+---------------------+
| SEVERITY | CONTROL NAME | FAILED RESOURCES | ALL RESOURCES | % RISK-SCORE |
+----------+-------------------------------------------------------+------------------+---------------+---------------------+
| Critical | Disable anonymous access to Kubelet service | 0 | 0 | Action Required * |
| Critical | Enforce Kubelet client TLS authentication | 0 | 0 | Action Required * |
| High | Forbidden Container Registries | 0 | 21 | Action Required *** |
| High | Resources memory limit and request | 0 | 21 | Action Required *** |
...
+----------+-------------------------------------------------------+------------------+---------------+---------------------+
| | RESOURCE SUMMARY | 47 | 204 | 8.78% |
+----------+-------------------------------------------------------+------------------+---------------+---------------------+
FRAMEWORKS: AllControls (risk: 9.17), NSA (risk: 11.82), MITRE (risk: 6.94)
polaris
# 설치
kubectl create ns polaris
#
cat <<EOT > polaris-values.yaml
dashboard:
replicas: 1
service:
type: LoadBalancer
EOT
# 배포
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm install polaris fairwinds-stable/polaris --namespace polaris --version 5.7.2 -f polaris-values.yaml
# CLB에 ExternanDNS 로 도메인 연결
kubectl annotate service polaris-dashboard "external-dns.alpha.kubernetes.io/hostname=polaris.$KOPS_CLUSTER_NAME" -n polaris
# 웹 접속 주소 확인 및 접속
echo -e "Polaris Web URL = http://polaris.$KOPS_CLUSTER_NAME"
Image tag 조치 - 링크
# 기존 netshoot-pod 삭제
kubectl delete deploy netshoot-pod
# netshoot-pod 1대 생성
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: netshoot-pod
spec:
replicas: 1
selector:
matchLabels:
app: netshoot-pod
template:
metadata:
labels:
app: netshoot-pod
spec:
containers:
- name: netshoot-pod
image: nicolaka/netshoot:v0.9
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
deployment 의 replica 조치 후 확인
kubectl scale deployment netshoot-pod --replicas 2
보안 모범 사례 적용 후 재점검
폴라리스 파드의 설정 참고
# 설치 및 확인
kubectl krew install neat
kubectl get deploy/polaris-dashboard -n polaris -o yaml | kubectl neat > polaris-pod.yaml
cat polaris-pod.yaml | yh
...
spec:
template:
spec:
containers:
imagePullPolicy: Always # 이미지를 항상 리포지토리에서 가져오게 설정
resources: # 리소스 자원 사용 보장 및 제한
limits:
cpu: 150m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
securityContext: # 컨테이너, 파드의 권한 및 접근 제어
allowPrivilegeEscalation: false # 컨테이너의 하위 프로세스가 상위 프로세스보다 많은 권한을 얻을 수 없게 설정
capabilities: # 호스트 커널 레벨 수정이 필요 시 root 권한으로 전체 커널을 수정하지 않고 특정 커널 권한만 부여 후 사용
drop:
- ALL
privileged: false # true인 경우 호스트의 모든 장치에 접근 권한 가짐, 컨테이너의 root권한이더라도 namespace/cgroup으로 격리되어 호스트의 다른 장치 접근 불가
readOnlyRootFilesystem: true # 컨테이너의 root 파일시스템에 읽기 전용
runAsNonRoot: true # root 권한으로 컨테이너를 실행하지 않음
...
netshoot-pod 에 보안 모범 사례 적용
# 삭제
kubectl delete deploy netshoot-pod
# netshoot-pod 생성
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: netshoot-pod
spec:
replicas: 2
selector:
matchLabels:
app: netshoot-pod
template:
metadata:
labels:
app: netshoot-pod
spec:
containers:
- name: netshoot-pod
image: nicolaka/netshoot:v0.9
command: ["tail"]
args: ["-f", "/dev/null"]
imagePullPolicy: Always
resources:
limits:
cpu: 150m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
readOnlyRootFilesystem: true
#runAsNonRoot: true
terminationGracePeriodSeconds: 0
EOF
참고로 polaris 파드와 CLB가 완료되었음에도 polaris.pjhtest.click 상태를 확인해봤다.
a38ef87cdbbe84265a4f545160f11186-2026951006.ap-northeast-2.elb.amazonaws.com로는 접속이 되지만 Route53 레코드가 없어서 아래 레코드 추가 후 정상적으로 사이트 호출 확인했다.
polaris.pjhtest.click | CNAME | 단순 | - | a38ef87cdbbe84265a4f545160f11186-2026951006.ap-northeast-2.elb.amazonaws.com |
[과제1] 파드에서 EC2 메타데이터의 IAM Role 토큰 정보를 활용하여(boto3), 스터디에서 소개한 것 이외의 다른 **AWS 서비스(혹은 Action)**를 사용 후 코드나 스샷을 올려주세요
nodes.pjhtest.click 에 AmazonS3FullAccess IAM 권한 추가
# boto3 사용을 위한 파드 생성
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: boto3-pod
spec:
replicas: 2
selector:
matchLabels:
app: boto3
template:
metadata:
labels:
app: boto3
spec:
containers:
- name: boto3
image: jpbarto/boto3
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
# 파드 이름 변수 지정
PODNAME1=$(kubectl get pod -l app=boto3 -o jsonpath={.items[0].metadata.name})
PODNAME2=$(kubectl get pod -l app=boto3 -o jsonpath={.items[1].metadata.name})
# 파드1에서 boto3 사용
kubectl exec -it $PODNAME1 -- sh
------------
cat <<EOF> s3.py
import boto3
s3 = boto3.client('s3')
response = s3.list_buckets()
print(response)
EOF
python s3.py
exit
------------
# 실습 완료 후 삭제
kubectl delete deploy boto3-pod
[과제2] 책 398~400페이지 - kubescape armo 웹 사용 후 관련 스샷을 올려주세요
1. https://portal.armo.cloud/ 접속
2. 회원가입
3. 클러스터 연결을 위해 필요한 패키지 설치
helm repo add kubescape https://kubescape.github.io/helm-charts/
helm repo update
helm upgrade --install kubescape kubescape/kubescape-cloud-operator -n kubescape --create-namespace --set account=b71b65a7-967c-48b2-8ffc-00cc1ef8d3a0 --set clusterName=`kubectl config current-context
4. 패키지 설치 후 자동 검색 후 연결완료 되면 아래와같이 확인됨
[과제3] polaris 관련 실습(아무거나) 후 관련 스샷을 올려주세요
위에 polaris 실습 부분에서 진행
[과제4] 신규 서비스 어카운트(SA) 생성 후 '클러스터 수준(모든 네임스페이스 포함)에서 읽기 전용'의 권한을 주고 테스트 후 코드나 스샷을 올려주세요
# 신규 어카운트 생성
kubectl create sa infra-k8s-cluster -n infra-team
# 신규 POD 생성
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
name: infra-kubectl-cluster
namespace: infra-team
spec:
serviceAccountName: infra-k8s-cluster
containers:
- name: kubectl-pod
image: bitnami/kubectl:1.24.10
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
# cluster 롤 생성
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: role-infra-team-cluster
namespace: infra-team
rules:
- apiGroups: [""]
resources: ["*"]
verbs: ["get", "watch", "list"]
EOF
# cluster 롤 확인
kubectl describe clusterRole role-infra-team-cluster -n infra-team
Name: role-infra-team-cluster
Labels: <none>
Annotations: <none>
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
* [] [] [get watch list]
# 롤바인딩 생성 : '서비스어카운트 <-> 롤' 간 서로 연동
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: roleB-infra-team-cluster
namespace: infra-team
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: role-infra-team-cluster
subjects:
- kind: ServiceAccount
name: infra-k8s-cluster
namespace: infra-team
EOF
# 확인
kubectl describe clusterrolebindings roleB-infra-team-cluster -n infra-team
Name: roleB-infra-team-cluster
Labels: <none>
Annotations: <none>
Role:
Kind: ClusterRole
Name: role-infra-team-cluster
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount infra-k8s-cluster infra-team
# 파드로 Shell 접속하여 정보 확인 : 단축 명령어(alias) 사용
alias k1='kubectl exec -it infra-kubectl-cluster -n infra-team -- kubectl'
# 권한 테스트
k1 get pods
k1 run nginx --image nginx:1.20-alpine
k1 get nodes
k1 get ns
k1 create ns test
# (옵션) kubectl auth can-i 로 kubectl 실행 사용자가 특정 권한을 가졌는지 확인
k1 auth can-i get pods
yes
'KOPS' 카테고리의 다른 글
쿠버네티스 kubespray 설치 (0) | 2023.03.14 |
---|---|
PKOS 6주차 - Alerting 얼럿매니저 로깅시스템 (0) | 2023.02.23 |
PKOS 5주차 - 프로메테우스 그라파나 (0) | 2023.02.14 |
PKOS 4주차 - Harbor Gitlab ArgoCD (0) | 2023.02.07 |
PKOS(쿠버네티스)3주차 - Ingress & Storage (0) | 2023.02.01 |