월루를 꿈꾸는 대학생

PKOS 5주차 보안 본문

Server&Network/Kubernets_Dokcer

PKOS 5주차 보안

하즈시 2023. 4. 9. 03:29
728x90

 

24단계 실습으로 정복하는 쿠버네티스’ 책을 기준하여 정리하였습니다.

http://www.yes24.com/Product/Goods/115187666

 

24단계 실습으로 정복하는 쿠버네티스 - YES24

실무 현장의 경험을 고스란히 담은 쿠버네티스 실습서!직접 해야만 알 수 있는 것들이 있다. 쿠버네티스도 마찬가지다. 쿠버네티스의 기반이 되는 컨테이너 기술은 기존의 가상 머신과 기본 전

www.yes24.com

 



인스턴스 중 1대는 메타데이터 보안을 제거 

 

#
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

 

 


 

# 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
## 1번은 안 나오고 2번은 나옴 
## 1번에서는 메타데이터를 받지 못함 
kubectl exec -it $PODNAME2 -- curl 169.254.169.254 ;echo
## 2번에는 보안삭제해서 ㅅ보이는 듯 

# 파드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

(hazu:N/A) [root@kops-ec2 ~]# kubectl exec -it $PODNAME2 -- curl 169.254.169.254/latest ;echo
dynamic
meta-data
user-data
(hazu:N/A) [root@kops-ec2 ~]# kubectl exec -it $PODNAME2 -- curl 169.254.169.254/latest/meta-data/iam/security-credentials/ ;echo
nodes.hazu.link
(hazu:N/A) [root@kops-ec2 ~]# kubectl exec -it $PODNAME2 -- curl 169.254.169.254/latest/meta-data/iam/security-credentials/nodes.$KOPS_CLUSTER_NAME | jq
{
  "Code": "Success",
  "LastUpdated": "2023-04-08T16:09:32Z",
  "Type": "AWS-HMAC",
  "AccessKeyId": "ASIAWEYDAGVRFQM6VDXF",
  "SecretAccessKey": "NqHLsYCr0SMWiiOlWzuV1PM04/tULdA4hu1hfmcp",
  "Token": "IQoJb3JpZ2luX2VjEHgaDmFwLW5vcnRoZWFzdC0yIkcwRQIhAMRd7ohZb71PfNMItu4XhYb/UWYDdGEYvI3f2N9VuyViAiA+2nEifU6Gb5pNUoSjyix7QHuKNzmgtsuoEj+sCiny9SrMBQhhEAEaDDQyMjUyMzcxMjg2NiIMXDwR3xLazR+ilbLSKqkF/baxb6/VuvxDuCcmDLOXvzCvPyWXJzy0vmsSZqVZYjuekXHMS7GjuN9UnZcLpqIE3XBpK1eV6fAnyXYtJWqd/1+SASAz4G/W9nhKbcFU+kASauwkoWeV2qn4H6lKYA9lzGU+IUOcpKSS2iV5kmD5WlWvot1ZuEHji1+HxvfVrX+BPl0auuI84bD9bjbrYv0IyJ++1/h3QUjsHlPA8YhL++kr+5PEZhI01R9lIJHyrf7vM9K9VPAUugafjgU3PN4sTaRGu1LaggbEEiAGOxo+6g4OHeQ3n5fkRWK0sTztKMkKAzkJ4gz0zmoKv5wdFOSAdKQUKY5ND+618ir7F8lHFIyAeHdq1DSim8ACFVy5YxU5FwwjdQE6slBGgQGWrofrsKoErNgOASTQDEsS+vublOwswHZkvr5DhRoll/D6hWNkiLTf07lPNWnRe6AdYvlTI/vkKesB8yGarzh+NmvBSBCoT1lJqd9zLnYbmH1KyaRKFI2BzhM+uKMGahzZCpxkspSnIuuDalPgP/xx73OHII1AWsCi+5yanjl2vvhByYfij/EDGa0mRs3PBThVbFufNeYKOBOeBRT4nC3a3dNCbJQXhA0mKrOCOcnhrtfSMt2viudu1f1qr+NrwnZyOg64Hkt6YhtilrtftoBTJZiYE15r0CmIC5nTW+V02/hk3LtcrUiMtWCcpQduqpUex6pnwwzADe7ybv9w5lowr/ogGlIkleVZ6sIwxdf/j7r5UP99TOMpWTEZc3FFrJWJyNPa1y7jfYVOXBsQOE3PcCrgALXEB5W++mkP0I0Wbyp4mKnflIXv9lYU/WTYWDjyTk35U2wHSDrqsPl4isrbQhTqA+FoJBgtnAh2vr2WZR7jOUUcb7nVo3OQGbiKCUScBqRpAkDsJpBbPf2YMOCjxqEGOrEBjYW31vcQMDQ1Zya0oIavAhYMvIYZrIBjKHyTmhWKxxpEUUSNKOMyvEsX7+L88a9Y/bwuI2mYzZyVReXFN7x/sCjKPCNnCwroY6xCaWxk5JonYfez6LRBnnNr+iCkhqiuGlyGzphFUnBOQNaMpagh5YRxX/CzifbJvo/vaiXNOUp/B4AkWEDuzrmwFEiNtYyDJVlmmZl+bnnfgNQZQTwmaqArdqAVi9/YWhm9fYH4LBpD",
  "Expiration": "2023-04-08T22:45:08Z"
}

