kubernetes – Authentication and Authorization

kubernetes.io Authenticating

Authentication

API 서버는 하나 이상의 인증 플러그인이 구성되어 있다.
https://dinonotes.com/archives/747 여기 페이지에 정리함.

1. User in Kubernetes

Kubernetes API Server에 접근하기 위해서는 인증과정을 거쳐야 하는데. API Server는 로컬에서 호출할 경우 8080, 외부에서는 6443(TLS인증 적용)으로 호출 가능하다.
즉 내부에서 API Server 에 호출할 때는 인증서가 필요가 없지만, 외부에서 API Server에 호출 할 때는 유요한 인증서가 필요하다.
kubernetes에서 인증을 요청하기 위한 사용자는 일반적인 사용자어카운트(user account) 와 서비스어카운트(service accout) 2가지 종류가 있다.

사용자 어카운트(user account)

kubernetes 에는 사용자에 대한 정보가 저장되어 않아, 외부의 별도 인증 시스템에 있는 사용자 정보들을 사용해야 한다.(google account, keystone, OAuth, LDAP 등)

서비스 어카운트(service account)

kubernetes.io serviceaccount

환경변수로 configmap을 사용하고, 민감한 정보는 secrtes로 만들어서 사용을 한다.
예를 들어 private register 만들어 사용할 때 secrets에서 만든 정보를 매번 꺼내서 사용한다는게 얼마나 귀찮은 작업일까?
서비스를 사용하고자 하는 사람에게 권한을 부여하고 인증만 거치면 암호화된 정보를 매번 꺼내는것보다 간편하다.

service account는 kubernetes가 직접 관리하는 계정이다. 시스템에서 api server에 호출시에 사용한다. 유저의 계정이 아니라 시스템에서 호출하는 것으로 생각 하면 된다.

Service Account 생성 방법

$ kubectl create serviceaccount foo
serviceaccount/foo created
$ kubectl describe sa foo
Name:                foo
Namespace:           default
Labels:              
Annotations:         
Image pull secrets:  
Mountable secrets:   foo-token-6s8gl. #mountable secrets가 수행됐을 때 시크릿 마운트
Tokens:              foo-token-6s8gl  #인증토큰
Events:
$ kubectl describe secrets foo-token-6s8gl
Name:         foo-token-6s8gl
Namespace:    default
Labels:       
Annotations:  kubernetes.io/service-account.name: foo
              kubernetes.io/service-account.uid: 90ad4b78-8184-4661-a92a-e0d3e27ff92e
Type:  kubernetes.io/service-account-token
Data
====
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImZvby10b2tlbi02czhnbCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJmb28iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI5MGFkNGI3OC04MTg0LTQ2NjEtYTkyYS1lMGQzZTI3ZmY5MmUiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpmb28ifQ.XYB0smWnCY87oQcfEaZ8KeBvH7l0r36qfRiatE4MCfFtd6Dd2S1dBe11gEuV4d-B-SnTuzDArAU-ncFBAbzLOq9_kIz2TMee_282-Nl_pN8vnWBZxui_jQYCRmRsFt9kzYm3sOa5aNTpqFuY2YTDVGp59jU8RmQQv0IkSFZbx50Tb6x9A7gzB7iyWQAgUZlf4EVIUs0GT3sMx8zcpUJ29palmsqtSDDLjnTI6ZHZNAAFq6NwTKH5Y0fZImfOZQbteuY-qc9HfjYjZL8UZVa44AjmYDNK8bC9WM4jR3jTMFzNuy7vwGWCGbRmcv4qwX1WVxiOGh0pDF3pfrSn83X7Qw
ca.crt:     1025 bytes
namespace:  7 bytes

pod에 service account 할당

apiVersion: v1
kind: Pod
metadata:
  name: curl-custom-sa
spec:
  serviceAccountName: foo
  containers:
  - name: main
     image: tutum/curl
     command: ["sleep", "9999999"]
 - name: ambassador
    image: luksa/kubectl-proxy:1.6.2

2. Authentication strategies

계정이 있을 때 이 계정을 가지고 kubernetes API에 어떻게 접근을 할까?

아래와 같은 방법으로 접근을 할 수 있다.

– X509 Client Certs

api server 의 –client-ca-file=SOMEFILE 로 인증을 사용 하면된다.
즉 API Server와 통신하기 위해서는 TLS인증을 사용하는데 해당 인증을 통하여 API server와 통신하는 방법이다. TLS 인증은 서버 뿐만 아니라 클라이언트가 유효한지를 검증하는 기능을 가지고 있어 API Server에 있는 인증서와 매치되는 클라이언트 인증서를 가지고 접속을 시도 하면 된다.
인증서의 조직 필드를 사용하여 사용자의 그룹 구성원을 나타낼수 있다.

대표적으로 kubectl 명령어가 TLS를 이용하여 API Server에 호출하는 형태 이다.
.kube/config 파일에 보면 정보가 나와 있다.(client-cert, client-key-data, certificate-auhority-data)

