쿠버네티스를 공부하면서 처음 User Account 와 Service Account 를 접했을 때 단순히 쿠버네티스 API 서버에게 자격 증명하는 리소스인가보다 하고 넘어갔던 적이 있습니다. 이해가 안되서 그냥 넘어갔던..
그래서 User Account 랑 Service Account 는 비슷한거 !! 같은 거 !! 라는 생각을 가지고 있었죠.. 하지만 이 둘은 분명 다릅니다.
쿠버네티스에는 쿠버네티스 내에 존재하는 자원에 대한 접근을 위한 2가지의 account 타입이 존재합니다.
- User Account
- Service Account
쿠버네티스 공식 문서에는 이와 같이 나와있습니다.
사용자 어카운트는 사람을 위한 것이다. 서비스 어카운트는 파드에서 실행되는 프로세스를 위한 것이다.
100% 맞는 말이지만, 처음 접한다면 잘 이해가 되지 않습니다. 저 또한 그랬고요 🤔
AWS 를 가지고 예를 들어보죠 !
우리가 AWS 홈페이지에 들어가게 된다면, 가장 먼저 해야할 것은 로그인 일 것입니다.
로그인 통해서 AWS 에게 우리가 누군지 증명을 할 수 있습니다.
로그인 후 EC2 를 이용합니다. EC2 는 가상 머신을 빌려주는 서비스입니다. 그리고 ssh 를 통해 EC2 에 접속합니다.
EC2 에서 우리는 S3 에 존재하는 test.img 를 사용하려고 합니다.
하지만 EC2 에선 S3 에 접근이 불가능하죠. 왜냐 EC2 는 S3 에 접근할 수 있는 권한이 없기 때문입니다.
AWS IAM 을 통해 EC2 가 S3 에 접근할 수 있다는 것을 증명해야 합니다.
로그인 통해서 AWS 에게 우리가 누군지 증명의 주체가 User Account (유저 어카운트),
EC2 가 S3 에 접근하기 위해 하는 증명 주체가 Service Account (서비스 어카운트) 입니다.
이를 쿠버네티스에 대입해본다면.. 🙃
쿠버네티스에 할당된 유저가 User Account (유저 어카운트),
Pod 가 다른 쿠버네티스 자원 (Pods, Services ..) 에 접근하기 위해 하는 증명 주체가 Service Account (서비스 어카운트) 입니다.
아직 감이 잘 안오시나요? 😅
그럼 한번 실제로 적용해보죠 !
apiVersion: v1
kind: ServiceAccount
metadata:
name: service-account-example-sa
namespace: sample
Service Account 를 생성해줍니다.
Service Account 를 생성하게 되면 Secret 으로 Token 이 하나 자동으로 생성되는데요, 이 Token 을 이용해서 쿠버네티스에게 자격 증명을 할 수 있습니다.
✅ 쿠버네티스 v1.24 이상부터는 자동으로 Secret 이 생성되지 않습니다
apiVersion: apps/v1
kind: Deployment
metadata:
name: service-account-example
namespace: sample
labels:
app: service-account-example
spec:
replicas: 1
selector:
matchLabels:
app: service-account-example
template:
metadata:
labels:
app: service-account-example
spec:
serviceAccountName: service-account-example-sa # SA 를 지정해줍니다
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
Deployment 도 생성해주죠 🤜
눈 여겨 볼 것이 있습니다. 바로 배포된 Pod 에 Service Account 가 마운트 된다는 점이죠 ⚡⚡
Containers:
nginx:
Container ID: docker://67919bf2e0cbcb079bf7a696fef23fd25d3e48691cb2329ac0dd761a251fd8a1
Image: nginx:latest
Image ID: docker-pullable://nginx@sha256:e209ac2f37c70c1e0e9873a5f7231e91dcd83fdf1178d8ed36c2ec09974210ba
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Sun, 20 Nov 2022 14:47:02 +0900
Ready: True
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-pclnt (ro)
그럼 저 경로에 있는 것이 무엇인지 바로 확인 해봐야겠죠? 😏
root@service-account-example-558865ff7d-vx5gl:/var/run/secrets/kubernetes.io/serviceaccount# ls -l
total 0
lrwxrwxrwx 1 root root 13 Nov 20 05:46 ca.crt -> ..data/ca.crt
lrwxrwxrwx 1 root root 16 Nov 20 05:46 namespace -> ..data/namespace
lrwxrwxrwx 1 root root 12 Nov 20 05:46 token -> ..data/token
아하 💡 바로 저기에 쿠버네티스 API 서버와 통신할 수 있는 Token 이 있습니다.
그럼 진짜인지 한번 확인해볼까요?
$ TOKEN=$(cat token)
$ curl -X GET https://$KUBERNETES_SERVICE_HOST/api/v1/namespaces/default/pods --header "Authorization: Bearer $TOKEN" --insecure
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "pods is forbidden: User \"system:serviceaccount:sample:service-account-example-sa\" cannot list resource \"pods\" in API group \"\" in the namespace \"default\": RBAC: clusterrole.rbac.authorization.k8s.io \"service-account-example-role\" not found",
"reason": "Forbidden",
"details": {
"kind": "pods"
},
"code": 403
}
401 (Unauthorized) 가 아닌 403 (Forbidden) 이 온 것을 보니 인증은 되었나 봅니다 🔥
이대로는 아쉬우니 그럼 한번 위에서 배포한 Pod 의 리스트를 가져와보죠 !
위에서 생성한 Service Account 는 자격 증명만 가능할 뿐 현재 어떠한 권한도 없습니다. ( Pods list, create, update .. 등)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: service-account-example-role
namespace: sample
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: service-account-example-role-binding
namespace: sample
subjects:
- kind: ServiceAccount
name: service-account-example-sa
namespace: sample
roleRef:
kind: Role
name: service-account-example-role
apiGroup: rbac.authorization.k8s.io
Role 을 생성하여 Service Account 와 Role Binding 해줍니다.
✅ Role 은 현재 pods 에 대해 ["get", "watch", "list"] 가 가능합니다
$ curl -X GET https://$KUBERNETES_SERVICE_HOST/api/v1/namespaces/default/pods --header "Authorization: Bearer $TOKEN" --insecure
여전히 Forbidden 이 되는 걸 확인할 수 있는데, 이는 바로 Role 의 기능 때문입니다. Cluster Role 과 달리 Role 은 특정 Namespace 에 대해서만 작업을 할 수 있습니다. 따라서 default NameSpace 가 아닌 sample NameSpace 로 요청을 보내봅시다 !
$ curl -X GET https://$KUBERNETES_SERVICE_HOST/api/v1/namespaces/sample/pods --header "Authorization: Bearer $TOKEN" --insecure
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "6608823"
},
"items": [
{
"metadata": {
"name": "service-account-example-558865ff7d-vx5gl",
"generateName": "service-account-example-558865ff7d-",
"namespace": "sample",
"uid": "c85ffc48-affb-4977-8686-657644717c0e",
"resourceVersion": "6604097",
"creationTimestamp": "2022-11-20T05:46:59Z",
....
200 요청이 왔습니다 💵
실습의 과정을 한번 정리해보죠 🙆♂️
- Service Account 와 Pods 를 생성했습니다
- Pods 에 Service Account 가 자동으로 마운트되고 이곳에 Token 이 존재합니다
- Pods 에 접속해서 curl 명령어를 날렸지만 Service Account 는 자격 증명만 된 상태이고 권한은 없습니다
- Role 과 Role Binding 을 생성해서 Service Account 에 권한도 부여해줍니다
- 다시 Pods 접속 후 curl 명령어를 날리면 200 응답 상태가 옵니다
이제 User Account 와 Service Account 의 차이점이 무엇인지 확실히 감이 왔을거라 생각합니다 😉
'DevOps > Kubernetes' 카테고리의 다른 글
[Kubernetes] 인증/인가와 ETCD 사이 그 녀석 - Admission Controller (0) | 2023.01.24 |
---|---|
[Kubernetes] CKA Certification 취득 후기 및 Tips (2) | 2022.01.04 |