home..

보안

kubernetes security msa mont-kim aws eks kops PKOS gasida CloudNet

7주차

KOPS를 이용한 프로비저닝

➝ 저번주차와 다르게 kops edit명령어를 별도로 선언하지않아도 cluster 정보가 custom 되어있는 클러스터를 프로비전이 할 수 있다.

추가적으로 이번주차에서 다루는 내용에선 큰 사이즈의 노드가 필요하지않기때문에, c5.2xlarge 가 아닌 t3.xlarge 인스턴스로 프로비저닝을 진행한다.

첫번째로 EC2의 IAM ROLE의 메타데이터를 제거한다.

kops edit ig nodes-ap-northeast-2a

---
spec:
  instanceMetadata:
    httpPutResponseHopLimit: 1
    httpTokens: required
---
세줄을 삭제해 해당 노드(AZ지만 해당AZ에 노드 한대)에서 메타데이터를 삭제한다.

Boto3을 이용해 pod에서 ec2의 메타데이터가 조회 가능한지 확인한다.

# 파드 이름 변수 지정
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/securi

권한이 있는 노드에서만 인스턴스의 메타데이터를 확인 할 수 있다.

https://t37022643.p.clickup-attachments.com/t37022643/c60d5f47-a6c7-42a0-a923-2af053daf0f6/image.png

키를 조금 더 확대해보면 다음과 같다.

{
  "Code": "Success",
  "LastUpdated": "2023-03-02T13:57:43Z",
  "Type": "AWS-HMAC",
  "AccessKeyId": "ASIAT65RMYESLPVSJLFJ",
  "SecretAccessKey": "5tXQiXVyVZ+xnsZSkTwfF/cDGrieLM8zAQWNy4xz",
  "Token": "IQoJb3JpZ2luX2VjEP7//////////wEaDmFwLW5vcnRoZWFzdC0yIkgwRgIhALaidTi8U836bYs04n4A/ayxXX1vihJmsNVmv2Tdm45kAiEAu1u7j86RiJATmW8epkfPFZ7eUJZka+eNaQBTb7CCFS4q1QUIp///////////ARAAGgwyNzI1NjU1ODQxNjQiDCXN19y8VktBq3cG1iqpBUspF6MmaYc2qAve4y4EkkZXe2AaRbVJSZP34JsZ7a+Jjh0/15Xe84x7VIeRIOyK12820il+6+F6wu1OkXHgNMp4NXrAmPALdG+AzHMMMMwWNOqHq2cGFjoIjY8UHa/Yl2WonqeXKmJjAsMld105TVDTcadD+rdT1tceZNfcy1SCsAL/g2lIV50hiK57G+6IummCz2kkMFNuDPdI6KQowb2g0cbGdQMbKtmGrE0UD1pYao937xEEmb4xvTbWNC+s/8ux1SromRuPU6j8ej517TfzVnmlEk8gpmsFptsqgwrRgtO/d1WthKFSUvMf3P8UozwdMVavgQae22nokm7x2a3Pt5/XNVxgFIX7tljShS4Dmoi7+toixADSjY9GPJ+ORrL160t4LeizeLlq4LXdF2gRyDd7d9KACxHxzy/69mHWTizVC/O9WFCn7Q5omkenf1E7Tv6IPK/T+0r8IzeOrEx4VKFbwI8zqqUqmAaMClAtiPpmA/UJUcii2WAclg36Qdzx7VbfUkgRavy+tUnyAg957OjmfQA/QBjMfpNdkvA3UEdiDbDfk/Axu9RTuNuhF2oJetFCP4td8c9p79IYg5FreSsZFnnUiCT+Ez72p1cSwDvQLNle1B/KElscuyJoXc6oSTD2jq8WlNnmC9x/OfyRhiBlT+KOdrzodeSsasOr7pD5WZYTpih+WE5hQL1CAM+l9kLwDv6oLNpZJdlmV2Dt7XA6SGJs9ic80jYZvoJEfhL5o80lJAIUdx8nFtm+ygV5Fa1vqR36AJkKA32g3dZQDJjAyRe8W5rWeounu+ukS03wjMAvWeUuue6wTJ5RO/pkjXfq3eMUCrkqmYGoTCqiF06ZCqFpepkPDFDKvqUZswq6SfzlN5Kfk0gLjek1Rm4CqVbYI7Ic5TC71oKgBjqwAVeeFxy183C86T4U8JQ9ahfsGgMyOYXg4hDGgxUIiRhtAmXUkpJaQsR+dURpGvKTX7+w064tP0H6FY19pg9p3/meOLC81s2ZnwINxpcgHUMsHGy0QCAtMBlemiJA5uza2QozoiwRprCUDmAKlW+U/uSMJxEzc+r7ZITwUcGofxNibl7pS1yZ5rV0YcY94V2eCehCNsiUYm/vHHr5Tl04dwifLS/SNNWqlNLH4uHcPQ2L",
  "Expiration": "2023-03-02T20:32:15Z"
}