저렇게 보이면 탈취되었다고 보고 해당 토큰을 가지고 악용이 가능 

 

 

# 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
------------

# 실습 완료 후 삭제
kubectl delete deploy boto3-pod

 

 

탈취가 되었을 때 악용될 수가 있으므로 IRSA를 사용하기 권장 

 

https://tech.devsisters.com/posts/pod-iam-role/

iam 역할을 공유하는 경우 pod 하나만 탈취되더라도 공유되기때문에 문제

IRSA를 사용하면 pod별 iam 규칙을 사용할 수 있어서 보다 안정적 


실제로 취득한 토큰과 키들을 넣고 확인해보면 aws 리소스를 확인하고 사용할 수 있음 

이래서 요금폭탄 맞는 경우가 생기는 듯 

# awscli 파드 생성
cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: awscli-pod
spec:
  replicas: 2
  selector:
    matchLabels:
      app: awscli-pod
  template:
    metadata:
      labels:
        app: awscli-pod
    spec:
      containers:
      - name: awscli-pod
        image: amazon/aws-cli
        command: ["tail"]
        args: ["-f", "/dev/null"]
      terminationGracePeriodSeconds: 0
EOF

# 파드 이름 변수 지정
APODNAME1=$(kubectl get pod -l app=awscli-pod -o jsonpath={.items[0].metadata.name})
APODNAME2=$(kubectl get pod -l app=awscli-pod -o jsonpath={.items[1].metadata.name})

