PKOS 7주차 - 보안
PKOS - Production Kubernetes Online Study 포스팅을 시작하며
PKOS 1주차 - AWS kOps 설치 및 기본 사용
PKOS 4주차 - Harbor & Gitlab & ArgoCD
PKOS 5주차 - Prometheus & Grafana
PKOS 6주차 - Alert Manager & Logging System
왜 그런지 모르겠는데 이미지 위아래로 여백이 생깁니다.
에디터에서는 안그러는데 왜 그런지 좀 찾아봐야겠습니다.
본 글은 초안이기에 다듬는 과정에서 내용이 수정될 수 있습니다.
PKOS 7주차
들어가기전에
본 내용은 CloudNet@
팀에서 진행하는 쿠버네티스 실무 실습
스터디를 기반으로 작성된 내용입니다.
또한 개념 설명에서 사용된 이미지의 출처는 스터디 학습 자료에서 가져온 것을 밝힙니다.
- 참조: https://www.notion.so/AWS-EKS-VPC-CNI-1-POD-f89e3e5967b24f8c9aa5bfaab1a82ceb
- 참조: ‘24단계 실습으로 정복하는 쿠버네티스 - 이정훈 저’ 책을 기준하여 정리
7주차에는 보안과 관련된 실습을 진행했습니다.
과제 수행결과
- 과제 수행과정은 본문에 자세히 기술했습니다.
과제1
-
목표 : 파드에서 EC2 메타데이터의 IAM Role 토큰 정보를 활용하여(boto3), 스터디에서 소개한 것 이외의 다른 AWS 서비스(혹은 Action)를 사용 후 코드나 스샷을 올려주세요
-
수행결과
과제2
-
목표 : 책 398~400페이지 - kubescape armo 웹 사용 후 관련 스샷을 올려주세요
-
수행결과
과제3
-
목표 : polaris 관련 실습(아무거나) 후 관련 스샷을 올려주세요
-
수행결과
과제4
-
목표 : 신규 서비스 어카운트(SA) 생성 후 ‘클러스터 수준(모든 네임스페이스 포함)에서 읽기 전용’의 권한을 주고 테스트 후 코드나 스샷을 올려주세요
-
수행결과
1. 실습 환경 세팅
1.1 구성 환경
- 사전 준비
- AWS 계정, SSH 키 페어, IAM 계정 생성 후 키, S3 버킷
- 전체 구성도
- 기본 구성 환경은 1주차 내용과 동일
- 실습 환경 내용
- CloudFormation 스택 실행 시 파라미터를 기입하면, 해당 정보가 반영되어 배포됩니다.
- VPC는 kOps 배포를 위한 EC2가 위치할 MyVPC 1개와 실제 kOps 가 배포되어 구동되는 VPC 1개로 총 2개가 생성됩니다.
- CloudFormation 에 EC2의 UserData 부분(Script 실행)으로 AWS kOps 설치를 진행합니다.
- 마스터 노드 1대, 워커 노드는 기본은 2대로 구성됩니다.
- 실습 환경은 지난 주차와 다르게 노드 사양은 c5.2xlarge(vCPU 8, Memory 16GiB) 으로 진행 됩니다.
1.2 실습 환경
- 본 실습은 미국 동부(버지니아 북부)
us-east-1
에서 진행됩니다.
1.2.1 S3 버킷 생성
- S3 URL 접속
- 버킷 만들기 버튼 클릭
- 버킷 만들기
- 버킷 이름 설정 후 기본 설정 그대로 버킷 만들기 버튼 클릭
- 버킷 이름 : 20230302-learn-s3-mybucket
- 버킷 이름 설정 후 기본 설정 그대로 버킷 만들기 버튼 클릭
1.2.2 Cloud Formation을 이용한 kOps 생성(이하 배포)
-
Cloud Formation URL 접속 및 스택 생성 버튼 클릭
-
스택 생성 - 1단계 스택 생성
- 템플릿 소스 URL 입력 - Amazon S3 URL
- https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/kops-oneclick2.yaml
- 이전 주차와 다르게 템플릿 소스가 변경되었으니 입력시 주의
- https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/kops-oneclick2.yaml
- 템플릿 소스 URL 입력 - Amazon S3 URL
-
스택 생성 - 2단계 스택 세부 정보 지정
-
스택 이름
- 스택 이름 : mkops
-
파라미터
-
««< Deploy EC2 : kops-ec2 »»>
- 설정 설명
- KeyName : kops-ec2에 SSH 접속을 위한 SSH 키페어 선택 <- 미리 SSH 키 생성 해두자!
- MyIamUserAccessKeyID : 관리자 수준의 권한을 가진 IAM User의 액세스 키ID 입력
- MyIamUserSecretAccessKey : 관리자 수준의 권한을 가진 IAM User의 시크릿 키ID 입력 <- 노출되지 않게 보안 주의
- SgIngressSshCidr : kops-ec2에 SSH 접속 가능한 IP 입력 (집 공인IP/32 입력), 보안그룹 인바운드 규칙에 반영됨
- LatestAmiId : kops-ec2에 사용할 AMI는 아마존리눅스2 최신 버전 사용, 기본값 그대로 사용
- 설정 내용
- 사용자 설정 입력
- 설정 설명
-
««< AWS kOps Config »»>
-
설정 설명
-
KubernetesVersion : 쿠버네티스 설치 버전 (기본 v1.24.9) ⇒ 변경 가능
-
ClusterBaseName : kOps 클러스터 이름이며, 사용하게될 도메인 이름이다. ‘퍼블릭 도메인’ or ‘프라이빗 도메인’ or ‘Gossip DNS’ 가능
-
S3StateStore : kOps 클러스터의 설정/상태 정보가 저장될 S3 버킷의 이름을 지정 ← 미리 S3 버킷을 생성 해두자!
-
MasterNodeInstanceType & WorkerNodeInstanceType: 마스터(기본 t3.medium) & 워커 노드 EC2 인스턴스의 타입 (기본 t3.medium) ⇒ 변경 가능
-
WorkerNodeCount : 워커노드의 갯수를 입력 ⇒ 변경 가능
-
VpcBlock : kOps 배포되고 동작할 VPC 네트워크 대역, 기본값 그대로 사용
-
-
설정 내용
- 다음 설정 외 기본 설정 사용
- ClusterBaseName
- learn-dc.link
- S3StateStore : 위에 생성한 버킷 명칭 입력
- 20230302-learn-s3-mybucket
- MasterNodeInstanceType & WorkerNodeInstanceType
- t3.xlarge
- ClusterBaseName
- 다음 설정 외 기본 설정 사용
-
-
««< Region AZ »»>
- 설정 설명
- TargetRegion : kOps를 배포할 리전
- AvailabliltyZone1 : kOps를 배포할 리전의 가용 영역
- AvailabliltyZone2 : kOps를 배포할 리전의 가용 영역
- 설정 내용
- TargetRegion : us-east-1
- AvailabliltyZone1 : us-east-1a
- AvailabliltyZone2 : us-east-1c
- 설정 설명
-
-
다음 버튼 클릭
-
-
스택 생성 - 3단계 스택 옵션
- 기본 설정 그대로 다음 버튼 클릭
- 기본 설정 그대로 다음 버튼 클릭
-
스택 생성 - 4단계 mkops 검토
- 스택 파라미터 설정 확인
- 기본 설정 그대로 전송 버튼 클릭
- 스택 파라미터 설정 확인
-
스택 생성 확인 및 접속 IP 확인
- 스택 생성 확인
- 접속 IP 확인
- KOPSEC2IP : 3.84.234.199
- 스택 생성 확인
1.2.3 kOps 배포 확인
- 스택 생성 후 약 13분 후 접속
- 내부적으로 설치되는데 시간 소요됨
1. 접속 후 기본 설정
-
마스터노드 SSH 접속 - Putty
-
default NS 진입
-
1
kubectl ns default
-
1.3 EC2 instance profiles 설정 및 Metrics-server 확인
1.3.1 EC2 instance profiles 설정
-
EC2 instance profiles 에 IAM Policy 추가(attach)
-
1 2 3 4 5
# 처음 입력 시 적용이 잘 안될 경우 다시 한번 더 입력 하자! - 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
-
1.3.2 Metrics-server 확인
-
메트릭 서버 확인 : 메트릭은 15초 간격으로 cAdvisor를 통하여 가져옴
-
1 2
kubectl top node kubectl top pod -A
-
2. EC2 IAM Role & Metadata
2.1 개요
- 참고 링크
- 쿠버네티스 Secret을 해킹하는 엔지니어를 위한 안내서 - https://blog.kaonmir.site/10
- [매뉴얼] Boto3가 AWS의 자격증명(Credentials)을 확인하는 순서 .from Python - https://tech.cloud.nongshim.co.kr/2021/03/12/boto3%EA%B0%80-aws%EC%9D%98-%EC%9E%90%EA%B2%A9%EC%A6%9D%EB%AA%85credentials%EC%9D%84-%ED%99%95%EC%9D%B8%ED%95%98%EB%8A%94-%EC%88%9C%EC%84%9C-from-python/
2.2 실습
2.2.1 워커 노드 1대 EC2 메타데이터 보안 제거
-
적용 및 재생성 5분 시간 소요
-
kOps 클러스터 편집
-
1 2 3 4 5 6 7 8 9 10
# kops edit ig nodes-ap-northeast-2a kops edit ig nodes-us-east-1a # ... # 아래 3줄 제거 # spec: # instanceMetadata: <- 제거 # httpPutResponseHopLimit: 1 <- 제거 # httpTokens: required <- 제거 # ...
-
-
업데이트 적용 : 노드1대 롤링업데이트
-
1
kops update cluster --yes && echo && sleep 3 && kops rolling-update cluster --yes
-
2.2.2 파드에서 EC2 메티데이터 사용 가능 확인
-
netshoot-pod 생성
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
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
-
-
파드 이름 변수 지정
-
1 2 3 4
PODNAME1=$(kubectl get pod -l app=netshoot-pod -o jsonpath={.items[0].metadata.name}) echo $PODNAME1 PODNAME2=$(kubectl get pod -l app=netshoot-pod -o jsonpath={.items[1].metadata.name}) echo $PODNAME2
-
-
EC2 메타데이터 정보 확인
-
1 2
kubectl exec -it $PODNAME1 -- curl 169.254.169.254 ;echo kubectl exec -it $PODNAME2 -- curl 169.254.169.254 ;echo
-
-
파드1에서 EC2 메타데이터 정보 확인
-
1 2 3
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 메타데이터 정보 확인
-
1 2 3
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
-
-
메타데이터 메모해두기
-
1 2 3 4 5 6 7 8 9
{ "Code": "Success", "LastUpdated": "2023-03-02T15:45:21Z", "Type": "AWS-HMAC", "AccessKeyId": "ASIAZ2FILNMLU2KBYJ4Q", "SecretAccessKey": "JrjrVVWzWjNdKSn7vrdcnyxC3Zc8Y5f7u3VPzvSG", "Token": "IQoJb3JpZ2luX2VjEAAaCXVzLWVhc3QtMSJHMEUCIQDaiskr3mHtaNN0/WFSMUv2Ole4zxizOeQBLP2h2pZ7zAIgJmTySF7gino+lzFnXx/xE3aptK/7arVheJPWWGfNX8oqxQUIqf//////////ARABGgw2NzQ2NjI5MzUzMTkiDAXCj999T5Mcmtkf+yqZBSJBfNctXHcp76DeoNYkP45rQWu9T/KTradQeBL+isBCrpJtj1IivkP0zel4MnjJNkPuhGb0bjMN880Fp3TO2VrcLoaMJM+lQAdAwYdC8hEexnilhdGSqbLz6HLXiWABWv0PTqdpBkEIEf/6QllZxM+ODc6bDjjwFfQqu+1cKOnEaa9iLRVbKkOVbzd2u3AJlYugGQNbwFkZF1/bxo1QbwPLHYxVthlz6Hx4ubpMwcvoJFN5OQmh5HsnG1dimXtWEJnVaoIHA+n+TRSQsceuhL4zH5uQ5MZ6v4vYsnLQwM3elYag46uJXuofNnkitDHvZqWcetACx6jGkzdAhnlSrK85xloG+0XP1wv/czBldQsr8Jl1Ja9dTw+DHUJUU0rP8sXA49ZrzPMtc2taNTJKlxsnlPnUvJn5j7DHddyLJ35HN2MmoxoBklpo0VLCLPiEIgXn3CHcXDrS/KGJcYEJWRzJKvyStUSM/zVMz8yqiiyAZoqf19xdDnrxrvXgxG6SrHzW9ZRa5dSghtVyS9p8fIl1Grj/HSJFlwrGj46iuta4H9E8fielWFP4ggO6uU1APj+4qa5vJKicwy2IeN/kU2OjvDlotWGdfYKRK8npPE0DERekzYIc1Ap7NAeRECuLnemwEnr02Cj9bFV0PilKKSFGaeaULhmH/DO6YOk0bxq/r9YUz+85HHRQufK8AMxtghX5yI6QLsSRi6P8aK/Uck1YvOLqhinWMmvCNvm2UmXETmzQc3pJiC8xSx/L9oOmp211OGMb6FKrQNGSNkmQEtg6wetCqBI7MNbJ8dqR5CpeDCkWFTy4I7eb9CQUZzVKeyDx8pnkcPT2fBe4zajHS+h8rN3l6KRGcUG7WK8QwIuA+quKtuqBRwJ7MIGJg6AGOrEBTP3tE8CzcmyPoh8VkhHLQIlyWCJSOAYhaPWaK7vgQbjlP6wqs7POo98iNGzbq2CM+AWfVyD6iVKuk0qOgbjANtWaJnMKeaqZrS54S26Ppu23mnpUNiAJbTDjHHEJKKp9bhG0CR4IiIqdQc3B00/YCQPng90gaBI72i/+S2w4v5JMpf2SL5CB9/skMxfM3YjIOUE5mAp+WvLjioFftoPgyDSUGGbSZgWiCyA22uQzMbok", "Expiration": "2023-03-02T22:20:05Z" }
-
2.2.3 파드(컨테이너) 탈취 후 EC2 메타데이터의 IAM Role 토큰 정보를 활용해 python boto3를 통해 SDK로 AWS 서비스 강제 사용
-
참고 링크
- Managing Amazon EC2 instances - https://boto3.amazonaws.com/v1/documentation/api/latest/guide/ec2-example-managing-instances.html
- [pkos] 쿠버네티스 스터디 - 7주차 과제 - https://velog.io/@xgro/pkos-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4-%EC%8A%A4%ED%84%B0%EB%94%94-7%EC%A3%BC%EC%B0%A8-%EA%B3%BC%EC%A0%9C#-%EA%B2%B0%EA%B3%BC
-
boto3 사용을 위한 파드 생성
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
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
-
-
파드 이름 변수 지정
-
1 2 3 4
PODNAME1=$(kubectl get pod -l app=boto3 -o jsonpath={.items[0].metadata.name}) echo $PODNAME1 PODNAME2=$(kubectl get pod -l app=boto3 -o jsonpath={.items[1].metadata.name}) echo $PODNAME2
-
-
파드1에서 boto3 사용 - ec2 메타정보를 가져오는 보안 비활성화
-
1 2 3 4 5 6 7 8 9 10 11 12 13
kubectl exec -it $PODNAME1 -- sh # ------------ cat <<EOF> ec2.py import boto3 ec2 = boto3.client('ec2', region_name = 'us-east-1') response = ec2.describe_instances() print(response) EOF python ec2.py # aws ec2 describe-vpcs exit # ------------
-
-
파드2에서 boto3 사용 - ec2 메타정보를 가져오는 보안 활성화
-
1 2 3 4 5 6 7 8 9 10 11 12 13
kubectl exec -it $PODNAME2 -- sh # ------------ cat <<EOF> ec2.py import boto3 ec2 = boto3.client('ec2', region_name = 'us-east-1') response = ec2.describe_instances() print(response) EOF python ec2.py # aws ec2 describe-vpcs exit # ------------
-
-
실습 완료 후 삭제
-
1
kubectl delete deploy boto3-pod
-
-
대응 방안 : EC2 메타데이터 접속 제한 or AWS IRSA 사용
2.2.4 기타
- 현재 ec2에 맵핑된 iam role 연동 정책(policy)를 사용할 수 있는 boto3 sdk를 사용해서 다른 서비스도 이용해보세요! ⇒ ELB 생성/삭제!
- awscli 파드를 추가하고, 획득한 IAM Role 토근을 활용해서 aws서비스를 강제 사용하는 실습을 추가해두자!
2.2.5 (추가) awscli 파드를 추가하고, 획득한 IAM Role Token을 활용해서 AWS 서비스를 강제 사용
-
awscli 파드 생성
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
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
-
-
파드 이름 변수 지정
-
1 2 3 4
APODNAME1=$(kubectl get pod -l app=awscli-pod -o jsonpath={.items[0].metadata.name}) echo $APODNAME1 APODNAME2=$(kubectl get pod -l app=awscli-pod -o jsonpath={.items[1].metadata.name}) echo $APODNAME2
-
-
파드에서 EC2 메타데이터 정보 확인
-
파드1
-
1 2 3
kubectl exec -it $APODNAME1 -- curl 169.254.169.254/latest ;echo kubectl exec -it $APODNAME1 -- curl 169.254.169.254/latest/meta-data/iam/security-credentials/ ;echo kubectl exec -it $APODNAME1 -- curl 169.254.169.254/latest/meta-data/iam/security-credentials/nodes.$KOPS_CLUSTER_NAME | jq
-
-
파드2
-
1 2 3
kubectl exec -it $APODNAME2 -- curl 169.254.169.254/latest ;echo kubectl exec -it $APODNAME2 -- curl 169.254.169.254/latest/meta-data/iam/security-credentials/ ;echo kubectl exec -it $APODNAME2 -- curl 169.254.169.254/latest/meta-data/iam/security-credentials/nodes.$KOPS_CLUSTER_NAME | jq
-
-
-
메타데이터 메모해두기 : 단 Expiration 시간이 지나면 Token은 유효하지 않음
-
1 2 3 4 5 6 7 8 9
{ "Code": "Success", "LastUpdated": "2023-03-02T15:45:21Z", "Type": "AWS-HMAC", "AccessKeyId": "ASIAZ2FILNMLU2KBYJ4Q", "SecretAccessKey": "JrjrVVWzWjNdKSn7vrdcnyxC3Zc8Y5f7u3VPzvSG", "Token": "IQoJb3JpZ2luX2VjEAAaCXVzLWVhc3QtMSJHMEUCIQDaiskr3mHtaNN0/WFSMUv2Ole4zxizOeQBLP2h2pZ7zAIgJmTySF7gino+lzFnXx/xE3aptK/7arVheJPWWGfNX8oqxQUIqf//////////ARABGgw2NzQ2NjI5MzUzMTkiDAXCj999T5Mcmtkf+yqZBSJBfNctXHcp76DeoNYkP45rQWu9T/KTradQeBL+isBCrpJtj1IivkP0zel4MnjJNkPuhGb0bjMN880Fp3TO2VrcLoaMJM+lQAdAwYdC8hEexnilhdGSqbLz6HLXiWABWv0PTqdpBkEIEf/6QllZxM+ODc6bDjjwFfQqu+1cKOnEaa9iLRVbKkOVbzd2u3AJlYugGQNbwFkZF1/bxo1QbwPLHYxVthlz6Hx4ubpMwcvoJFN5OQmh5HsnG1dimXtWEJnVaoIHA+n+TRSQsceuhL4zH5uQ5MZ6v4vYsnLQwM3elYag46uJXuofNnkitDHvZqWcetACx6jGkzdAhnlSrK85xloG+0XP1wv/czBldQsr8Jl1Ja9dTw+DHUJUU0rP8sXA49ZrzPMtc2taNTJKlxsnlPnUvJn5j7DHddyLJ35HN2MmoxoBklpo0VLCLPiEIgXn3CHcXDrS/KGJcYEJWRzJKvyStUSM/zVMz8yqiiyAZoqf19xdDnrxrvXgxG6SrHzW9ZRa5dSghtVyS9p8fIl1Grj/HSJFlwrGj46iuta4H9E8fielWFP4ggO6uU1APj+4qa5vJKicwy2IeN/kU2OjvDlotWGdfYKRK8npPE0DERekzYIc1Ap7NAeRECuLnemwEnr02Cj9bFV0PilKKSFGaeaULhmH/DO6YOk0bxq/r9YUz+85HHRQufK8AMxtghX5yI6QLsSRi6P8aK/Uck1YvOLqhinWMmvCNvm2UmXETmzQc3pJiC8xSx/L9oOmp211OGMb6FKrQNGSNkmQEtg6wetCqBI7MNbJ8dqR5CpeDCkWFTy4I7eb9CQUZzVKeyDx8pnkcPT2fBe4zajHS+h8rN3l6KRGcUG7WK8QwIuA+quKtuqBRwJ7MIGJg6AGOrEBTP3tE8CzcmyPoh8VkhHLQIlyWCJSOAYhaPWaK7vgQbjlP6wqs7POo98iNGzbq2CM+AWfVyD6iVKuk0qOgbjANtWaJnMKeaqZrS54S26Ppu23mnpUNiAJbTDjHHEJKKp9bhG0CR4IiIqdQc3B00/YCQPng90gaBI72i/+S2w4v5JMpf2SL5CB9/skMxfM3YjIOUE5mAp+WvLjioFftoPgyDSUGGbSZgWiCyA22uQzMbok", "Expiration": "2023-03-02T22:20:05Z" }
-
-
파드 bash 실행 : 임시자격증명을 직접 입력하는 거라서 아무곳에서나 해도됨
-
1 2
# kubectl exec -it $APODNAME1 -- bash kubectl exec -it $APODNAME2 -- bash
-
-
위에서 출력된 AccessKeyId , SecretAccessKey , SessionToken 으로 임시자격증명 적용
-
1 2 3
export AWS_ACCESS_KEY_ID="ASIAZ2FILNMLU2KBYJ4Q" export AWS_SECRET_ACCESS_KEY="JrjrVVWzWjNdKSn7vrdcnyxC3Zc8Y5f7u3VPzvSG" export AWS_SESSION_TOKEN="IQoJb3JpZ2luX2VjEAAaCXVzLWVhc3QtMSJHMEUCIQDaiskr3mHtaNN0/WFSMUv2Ole4zxizOeQBLP2h2pZ7zAIgJmTySF7gino+lzFnXx/xE3aptK/7arVheJPWWGfNX8oqxQUIqf//////////ARABGgw2NzQ2NjI5MzUzMTkiDAXCj999T5Mcmtkf+yqZBSJBfNctXHcp76DeoNYkP45rQWu9T/KTradQeBL+isBCrpJtj1IivkP0zel4MnjJNkPuhGb0bjMN880Fp3TO2VrcLoaMJM+lQAdAwYdC8hEexnilhdGSqbLz6HLXiWABWv0PTqdpBkEIEf/6QllZxM+ODc6bDjjwFfQqu+1cKOnEaa9iLRVbKkOVbzd2u3AJlYugGQNbwFkZF1/bxo1QbwPLHYxVthlz6Hx4ubpMwcvoJFN5OQmh5HsnG1dimXtWEJnVaoIHA+n+TRSQsceuhL4zH5uQ5MZ6v4vYsnLQwM3elYag46uJXuofNnkitDHvZqWcetACx6jGkzdAhnlSrK85xloG+0XP1wv/czBldQsr8Jl1Ja9dTw+DHUJUU0rP8sXA49ZrzPMtc2taNTJKlxsnlPnUvJn5j7DHddyLJ35HN2MmoxoBklpo0VLCLPiEIgXn3CHcXDrS/KGJcYEJWRzJKvyStUSM/zVMz8yqiiyAZoqf19xdDnrxrvXgxG6SrHzW9ZRa5dSghtVyS9p8fIl1Grj/HSJFlwrGj46iuta4H9E8fielWFP4ggO6uU1APj+4qa5vJKicwy2IeN/kU2OjvDlotWGdfYKRK8npPE0DERekzYIc1Ap7NAeRECuLnemwEnr02Cj9bFV0PilKKSFGaeaULhmH/DO6YOk0bxq/r9YUz+85HHRQufK8AMxtghX5yI6QLsSRi6P8aK/Uck1YvOLqhinWMmvCNvm2UmXETmzQc3pJiC8xSx/L9oOmp211OGMb6FKrQNGSNkmQEtg6wetCqBI7MNbJ8dqR5CpeDCkWFTy4I7eb9CQUZzVKeyDx8pnkcPT2fBe4zajHS+h8rN3l6KRGcUG7WK8QwIuA+quKtuqBRwJ7MIGJg6AGOrEBTP3tE8CzcmyPoh8VkhHLQIlyWCJSOAYhaPWaK7vgQbjlP6wqs7POo98iNGzbq2CM+AWfVyD6iVKuk0qOgbjANtWaJnMKeaqZrS54S26Ppu23mnpUNiAJbTDjHHEJKKp9bhG0CR4IiIqdQc3B00/YCQPng90gaBI72i/+S2w4v5JMpf2SL5CB9/skMxfM3YjIOUE5mAp+WvLjioFftoPgyDSUGGbSZgWiCyA22uQzMbok"
-
-
ec2 정보 확인
-
1
aws ec2 describe-instances --region us-east-1 | head
-
-
vpc 정보 확인
-
1
aws ec2 describe-vpcs --region us-east-1 | head
-
-
빠져나오기
-
1
exit
-
2.2.6 AWS IRSA : 파드별 IAM Role 부여 - kOps
- Pod 별로 IAM 권한을 분리하는 경우와 그렇지 않은 경우
- AWS EKS Service Account에 AWS IAM Role 부여
2.3 과제1
-
목표: 파드에서 EC2 메타데이터의 IAM Role 토큰 정보를 활용하여(boto3), 스터디에서 소개한 것 이외의 다른 AWS 서비스(혹은 Action)를 사용 후 코드나 스샷을 올려주세요
-
수행결과 및 과정
-
노드 권한 확인
-
AWSLoadBalancerControllerIAMPolicy 정책
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iam:CreateServiceLinkedRole" ], "Resource": "*", "Condition": { "StringEquals": { "iam:AWSServiceName": "elasticloadbalancing.amazonaws.com" } } }, { "Effect": "Allow", "Action": [ "ec2:DescribeAccountAttributes", "ec2:DescribeAddresses", "ec2:DescribeAvailabilityZones", "ec2:DescribeInternetGateways", "ec2:DescribeVpcs", "ec2:DescribeVpcPeeringConnections", "ec2:DescribeSubnets", "ec2:DescribeSecurityGroups", "ec2:DescribeInstances", "ec2:DescribeNetworkInterfaces", "ec2:DescribeTags", "ec2:GetCoipPoolUsage", "ec2:DescribeCoipPools", "elasticloadbalancing:DescribeLoadBalancers", "elasticloadbalancing:DescribeLoadBalancerAttributes", "elasticloadbalancing:DescribeListeners", "elasticloadbalancing:DescribeListenerCertificates", "elasticloadbalancing:DescribeSSLPolicies", "elasticloadbalancing:DescribeRules", "elasticloadbalancing:DescribeTargetGroups", "elasticloadbalancing:DescribeTargetGroupAttributes", "elasticloadbalancing:DescribeTargetHealth", "elasticloadbalancing:DescribeTags" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "cognito-idp:DescribeUserPoolClient", "acm:ListCertificates", "acm:DescribeCertificate", "iam:ListServerCertificates", "iam:GetServerCertificate", "waf-regional:GetWebACL", "waf-regional:GetWebACLForResource", "waf-regional:AssociateWebACL", "waf-regional:DisassociateWebACL", "wafv2:GetWebACL", "wafv2:GetWebACLForResource", "wafv2:AssociateWebACL", "wafv2:DisassociateWebACL", "shield:GetSubscriptionState", "shield:DescribeProtection", "shield:CreateProtection", "shield:DeleteProtection" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "ec2:AuthorizeSecurityGroupIngress", "ec2:RevokeSecurityGroupIngress" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "ec2:CreateSecurityGroup" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "ec2:CreateTags" ], "Resource": "arn:aws:ec2:*:*:security-group/*", "Condition": { "StringEquals": { "ec2:CreateAction": "CreateSecurityGroup" }, "Null": { "aws:RequestTag/elbv2.k8s.aws/cluster": "false" } } }, { "Effect": "Allow", "Action": [ "ec2:CreateTags", "ec2:DeleteTags" ], "Resource": "arn:aws:ec2:*:*:security-group/*", "Condition": { "Null": { "aws:RequestTag/elbv2.k8s.aws/cluster": "true", "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" } } }, { "Effect": "Allow", "Action": [ "ec2:AuthorizeSecurityGroupIngress", "ec2:RevokeSecurityGroupIngress", "ec2:DeleteSecurityGroup" ], "Resource": "*", "Condition": { "Null": { "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" } } }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:CreateLoadBalancer", "elasticloadbalancing:CreateTargetGroup" ], "Resource": "*", "Condition": { "Null": { "aws:RequestTag/elbv2.k8s.aws/cluster": "false" } } }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:CreateListener", "elasticloadbalancing:DeleteListener", "elasticloadbalancing:CreateRule", "elasticloadbalancing:DeleteRule" ], "Resource": "*" }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:AddTags", "elasticloadbalancing:RemoveTags" ], "Resource": [ "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*", "arn:aws:elasticloadbalancing:*:*:loadbalancer/net/*/*", "arn:aws:elasticloadbalancing:*:*:loadbalancer/app/*/*" ], "Condition": { "Null": { "aws:RequestTag/elbv2.k8s.aws/cluster": "true", "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" } } }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:AddTags", "elasticloadbalancing:RemoveTags" ], "Resource": [ "arn:aws:elasticloadbalancing:*:*:listener/net/*/*/*", "arn:aws:elasticloadbalancing:*:*:listener/app/*/*/*", "arn:aws:elasticloadbalancing:*:*:listener-rule/net/*/*/*", "arn:aws:elasticloadbalancing:*:*:listener-rule/app/*/*/*" ] }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:ModifyLoadBalancerAttributes", "elasticloadbalancing:SetIpAddressType", "elasticloadbalancing:SetSecurityGroups", "elasticloadbalancing:SetSubnets", "elasticloadbalancing:DeleteLoadBalancer", "elasticloadbalancing:ModifyTargetGroup", "elasticloadbalancing:ModifyTargetGroupAttributes", "elasticloadbalancing:DeleteTargetGroup" ], "Resource": "*", "Condition": { "Null": { "aws:ResourceTag/elbv2.k8s.aws/cluster": "false" } } }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:RegisterTargets", "elasticloadbalancing:DeregisterTargets" ], "Resource": "arn:aws:elasticloadbalancing:*:*:targetgroup/*/*" }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:SetWebAcl", "elasticloadbalancing:ModifyListener", "elasticloadbalancing:AddListenerCertificates", "elasticloadbalancing:RemoveListenerCertificates", "elasticloadbalancing:ModifyRule" ], "Resource": "*" } ] }
-
-
boto3 사용을 위한 파드 생성
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
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
-
-
파드 이름 변수 지정
-
1 2 3 4
PODNAME1=$(kubectl get pod -l app=boto3 -o jsonpath={.items[0].metadata.name}) echo $PODNAME1 PODNAME2=$(kubectl get pod -l app=boto3 -o jsonpath={.items[1].metadata.name}) echo $PODNAME2
-
-
파드1에서 boto3 사용 - ec2 메타정보를 가져오는 보안 비활성화
-
Describe Regions and Availability Zones
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
kubectl exec -it $PODNAME1 -- sh # ------------ cat <<EOF> az.py import boto3 ec2 = boto3.client('ec2', region_name='us-east-1') # Retrieves all regions/endpoints that work with EC2 response = ec2.describe_regions() print('Regions:', response['Regions']) EOF python az.py exit # ------------
-
-
3. Kubescape
3.1 개요
-
참고 링크
-
소개 및 사용 : 보안 권고 사항 기반 현재 쿠버네티스 클러스터(YAML, Helm chart)의 취약점을 점검
- Kubescape Component architecture
- 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.
- Did you know you can use Kubescape in all these places?
3.2 실습
-
설치
-
1
curl -s https://raw.githubusercontent.com/kubescape/kubescape/master/install.sh | /bin/bash
-
-
Download all artifacts and save them in the default path (~/.kubescape)
-
1 2 3
kubescape download artifacts tree ~/.kubescape/ cat ~/.kubescape/attack-tracks.json | jq
-
-
제공하는 보안 프레임워크 확인
-
1
kubescape list frameworks --format json | jq '.[]'
-
-
제공하는 통제 정책 확인
-
1
kubescape list controls
-
-
모니터링
-
1
watch kubectl get pod -A
-
-
클러스터 스캔
-
1 2 3 4 5
# 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
-
-
(옵션1) armo 웹 사용 : 책 398~400 참고
-
(옵션3) VSCODE - 링크
3.3 과제2
-
목표: 책 398~400페이지 - kubescape armo 웹 사용 후 관련 스샷을 올려주세요
-
수행결과 및 과정
-
웹 브라우저에서
portal.armo.cloud
주소로 접근하여 회원 가입 -
실행스크립트 확인 후 실행
-
1 2 3
helm repo add kubescape https://kubescape.github.io/helm-charts/ helm repo update helm upgrade --install kubescape kubescape/kubescape-cloud-operator -n kubescape --create-namespace --set account=2b976a0e-afb8-4cf9-8a15-102c80060ac1 --set clusterName=`kubectl config current-context`
-
-
I ran the script
클릭
-
4. Polaris
4.1 개요
-
참고 링크
-
소개 및 설치 : 오픈소스 보안 점검 도구, Polaris is an open source policy engine for Kubernetes that validates and remediates resource configuration - helm
- 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.
- 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.
4.2 실습
4.2.1 설치 및 배포
-
네임스페이스 생성
-
1
kubectl create ns polaris
-
-
-
1 2 3 4 5 6
cat <<EOT > polaris-values.yaml dashboard: replicas: 1 service: type: LoadBalancer EOT
-
-
배포
-
1 2
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 로 도메인 연결
-
1
kubectl annotate service polaris-dashboard "external-dns.alpha.kubernetes.io/hostname=polaris.$KOPS_CLUSTER_NAME" -n polaris
-
-
웹 접속 주소 확인 및 접속
-
1
echo -e "Polaris Web URL = http://polaris.$KOPS_CLUSTER_NAME"
-
-
Score : 모범 사례 대비 전체 클러스터 구성 내역 점수, 권고 사항 만족이 많을 수록 점수 상승
-
Passing/Warning/Dangerous Checks : 위험 등급 분류, 위험 단계 취약점은 조치를 권고
-
측정 범위
: Efficiency, Reliability, Security
-
검사 항목 상세 - 링크
4.2.2 보안취약점 점검
-
polaris 웹 접속 → 중간 Filter by Namespace 에서 default 네임스페이스 클릭 후 Apply
-
Namespaces : default 아래 netshoot-pod 부분 ⇒ 아래 항목의 ? 클릭으로 상세 정보 확인
-
Image tag 조치 - 링크
-
기존 netshoot-pod 삭제
-
1
kubectl delete deploy netshoot-pod
-
-
netshoot-pod 1대 생성
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
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
-
-
대시보드 새로고침 후 확인 : 해결됬지만, 상단에 replica 인데 1개라 Warning 확인
-
deployment 의 replica 조치 후 확인
-
1
kubectl scale deployment netshoot-pod --replicas 2
-
-
대시보드 새로고침 후 확인 : 해결!
-
4.2.3 보안 모범 사례 적용 후 재점검
-
폴라리스 파드의 설정 참고
-
1 2
kubectl krew install neat kubectl get deploy/polaris-dashboard -n polaris -o yaml | kubectl neat > polaris-pod.yaml
-
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
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 에 보안 모범 사례 적용
-
삭제
-
1
kubectl delete deploy netshoot-pod
-
-
netshoot-pod 생성
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
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
-
-
폴라리스 웹 확인! → 더 필요한 부분은 조치를 해보자
-
다음 실습을 위해 삭제
-
1
kubectl delete deploy netshoot-pod
-
-
4.2.4 webhook 활성화 후 테스트 - 링크
-
webhook 활성화 적용
-
1 2
helm upgrade polaris fairwinds-stable/polaris --namespace polaris --version 5.7.2 --reuse-values --set webhook.enable=true kubectl get pod,svc -n polaris
-
-
취약한 파드 배포 시도
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# 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
-
4.2.5 IaC 활용 cli - 링크
-
다운로드
-
1 2 3 4
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 점검
-
1
polaris audit --audit-path ~/pkos/1/mario.yaml --format=pretty
-
4.2.6 기타
-
(참고) Github Action 에 polaris actoin 수행 - 링크
-
다음 실습을 위해 polaris 삭제:
-
1
helm uninstall -n polaris polaris
-
-
컨테이너 보안 컨텍스트 : 정리 예정 - 책 p590 - 링크
4.3 과제3
-
목표: polaris 관련 실습(아무거나) 후 관련 스샷을 올려주세요
-
수행결과 및 과정
-
문제 확인
-
문제 해결을 위한 netshoot-pod 생성
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
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 # root 권한으로 컨테이너를 실행하지 않음 terminationGracePeriodSeconds: 0 EOF
-
폴라리스 웹 확인
-
다음 실습을 위해 삭제
-
1
kubectl delete deploy netshoot-pod
-
-
-
5. K8S 인증/인가 & RBAC
5.1 개요
-
인증(Authentication)
- X.509 Client Certs : kubeconfig 에 CA crt(발급 기관 인증서) , Client crt(클라이언트 인증서) , Client key(클라이언트 개인키) 를 통해 인증
- kubectl : 여러 클러스터(kubeconfig)를 관리 가능 - contexts 에 클러스터와 유저 및 인증서/키 참고
- Service Account : 기본 서비스 어카운트(default) - 시크릿(CA crt 와 token)
-
- 출처: PKOS 스터디 7주차(CloudNet@ Blog)
-
인가(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(클러스터 수준의 자원의 권한)
-
- 출처: PKOS 스터디 7주차(CloudNet@ Blog)
- 인가 방식 : RBAC(Role, RoleBinding), ABAC, Webhook, Node Authorization⇒
-
.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 을 사용하려면 여러 개의 컨텍스트 중 하나를 선택.
- 예를 들어 clusters 항목에 클러스터 A,B 가 정의돼 있고, users 항목에 사용자 a,b 가 정의돼 있다면
-
1
cat .kube/config
-
5.2 실습
5.2.1 실습환경
- 쿠버네티스에 사용자를 위한 서비스 어카운트(Service Account, SA)를 생성 : dev-k8s, infra-k8s
- 사용자는 각기 다른 권한(Role, 인가)을 가짐 : dev-k8s(dev-team 네임스페이스 내 모든 동작) , infra-k8s(dev-team 네임스페이스 내 모든 동작)
- 각각 별도의 kubectl 파드를 생성하고, 해당 파드에 SA 를 지정하여 권한에 대한 테스트를 진행
- EKS 대신 저희는 kOps 를 사용합니다!
-
- 출처: PKOS 스터디 7주차(CloudNet@ Blog)
-
5.2.2 네임스페이스와 서비스 어카운트 생성 후 확인
-
파드 기동 시 서비스 어카운트 한 개가 할당되며, 서비스 어카운트 기반 인증/인가를 함, 미지정 시 기본 서비스 어카운트가 할당
-
서비스 어카운트에 자동 생성된 시크릿에 저장된 토큰으로 쿠버네티스 API에 대한 인증 정보로 사용 할 수 있다 ← 1.23 이전 버전의 경우에만 해당
-
네임스페이스(Namespace, NS) 생성 및 확인
-
1 2
kubectl create namespace dev-team kubectl create ns infra-team
-
-
네임스페이스 확인
-
1
kubectl get ns
-
-
네임스페이스에 각각 서비스 어카운트 생성 : serviceaccounts 약자(=sa)
-
1 2
kubectl create sa dev-k8s -n dev-team kubectl create sa infra-k8s -n infra-team
-
-
서비스 어카운트 정보 확인
-
1 2
kubectl get sa -n dev-team kubectl get sa dev-k8s -n dev-team -o yaml | yh
-
1 2
kubectl get sa -n infra-team kubectl get sa infra-k8s -n infra-team -o yaml | yh
-
5.2.3 (심화 참고) dev-k8s 서비스어카운트의 토큰 정보 확인 - https://jwt.io/ → Bearer type - JWT(JSON Web Token) - 링크
-
JSON Web Token (jwt)
-
dev-k8s 서비스어카운트의 토큰 정보 확인
-
1 2 3
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의 변조 가능성을 검증합니다.
- jwt는 JSON 형태로 토큰 형식을 정의한 스펙입니다. jwt는 쿠버네티스에서 뿐만 아니라 다양한 웹 사이트에서 인증, 권한 허가, 세션관리 등의 목적으로 사용합니다.
-
각 파트는 base64 URL 인코딩이 되어서
.
으로 합쳐지게 됩니다.
-
5.2.4 서비스 어카운트를 지정하여 파드 생성 후 권한 테스트
-
각각 네임스피이스에 kubectl 파드 생성 - 컨테이너이미지
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# 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
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
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
-
-
확인
-
1 2
kubectl get pod -A kubectl get pod -o dev-kubectl -n dev-team -o yaml
-
1
kubectl get pod -o infra-kubectl -n infra-team -o yaml
-
-
파드에 기본 적용되는 서비스 어카운트(토큰) 정보 확인
-
1 2 3 4
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) 사용
-
1 2
alias k1='kubectl exec -it dev-kubectl -n dev-team -- kubectl' alias k2='kubectl exec -it infra-kubectl -n infra-team -- kubectl'
-
-
권한 테스트
-
1 2 3
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
-
1 2 3
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 실행 사용자가 특정 권한을 가졌는지 확인
-
1
k1 auth can-i get pods
-
5.2.5 각각 네임스페이스에 롤(Role)를 생성 후 서비스 어카운트 바인딩
-
롤(Role) : apiGroups 와 resources 로 지정된 리소스에 대해 verbs 권한을 인가
-
실행 가능한 조작(verbs) : *(모두 처리), create(생성), delete(삭제), get(조회), list(목록조회), patch(일부업데이트), update(업데이트), watch(변경감시)
-
각각 네임스페이스내의 모든 권한에 대한 롤 생성
-
1 2 3 4 5 6 7 8 9 10 11
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
-
1 2 3 4 5 6 7 8 9 10 11
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
-
-
롤 확인
-
1 2 3
kubectl get roles -n dev-team kubectl get roles -n infra-team kubectl get roles -n dev-team -o yaml
-
1
kubectl describe roles role-dev-team -n dev-team
-
-
롤바인딩 생성 : ‘서비스어카운트 <-> 롤’ 간 서로 연동
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
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
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
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
-
-
롤바인딩 확인
-
1 2 3
kubectl get rolebindings -n dev-team kubectl get rolebindings -n infra-team kubectl get rolebindings -n dev-team -o yaml
-
1
kubectl describe rolebindings roleB-dev-team -n dev-team
-
5.2.6 서비스 어카운트를 지정하여 생성한 파드에서 다시 권한 테스트
-
각각 파드로 Shell 접속하여 정보 확인 : 단축 명령어(alias) 사용
-
1 2
alias k1='kubectl exec -it dev-kubectl -n dev-team -- kubectl' alias k2='kubectl exec -it infra-kubectl -n infra-team -- kubectl'
-
-
권한 테스트
-
1 2 3 4 5 6
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
-
1 2 3 4 5 6
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 실행 사용자가 특정 권한을 가졌는지 확인
-
1
k1 auth can-i get pods
-
5.2.7 리소스 삭제
-
1
kubectl delete ns dev-team infra-team
5.3 과제4
-
목표: 신규 서비스 어카운트(SA) 생성 후 ‘클러스터 수준(모든 네임스페이스 포함)에서 읽기 전용’의 권한을 주고 테스트 후 코드나 스샷을 올려주세요
-
수행결과 및 과정
-
본 과제는 박정희(카이도스)님의 과제 수행 과정을 참조하여 진행했습니다.
-
네임스페이스(Namespace, NS) 생성 및 확인
-
1 2
kubectl create ns infra-team k get ns
-
-
신규 어카운트 생성
-
1
kubectl create sa infra-k8s-cluster -n infra-team
-
-
신규 POD 생성
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
cat <<EOF | kubectl create -f - apiVersion: v1 kind: Pod metadata: name: infra-kubectl-cluster namespace: infra-team spec: serviceAccountName: infra-k8s-cluster containers: - name: kubectl-pod image: bitnami/kubectl:1.24.10 command: ["tail"] args: ["-f", "/dev/null"] terminationGracePeriodSeconds: 0 EOF
-
-
cluster 롤 생성
-
1 2 3 4 5 6 7 8 9 10 11
cat <<EOF | kubectl create -f - apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: role-infra-team-cluster namespace: infra-team rules: - apiGroups: [""] resources: ["*"] verbs: ["get", "watch", "list"] EOF
-
-
cluster 롤 확인
-
1
kubectl describe clusterRole role-infra-team-cluster -n infra-team
-
-
롤바인딩 생성 : ‘서비스어카운트 <-> 롤’ 간 서로 연동
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
cat <<EOF | kubectl create -f - apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: roleB-infra-team-cluster namespace: infra-team roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: role-infra-team-cluster subjects: - kind: ServiceAccount name: infra-k8s-cluster namespace: infra-team EOF
-
-
확인
-
1
kubectl describe clusterrolebindings roleB-infra-team-cluster -n infra-team
-
-
파드로 Shell 접속하여 정보 확인 : 단축 명령어(alias) 사용
-
1
alias k1='kubectl exec -it infra-kubectl-cluster -n infra-team -- kubectl'
-
-
권한 테스트
-
1 2 3 4 5
k1 get pods k1 run nginx --image nginx:1.20-alpine k1 get nodes k1 get ns k1 create ns test
-
-
(옵션) kubectl auth can-i 로 kubectl 실행 사용자가 특정 권한을 가졌는지 확인
-
1
k1 auth can-i get pods
-
-
6. (실습 완료 후) 자원 삭제
-
kOps 클러스터 삭제 & AWS CloudFormation 스택 삭제
-
1
kops delete cluster --yes && aws cloudformation delete-stack --stack-name mykops
-