7주차 과제

  • [과제1] 파드에서 EC2 메타데이터의 IAM Role 토큰 정보를 활용하여(boto3), 스터디에서 소개한 것 이외의 다른 AWS 서비스(혹은 Action)를 사용 후 코드나 스샷을 올려주세요

새로운 IAM을 추가해 인스턴스에 적용을 한다.

IAM 콘솔에서 역할 ➝ 역할 생성

https://t37022643.p.clickup-attachments.com/t37022643/a2f735e8-fe80-4095-bd79-858a37ab097f/image.png

사용사례 ➝ EC2 를 선택해

정책을 선택한다.

https://t37022643.p.clickup-attachments.com/t37022643/d8a36707-4e83-4c30-b140-bd39cc36cc2e/image.png

해당 역할을 선택후 역할생성은 완료한다

이후에 인스턴스에서 해당 IAM을 선택해 별도로 적용해주는 과정을 거쳐야 한다.

https://t37022643.p.clickup-attachments.com/t37022643/3328c602-44f7-4e99-86bf-c001ed5e9d45/image.png

EC2 콘솔에 들어가 인스턴스 정보 수정을 진행한다.

작업 ➝ 보안 ➝ IAM 역할수정을 선택해 역할을 수정 또는 편집을 진행한다.

https://t37022643.p.clickup-attachments.com/t37022643/4baa3795-28cc-4744-b775-e26df5724824/image.png

방금전 IAM 콘솔에서 생성했던 Read Only 인스턴스 IAM을 선택 후,

IAM 역할 업데이트를 시작한다.

boto3 이미지를 사용해 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})

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

https://t37022643.p.clickup-attachments.com/t37022643/05308895-41ac-4145-9993-d631e6fea3d1/image.png

PODNAME1의 경우엔 권한이 없어 정보획득에 실패한것을 볼 수 있다.

https://t37022643.p.clickup-attachments.com/t37022643/930cbebe-a8e1-4d6f-aca3-f87603d3862f/image.png

반면에 PODNAME2의 경우엔 노드의 정보들을 그대로 확인한것을 볼 수 있다.

kubescape

kubescape는 쿠버네티스 클러스터의 yaml, helm chart등의 취약점을 점검하는 도구이다.

cli 기반 환경을 다루는것과 web에서 다루는것은 큰 차이가 없으나, 과제에서 다루는 내용과 동일하여 과제설명창에서 같이 다룬다.

  • [과제2] 책 398~400페이지 - kubescape armo 웹 사용 후 관련 스샷을 올려주세요

kubescape 다운로드

curl -s https://raw.githubusercontent.com/kubescape/kubescape/master/install.sh | /bin/bash
kubescape download artifacts

kubescape scan --enable-host-scan --verbos

https://t37022643.p.clickup-attachments.com/t37022643/0436e89e-b0de-4fd0-be9f-ed0994af0416/image.png

로컬에서 kubescape scan 명령어를 하면 위와같이 결과물이 나온다.

웹에서 회원가입후 Repository Scan 버튼을 누르면, account info가 출력된 명령어를 안내해준다.

https://t37022643.p.clickup-attachments.com/t37022643/9e6f740a-97da-4868-b6f2-9aaaed733b33/image.png

문제는 웹에서 정보 연동을 위한 account 파라미터를 추가해도 실패한다…

  • v 옵션을 붙여 자세한 정보를 확인해보려했지만, 여전히 연동이되지않는다.

이유가 뭘까…?

Polaris

Polaris 또한 kubescape와 유사한 오픈소스 보안 점검 도구이다.

kubescape와 동일하게 cli기반 / 웹기반 서비스가 모두 존재하기때문에, web에서 다루는 과제의 내용과 함께 다루도록 한다.

  • [과제3] polaris 관련 실습(아무거나) 후 관련 스샷을 올려주세요

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.yam

polaris-values.yaml 파일에서 Classic Loadbalancer Type로 생성을하지만

annotate service 기능을 이용해 도메인을 연결이 안된다…

CLB이기때문에 생성까지 약 5분 소요된다.

CLB 주소로 로그인을 진행한다.

AWS EC2 ➝ 로드밸런서 항목에서 Endpoint를 획득하거나

kubectl get svc