---
# 메타데이터 메모해두기 : 단 Expiration 시간이 지나면 Token은 유효하지 않음
{
  "Code": "Success",
  "LastUpdated": "2023-03-01T14:11:26Z",
  "Type": "AWS-HMAC",
  "AccessKeyId": "ASIA5ILF2FJIZ3VBD6DB",
  "SecretAccessKey": "6fCWhz1eKupIXNl9w/BMcHh1YdSOYcFsGv3r+EX/",
  "Token": "IQoJb3JpZ2luX2VjEOb//////////wEaDmFwLW5vcnRoZWFzdC0yIkcwRQIhAJRp7ov3nvS7fErWhNqo7ebeYZSS5UpL/pFP763QGDu7AiB23SvUsLr0J1bU/7gDsVH7KHta9Jm7pNwHyQrXZIMQSSrVBQiP//////////8BEAEaDDkxMTI4MzQ2NDc4NSIMgF5IMoJtct/G4uoYKqkFpUmOepDUb2NyRJ5b4CoeAzfEAReqtndk3EJiodz9RQiR0HTtkjfSHpQpCA5JuKDJR+kU8vkhbB+YHgrcL167k+lnblzJuhqYIAtTVYQ3UmZCfVYiwnA/ZhBxqzEvfQrmXQck990rT0sCHf0+fsWeeZHylsHi4DXINSv8BZbgm3leC/n77bJifeYvskbcWML9yEYAMK/rolnehtz/yuKqdWqN1PcmzL8KfkytBkCIEzezDVPF+9DLXbvOQXn26+41PzvXd+pB+d+IkbP8zCnC5hcbLZwE5z8/KYyqTdj9cJqTzQhSnMFkWFiYh4HddVpOq6oj0hOmIbjH8iAD9oMwEuVd/BgBPm9yadVugDVp6XWkLSaQ0esCoVALKzlbr06Tg7JUSpniuSEApqbAKM1dJlHck76UQwXot1n/D54JNyAq2GXbJz/ndqNsBCdtbVWERjcOyCZOH14uLlrRKZUmTEXpIhGOgpq4AHE+/KdisVDu0aaOvaQUhAzMg+x5ROqHCtJoLByYcez0A6PNqiBRIupKWYyRhZY7WzyH21BYw4pgI6ytjBOAQIknCyf5XzU/r+g6r8Ts9BXF75gPfIsMQQbKXdvjoJAHN3HMcfeiiuu6/LQ+bUkkiWdGepyx8iE+UzT8+AMa0Le3zNVSJCK+qz4gSnD/HW87+JPzzZyHA2yYMyXXAq0mBqxtiqI/maMx2o7Mi+xfsBa8cnvWOV3oAQN+drfkkRWWMZaEGVrCLBUf8KSQKup6hu4m257ytBUR3TH5schErAmksSadBzkiK8QX8ZOWNcuHQNcvPd56oLvKgDb1I5ehe96wgHWa/ZZz4jZZIrXKlVC30hRARARqTQxeo1CPi9P2lZrC+Z7vlHVGtazonB+atbQOFScDLAnBrAW4cpxM3sK9MOK5/Z8GOrEB+xhO3/OVp3bCpZ92G97tUUS07j4DWyCeFs1FXSUgLfwvXh7w0e9KPNW+tq87knudsCimTlsw5b/BFBCk5T386qv12m5CqYfOmTwLovpVUmR1wAoeIMgpBTb5AdpXkeuuMdCAc5nNqv3Zdp84+acyR1V2DmvRcFkQqtrCuc4Wt9FYi2QAcurNK9+HGDtlOstFVr2TiiPHpg1hCB3AhX8gpiiC4p5sK5P0VePWyjvSfirl",
  "Expiration": "2023-03-01T20:12:11Z"
}
---

