일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Kubernetes
- tekton
- serving
- CI/CD
- Kopf
- CANARY
- mlops
- gitops
- kubernetes operator
- xdp
- nginx ingress
- opensearch
- Continuous Deployment
- argocd
- keda
- 오퍼레이터
- knative
- Kubeflow
- seldon core
- Kubernetes 인증
- eBPF
- operator
- MLflow
- Model Serving
- 카오스 엔지니어링
- Litmus
- Argo
- opentelemetry
- blue/green
- Pulumi
- Today
- Total
Kubernetes 이야기
Impersonation (Kubernetes Authentication) 본문
Kubernetes에는 서비스 계정과 일반 사용자라는 두 가지 사용자 범주가 있다. 서비스 계정은 Kubernetes API에서 관리하는 사용자를 의미하고, 일반 사용자는 개인키, Keystone 또는 Google 계정과 같은 사용자 저장소, ID/Password 등의 계정을 의미한다.
Kubernetes에서는 일반 사용자 계정을 나타내는 객체가 없다.
일반 사용자 계정을 통해 Kubernetes API Server에 접근해야 하는 경우가 있다. 이렇게 하려면 일반 사용자 계정을 Kubernetes의 인증과 연동할 수 있는 방법이 필요하다.
이번에는 사용자 인증 방식 중 Impersonation이라는 방식을 알아보자.
먼저 Kubernetes API Server에 접근하여 Pod정보를 조회하는 방법을 살펴보자.
curl -XGET https://localhost:6443/api/v1/pods --insecure
이 명령을 실행하면 다음과 같이 권한 오류가 발생한다.
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
"reason": "Forbidden",
"details": {},
"code": 403
}
anonymous 사용자로는 Cluster에 배포된 Pod정보를 조회할 수 없다.
Kubernetes의 서비스 계정을 만들어 조회해 보자.
먼저 Service Account를 만들어보자.
apiVersion: v1
kind: ServiceAccount
metadata:
name: pod-viewer
namespace: demo
이제 서비스 계정에 Cluster Pod를 조회할 수 있는 Cluster Role을 만들어보자.
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: pods-view-role
rules:
- apiGroups: ["", "extensions", "apps"]
resources: ["pods"]
verbs: ["get", "list", "watch"]
pod-viewer라는 SA에 권한을 할당한다.
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: pods-view-rolebinding
subjects:
- kind: ServiceAccount
name: pod-viewer
namespace: demo
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: pods-view-role
이제 Service Account Token을 생성하자.
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: pod-viewer
namespace: demo
annotations:
kubernetes.io/service-account.name: "pod-viewer"
서비스 계정의 Token정보를 조회해 보자.
# kubectl get secret -n demo pod-viewer -o jsonpath='{$.data.token}' | base64 --decode
eyJhbGciOiJSUzI1NiIsImtpZCI6ImRELTV0T1hZUTR0OTV6....
이 서비스 계정의 token을 이용하여 Kuberntes API Server에 접근해 보자.
curl -XGET -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImRELTV0T1h...J_bqiv4oGxlPQAxXy1sOtYlE8zlDDg69v4s2A" https://localhost:6443/api/v1/pods --insecure
[실행결과]
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "217893655"
},
"items": [
{
"metadata": {
"name": "xxx-58cfb95d5b-t5vzz",
"generateName": "xxx-58cfb95d5b-",
"namespace": "xxx",
"uid": "98c626ef-3f64-4f2c-ac0e-4dc30e7d1c5a",
"resourceVersion": "21609324",
"creationTimestamp": "2022-10-25T08:28:57Z",
"labels": {
"app": "xxx",
"pod-template-hash": "58cfb95d5b"
},
"annotations": {
"cni.projectcalico.org/containerID": "22f44e1bfa199219490e4f2c94a160f44b71b55586e19041ed984533ab05c807",
"cni.projectcalico.org/podIP": "192.168.166.165/32",
"cni.projectcalico.org/podIPs": "192.168.166.165/32"
},
"ownerReferences": [
...
}
만약 잘못된 Token으로 조회하면 다음과 같다.
# curl -XGET -H "Authorization: Bearer 123" https://localhost:6443/api/v1/deployments --insecure
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
}
에러 코드를 보면 401이다. 401 에러는 인증에 실패한 것이고 403에러는 인가에 실패했다는 의미이다.
생성된 Token으로 deployment를 조회해 보자.
curl -XGET -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImRELTV0T1h...J_bqiv4oGxlPQAxXy1sOtYlE8zlDDg69v4s2A" https://localhost:6443/api/v1/deployments --insecure
[실행결과]
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "deployments is forbidden: User \"system:serviceaccount:demo:pod-viewer\" cannot list resource \"deployments\" in API group \"\" at the cluster scope",
"reason": "Forbidden",
"details": {
"kind": "deployments"
},
"code": 403
}
Impersonation
Kubernetes의 가장(Impersonation)은 사용자 또는 서비스 계정이 Kubernetes API 서버에 API 요청을 할 때 다른 사용자 또는 서비스 계정의 ID를 가장하는 기능을 의미한다.
이는 일반적으로 사용자 또는 서비스 계정에 특정 작업을 수행하는 데 필요한 권한이 없지만 다른 사용자 또는 서비스 계정에는 있는 상황에서 사용된다. 또는 관리자는 이 기능을 사용하여 일시적으로 다른 사용자를 가장하고 요청이 거부되었는지 확인하여 권한 부여 정책을 디버깅할 수도 있다.
가장 요청은 먼저 요청한 사용자로 인증한 다음 가장된 사용자 정보로 전환한다.
- 사용자는 자격 증명 및 가장 헤더 를 사용하여 API를 호출한다.
- API 서버가 사용자를 인증한다.
- API 서버는 인증된 사용자에게 가장 권한이 있는지 확인한다.
- 요청 사용자 정보는 가장 값으로 대체된다.
가장 요청을 수행하는 데 다음 HTTP 헤더를 사용할 수 있다.
- Impersonate-User: 역할을 할 사용자 이름.
- Impersonate-Group: 활동할 그룹명. 여러 그룹을 설정하기 위해 여러 번 제공될 수 있다. "Impersonate-User"가 필요한다.
- Impersonate-Extra-( extra name ): 추가 필드를 사용자와 연결하는 데 사용되는 동적 헤더. "Impersonate-User"가 필요하다.
- Impersonate-Uid: 가장 중인 사용자를 나타내는 고유 식별자. "Impersonate-User"가 필요합니다. Kubernetes는 이 문자열에 형식 요구 사항을 부과하지 않는다.
[예제]
Impersonate-User: jane.doe@example.com
Impersonate-Extra-dn: cn=jane,ou=engineers,dc=example,dc=com
Impersonate-Extra-acme.com%2Fproject: some-project
Impersonate-Extra-scopes: view
Impersonate-Extra-scopes: development
Impersonate-Uid: 06f6ce97-e2c5-4ab8-7ba5-7654dd08d52b
Kubernetes에서 다음과 같은 몇 가지 방법으로 Impersonation을 수행할 수 있다.
1) kubectl 명령줄 도구를 사용하면 --as 또는 --as-user 플래그를 사용하여 사용자 또는 서비스 계정을 가장할 수 있다. 예를 들어 다음 명령을 사용하면 사용자 "jane"으로 kubectl get pods 명령을 실행할 수 있다.
kubectl --as=jane get pods
kubectl에서는 추가 필드 또는 UID를 가장할 수 없다.
2) 가장은 API 요청에서 Impersonate-User 및 Impersonate-Group 헤더를 사용하여 수행할 수 있다. 이러한 헤더를 사용하면 요청을 수행해야 하는 사용자 및 그룹을 지정할 수 있다. 예를 들어 다음 명령을 사용하면 사용자 "jane" 및 그룹 "developers"로 포드를 가져올 수 있다.
curl -H "Impersonate-User: jane" -H "Impersonate-Group: developers" https://<k8s-apiserver-url>/api/v1/pods
3) 포드 및 배포와 같은 일부 Kubernetes 리소스는 컨테이너를 실행하는 동안 사용자를 가장하는 데 사용할 수 있는 사양 섹션의 runAsUser 및 fsGroup 필드를 설정할 수도 있다.
가장하려는 사용자 또는 서비스 계정에 해당 작업을 수행하는 데 필요한 권한이 있는 경우에만 가장이 작동한다는 점에 유의해야 한다. 또한 가장은 리소스에 대한 액세스 권한을 얻거나 가장하는 사용자 또는 서비스 계정이 일반적으로 액세스할 수 없는 작업을 수행하는 데 사용될 수 있으므로 가장은 주의해서 사용해야 한다.
테스트
john이라는 사용자 계정에 pod의 조회 권한을 줘 보도록 하자.
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: john-binding
subjects:
- kind: User
name: john
apiGroup: rbac.authorization.k8s.io
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: john-role
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: john-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
admin 계정인 kubeconfig를 이용하여 pod정보를 조회해 보자.
# kubectl get pods --as=john -A
NAMESPACE NAME READY STATUS RESTARTS AGE
cert-manager cert-manager-66bd77df8f-qm2jg 1/1 Running 15 (8d ago) 92d
cert-manager cert-manager-cainjector-6495667ff4-bt5bw 1/1 Running 67 (8d ago) 92d
...
service 정보를 조회해 보자.
# kubectl get svc --as=john -A
Error from server (Forbidden): services is forbidden: User "john" cannot list resource "services" in API group "" at the cluster scope
can-i로도 확인이 가능하다.
# kubectl auth can-i create pods --as john
no
# kubectl auth can-i get pods --as john
yes
Impersonation을 사용하면 외부 인증서버 ( 예:Keycloak 등 ) 의 Account 및 Group정보를 이용하여 Kubernetes의 인증과 연동할 수 있고, 다수의 Kubernetes Cluster를 중앙에서 인증/인가를 할 수 있는 Gateway를 만들면 멀티클러스터 관리를 손쉽게 할 수 있다.
참고
https://kubernetes.io/docs/reference/access-authn-authz/authentication/
'Kubernetes > 일반' 카테고리의 다른 글
Chaos Mesh 에서 Physical Machines 카오스 엔지니어링 (0) | 2023.02.08 |
---|---|
KubeVela (0) | 2023.01.26 |
GitOps의 장단점 (0) | 2023.01.10 |
Ingress vs Service Mesh (0) | 2022.12.28 |
Kubernetes와 Edge computing (0) | 2022.12.09 |