에서 서비스에 부여된 Endpoint를 획득해 해당 주소로 polaris에 접근한다.

https://t37022643.p.clickup-attachments.com/t37022643/f521819a-dbe3-43e7-b6af-ebc21eb01c7e/image.png

polaris 서비스에 접속하면 클러스터의 정보를 조회 할 수 있다.

클러스터 한정이 아닌, 특정 pod 자체에 대해 진단결과를 확인 할 수 있다

cat <<EOT > polaris-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: polaris-demo
spec:
  containers:
    - name: nginx
      image: nginx:latest
      resources:
        requests:
          memory: "64Mi"
          cpu: "250m"
        limits:
          memory: "128Mi"
          cpu: "500m"
EOT

kubectl apply -f polaris-demo.yaml

해당 pod을 배포후, polaris 웹 에서의 “Filter by namespace” 를 apply 해

polaris-demo pod의 상태를 확인 할 수 있다.

https://t37022643.p.clickup-attachments.com/t37022643/6b2f6403-5675-4ba8-a63b-5eaa487c3f7c/image.png

demo pod의 몇가지 문제점에 대해 진단을 해준것을 확인할 수 있다.

해당 문제점을 수정후 pod을 재배포 해본다.

kubectl delete -f polaris-demo.yaml

cat <<EOT > polaris-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: polaris-demo
spec:
  containers:
    - name: nginx
      image: nginx:1.23.3
      imagePullPolicy: Always
      resources:
        requests:
          memory: "64Mi"
          cpu: "250m"
        limits:
          memory: "128Mi"
          cpu: "500m"
      securityContext:
        runAsUser: 1000
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        capabilities:
          drop:
            - ALL
EOT

kubectl apply -f polaris-demo.y

문제점을 수정후 배포된 pod의 상태를 진단한다

https://t37022643.p.clickup-attachments.com/t37022643/06950c99-93d0-43c3-92dc-8480534d3dd4/image.png

warning은 모두 사라지고, 주의가 필요한 pod중, pod이 정상적으로 구동되고있는지

readiness, liveness 를 추가해주면 좋다는 조언만 한 채로 마친다.

web에서 생성되어있는 pod을 확인해보는것 뿐만 아니라

cli 기반 환경에서도 작성한 yaml 파일을 진단 할 수 있는 기능도 있다.

wget https://github.com/FairwindsOps/polaris/releases/download/7.3.2/polaris_linux_amd64.tar.gz
tar zxvf polaris_linux_amd64.tar.gz
mv polaris /usr/local/bin
polaris audit --audit-path ~/pkos/1/mario.yaml --format=pretty

https://t37022643.p.clickup-attachments.com/t37022643/1c224bc6-57c3-4131-a2da-89b85b844c0a/image.png

polaris에서 주로 진단해주는 기능들은 security에 관련된것이 많다.

CKS 시험에서도 주로 다루는 영역이기도하면서

실제로 보안 (pod내부에서 호스트에 미치는 영역) 등에 관련된 항목들이 많은것 같다.

주로 확인해볼만한 부분은 securityContext와 Pod Security Policy 인것같다.

다만 PSP의 경우 1.21버젼에서 deprecated 되었기때문에 특별히 다루지않는다.

인증 / 인가 & RBAC

인증 및 인가에 개념에 대해 간단하 다뤄본다.

인증은 자격을 증명하는 행위이고

인가는 해당 인증의 접근권한을 부여/거부하는 행위입니다

쿠버네티스에서의 인증은 X509 인증서 (kube config 에서 사용하는 ca.crt, client.crt, client key)

kubectl에서 사용하는 config와 context들

그리고 Service Account가 있다.

반면에 쿠버네티스에서의 인가는 RBAC, ABAC, Webhook, Node Authorization이 있다.

가장 대표적으로 사용되는 인가는 RBAC이다

새로운 SA를 생성해서 dev와 infra 관리자를 구현하는 과정을 담아본다

kubectl create namespace dev-team
kubectl create ns infra-team

kubectl create sa dev-k8s -n dev-team
kubectl create sa infra-k8s -n infra-team

cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: role-dev-team
  namespace: dev-team
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]
EOF

cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: role-infra-team
  namespace: infra-team
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]
EOF

cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: roleB-dev-team
  namespace: dev-team
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: role-dev-team
subjects:
- kind: ServiceAccount
  name: dev-k8s
  namespace: dev-team
EOF

cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: roleB-infra-team
  namespace: infra-team
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: role-infra-team
subjects:
- kind: ServiceAccount
  name: infra-k8s
  namespace: infra-team