# 파드 bash 실행 : 임시자격증명을 직접 입력하는 거라서 아무곳에서나 해도됨 >> 즉 별도의 ec2 1대를 신규 생성 후 임시자격증명 설정 후 확인해보자
# 실행하는 파드는 메타데이터 사용 시 Token이 필요한 노드에 배치된 파드에서 해볼 것!
kubectl get pod -owide
kubectl exec -it $APODNAME1 -- bash
kubectl exec -it $APODNAME2 -- bash
----------------------------------------------------------
# 위에서 출력된 AccessKeyId , SecretAccessKey , SessionToken 으로 임시자격증명 적용
export AWS_ACCESS_KEY_ID="ASIA5ILF2FJIZ3VBD6DB"
export AWS_SECRET_ACCESS_KEY="6fCWhz1eKupIXNl9w/BMcHh1YdSOYcFsGv3r+EX/"
export AWS_SESSION_TOKEN="IQoJb3JpZ2luX2VjEOb//////////wEaDmFwLW5vcnRoZWFzdC0yIkcwRQIhAJRp7ov3nvS7fErWhNqo7ebeYZSS5UpL/pFP763QGDu7AiB23SvUsLr0J1bU/7gDsVH7KHta9Jm7pNwHyQrXZIMQSSrVBQiP//////////8BEAEaDDkxMTI4MzQ2NDc4NSIMgF5IMoJtct/G4uoYKqkFpUmOepDUb2NyRJ5b4CoeAzfEAReqtndk3EJiodz9RQiR0HTtkjfSHpQpCA5JuKDJR+kU8vkhbB+YHgrcL167k+lnblzJuhqYIAtTVYQ3UmZCfVYiwnA/ZhBxqzEvfQrmXQck990rT0sCHf0+fsWeeZHylsHi4DXINSv8BZbgm3leC/n77bJifeYvskbcWML9yEYAMK/rolnehtz/yuKqdWqN1PcmzL8KfkytBkCIEzezDVPF+9DLXbvOQXn26+41PzvXd+pB+d+IkbP8zCnC5hcbLZwE5z8/KYyqTdj9cJqTzQhSnMFkWFiYh4HddVpOq6oj0hOmIbjH8iAD9oMwEuVd/BgBPm9yadVugDVp6XWkLSaQ0esCoVALKzlbr06Tg7JUSpniuSEApqbAKM1dJlHck76UQwXot1n/D54JNyAq2GXbJz/ndqNsBCdtbVWERjcOyCZOH14uLlrRKZUmTEXpIhGOgpq4AHE+/KdisVDu0aaOvaQUhAzMg+x5ROqHCtJoLByYcez0A6PNqiBRIupKWYyRhZY7WzyH21BYw4pgI6ytjBOAQIknCyf5XzU/r+g6r8Ts9BXF75gPfIsMQQbKXdvjoJAHN3HMcfeiiuu6/LQ+bUkkiWdGepyx8iE+UzT8+AMa0Le3zNVSJCK+qz4gSnD/HW87+JPzzZyHA2yYMyXXAq0mBqxtiqI/maMx2o7Mi+xfsBa8cnvWOV3oAQN+drfkkRWWMZaEGVrCLBUf8KSQKup6hu4m257ytBUR3TH5schErAmksSadBzkiK8QX8ZOWNcuHQNcvPd56oLvKgDb1I5ehe96wgHWa/ZZz4jZZIrXKlVC30hRARARqTQxeo1CPi9P2lZrC+Z7vlHVGtazonB+atbQOFScDLAnBrAW4cpxM3sK9MOK5/Z8GOrEB+xhO3/OVp3bCpZ92G97tUUS07j4DWyCeFs1FXSUgLfwvXh7w0e9KPNW+tq87knudsCimTlsw5b/BFBCk5T386qv12m5CqYfOmTwLovpVUmR1wAoeIMgpBTb5AdpXkeuuMdCAc5nNqv3Zdp84+acyR1V2DmvRcFkQqtrCuc4Wt9FYi2QAcurNK9+HGDtlOstFVr2TiiPHpg1hCB3AhX8gpiiC4p5sK5P0VePWyjvSfirl"

