[CloudNet@] PKOS 스터디는 '24단계 실습으로 정복하는 쿠버네티스' 도서를 베이스로 진행됩니다!!
Related URL: https://www.yes24.com/Product/Goods/115187666
안녕하세요 늑대양입니다 😍
이번에 CloudNet@에서 진행하는 Production Kubernetes Online Study(PKOS)에 참여하여 관련 내용을 공유드리고자 합니다.
벌써 PKOS 스터디의 마지막 주차군요 👻
오늘은 PKOS 스터디 7주차 학습 내용을 안내해드리록하겠습니다.
CloudNet@ 팀 블로그 Main URL:
https://www.notion.so/gasidaseo/CloudNet-Blog-c9dfa44a27ff431dafdd2edacc8a1863
CloudNet@ Blog
CloudNet@ 팀에서 Cloud Infra & Network 기술에 대한 정보를 공유하는 블로그 입니다.
www.notion.so
Production Kubernetes Online Study - 7주차
7주차 학습 주제: 쿠버네티스 보안 (Alertmanager & Loki & PLG Stack)
Index.
- 이론
- 실습 환경 배포
- EC2 IAM Role & 메타데이터
- kubescape
- polaris
- K8s 인증/인가 & RBAC
- (실습 완료 후) 자원 삭제
- 과제
- 과제 1. 파드에서 EC2 메타데이터의 IAM Role 토큰 정보를 활용하여(boto3), 스터디에서 소개한 것 이외의 다른 AWS 서비스(혹은 Action)를 사용 후 코드나 스샷을 올려주세요
- 과제 2. 책 398~400페이지 - kubescape armo 웹 사용 후 관련 스샷을 올려주세요
- 과제 3. polaris 관련 실습(아무거나) 후 관련 스샷을 올려주세요
- 과제 4. 신규 서비스 어카운트(SA) 생성 후 '클러스터 수준(모든 네임스페이스 포함)에서 읽기 전용'의 권한을 주고 테스트 후 코드나 스샷을 올려주세요
이론
실습 환경 배포
- kops 인스턴스 t3.small & 노드 t3.xlarge (vCPU 4, Memory 16GiB) 배포 진행
- kops 인스턴스(t3.small)에 ⇒ 13분 후 SSH 접속후 EC2 instance profiles 설정
# YAML 파일 다운로드
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/kops-oneclick2.yaml
# CloudFormation 스택 배포 : 노드 인스턴스 타입 변경 - MasterNodeInstanceType=c5d.large WorkerNodeInstanceType=c5d.large
aws cloudformation deploy --template-file kops-oneclick2.yaml --stack-name mykops --parameter-overrides KeyName=sainthm-kops-key SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 MyIamUserAccessKeyID=AKIAX66... MyIamUserSecretAccessKey=K+0VWS... ClusterBaseName=wolf-sheep.name S3StateStore=sainthm-kops-test MasterNodeInstanceType=t3.xlarge WorkerNodeInstanceType=t3.xlarge --region ap-northeast-2
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - mykops
# CloudFormation 스택 배포 완료 후 kOps EC2 IP 출력
aws cloudformation describe-stacks --stack-name mykops --query 'Stacks[*].Outputs[0].OutputValue' --output text
# 13분 후 작업 SSH 접속
ssh -i ~/.ssh/kp-gasida.pem ec2-user@$(aws cloudformation describe-stacks --stack-name mykops --query 'Stacks[*].Outputs[0].OutputValue' --output text)
# EC2 instance profiles 에 IAM Policy 추가(attach) : 처음 입력 시 적용이 잘 안될 경우 다시 한번 더 입력 하자! - IAM Role에서 새로고침 먼저 확인!
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
# 메트릭 서버 확인 : 메트릭은 15초 간격으로 cAdvisor를 통하여 가져옴
kubectl top node
kubectl top pod -A
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
Boto3가 AWS의 자격증명(Credentials)을 확인하는 순서 .from Python
[매뉴얼] Boto3가 AWS의 자격증명(Credentials)을 확인하는 순서 .from Python
I. 개요 이번 포스팅은 'Boto3가 AWS의 자격증명(Credentials)을 확인하는 순서' 인 Credentials — Boto3 Docs 1.17.21 documentation > Configuring credentials
tech.cloud.nongshim.co.kr
파드에서 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
# 메타데이터 메모해두기
{
"Code": "Success",
"LastUpdated": "2023-03-05T09:08:04Z",
"Type": "AWS-HMAC",
"AccessKeyId": "ASIAX66ZKAZSADHNQOIF",
"SecretAccessKey": "Bgcz3abCNU7fXg1RT7SBpl12/AZV9dv7a8My8sOU",
"Token": "IQoJb3JpZ2luX2VjEEEaDmFwLW5vcnRoZWFzdC0yIkcwRQIhANlP45u5pzCGebnG1L+XO+oC6lgKguAEs34MDvujZ5xkAiBf60PfmbyKR5SigHlxBe02dmT54ldG5o1zU4kgoesiQCrVBQjq//////////8BEAQaDDU0NzUyNzE5ODMwOCIMPgtm2HidxRv/41BFKqkF2utTjwqQlA671RoFpmuoEND4pNNp3jU+cQBNxNucW5wZswwiSwgvmL1j6Np0foVktFWh+idOHsMD5KJ+VE27pNDLLUoqN8vsEfgB7xOI15uyz3VBeQRU60eE35RUzWd2td2uSBw6ezksbLxK5KC//LHORJIujj19+9hm3hPjYolvJ0It9GpEuJFb5GC0YCS4oQtyHBaFXdQBVYzBmc65fhjgqCC+y0nl2/H4mYaxAVT16wzCrmzyqiZylGjKkJlq52PP12eTJioy6U1TvgD6GZW6iHPVwFn2U1Pgs2C+9jNcW4m7Mz9aMV9TnFjM7gJIuUlgBl9q3i1J41rCPUY+/C+zATQ1Ma0LfRTTGWfKENqEdGrkdJmrthVKOSnPvM+BvrjsaNhx4NWIVHFEtc3bIKQrsNfSqGpf/VCoWyrgpxqvuENrW/duDC2vL5i9RUxXdep7BdGdJbWBTkLMilFOgMLLIuQjovYlNHLutqb1kcmETCu5Lbcc54Z1NTrr5ola6BEARTK7++kOIfJA1QbKyLrnq9cdGq9DMTiC0X2/Dt+6Cuy54VlNolWUdqU94g9joeHa/Sxa+jDs+TcbFpNpakqIf3E7Qm7Q3yUZVL3wR6Xmd7uU52PGfihG6PV6wy33/ey0FMr5RazQSPjN4wDEfb8/8FZy8nbIITtBYUcDyBFm48usW47Z5re/JM53M26sYLY23lHthWN6LgQ0Aemdd7NMrdrtR2GPSs+JKNy6dUKirgyD98mg7uhM9PQJIKVYRKb/nxHyOHwvIuzG6Vg9gctuJHawZcNfIvq2XfQldFkkcQ8hap8NhhtHTT+Kr9cY2n6mxtt2IoXrGPgH6UernLXlOSI3/y9CmJQAT+w6+RAIhKUDnkExWfRL2YXEK9HhFefIFPbG1x1SMIq4kaAGOrEBdKXGo3uubRhuF3tafJNlN7Y8vMopVmB6hQnf3DBEhdMUs9H41B0gJ+kMzHDzQs6+SSqtUbiwqNNt6bAqiQuBmqEA3MWoAHfIBd8ih/xqVkn7v6X5ExgLZiJKCuXd9kmXu21F2G+MACJWdbmvvvPGOB2NLYO8k9Nd5ZUXGjf3sfocVFBqI2K5C6neHZ4Wn0lXZH0IgQPTvxn7TwRu09lWSIyzISIyex7RJzCNtiL7+Y8x",
"Expiration": "2023-03-05T15:43:26Z"
}
파드(컨테이너) 탈취 후 EC2 메타데이터의 IAM Role 토큰 정보를 활용해 python boto3를 통해 SDK로 AWS 서비스 강제 사용
[참고] [boto3-docs] Managing Amazon EC2 instances
https://boto3.amazonaws.com/v1/documentation/api/latest/guide/ec2-example-managing-instances.html
Managing Amazon EC2 instances — Boto3 Docs 1.26.84 documentation
Managing Amazon EC2 instances This Python example shows you how to: Get basic information about your Amazon EC2 instances Start and stop detailed monitoring of an Amazon EC2 instance Start and stop an Amazon EC2 instance Reboot an Amazon EC2 instance Prere
boto3.amazonaws.com
# 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
⇒ 대응 방안 : EC2 메타데이터 접속 제한 or AWS IRSA 사용
(추가) awscli 파드를 추가하고, 획득한 IAM Role Token을 활용해서 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 실행 : 임시자격증명을 직접 입력하는 거라서 아무곳에서나 해도됨
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
----------------------------------------------------------
AWS IRSA : 파드별 IAM Role 부여
관련 링크: https://ssup2.github.io/theory_analysis/AWS_EKS_Service_Account_IAM_Role/
AWS EKS Service Account에 AWS IAM Role 부여
AWS EKS Cluster의 Service Account에 AWS IAM Role을 부여하는 과정을 정리한다. 이러한 기능을 IRSA(IAM Roles for Service Accounts)라고 명칭한다.
ssup2.github.io
kubescape
보안 권고 사항 기반 현재 쿠버네티스 클러스터(YAML, Helm chart)의 취약점을 점검
- Kubescape is an open-source Kubernetes security platform for your IDE, CI/CD pipelines, and clusters. It includes risk analysis, security, compliance, and misconfiguration scanning, saving Kubernetes users and administrators precious time, effort, and resources.
- Kubescape scans clusters, YAML files, and Helm charts. It detects misconfigurations according to multiple frameworks (including NSA-CISA, MITRE ATT&CK® and the CIS Benchmark).
- Kubescape was created by ARMO and is a Cloud Native Computing Foundation (CNCF) sandbox project.
# 설치
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
소개 및 설치 진행
- 오픈소스 보안 점검 도구
- Polaris is an open source policy engine for Kubernetes that validates and remediates resource configuration
- It includes 30+ built in configuration policies, as well as the ability to build custom policies with JSON Schema
- When run on the command line or as a mutating webhook, Polaris can automatically remediate issues based on policy criteria
- helm URL: https://artifacthub.io/packages/helm/fairwinds-stable/polaris
polaris 5.7.2 · fairwinds/fairwinds-stable
Validation of best practices in your Kubernetes clusters
artifacthub.io
- As a dashboard - Validate Kubernetes resources against policy-as-code ⇒ 실습 범위
- As an admission controller - Automatically reject or modify workloads that don't adhere to your organization's policies ⇒ 실습 범위
- Validating Webhook : 새 워크로드 배포 시 체크 항목 만족 되지 않을 경우, 배포 차단 ⇒ helm 배포 때 webhook 활성화 필요
- As a command-line tool - Incorporate policy-as-code into the CI/CD process to test local YAML files.
# 설치
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"
- Score : 모범 사례 대비 전체 클러스터 구성 내역 점수, 권고 사항 만족이 많을 수록 점수 상승
- Passing/Warning/Dangerous Checks : 위험 등급 분류, 위험 단계 취약점은 조치를 권고
- 측정 범위 : Efficiency, Reliability, Security
- 검사 항목 상세 - 링크
보안 취약점 점검
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 조치 후 확인
# replica 개수 증가
kubectl scale deployment netshoot-pod --replicas 2
보안 모범 사례 적용 후 재점검
폴라리스 파드(polaris-dashboard)의 설정 참고
#
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
webhook 활성화 후 테스트 - 링크
# webhook 활성화 적용
helm upgrade polaris fairwinds-stable/polaris --namespace polaris --version 5.7.2 --reuse-values --set webhook.enable=true
kubectl get pod,svc -n polaris
# 취약한 파드 배포 시도
# 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
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
IaC 활용 cli - 링크
# 다운로드
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 --help
# 마리오 파드 yaml 점검
polaris audit --audit-path ~/pkos/1/mario.yaml --format=pretty
- (참고) Github Action 에 polaris actoin 수행 - 링크
- 다음 실습을 위해 polaris 삭제: helm uninstall -n polaris polaris
- 컨테이너 보안 컨텍스트 : 정리 예정 - 책 p590 - 링크
- 파드 보안 컨텍스트 : 정리 예정 - 책 p592 - 링크 링크2
K8s 인증/인가 & RBAC
인증(Authentication)
- X.509 Client Certs : kubeconfig 에 CA crt(발급 기관 인증서) , Client crt(클라이언트 인증서) , Client key(클라이언트 개인키) 를 통해 인증
- kubectl : 여러 클러스터(kubeconfig)를 관리 가능 - contexts 에 클러스터와 유저 및 인증서/키 참고
- Service Account : 기본 서비스 어카운트(default) - 시크릿(CA crt 와 token)
인가(Authorization)
- 인가 방식 : RBAC(Role, RoleBinding), ABAC, Webhook, Node Authorization⇒ RBAC 발음을 어떻게 하시나요?
- RBAC : 역할 기반의 권한 관리, 사용자와 역할을 별개로 선언 후 두가지를 조합(binding)해서 사용자에게 권한을 부여하여 kubectl or API로 관리 가능
- Namespace/Cluster - Role/ClusterRole, RoleBinding/ClusterRoleBinding, Service Account
- Role(롤) - (RoleBinding 롤 바인딩) - Service Account(서비스 어카운트) : 롤 바인딩은 롤과 서비스 어카운트를 연결
- Role(네임스페이스내 자원의 권한) vs ClusterRole(클러스터 수준의 자원의 권한)
.kube/config 파일 내용
- clusters : kubectl 이 사용할 쿠버네티스 API 서버의 접속 정보 목록. 원격의 쿠버네티스 API 서버의 주소를 추가해 사용 가능
- users : 쿠버네티스의 API 서버에 접속하기 위한 사용자 인증 정보 목록. (서비스 어카운트의 토큰, 혹은 인증서의 데이터 등)
- contexts : cluster 항목과 users 항목에 정의된 값을 조합해 최종적으로 사용할 쿠버네티스 클러스터의 정보(컨텍스트)를 설정
- 예를 들어 clusters 항목에 클러스터 A,B 가 정의돼 있고, users 항목에 사용자 a,b 가 정의돼 있다면 cluster A + user a 를 조합해, 'cluster A 에 user a 로 인증해 쿠버네티스를 사용한다' 라는 새로운 컨텍스트를 정의할 수 있습니다
- kubectl 을 사용하려면 여러 개의 컨텍스트 중 하나를 선택
# .kube/config 파일 예시
cat .kube/config
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM1ekNDQWMrZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJeE1Ea3dNVEl5TkRjMU1sb1hEVE14TURnek1ESXlORGMxTWxvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTG1qCml1cW11UUxWTXN6UE83VUpxTkdCNHdXQ3RnYTl1cFcwYUVNVmUrZm41YXZZMWxUWUZqZjBCb1VlQXhOWmc5YXoKRU1FZVJMWCt1ZzhqTDNETjhCTzEwdUEwSzF6b3ZpQVVtbDlCU2dNWU9FOHpUMFJsV2tvcnBtVDNGai9td1lJagpEemRxYld6MlpuQ1FoQ3dvYURzdlpoUVNMRTh6dnFwU0F5c0hNSUdzV3J0anI4aC9QaW52dnF5bUo0UlFhWlY3CnNuZ0lzMDBqakdGbFowcUVueWZMSGtBeHpjSktVUnJHamFsZm1RdmZ3WkZ2Z0pjam5rSG9jb3g0T0JKUEh0N2EKdFE1OEpBTTF3cng0b3pFSjh1MExsa21LOWYwWGVzQmRGeUhFamZ1elhTYml0Q09sbTR1Q1o3UkVRVmRjZWk1SAo3Tjg1M1RjbWRIck9tRkQwZVpVQ0F3RUFBYU5DTUVBd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZLRVYvZFNBUkJteVhyLytxUkVnb1h5QUg3UTZNQTBHQ1NxR1NJYjMKRFFFQkN3VUFBNElCQVFDQ0M4cDRQRmdoVVFDbW5weWk1SDAxYVRNYXp0Si9pdkw0amxiMWJNdXc3ZjJNZmM0UQpDRGw2UWVNd2FpYk9raHNrVGhMTEtRckQwQ0xqWXNCSy9iNVhQSTNtMmoxS0cvc1ExREFPL0hNdmt6RmkzUDdrCmJHOUErdWk1YXJPREs5eWJFQ2NtUG5adnVmWkFSY3d3dkp1ZGRMUy9QZERkOW9ZVGgzV3FQMjloVk9tZnZUS3kKNFhzeVg0cHk5dzVTNkYxaGVpUE9odnprMWRzNWFZZENBR1E5R0ZRb3BIQSs1Wm9YOWJjazFuN0FiMDVua0UrUQprMTVnc1VhQWFEMGVGUlRHY0tRTzM5dW1ZdkxhVnUrL20xcDFFRWU0YWdLdktvUGZlZ1VJTFQ0dGtLdjFwcWYvCmhIZldDUFo3Vy9ldmRZODI5WmtudE1HWHZ5QXZaWHFUZE1KZwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
server: https://192.168.100.10:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
namespace: default
user: kubernetes-admin
name: admin@k8s
current-context: admin@k8s
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURJVENDQWdtZ0F3SUJBZ0lJUzFnbmhwU0N5Q2d3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TVRBNU1ERXlNalEzTlRKYUZ3MHlNakE1TURFeU1qUTNOVFZhTURReApGekFWQmdOVkJBb1REbk41YzNSbGJUcHRZWE4wWlhKek1Sa3dGd1lEVlFRREV4QnJkV0psY201bGRHVnpMV0ZrCmJXbHVNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQW52eXoxc1R1SXRpKzE3WmQKVVRXTFVxMUxIL2VJN01lMkI0K2ZNZlhKSStlM2xCVnp5RXpIV0ZOR1phM2JYbkYvS0VJaDJRcmpOcXh0bGswSgpIOW83dUtVZmRyVjhNL3IzZmxidUN1VG9lZnN3UFROQmJhbGladzVPRXl0VWV6V3ZxK3VUZzFmeExZVUl6Zk4xCldxMzhiU2pjYlhQa3Q3UWJZVThqUEpMMmlKalBlbVFRN1FnTW9pUmlsNXM2TzRCZnNYbzNCbDNrdUY0VDlCK1MKVzE2VmpQTnRMQ0pxQW1ENEt1ZWdBcWl3RHdDNFVScjhNbDhJaHJmL2FzT2JTZnVqTG5HL1Npd2V6dnJ4bHJnUgo0QVBlNjFSOU1RZFFjaldsT1Z2TXQrSXhlSnlrbWdmeHJsNFJmbytFOWVNK0VTNzFHaVhnQmtycFp0NGxQWURsClllSVZQd0lEQVFBQm8xWXdWREFPQmdOVkhROEJBZjhFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZQkJRVUgKQXdJd0RBWURWUjBUQVFIL0JBSXdBREFmQmdOVkhTTUVHREFXZ0JTaEZmM1VnRVFac2w2Ly9xa1JJS0Y4Z0IrMApPakFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBa0ZqdDJPNW5ZQUkxRHRrZnh6R1RPbFdGT1F3b3FKelBHQXJSCmRoTnFXL3JjUlhyYkgzZ3FHaXF4cmQ2anczblJiYThCRWxOazE0YUtYWGVYRnU0U0YyYTJCY3RzKzhkNE9VSkwKeU1pUVBpN0g2Q3RrQ0o2QzRCZDU4Vk5XaVM0YVg4b0ExQWloZWp0cURRc2U2MCtna2JoSlJwdnM0WGRVUkNTdgpFL3NqZWgvc1JIVjBJYWNrNzlTVEduSUdlVVUrbUxwVlF1bHZkd1lkVDhXK08zMkpRbFk1Z3pTZllFMkI2YjB4Ci9TK1dORU9QTzhhaTlmQkQ5cWJ1dWdRd2wzSkNYT005amZLV1gzOTBZZzhYcWhndEhuR0JDdlcwbjQxY0ZLUDgKQVFFdXRnbDNhQ0ZibWZFZ2Z3cWlUVFc3R3EzSklZSTZrZ3EwNGxUbVdKa1gvQnZmaXc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBbnZ5ejFzVHVJdGkrMTdaZFVUV0xVcTFMSC9lSTdNZTJCNCtmTWZYSkkrZTNsQlZ6CnlFekhXRk5HWmEzYlhuRi9LRUloMlFyak5xeHRsazBKSDlvN3VLVWZkclY4TS9yM2ZsYnVDdVRvZWZzd1BUTkIKYmFsaVp3NU9FeXRVZXpXdnErdVRnMWZ4TFlVSXpmTjFXcTM4YlNqY2JYUGt0N1FiWVU4alBKTDJpSmpQZW1RUQo3UWdNb2lSaWw1czZPNEJmc1hvM0JsM2t1RjRUOUIrU1cxNlZqUE50TENKcUFtRDRLdWVnQXFpd0R3QzRVUnI4Ck1sOElocmYvYXNPYlNmdWpMbkcvU2l3ZXp2cnhscmdSNEFQZTYxUjlNUWRRY2pXbE9Wdk10K0l4ZUp5a21nZngKcmw0UmZvK0U5ZU0rRVM3MUdpWGdCa3JwWnQ0bFBZRGxZZUlWUHdJREFRQUJBb0lCQUQzOHFPR0R4cFV2akxqdQpFVlFvWERuUDl3cHZxS01vK24vWUwybDdPd0VVeHk2bGJvOFo0RjgvbUtMc05pdU1kTmR0Y1dUK0tiaVhZZUxJCkJsYTA3N1ArTFZaTFRERzRGK2JhWGRWQmlxS0VuVG8vVWJNLzUyM20xZW9EYXR6ZkFhODJHajJMZkMwVFFXdUwKRUtaYVQ2RC8zWEdQVGcyUjIxc0ZUK2UrSlFEOGRnc25oNE9vVlQrTkRacC9kU0JHYXZNQTFZUmo0bFhwY1U5RAo5bW15ckxRZFlRcE56K1U4cGZKdHhIcXlGSWhOakZmK0JkNHdRdEhrN3NOODE4Um9JalZHV3RYeGVhZXFOMXVtCnFlWEhFNHVDRG5tYS9qTElLLzBRaWlMZTZ1WGVTMk1udG1UUjJ1d0paOWh5V3NsYnlTb2oyQmNONVBaaHpGK3kKMUtyZEFZRUNnWUVBenNEeUFtZ1dUUXI5M083ZnlSR1U5azBad01LRFVSK25Lb0xQcUNhSmxQeE4xaG1zTkJmWApKWURsZ3cwVTk5R1lmRGJZUTdjS3BaRE8xWHZpWTI4K1UxY21nM2xVMVFVOTdFR0N3ejVxMnNjUFY0SDBhZmxnCmNUQko5dGo1ZTkzVS9sVDFpd0M1eEFONlpjektTbzhYSytNQ29nUkEyeEFZZjFJZnJTZmhoVzBDZ1lFQXhOc2kKQ2oxS29FQzV0TjlEaW41eFQzMUVBTjlwVmtONkZlcy9nZC9JSFREWXJLSytaMnNpVVNhR1NyaHYwZkc1ZGVwagpIMjdEeVF6cW1aUUlpaE44cFB5TzRSOXMya21la3RISUZqMjRnSUpQZDNzS3BaS1QwQjJmZUErTXVCOFlsclRGCk0ycTJ2V1JHeHFmMERMZmpWNm5JVkZkQ1hJWFZLMjlRcWprdkZkc0NnWUFmUGRxVDhJU0dLY1lJajNQelh4dkMKU0E0L0tXVk1hZHNKdW5DRWVTWkxCQUVDL0NnZ1N3WHduZFNRZy9hS0ovckJza3ZsbDVBZFNvOW1oT3pGbDdhMApRelFIbzlya3dZRUU1VFZNS1c5ZUZieEV2ZGRmK0JYUnBMbFllcHJnVTdudW9Jbmw4anNmMm1LeFpVdWdEcFV5CnhYL05XWlV2UlBSZXNOc21nQ004MVFLQmdRQ0xSOFFJM0o3TlRaNVhNOVJVeSt1ZDR6SlhMN3NXMXIwdGZ2bTcKQ1R0TU5BQkovUWVjb25kd1ZVS1U0WFAwWmdQalF3Z0krRlM4RGxCNmd2dWJ2ZmZsdisvVHBtbGM5Tk9tYTVrVwo2MnA4T2piQmdhUGh6QmliR2lwM1J3RTRVSUFVT1NpQm5aSlg0L2dUbkVlWExCQkZPUkpOWWtQSXRNUkRiQW4xCnRtbnpHd0tCZ0J3NHhLanNEUUozcCtxWW50cTdtVzhLS2hPWTFMRWczOVJ4Snd1aEord0VSZUh5TGhIcEU5SFkKUndxbUVCYjdvY2dDcmV6bWR5WndUSXZkMGEzaStBbWpucTd1QU1DUFpNUjU0a2FkNUpmZmVib0FzbXcwSW5aeApvVGltQXNya3BmRlVxZzZsSVBIMEtuUEVTVWQxQlJLS2I5dTUzTWpwZEZiVkhWZVZhVEtlCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==
실습 환경
- 쿠버네티스에 사용자를 위한 서비스 어카운트(Service Account, SA)를 생성 : dev-k8s, infra-k8s
- 사용자는 각기 다른 권한(Role, 인가)을 가짐 : dev-k8s(dev-team 네임스페이스 내 모든 동작) , infra-k8s(dev-team 네임스페이스 내 모든 동작)
- 각각 별도의 kubectl 파드를 생성하고, 해당 파드에 SA 를 지정하여 권한에 대한 테스트를 진행
네임스페이스와 서비스 어카운트 생성 후 확인
- 파드 기동 시 서비스 어카운트 한 개가 할당되며, 서비스 어카운트 기반 인증/인가를 함, 미지정 시 기본 서비스 어카운트가 할당
- 서비스 어카운트에 자동 생성된 시크릿에 저장된 토큰으로 쿠버네티스 API에 대한 인증 정보로 사용 할 수 있다 ← 1.23 이전 버전의 경우에만 해당
# 네임스페이스(Namespace, NS) 생성 및 확인
kubectl create namespace dev-team
kubectl create ns infra-team
# 네임스페이스 확인
kubectl get ns
# 네임스페이스에 각각 서비스 어카운트 생성 : serviceaccounts 약자(=sa)
kubectl create sa dev-k8s -n dev-team
kubectl create sa infra-k8s -n infra-team
# 서비스 어카운트 정보 확인
kubectl get sa -n dev-team
kubectl get sa dev-k8s -n dev-team -o yaml | yh
kubectl get sa -n infra-team
kubectl get sa infra-k8s -n infra-team -o yaml | yh
(심화 참고) dev-k8s 서비스어카운트의 토큰 정보 확인 - https://jwt.io/ → Bearer type - JWT(JSON Web Token) - 링크
# dev-k8s 서비스어카운트의 토큰 정보 확인
DevTokenName=$(kubectl get sa dev-k8s -n dev-team -o jsonpath="{.secrets[0].name}")
DevToken=$(kubectl get secret -n dev-team $DevTokenName -o jsonpath="{.data.token}" | base64 -d)
echo $DevToken
Bearer type - JWT(JSON Web Token)
- Bearer type 경우, 서버에서 지정한 어떠한 문자열도 입력할 수 있습니다. 하지만 굉장히 허술한 느낌을 받습니다
- 이를 보완하고자 쿠버네티스에서 Bearer 토큰을 전송할 때 주로 JWT (JSON Web Token) 토큰을 사용합니다
- JWT는 X.509 Certificate와 마찬가지로 private key를 이용하여 토큰을 서명하고 public key를 이용하여 서명된 메세지를 검증합니다
- 이러한 메커니즘을 통해 해당 토큰이 쿠버네티스를 통해 생성된 valid한 토큰임을 인증할 수 있습니다
- X.509 Certificate의 lightweight JSON 버전이라고 생각하면 편리합니다
- jwt는 JSON 형태로 토큰 형식을 정의한 스펙입니다. jwt는 쿠버네티스에서 뿐만 아니라 다양한 웹 사이트에서 인증, 권한 허가, 세션관리 등의 목적으로 사용합니다
- Header: 토큰 형식와 암호화 알고리즘을 선언합니다
- Payload: 전송하려는 데이터를 JSON 형식으로 기입합니다
- Signature: Header와 Payload의 변조 가능성을 검증합니다
- 각 파트는 base64 URL 인코딩이 되어서 .으로 합쳐지게 됩니다
서비스 어카운트를 지정하여 파드 생성 후 권한 테스트
# 각각 네임스피이스에 kubectl 파드 생성 - 컨테이너이미지
# docker run --rm --name kubectl -v /path/to/your/kube/config:/.kube/config bitnami/kubectl:latest
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
# 확인
kubectl get pod -A
kubectl get pod -o dev-kubectl -n dev-team -o yaml
serviceAccount: dev-k8s
...
kubectl get pod -o infra-kubectl -n infra-team -o yaml
serviceAccount: infra-k8s
...
# 파드에 기본 적용되는 서비스 어카운트(토큰) 정보 확인
kubectl exec -it dev-kubectl -n dev-team -- ls /run/secrets/kubernetes.io/serviceaccount
kubectl exec -it dev-kubectl -n dev-team -- cat /run/secrets/kubernetes.io/serviceaccount/token
kubectl exec -it dev-kubectl -n dev-team -- cat /run/secrets/kubernetes.io/serviceaccount/namespace
kubectl exec -it dev-kubectl -n dev-team -- cat /run/secrets/kubernetes.io/serviceaccount/ca.crt
# 각각 파드로 Shell 접속하여 정보 확인 : 단축 명령어(alias) 사용
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 # kubectl exec -it dev-kubectl -n dev-team -- kubectl get pods 와 동일한 실행 명령이다!
k1 run nginx --image nginx:1.20-alpine
k1 get pods -n kube-system
k2 get pods # kubectl exec -it infra-kubectl -n infra-team -- kubectl get pods 와 동일한 실행 명령이다!
k2 run nginx --image nginx:1.20-alpine
k2 get pods -n kube-system
# (옵션) kubectl auth can-i 로 kubectl 실행 사용자가 특정 권한을 가졌는지 확인
k1 auth can-i get pods
no
각각 네임스페이스에 롤(Role)를 생성 후 서비스 어카운트 바인딩
- 롤(Role) : apiGroups 와 resources 로 지정된 리소스에 대해 verbs 권한을 인가
- 실행 가능한 조작(verbs) : *(모두 처리), create(생성), delete(삭제), get(조회), list(목록조회), patch(일부업데이트), update(업데이트), watch(변경감시)
# 각각 네임스페이스내의 모든 권한에 대한 롤 생성
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
# 롤 확인
kubectl get roles -n dev-team
kubectl get roles -n infra-team
kubectl get roles -n dev-team -o yaml
kubectl describe roles role-dev-team -n dev-team
...
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
*.* [] [] [*]
# 롤바인딩 생성 : '서비스어카운트 <-> 롤' 간 서로 연동
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
EOF
# 롤바인딩 확인
kubectl get rolebindings -n dev-team
kubectl get rolebindings -n infra-team
kubectl get rolebindings -n dev-team -o yaml
kubectl describe rolebindings roleB-dev-team -n dev-team
...
Role:
Kind: Role
Name: role-dev-team
Subjects:
Kind Name Namespace
---- ---- ---------
ServiceAccount dev-k8s dev-team
서비스 어카운트를 지정하여 생성한 파드에서 다시 권한 테스트
# 각각 파드로 Shell 접속하여 정보 확인 : 단축 명령어(alias) 사용
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
k1 delete pods nginx
k1 get pods -n kube-system
k1 get nodes
k2 get pods
k2 run nginx --image nginx:1.20-alpine
k2 get pods
k2 delete pods nginx
k2 get pods -n kube-system
k2 get nodes
# (옵션) kubectl auth can-i 로 kubectl 실행 사용자가 특정 권한을 가졌는지 확인
k1 auth can-i get pods
yes
# 실습 리소스 삭제
kubectl delete ns dev-team infra-team
(실습 완료 후) 자원 삭제
kOps 클러스터 삭제 & AWS CloudFormation 스택 삭제
kops delete cluster --yes && aws cloudformation delete-stack --stack-name mykops
과제
과제 1. 파드에서 EC2 메타데이터의 IAM Role 토큰 정보를 활용하여(boto3), 스터디에서 소개한 것 이외의 다른 AWS 서비스(혹은 Action)를 사용 후 코드나 스샷을 올려주세요
Describe Amazon EC2 Regions and Availability Zones
참고 URL: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/ec2-example-regions-avail-zones.html
Describe Amazon EC2 Regions and Availability Zones — Boto3 Docs 1.26.84 documentation
Describe Amazon EC2 Regions and Availability Zones Amazon EC2 is hosted in multiple locations worldwide. These locations are composed of regions and Availability Zones. Each region is a separate geographic area. Each region has multiple, isolated locations
boto3.amazonaws.com
cat <<EOF> ec2-region.py
import boto3
ec2 = boto3.client('ec2', region_name='ap-northeast-2')
response = ec2.describe_regions()
print('Regions:', response['Regions'])
EOF
과제 2. 책 398~400페이지 - kubescape armo 웹 사용 후 관련 스샷을 올려주세요
kubescape armo 웹 URL:
- portal.armo.cloud
- https://cloud.armosec.io/account/login?redirectUrl=%2Fdashboard
# 연결 진행
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=22d2b732-21fb-4885-9b40-a69ca40eacda --set clusterName=`kubectl config current-context`
ID: C-0057 URL: https://hub.armosec.io/docs/c-0057
C-0057 - Privileged container
Privileged container Framework AllControls, ArmoBest, NSA, MITRE Severity High Description of the the issue A privileged container is a container that has all the capabilities of the host machine, which lifts all the limitations regular containers have. Pr
hub.armosec.io
과제 3. polaris 관련 실습(아무거나) 후 관련 스샷을 올려주세요
과제 4. 신규 서비스 어카운트(SA) 생성 후 '클러스터 수준(모든 네임스페이스 포함)에서 읽기 전용'의 권한을 주고 테스트 후 코드나 스샷을 올려주세요
# 네임스페이스 생성
kubectl create ns read-only
# 서비스 어카운트 생성
kubectl create sa read-only-sa -n read-only
# 파드 생성
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
name: read-only-pod
namespace: read-only
spec:
serviceAccountName: read-only-sa
containers:
- name: kubectl-pod
image: bitnami/kubectl:1.24.10
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
# ClusterRole 생성
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: read-only-cluster-role
namespace: read-only
rules:
- apiGroups: [""]
resources: ["*"]
verbs: ["get","watch","list"]
EOF
# Role 확인
kubectl get roles -o yaml
kubectl describe roles read-only-role
# ClusterRoleBinding 생성
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: read-only-cluster-role-binding
namespace: read-only
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: read-only-cluster-role
subjects:
- kind: ServiceAccount
name: read-only-sa
namespace: read-only
EOF
# 바인딩 확인
kubectl get clusterrolebindings -n read-only -o yaml
kubectl describe clusterrolebindings read-only-cluster-role-binding
# 검증
alias kro="kubectl exec -it read-only-pod -n read-only -- kubectl"
kro get pods
kro run nginx --image nginx:1.20-alpine
kro delete pods nginx
kro get pods -n kube-system
kro get ns
kro create ns test-ns
kro auth can-i get pods

지금까지 KOPS 스터디 관련 긴 글 읽어주셔서 감사합니다 🤗
다음에도 좋은 기회가 있다면 다른 스터디 주제로 돌아오겠습니다 🥸
감사합니다!!
'k8s > CloudNet@' 카테고리의 다른 글
[CloudNet@] AWS EKS Workshop Study - 2주차. (0) | 2023.05.07 |
---|---|
[CloudNet@] AWS EKS Workshop Study - 1주차. (0) | 2023.04.30 |
[CloudNet@] Production Kubernetes Online Study - 6주차. (0) | 2023.02.25 |
[CloudNet@] Production Kubernetes Online Study - 5주차. (3) | 2023.02.19 |
[CloudNet@] Production Kubernetes Online Study - 4주차. (0) | 2023.02.12 |