E
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: dev-kubectl
  namespace: dev-team
spec:
  serviceAccountName: dev-k8s
  containers:
  - name: kubectl-pod
    image: bitnami/kubectl:1.24.10
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0
EOF

cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: infra-kubectl
  namespace: infra-team
spec:
  serviceAccountName: infra-k8s
  containers:
  - name: kubectl-pod
    image: bitnami/kubectl:1.24.10
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0
EOF

alias k1='kubectl exec -it dev-kubectl -n dev-team -- kubectl'
alias k2='kubectl exec -it infra-kubectl -n infra-team -- kubectl'

k1 get pods
k1 run nginx --image nginx:1.20-alpine
k1 get pods -n kube-system

k2 get pods
k2 run nginx --image nginx:1.20-alpine
k2 get pods -n kube-system

각각 role와 rolebinding을 통해 각각 dev / infra의 권한을 부여해주고 binding을 통해 연동해줬다

dev-k8s 라는 Service Account와 infra-k8s라는 Service Account를 생성해 각각 pod의 정보 조회, pod 생성하는 과정을 담았다

  • [과제4] 신규 서비스 어카운트(SA) 생성 후 ‘클러스터 수준(모든 네임스페이스 포함)에서 읽기 전용’의 권한을 주고 테스트 후 코드나 스샷을 올려주세요

SA 생성후 권한을 부여하는과정은

CKA에서 다루는 비중이 큰 문제이기도하다

Role Based Access Control (RBAC)을 자랑하는 쿠버네티스의 대표적인 기능이라고도 볼 수 있기 때문이다.

Service Account, ClusterRole을 생성후

ClusterRolebinding을

clusterrole.yaml

cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kube-reader-cluster-role
rules:
- apiGroups:
  - '*'
  resources:
  - '*'
  verbs:
  - get
  - list
  - watch
EOF

clusterrole을 생성한다.

kubectl create sa kubernetes-monitor

kubectl create clusterrolebinding kubernetes-monitor --clusterrole=kube-reader-cluster-role --serviceaccount=default:kubernetes-monitor

kubectl describe clusterrolebindings  kubernetes-monito

service account를 생성하고

생성했던 clusterrole와 serviceaccount를 연결하는 clusterrolebinding을 생성한다.

cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: read-only-kubectl
  namespace: default
spec:
  serviceAccountName: kubernetes-monitor
  containers:
  - name: kubectl-pod
    image: bitnami/kubectl:1.24.10
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0
EOF

생성된 SA를 이용해 pod을 생성하는 yaml 파일을 작성후 실행해본다.

kubectl exec -it read-only-kubectl -n default -- ls /run/secrets/kubernetes.io/serviceaccount
kubectl exec -it read-only-kubectl -n default -- cat /run/secrets/kubernetes.io/serviceaccount/token
kubectl exec -it read-only-kubectl -n default -- cat /run/secrets/kubernetes.io/serviceaccount/namespace
kubectl exec -it read-only-kubectl -n default -- cat /run/secrets/kubernetes.io/serviceaccount/ca.crt

pod에 부여된 정보들을 확인해본다.

alias k3='kubectl exec -it read-only-kubectl -n default -- kubectl'

이제 생성한 pod을 이용해 kubectl 명령어를 사용하는 단축키를 지정했다.

k3 get pods -n kube-system

k3 run nginx --image nginx:1.20-alpine

Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:kubernetes-monitor" cannot create resource "pods" in API group "" in the namespace "default"
command terminated with exit code

get pod는 정상적으로 응답이 오지만, run 명령어는 실행 할 수 없는것을 확인 할 수 있다.

이렇게 이번주차마저 스터디가 끝났다 7주차로 구성된 PKOS 스터디는 길다면 길고 짧다면 짧은 스터디였던것같다.

마지막 주차는 쿠버네티스 운영을하면서 조금씩 쌓아가던 보안에서 다루지 못했던부분들 그리고 어떤 발표에서 들었던 “인증, 인가의 중요성”을 다시끔 상기하면서 공부할수 있어서 좋았다

생각보다 흔하게 알고있던 지식을 다시끔 한번 밟으며 놓쳤던 부분들을 다시 배우며 많은 실력을 쌓을 수 있었고, 무엇보다 클라우드 기반으로 구현을 진행하며 배우는것들이 더욱 많았던것같다.

이번 스터디를 마무리하면서 그동안 알고있었던 지식을 정형적으로 정리를 해보는게 스스로에게 도움이 될거같다는 생각을 하게된다.

외쳐 갓시다!!!!

© 2024 mont kim   •  Powered by Soopr   •  Theme  Moonwalk