[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
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
파드에서 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
# 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/
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
- 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
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
과제 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 |