# ec2 정보 확인
bash-4.2# aws ec2 describe-instances --region ap-northeast-2 | head
{
    "Reservations": [
        {
            "Groups": [],
            "Instances": [
                {
                    "AmiLaunchIndex": 0,
                    "ImageId": "ami-0443a21cb1a8f238e",
                    "InstanceId": "i-0003f6c91590ed72a",
                    "InstanceType": "t2.micro",
...

# vpc 정보 확인
bash-4.2# aws ec2 describe-vpcs --region ap-northeast-2 | head
...

# 빠져나오기
exit
----------------------------------------------------------

 

 


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


 

보안 컨텍스트 : 컨테이너 , 파드 보안 통제 기법 중 하나 ! 

 

#
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: rootfile-readonly
spec:
  containers:
  - name: netshoot
    image: nicolaka/netshoot
    command: ["tail"]
    args: ["-f", "/dev/null"]
    securityContext:
      readOnlyRootFilesystem: true
  terminationGracePeriodSeconds: 0
EOF
## 컨테이너 레벨에 들어가 있음 
## 읽기 전용이라 파일 생성 불가 

# 파일 생성 시도
kubectl exec -it rootfile-readonly -- touch /tmp/text.txt
touch: /tmp/text.txt: Read-only file system
command terminated with exit code 1

 

linux capabiliites 

- 유저의 권한으로는 권한 통제 단위가 부족하니까 또 나눔 

 

#
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: sample-capabilities2
spec:
  containers:
  - name: nginx-container
    image: masayaaoyama/nginx:capsh
    command: ["tail"]
    args: ["-f", "/dev/null"]
    securityContext:
      capabilities:
        add: ["NET_ADMIN", "SYS_TIME"]
        drop: ["AUDIT_WRITE"]
  terminationGracePeriodSeconds: 0
EOF

# 파드의 Linux Capabilities 기본 확인
kubectl exec -it sample-capabilities2 -- capsh --print | grep Current
Current: = cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_admin,cap_net_raw,cap_sys_chroot,cap_sys_time,cap_mknod,cap_setfcap+ep
cap_chown,
cap_dac_override,
cap_fowner,
cap_fsetid,
cap_kill,
cap_setgid,
cap_setuid,
cap_setpcap,
cap_net_bind_service,
cap_net_admin, # 추가
cap_net_raw,
cap_sys_chroot,
cap_sys_time, # 추가
cap_mknod,
cap_setfcap+ep
# 제거됨 cap_audit_write

# 파드 상세 정보 확인
kubectl get pod sample-capabilities2 -o jsonpath={.spec.containers[0].securityContext} | jq
{
  "capabilities": {
    "add": [
      "NET_ADMIN",
      "SYS_TIME"
    ],
    "drop": [
      "AUDIT_WRITE"
    ]
  }
}

# proc 에서 확인 : bit 별 Capabilities - 링크
kubectl exec -it sample-capabilities2 -- cat /proc/1/status | egrep 'CapPrm|CapEff'
CapPrm:	000000008a0435fb
CapEff:	000000008a0435fb

# 파드에서 시간 변경 시도 : 시간 동기화하는 다른 우선순위가 있는것 같습니다! 혹신 아시는 분들은 댓글 부탁드립니다!
## 확인해 보니 시간이 변경되었지만 해당 파드가 동작되는 노드의 시간을 sync 하고 있습니다. 
## 노드에 접근해서 systemd-timesyncd 종료하면은 노드의 바뀐 시간까지는 따라가는 것을 확인했습니다. 
## systemctl stop systemd-timesyncd 그리고 파드에서 시간 변경시 해당 노드의 시간도 바뀌는 것을 확인 했습니다.
kubectl exec -it sample-capabilities2 -- date
kubectl exec -it sample-capabilities2 -- date -s "12:00:00"
kubectl exec -it sample-capabilities2 -- date

시간 권한 변경을 따로 주니까 에러가 안나고 시간 변경이 가능 

 


파드 보안 컨텍스트 

- 파드에 포함된 컨테이너가 영향을 받음 

- 컨테이너 정책이 우선순위가 높음 

#
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: rundefault
spec:
  containers:
  - name: centos
    image: centos:7
    command: ["tail"]
    args: ["-f", "/dev/null"]
    securityContext:
      readOnlyRootFilesystem: true
  terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Pod
metadata:
  name: runuser
spec:
  securityContext:
    runAsUser: 65534
    runAsGroup: 65534
    supplementalGroups:
    - 1001
    - 1002
  containers:
  - name: centos
    image: centos:7
    command: ["tail"]
    args: ["-f", "/dev/null"]
    securityContext:
      readOnlyRootFilesystem: true
  terminationGracePeriodSeconds: 0
EOF

#
kubectl get pod rundefault -o jsonpath={.spec.securityContext} | jq
kubectl get pod runuser -o jsonpath={.spec.securityContext} | jq

# 실행 사용자 정보 확인
kubectl exec -it rundefault -- id
uid=0(root) gid=0(root) groups=0(root)

kubectl exec -it runuser    -- id
uid=65534 gid=65534 groups=65534,1001,1002

# 프로세스 정보 확인
kubectl exec -it rundefault -- ps -axo uid,user,gid,group,pid,comm
  UID USER       GID GROUP        PID COMMAND
    0 root         0 root           1 tail
    0 root         0 root          13 ps

kubectl exec -it runuser    -- ps -axo uid,user,gid,group,pid,comm
  UID USER       GID GROUP        PID COMMAND
65534 65534    65534 65534          1 tail
65534 65534    65534 65534         19 ps

유저 정보를 바꿨고 확인 해보니 하나는 루트 하나는 지정한 유저 

보안을 강화하기 위해 루트 말고 다른 유저로 지정하는 편이 좋다 

 

파일시스템 그룹 지정 

- 마운트 하는 볼륨 그룹 변경 가능 

#
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: fsgoup1
spec:
  volumes:
  - name: vol1
    emptyDir: {}
  containers:
  - name: centos
    image: centos:7
    command: [ "sh", "-c", "sleep 1h" ]
    volumeMounts:
    - name: vol1
      mountPath: /data/demo
  terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Pod
metadata:
  name: fsgoup2
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
  volumes:
  - name: vol2
    emptyDir: {}
  containers:
  - name: centos
    image: centos:7
    command: [ "sh", "-c", "sleep 1h" ]
    volumeMounts:
    - name: vol2
      mountPath: /data/demo
  terminationGracePeriodSeconds: 0
EOF

#
kubectl get pod fsgoup1 -o jsonpath={.spec.securityContext} | jq
kubectl get pod fsgoup2 -o jsonpath={.spec.securityContext} | jq

# 실행 사용자 정보 확인
kubectl exec -it fsgoup1 -- id
uid=0(root) gid=0(root) groups=0(root)

kubectl exec -it fsgoup2 -- id
uid=1000 gid=3000 groups=3000,2000

# 프로세스 정보 확인
kubectl exec -it fsgoup1 -- ps -axo uid,user,gid,group,pid,comm
kubectl exec -it fsgoup2 -- ps -axo uid,user,gid,group,pid,comm

# 디렉터리 정보 확인 : fsgoup2파드의 마운트 볼륨 그룹의 GID가 2000 (fsGroup: 2000)
kubectl exec -it fsgoup1 -- ls -l /data
drwxrwxrwx 2 root root 4096 Apr  1 05:15 demo

kubectl exec -it fsgoup2 -- ls -l /data
drwxrwsrwx 2 root 2000 4096 Apr  1 05:15 demo

 

 


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"

# 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

1개만 돌리고 있어서 권고사항 뜸 


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 권한으로 컨테이너를 실행하지 않음
...

권고사항에 적합하지 않은 부분들을 수정해서 다시 배포 

# 삭제
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

 

 


kubescape

- 보안 권고 사항 대비 지금 구성된 클러스터의 취약점을 점검하는 도구 

 

보안 점검 결과 

 

 

728x90

'Server&Network > Kubernets_Dokcer' 카테고리의 다른 글

PKOS 4주차 모니터링  (0) 2023.04.02
PKOS 3주차 GitOps  (0) 2023.03.26
PKOS 2주차  (1) 2023.03.19
PKOS 1주차  (2) 2023.03.12
로컬에서 k8s 구축하기  (1) 2023.03.04