kubectl에서 사용하는 TLS를 이용하여 API server을 이용하는 방법

$ export client=$(grep client-cert ~/.kube/config | cut -d" " -f 6)
$ echo $client
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM4akNDQWRxZ0F3SUJBZ0lJVWZlb
DNsc1JHbG93RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWE
p1WlhSbGN6QWVGdzB5TURBeE1qa3dNVE0yTkRkYUZ3MHlNVEF4TWpnd01UTTJ~~~~~

$ export key=$(grep client-key-data ~/.kube/config | cut -d” ” -f 6)
$ echo $key
LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBd0Qzd
21QbmE5NkFSUExUZ3VRWjIzbS9IVTR6dktobFV4VEtnZ1dxQVNxVHRma0NhCnV1ZDl5Vn
VrZW~~~

$ export auth=$(grep certificate-authority-data ~/.kube/config | cut -d” ” -f 6)
$ echo $auth
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBT
kJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQj
RY~~

$ echo $client | base64 -d – > ./client.pem
$ echo $key | base64 -d – > ./client-key.pem
$ echo $auth | base64 -d – > ./ca.pem

$ curl –cert ./client.pem –key ./client-key.pem –cacert ./ca.pem https://k8smaster:6443/ap/v1/namespaces/default/pods

– Putting a Bearer Token in a Request

pod 내부에서 API Server 와 통신하기

pod 내부에 (/var/run/secrets/kubernetes.io/serviceaccount/) 자동생성 시크릿이 있다.
(ca.crt, token, namespace 파일)

$ export CURL_CA_BUNDLE=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
$ TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
$ curl -H "Authorization: Bearer $TOKEN" https://kubernetes

– Authenticating Proxy

curl을 이용해서 호출할 경우에는 kubectl proxy명령어를 이용하여 호출하면 자동으로 proxy가 현재 클라이언트의 kubeconfig file에 저장되어 있는 인증정보를 채워서 자동으로 호출한다.

$ kubectl proxy --port=8080
$ curl localhost:8080/api

– Bootstrap Tokens

– Static Password File

– Service Account Tokens

– OpenID Connect Tokens

– Configuring the API Server

– Using kubectl

– Webhook Token Authentication

Authorization

kubernetes.io rbac

kubernetes의 권한 처리는 기본적으로 역활 기반의 권한 인가체계를 가지고 있다.(RBAC)

인증된 계정이 어떤 role을 가지고 어떤 resource에 접근을 할 수 있는지 인가를 하는 것이다.

resource : pod, node, service . . . . . . . . . .
role :  get, list, watch, create, update, patch, delete

TEST 환경설정

$ kubectl create ns foo
namespace "foo" created

$ kubectl run test –image=luksa/kubectl-proxy -n foo
deployment “test” created

$ kubectl create ns bar
namespace “bar” created

$ kubectl run test –image=luksa/kubectl-proxy -n bar
deployment “test” created

$ kubectl get po -n foo
NAME                    READY   STATUS    RESTARTS   AGE
test-57d9d57995-ptqk6   1/1     Running   0          95s
$ kubectl exec -it test-57d9d57995-ptqk6 -n foo sh
/ # curl localhost:8001/api/v1/namespaces/foo/services
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {
 },
  "status": "Failure",
  "message": "services is forbidden: User "system:serviceaccount:foo:default" cannot list resource "services" in API group "" in the namespace "foo"",
  "reason": "Forbidden",
  "details": {
    "kind": "services"
  },
  "code": 403
}

pod가 클러스터 상태를 읽지 못한다. API 서버는 pod가 동일한 네이스페이스에서 실행 중이더라도 서이브어카운트가 foo네임스페이스의 서비스의 리스트 요청을 허용할 수 없다고 응답했다.

1. role와 rolebinding, clusterrole와 clusterrolebinding

롤과 롤바인딩이 네임스페이스 수준 리소스인 반면, 클러스터롤과 클러소트롤바인딩은 클러스터 수준의 리소스이다.

일반 롤은 록이 위치한 동일한 네임스페이스의 리소스에만 접근할 수 있다. 다른 네임스페이스의 리소스에 접근할 수 있게 하려면 각 네이스페이스에 롤 및 롤바인딩을 생성해야 한다.
이를 모든 네임스페이스로 확장해 적용하려면 각각의 네임스페이스에 동일한 롤 및 롤바인딩을 만들어야 한다. 추가 네임스페이스를 만들 때 마다 이 두 개의 리소스를 함꼐 만들어야 한다는 것이다.

특정 리소스는 전혀 네임스페이스와 연관되어 있지 않다.(node, pv, namespace) API 서버는 리소스를 나타내지 않는 URL 경로를 노출할 수 있다. 일반적인인 롤은 이런 리소스 또는 리소스가 아닌 URL에 접근을 부여 할 수 없지만, 클러스터롤은 수행할 수 있다.

