์ถ์ฒ : ๊นํ๋ฏผ ๊ธฐ์ ๋ธ๋ก๊ทธ
์ธ์ฆ(Authentication)
์ถ์ฒ : ๊นํ๋ฏผ ๊ธฐ์ ๋ธ๋ก๊ทธ
์ธ๊ฐ(Authorization)
RBAC ๋ฐ์
์ ์ด๋ป๊ฒ ํ์๋์?# ๋ค์์คํ์ด์ค(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
์ถ์ฒ : https://kubetm.github.io/practice/intermediate/object-authentication/
# ๊ฐ๊ฐ ๋ค์์คํผ์ด์ค์ 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
# ๊ฐ๊ฐ ๋ค์์คํ์ด์ค๋ด์ ๋ชจ๋ ๊ถํ์ ๋ํ ๋กค ์์ฑ
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 krew install access-matrix rbac-tool rbac-view rolesum
# Show an RBAC access matrix for server resources
kubectl access-matrix # Review access to cluster-scoped resources
kubectl access-matrix --namespace default # Review access to namespaced resources in 'default'
# RBAC Lookup by subject (user/group/serviceaccount) name
kubectl rbac-tool lookup
kubectl rbac-tool lookup system:masters
SUBJECT | SUBJECT TYPE | SCOPE | NAMESPACE | ROLE
+----------------+--------------+-------------+-----------+---------------+
system:masters | Group | ClusterRole | | cluster-admin
kubectl rbac-tool lookup system:nodes # eks:node-bootstrapper
kubectl rbac-tool lookup system:bootstrappers # eks:node-bootstrapper
kubectl describe ClusterRole eks:node-bootstrapper
# RBAC List Policy Rules For subject (user/group/serviceaccount) name
kubectl rbac-tool policy-rules
kubectl rbac-tool policy-rules -e '^system:.*'
# Generate ClusterRole with all available permissions from the target cluster
kubectl rbac-tool show
# Shows the subject for the current context with which one authenticates with the cluster
kubectl rbac-tool whoami
{Username: "kubernetes-admin",
UID: "aws-iam-authenticator:911283.....:AIDA5ILF2FJ......",
Groups: ["system:masters",
"system:authenticated"],
Extra: {accessKeyId: ["AKIA5ILF2FJ....."],
arn: ["arn:aws:iam::911283....:user/admin"],
canonicalArn: ["arn:aws:iam::911283....:user/admin"],
principalId: ["AIDA5ILF2FJ....."],
sessionName: [""]}}
# Summarize RBAC roles for subjects : ServiceAccount(default), User, Group
kubectl rolesum -h
kubectl rolesum aws-node -n kube-system
kubectl rolesum -k User system:kube-proxy
kubectl rolesum -k Group system:masters
# [ํฐ๋ฏธ๋1] A tool to visualize your RBAC permissions
kubectl rbac-view
INFO[0000] Getting K8s client
INFO[0000] serving RBAC View and http://localhost:8800
## ์ดํ ํด๋น ์์
์ฉPC ๊ณต์ธ IP:8800 ์น ์ ์
echo -e "RBAC View Web http://$(curl -s ipinfo.io/ip):8800"
์ถ์ฒ : https://docs.aws.amazon.com/eks/latest/userguide/cluster-auth.html
aws sts get-caller-identity --query Arn
cat ~/.kube/config | yh
aws eks get-token --cluster-name $CLUSTER_NAME | jq
aws eks get-token --cluster-name $CLUSTER_NAME | jq -r '.status.token'
"expirationTimestamp": "2023-06-03T07:12:18Z",
"token": "k8s-aws-v1.aHR0cHM6Ly9zdHMuYXAtbm9ydGhlYXN0LTIuYW1hem9uYXdzLmNvbS8_QWN0aW9uPUdldENhbGxlcklkZW50aXR5JlZlcnNpb249MjAxMS0wNi0xNSZYLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFTNzdKQk9ZNVVZTjZSUzdPJTJGMjAyMzA2MDMlMkZhcC1ub3J0aGVhc3QtMiUyRnN0cyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjMwNjAzVDA2NTgxOFomWC1BbXotRXhwaXJlcz02MCZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QlM0J4LWs4cy1hd3MtaWQmWC1BbXotU2lnbmF0dXJlPTAwZWFiM2MwZTlmMDExYzBkYmMzNjU2Zjc5OTJmYjFiZGI5NmMwMTc1Y2FmYjhjZmNjZGE4MGY0ZGRhZjZkODk"
}
}
# tokenreviews api ๋ฆฌ์์ค ํ์ธ
kubectl api-resources | grep authentication
tokenreviews authentication.k8s.io/v1 false TokenReview
# List the fields for supported resources.
kubectl explain tokenreviews
...
DESCRIPTION:
TokenReview attempts to authenticate a token to a known user. Note:
TokenReview requests may be cached by the webhook token authenticator
plugin in the kube-apiserver.
# Webhook api ๋ฆฌ์์ค ํ์ธ
kubectl api-resources | grep Webhook
mutatingwebhookconfigurations admissionregistration.k8s.io/v1 false MutatingWebhookConfiguration
validatingwebhookconfigurations admissionregistration.k8s.io/v1 false ValidatingWebhookConfiguration
# validatingwebhookconfigurations ๋ฆฌ์์ค ํ์ธ
kubectl get validatingwebhookconfigurations
NAME WEBHOOKS AGE
eks-aws-auth-configmap-validation-webhook 1 50m
vpc-resource-validating-webhook 2 50m
aws-load-balancer-webhook 3 8m27s
kubectl get validatingwebhookconfigurations eks-aws-auth-configmap-validation-webhook -o yaml | kubectl neat | yh
# aws-auth ์ปจํผ๊ทธ๋งต ํ์ธ
kubectl get cm -n kube-system aws-auth -o yaml | kubectl neat | yh
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- groups:
- system:bootstrappers
- system:nodes
rolearn: arn:aws:iam::91128.....:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-1OS1WSTV0YB9X
username: system:node:{{EC2PrivateDNSName}}
#---<์๋ ์๋ต(์ถ์ ), ARN์ EKS๋ฅผ ์ค์นํ IAM User , ์ฌ๊ธฐ ์์์๊ฒฝ์ฐ ๋ง์ฝ ์ค์๋ก ์ญ์ ์ ๋ณต๊ตฌ๊ฐ ๊ฐ๋ฅํ์๊น?---
mapUsers: |
- groups:
- system:masters
userarn: arn:aws:iam::111122223333:user/admin
username: kubernetes-admin
# EKS ์ค์นํ IAM User ์ ๋ณด >> system:authenticated๋ ์ด๋ค ๋ฐฉ์์ผ๋ก ์ถ๊ฐ๊ฐ ๋์๋์ง ๊ถ๊ธ???
kubectl rbac-tool whoami
{Username: "kubernetes-admin",
UID: "aws-iam-authenticator:9112834...:AIDA5ILF2FJIR2.....",
Groups: ["system:masters",
"system:authenticated"],
...
# system:masters , system:authenticated ๊ทธ๋ฃน์ ์ ๋ณด ํ์ธ
kubectl rbac-tool lookup system:masters
kubectl rbac-tool lookup system:authenticated
kubectl rolesum -k Group system:masters
kubectl rolesum -k Group system:authenticated
# system:masters ๊ทธ๋ฃน์ด ์ฌ์ฉ ๊ฐ๋ฅํ ํด๋ฌ์คํฐ ๋กค ํ์ธ : cluster-admin
kubectl describe clusterrolebindings.rbac.authorization.k8s.io cluster-admin
Name: cluster-admin
Labels: kubernetes.io/bootstrapping=rbac-defaults
Annotations: rbac.authorization.kubernetes.io/autoupdate: true
Role:
Kind: ClusterRole
Name: cluster-admin
Subjects:
Kind Name Namespace
---- ---- ---------
Group system:masters
# cluster-admin ์ PolicyRule ํ์ธ : ๋ชจ๋ ๋ฆฌ์์ค ์ฌ์ฉ ๊ฐ๋ฅ!
kubectl describe clusterrole cluster-admin
Name: cluster-admin
Labels: kubernetes.io/bootstrapping=rbac-defaults
Annotations: rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
*.* [] [] [*]
[*] [] [*]
# system:authenticated ๊ทธ๋ฃน์ด ์ฌ์ฉ ๊ฐ๋ฅํ ํด๋ฌ์คํฐ ๋กค ํ์ธ
kubectl describe ClusterRole system:discovery
kubectl describe ClusterRole system:public-info-viewer
kubectl describe ClusterRole system:basic-user
kubectl describe ClusterRole eks:podsecuritypolicy:privileged
# testuser ์ฌ์ฉ์ ์์ฑ
aws iam create-user --user-name testuser
# ์ฌ์ฉ์์๊ฒ ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ์ ์ก์ธ์ค ๊ถํ ๋ถ์ฌ
aws iam create-access-key --user-name testuser
{
"AccessKey": {
"UserName": "testuser",
"AccessKeyId": "AKIA5ILF2##",
"Status": "Active",
"SecretAccessKey": "TxhhwsU8##",
"CreateDate": "2023-05-23T07:40:09+00:00"
}
}
{
"AccessKey": {
"UserName": "testuser",
"AccessKeyId": "AKIAS77JBOY5VWZZMROH",
"Status": "Active",
"SecretAccessKey": "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",
"CreateDate": "2023-06-03T07:57:35+00:00"
}
}
# testuser ์ฌ์ฉ์์ ์ ์ฑ
์ ์ถ๊ฐ
aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess --user-name testuser
# get-caller-identity ํ์ธ
aws sts get-caller-identity --query Arn
"arn:aws:iam::911283464785:user/admin"
# EC2 IP ํ์ธ : myeks-bastion-EC2-2 PublicIPAdd ํ์ธ
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,PrivateIPAdd:PrivateIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output table
# get-caller-identity ํ์ธ >> ์ ์๋ ๊น์?
aws sts get-caller-identity --query Arn
# testuser ์๊ฒฉ์ฆ๋ช
์ค์
aws configure
AWS Access Key ID [None]: AKIA5ILF2F...
AWS Secret Access Key [None]: ePpXdhA3cP....
Default region name [None]: ap-northeast-2
# get-caller-identity ํ์ธ
aws sts get-caller-identity --query Arn
"arn:aws:iam::911283464785:user/testuser"
# kubectl ์๋ >> testuser๋ AdministratorAccess ๊ถํ์ ๊ฐ์ง๊ณ ์๋๋ฐ, ์คํจ ์ด์ ๋?
kubectl get node -v6
ls ~/.kube
# ๋ฐฉ์1 : eksctl ์ฌ์ฉ >> iamidentitymapping ์คํ ์ aws-auth ์ปจํผ๊ทธ๋งต ์์ฑํด์ค
# Creates a mapping from IAM role or user to Kubernetes user and groups
eksctl create iamidentitymapping --cluster $CLUSTER_NAME --username testuser --group system:masters --arn arn:aws:iam::$ACCOUNT_ID:user/testuser
# ํ์ธ
kubectl get cm -n kube-system aws-auth -o yaml | kubectl neat | yh
...
# ํ์ธ : ๊ธฐ์กด์ ์๋ role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-YYYYY ๋ ์ด๋ค ์ญํ /๋์์ ํ๋ ๊ฑธ๊น์?
eksctl get iamidentitymapping --cluster $CLUSTER_NAME
ARN USERNAME GROUPS ACCOUNT
arn:aws:iam::911283464785:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-LHQ7DWHQQRZJ system:node:{{EC2PrivateDNSName}} system:bootstrappers,system:nodes
arn:aws:iam::911283464785:user/testuser testuser system:masters
# testuser kubeconfig ์์ฑ >> aws eks update-kubeconfig ์คํ์ด ๊ฐ๋ฅํ ์ด์ ๋?, 3๋ฒ ์ค์ ํ ์ฝ๊ฐ์ ์ ์ฉ ์๊ฐ ํ์
aws eks update-kubeconfig --name $CLUSTER_NAME --user-alias testuser
# ์ฒซ๋ฒ์งธ bastic ec2์ config์ ๋น๊ตํด๋ณด์
cat ~/.kube/config | yh
# kubectl ์ฌ์ฉ ํ์ธ
kubectl ns default
kubectl get node -v6
# rbac-tool ํ ํ์ธ >> ๊ธฐ์กด ๊ณ์ ๊ณผ ๋น๊ตํด๋ณด์ >> system:authenticated ๋ system:masters ์ค์ ์ ๋ฐ๋ผ์ค๋ ๊ฒ ๊ฐ์๋ฐ, ์ถ๊ฐ ๋์ ์๋ฆฌ๋ ๋ชจ๋ฅด๊ฒ ๋ค์???
kubectl krew install rbac-tool && kubectl rbac-tool whoami
{Username: "testuser",
UID: "aws-iam-authenticator:911283464785:AIDA5ILF2FJIV65KG6RBM",
Groups: ["system:masters",
"system:authenticated"],
Extra: {accessKeyId: ["AKIA5ILF2FJIZJUZSG4D"],
arn: ["arn:aws:iam::911283464785:user/testuser"],
canonicalArn: ["arn:aws:iam::911283464785:user/testuser"],
...
# ๋ฐฉ์2 : ์๋ edit๋ก mapUsers ๋ด์ฉ ์ง์ ์์ system:authenticated
kubectl edit cm -n kube-system aws-auth
...
# ํ์ธ
eksctl get iamidentitymapping --cluster $CLUSTER_NAME
# ์๋
kubectl get node -v6
kubectl api-resources -v5
# testuser IAM ๋งตํ ์ญ์
eksctl delete iamidentitymapping --cluster $CLUSTER_NAME --arn arn:aws:iam::$ACCOUNT_ID:user/testuser
# Get IAM identity mapping(s)
eksctl get iamidentitymapping --cluster $CLUSTER_NAME
kubectl get cm -n kube-system aws-auth -o yaml | yh
# ์๋
kubectl get node -v6
kubectl api-resources -v5
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
mapRoles: |
- groups:
- system:bootstrappers
- system:nodes
rolearn: arn:aws:iam::111122223333:role/my-role
username: system:node:{{EC2PrivateDNSName}}
- groups:
- eks-console-dashboard-full-access-group
rolearn: arn:aws:iam::111122223333:role/my-console-viewer-role
username: my-console-viewer-role
mapUsers: |
- groups:
- system:masters
userarn: arn:aws:iam::111122223333:user/admin
username: admin
- groups:
- eks-console-dashboard-restricted-access-group
userarn: arn:aws:iam::444455556666:user/my-user
username: my-user
# ์ค์ ์์ 1 : eksctl ์ฌ์ฉ ์
eksctl create cluster --name $CLUSTER_NAME ... --external-dns-access --full-ecr-access --asg-access
# ์ค์ ์์ 2 : eksctl๋ก yaml ํ์ผ๋ก ๋
ธ๋ ์์ฑ ์
cat myeks.yaml | yh
...
managedNodeGroups:
- amiFamily: AmazonLinux2
iam:
withAddonPolicies:
albIngress: false
appMesh: false
appMeshPreview: false
autoScaler: true
awsLoadBalancerController: false
certManager: true
cloudWatch: true
ebs: false
efs: false
externalDNS: true
fsx: false
imageBuilder: true
xRay: false
...
# ์ค์ ์์ 3 : ํ
๋ผํผ
...
Service Account Token Volume Projection
: '์๋น์ค ๊ณ์ ํ ํฐ'์ ์ํฌ๋ฆฟ ๊ธฐ๋ฐ ๋ณผ๋ฅจ ๋์ 'projected volume' ์ฌ์ฉ
Service Account Token Volume Projection
ย ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด ์ด๋ฌํ ๋ถ์กฑํ ์ ๋ค์ ํด๊ฒฐํ ์ ์์ต๋๋ค.apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /var/run/secrets/tokens
name: vault-token
serviceAccountName: build-robot
volumes:
- name: vault-token
projected:
sources:
- serviceAccountToken:
path: vault-token
expirationSeconds: 7200
audience: vault
Kubernetes v1.22 [stable]
- name: kube-api-access-<random-suffix>
projected:
defaultMode: 420 # 420์ rw- ๋ก ์์ ์๋ ์ฝ๊ณ ์ฐ๊ธฐ ๊ถํ๊ณผ ๊ทธ๋ฃน๋ด ์ฌ์ฉ์๋ ์ฝ๊ธฐ๋ง, ๋ณดํต 0644๋ ์์ ์๋ ์ฝ๊ณ ์ฐ๊ณ ์คํ ๊ถํ๊ณผ ๋๋จธ์ง๋ ์ฝ๊ณ ์ฐ๊ธฐ ๊ถํ
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace
ํ๋ก์ ํฐ๋ ๋ณผ๋ฅจ์ ์ธ ๊ฐ์ง๋ก ๊ตฌ์ฑ๋จkube-apiserver
๋ก๋ถํฐ TokenRequest API๋ฅผ ํตํด ์ป์ย ์๋น์ค์ด์นด์ดํธํ ํฐ(ServiceAccountToken)
. ์๋น์ค์ด์นด์ดํธํ ํฐ์ ๊ธฐ๋ณธ์ ์ผ๋ก 1์๊ฐ ๋ค์, ๋๋ ํ๋๊ฐ ์ญ์ ๋ ๋ ๋ง๋ฃ๋๋ค. ์๋น์ค์ด์นด์ดํธํ ํฐ์ ํ๋์ ์ฐ๊ฒฐ๋๋ฉฐ kube-apiserver๋ฅผ ์ํด ์กด์ฌํจ์ปจํผ๊ทธ๋งต(ConfigMap)
.DownwardA
This page shows how to use aย [projected](https://kubernetes.io/docs/concepts/storage/volumes/#projected)
ย Volume to mount several existing volume sources into the same directory. Currently,ย secret
,ย configMap
,ย downwardAPI
, andย serviceAccountToken
ย volumes can be projected.
Note:ย serviceAccountToken
ย is not a volume type.
apiVersion: v1
kind: Pod
metadata:
name: test-projected-volume
spec:
containers:
- name: test-projected-volume
image: busybox:1.28
args:
- sleep
- "86400"
volumeMounts:
- name: all-in-one
mountPath: "/projected-volume"
readOnly: true
volumes:
- name: all-in-one
**projected**:
sources:
- secret:
name: user
- secret:
name: pass
# Create the Secrets:
## Create files containing the username and password:
echo -n "admin" > ./username.txt
echo -n "1f2d1e2e67df" > ./password.txt
## Package these files into secrets:
kubectl create secret generic user --from-file=./username.txt
kubectl create secret generic pass --from-file=./password.txt
# ํ๋ ์์ฑ
kubectl apply -f https://k8s.io/examples/pods/storage/projected.yaml
# ํ๋ ํ์ธ
kubectl get pod test-projected-volume -o yaml | kubectl neat | yh
...
volumes:
- name: all-in-one
**projected**:
defaultMode: 420
sources:
- secret:
name: user
- secret:
name: pass
- name: kube-api-access-n6n9v
**projected**:
defaultMode: 420
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace
# ์ํฌ๋ฆฟ ํ์ธ
kubectl exec -it test-projected-volume -- ls /projected-volume/
***password.txt username.txt***
kubectl exec -it test-projected-volume -- cat /projected-volume/username.txt ;echo
***admin***
kubectl exec -it test-projected-volume -- cat /projected-volume/password.txt ;echo
***1f2d1e2e67df***
# ์ญ์
kubectl delete pod test-projected-volume && kubectl delete secret user pass
์ถ์ฒ: https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/
MutatingWebhook
์ ์ฌ์ฉ์๊ฐ ์์ฒญํ request์ ๋ํด์ ๊ด๋ฆฌ์๊ฐ ์์๋ก ๊ฐ์ ๋ณ๊ฒฝํ๋ ์์
ValidatingWebhook
์ ์ฌ์ฉ์๊ฐ ์์ฒญํ request์ ๋ํด์ ๊ด๋ฆฌ์๊ธฐ ํ์ฉ์ ๋ง๋ ์์
kubectl get **validatingwebhook**configurations
kubectl get **mutatingwebhook**configurations
.
์ผ๋ก ํฉ์ณ์ง๊ฒ ๋ฉ๋๋ค.iss
: ํ ํฐ ๋ฐํ์sub
: ์ฌ์ฉ์๋ฅผ ๊ตฌ๋ถํ๊ธฐ ์ํ ์ ๋ํฌํ ๊ตฌ๋ถ์email
: ์ฌ์ฉ์์ ์ด๋ฉ์ผiat
: ํ ํฐ์ด ๋ฐํ๋๋ ์๊ฐ์ Unix time์ผ๋ก ํ๊ธฐํ ๊ฒexp
: ํ ํฐ์ด ๋ง๋ฃ๋๋ ์๊ฐ์ Unix time์ผ๋ก ํ๊ธฐํ ๊ฒaud
: ID Token์ด ์ด๋ค Client๋ฅผ ์ํด ๋ฐ๊ธ๋ ๊ฒ์ธ์ง.# ํ๋1 ์์ฑ
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: eks-iam-test1
spec:
containers:
- name: my-aws-cli
image: amazon/aws-cli:latest
args: ['s3', 'ls']
restartPolicy: Never
automountServiceAccountToken: false
EOF
# ํ์ธ
kubectl get pod
kubectl describe pod
# ๋ก๊ทธ ํ์ธ
kubectl logs eks-iam-test1
# ํ๋1 ์ญ์
kubectl delete pod eks-iam-test1
Kubernetes Service Accounts : https://jwt.io/
# ํ๋2 ์์ฑ
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: eks-iam-test2
spec:
containers:
- name: my-aws-cli
image: amazon/aws-cli:latest
command: ['sleep', '36000']
restartPolicy: Never
EOF
# ํ์ธ
kubectl get pod
kubectl describe pod
# aws ์๋น์ค ์ฌ์ฉ ์๋
kubectl exec -it eks-iam-test2 -- aws s3 ls
# ์๋น์ค ์ด์นด์ดํธ ํ ํฐ ํ์ธ
SA_TOKEN=$(kubectl exec -it eks-iam-test2 -- cat /var/run/secrets/kubernetes.io/serviceaccount/token)
echo $SA_TOKEN
# jwt ํน์ ์๋ JWT ์น ์ฌ์ดํธ ์ด์ฉ
jwt decode $SA_TOKEN --json --iso8601
...
#ํค๋
{
"alg": "RS256",
"kid": "1a8fcaee12b3a8f191327b5e9b997487ae93baab"
}
# ํ์ด๋ก๋ : OAuth2์์ ์ฐ์ด๋ aud, exp ์์ฑ ํ์ธ! > projectedServiceAccountToken ๊ธฐ๋ฅ์ผ๋ก ํ ํฐ์ audience,exp ํญ๋ชฉ์ ๋ง๋ถํ
## iss ์์ฑ : EKS OpenID Connect Provider(EKS IdP) ์ฃผ์ > ์ด EKS IdP๋ฅผ ํตํด ์ฟ ๋ฒ๋คํฐ์ค๊ฐ ๋ฐ๊ธํ ํ ํฐ์ด ์ ์ํ์ง ๊ฒ์ฆ
{
"aud": [
"https://kubernetes.default.svc" # ํด๋น ์ฃผ์๋ k8s api์ ClusterIP ์๋น์ค ์ฃผ์ ๋๋ฉ์ธ๋ช
, kubectl get svc kubernetes
],
"exp": 1716619848,
"iat": 1685083848,
"iss": "https://oidc.eks.ap-northeast-2.amazonaws.com/id/F6A7523462E8E6CDADEE5D41DF2E71F6",
"kubernetes.io": {
"namespace": "default",
"pod": {
"name": "eks-iam-test2",
"uid": "10dcccc8-a16c-4fc7-9663-13c9448e107a"
},
"serviceaccount": {
"name": "default",
"uid": "acb6c60d-0c5f-4583-b83b-1b629b0bdd87"
},
"warnafter": 1685087455
},
"nbf": 1685083848,
"sub": "system:serviceaccount:default:default"
}
# ํ๋2 ์ญ์
kubectl delete pod eks-iam-test2
eksctl create iamserviceaccount
ย command creates:# Create an iamserviceaccount - AWS IAM role bound to a Kubernetes service account
eksctl create iamserviceaccount \
--name my-sa \
--namespace default \
--cluster $CLUSTER_NAME \
--approve \
--attach-policy-arn $(aws iam list-policies --query 'Policies[?PolicyName==`AmazonS3ReadOnlyAccess`].Arn' --output text)
# ํ์ธ >> ์น ๊ด๋ฆฌ ์ฝ์์์ CloudFormation Stack >> IAM Role ํ์ธ
# aws-load-balancer-controller IRSA๋ ์ด๋ค ๋์์ ์ํํ ๊ฒ ์ธ์ง ์๊ฐํด๋ณด์!
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
# Inspecting the newly created Kubernetes Service Account, we can see the role we want it to assume in our pod.
kubectl get sa
kubectl describe sa my-sa
Name: my-sa
Namespace: default
Labels: app.kubernetes.io/managed-by=eksctl
Annotations: eks.amazonaws.com/role-arn: arn:aws:iam::911283464785:role/eksctl-myeks-addon-iamserviceaccount-default-Role1-1MJUYW59O6QGH
Image pull secrets: <none>
Mountable secrets: <none>
Tokens: <none>
Events: <none>
# ํ๋3๋ฒ ์์ฑ
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: eks-iam-test3
spec:
serviceAccountName: my-sa
containers:
- name: my-aws-cli
image: amazon/aws-cli:latest
command: ['sleep', '36000']
restartPolicy: Never
EOF
# ํด๋น SA๋ฅผ ํ๋๊ฐ ์ฌ์ฉ ์ mutatingwebhook์ผ๋ก Env,Volume ์ถ๊ฐํจ
kubectl get mutatingwebhookconfigurations pod-identity-webhook -o yaml | kubectl neat | yh
# ํ๋ ์์ฑ yaml์ ์๋ ๋ด์ฉ์ด ์ถ๊ฐ๋จ!!!!!
# Pod Identity Webhook์ mutating webhook์ ํตํด ์๋ Env ๋ด์ฉ๊ณผ 1๊ฐ์ ๋ณผ๋ฅจ์ ์ถ๊ฐํจ
kubectl get pod eks-iam-test3
kubectl describe pod eks-iam-test3
...
Environment:
AWS_STS_REGIONAL_ENDPOINTS: regional
AWS_DEFAULT_REGION: ap-northeast-2
AWS_REGION: ap-northeast-2
AWS_ROLE_ARN: arn:aws:iam::911283464785:role/eksctl-myeks-addon-iamserviceaccount-default-Role1-GE2DZKJYWCEN
AWS_WEB_IDENTITY_TOKEN_FILE: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
Mounts:
/var/run/secrets/eks.amazonaws.com/serviceaccount from aws-iam-token (ro)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-69rh8 (ro)
...
Volumes:
aws-iam-token:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 86400
kube-api-access-sn467:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
...
# ํ๋์์ aws cli ์ฌ์ฉ ํ์ธ
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
kubectl exec -it eks-iam-test3 -- aws sts get-caller-identity --query Arn
"arn:aws:sts::911283464785:assumed-role/eksctl-myeks-addon-iamserviceaccount-default-Role1-GE2DZKJYWCEN/botocore-session-1685179271"
# ๋๋ ๊ฒ๊ณ ์๋๋ ๊ฒ์ ์๊ทธ๋ฐ๊ฐ?
kubectl exec -it eks-iam-test3 -- aws s3 ls
kubectl exec -it eks-iam-test3 -- aws ec2 describe-instances --region ap-northeast-2
kubectl exec -it eks-iam-test3 -- aws ec2 describe-vpcs --region ap-northeast-2
aws-iam-token
ย is still being generated by the Kubernetes API Server, but with a new OIDC JWT audience.# ํ๋์ ๋ณผ๋ฅจ ๋ง์ดํธ 2๊ฐ ํ์ธ
kubectl get pod eks-iam-test3 -o json | jq -r '.spec.containers | .[].volumeMounts'
[
{
"mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
"name": "kube-api-access-sn467",
"readOnly": true
},
{
"mountPath": "/var/run/secrets/eks.amazonaws.com/serviceaccount",
"name": "aws-iam-token",
"readOnly": true
}
]
# aws-iam-token ๋ณผ๋ฅจ ์ ๋ณด ํ์ธ : JWT ํ ํฐ์ด ๋ด๊ฒจ์ ธ์๊ณ , exp, aud ์์ฑ์ด ์ถ๊ฐ๋์ด ์์
kubectl get pod eks-iam-test3 -o json | jq -r '.spec.volumes[] | select(.name=="aws-iam-token")'
{
"name": "aws-iam-token",
"projected": {
"defaultMode": 420,
"sources": [
{
"serviceAccountToken": {
"audience": "sts.amazonaws.com",
"expirationSeconds": 86400,
"path": "token"
}
}
]
}
}
# api ๋ฆฌ์์ค ํ์ธ
kubectl api-resources |grep hook
mutatingwebhookconfigurations admissionregistration.k8s.io/v1 false MutatingWebhookConfiguration
validatingwebhookconfigurations admissionregistration.k8s.io/v1 false ValidatingWebhookConfiguration
#
kubectl explain mutatingwebhookconfigurations
#
kubectl get MutatingWebhookConfiguration
NAME WEBHOOKS AGE
pod-identity-webhook 1 147m
vpc-resource-mutating-webhook 1 147m
# pod-identity-webhook ํ์ธ
kubectl describe MutatingWebhookConfiguration pod-identity-webhook
kubectl get MutatingWebhookConfiguration pod-identity-webhook -o yaml | yh
sts.amazonaws.com
, the issuer who has created and signed this token is still our OIDC provider, and finally, the expiration of the token is much shorter at 24 hours. We can modify the expiration duration for the service account usingย eks.amazonaws.com/token-expiration
ย annotation in our Pod definition or Service Account definition.# AWS_WEB_IDENTITY_TOKEN_FILE ํ์ธ
IAM_TOKEN=$(kubectl exec -it eks-iam-test3 -- cat /var/run/secrets/eks.amazonaws.com/serviceaccount/token)
echo $IAM_TOKEN
# JWT ์น ํ์ธ
{
"aud": [
"sts.amazonaws.com"
],
"exp": 1685175662,
"iat": 1685089262,
"iss": "https://oidc.eks.ap-northeast-2.amazonaws.com/id/F6A7523462E8E6CDADEE5D41DF2E71F6",
"kubernetes.io": {
"namespace": "default",
"pod": {
"name": "eks-iam-test3",
"uid": "73f66936-4d66-477a-b32b-853f7a1c22d9"
},
"serviceaccount": {
"name": "my-sa",
"uid": "3b31aa85-2718-45ed-8c1c-75ed012c1a68"
}
},
"nbf": 1685089262,
"sub": "system:serviceaccount:default:my-sa"
}
# env ๋ณ์ ํ์ธ
kubectl get pod eks-iam-test3 -o json | jq -r '.spec.containers | .[].env'
[
{
"name": "AWS_STS_REGIONAL_ENDPOINTS",
"value": "regional"
},
{
"name": "AWS_DEFAULT_REGION",
"value": "ap-northeast-2"
},
{
"name": "AWS_REGION",
"value": "ap-northeast-2"
},
{
"name": "AWS_ROLE_ARN",
"value": "arn:aws:iam::911283464785:role/eksctl-myeks-addon-iamserviceaccount-default-Role1-1MJUYW59O6QGH"
},
{
"name": "AWS_WEB_IDENTITY_TOKEN_FILE",
"value": "/var/run/secrets/eks.amazonaws.com/serviceaccount/token"
}
]
AssumeRoleWithWebIdentity
ย API operation to get temporary IAM credentials.AssumeRoleWithWebIdentity
ย API operation can send the temporary credentials. As part of theย Service Account Issuer Discoveryย feature of Kubernetes, EKS is hosting a public OpenID provider configuration document (Discovery endpoint) and the public keys to validate the token signature (JSON Web Key Sets โ JWKS) atย https://OIDC_PROVIDER_URL/.well-known/openid-configuration
.# Letโs take a look at this endpoint. We can use the aws eks describe-cluster command to get the OIDC Provider URL.
IDP=$(aws eks describe-cluster --name myeks --query cluster.identity.oidc.issuer --output text)
# Reach the Discovery Endpoint
curl -s $IDP/.well-known/openid-configuration | jq -r '.'
# In the above output, you can see the jwks (JSON Web Key set) field, which contains the set of keys containing the public keys used to verify JWT (JSON Web Token).
# Refer to the documentation to get details about the JWKS properties.
curl -s $IDP/keys | jq -r '.'