Role 생성

롤 리소스는 어떤 리소스에서 수행할 수 있는 액션을 정의 한다. 사용자가 foo 네임스페이스에서 서비스를 get 하고, list 수행을 허용하는 롤을 적용한다.

$ vi service-reader.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: foo
name: service-reader
rules:
- apiGroups: [""]
  verbs: ["get", "list"]
  resources: ["services"]

$ kubectl create -f service-reader.yaml -n foo
role.rbac.authorization.k8s.io/service-reader created

or

$ kubectl create role service-reader –verb=get –verb=list –resources=services -n foo

Rolebinding 생성

$ kubectl create rolebinding test --role=service-reader --serviceaccount=foo:default -n foo
rolebinding.rbac.authorization.k8s.io/test created
$ kubectl exec -it test-57d9d57995-s4dgp -n bar sh
/ # curl localhost:8001/api/v1/namespaces/foo/services
{
  "kind": "ServiceList",
  "apiVersion": "v1",
  "metadata": {
    "selfLink": "/api/v1/namespaces/foo/services",
   "resourceVersion": "2260916"
  },
  "items": []
}/

Role binding에서 다른 네임스페이스의 ServiceAccount 포함하기

bar 네임스페이스 pod는 자신의 네임스페이서 서비스를 리스트할 수 없으며, foo 네임스페이스의 pod도 분명히 리스트할 수 없다. 그러나 foo 네임스페이스에서 롤바인딩을 편집하고 ㄷㅏ른 네임스페이스에 있더라도 다른 pod의 서비스어카운트를 추가할 수 있다.

$ kubectl edit rolebinding test -n foo
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  creationTimestamp: "2020-05-01T06:41:14Z"
  name: test
  namespace: foo
  resourceVersion: "2260630"
  selfLink: /apis/rbac.authorization.k8s.io/v1/namespaces/foo/rolebindings/test
  uid: aa20e2c4-e5ad-4d72-8ace-5b81fb2925e1
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: service-reader
subjects:
- kind: ServiceAccount
  name: default
  namespace: foo
- kind: ServiceAccount
  name: default
  namespace: bar

이제 bar 네임스페이스에서 실행 중인 pod 내부에서 foo 네임스페이스의 서비스를 리스트 할 수 있다.
foo 네임스페이스에 롤바인딩이 있는데, 이는 foo 네임스페이스의 service-reader롤을 참조하고 foo와 bar 네임스페이스의 기본 어카운트를 바인딩한다.

ClusterRole 생성

foo 네임스페이스의 pod 내부에서 persistentvolume 를 확인 시 실패

# curl localhost:8001/api/v1/persistentvolumes
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {
  },
  "status": "Failure",
  "message": "persistentvolumes is forbidden: User "system:serviceaccount:bar:default" cannot list resource "persistentvolumes" in API group "" at the cluster scope",
  "reason": "Forbidden",
  "details": {
    "kind": "persistentvolumes"
  },
  "code": 403

Cluster 에서 포드가 PersistentVolume를 나열하도록 하는 방법

$ kubectl create clusterrole pv-reader --verb=get,list --resource=persistentvolumes

ClusterRole을 Rolebinding 한 경우

$ kubectl create rolebinding pv-test --clusterrole=pv-reader --serviceaccount=foo:default -n foo
rolebinding.rbac.authorization.k8s.io/pv-test created
$ kubectl exec -it test-57d9d57995-ptqk6 -n foo sh
/ # curl localhost:8001/api/v1/persistentvolumes
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {

},
“status”: “Failure”,
“message”: “persistentvolumes is forbidden: User “system:serviceaccount:foo:default” cannot list resource “persistentvolumes” in API group “” at the cluster scope”,
“reason”: “Forbidden”,
“details”: {
“kind”: “persistentvolumes”
},
“code”: 403
}/

RoleBinding을 생성하고 ClusterRoke 참조하게 해 네임스페이스가 있는 리소스에 접근 할 수 있게 할 수 있지만 클러스터 수준 리소스에 동일한 방식을 사용할 수는 없다.
클러스터 수준 리소스에 대한 접근 권한을 부여하려면 항상 ClusterRoleBinding을 사용해야 한다.

$ kubectl delete rolebinding pv-test -n foo
rolebinding.rbac.authorization.k8s.io "pv-test" deleted

ClusterRoleBinding 생성

$ kubectl create clusterrolebinding pv-test --clusterrole=pv-reader --serviceaccount=foo:default
clusterrolebinding.rbac.authorization.k8s.io/pv-test created
$ kubectl exec -it test-57d9d57995-ptqk6 -n foo sh
/ # curl localhost:8001/api/v1/persistentvolumes
{
  "kind": "PersistentVolumeList",
  "apiVersion": "v1",
  "metadata": {
    "selfLink": "/api/v1/persistentvolumes",
    "resourceVersion": "2294585"
  },
  "items": []
}

답글 남기기