0부터 시작하는 Kubernetes 공부 - ServiceAccount & Api Server 활용

Jaehong Lee·2022년 9월 13일
2
post-thumbnail

1. ServiceAccount

ServiceAccount 란

K8S 는 다양한 오브젝트를 이용하는 것을 User 가 아닌, System 레벨에서 동작한다고 하여, UserAccount 라는 개념 보다는 ServiceAccount 를 사용한다

  • 다른 서버에서 처럼 사용자를 이용하고 싶다면, 별도로 UserAccount 를 생성하여 사용할 수 있으나, 이는 별도의 인증 서버를 연결하여야 한다

일반적으로 ServiceAccount 를 사용한다

default SA & Secret

K8S -------------> linux
default ( admin ) root ( ~/.kube/config )

  • 이를 통해 root 는 K8S admin 정보를 포함하고 있다
  • 우리는 Linux Root 사용자에게 K8S 전체 System 에 대한 모든 권한을 Cluster-Admin 게정 정보를 부여했다. default 라는 이름의 secret 을 이용하고, 이 Secret 내에 토큰을 이용하여 사용할 수 있다
  • 각 NS 별 기본적으로 default SA 가 생성된다
  • 해당 SA 의 Secret 의 상세정보를 확인하면, 토큰 정보를 확인할 수 있다

우리 회사에 서비스를 요청한 사용자가 자신의 ns 에 속한 포드의 정보를 확인하고 싶다면

  • 각 NS 별로 별도의 SA 를 생성하여 고객사에게 전달한다. 이때 고객사에서는 협의 사항에 있지 않은 서비스를 사용할 수 없도록 CREATE 와 같은 명령은 제거한다
  • GET 과 같은 확인 명령어만 허용한다

SA & Role

Role -> 특정 NS 에서만 동작
ClusterRole -> Cluster 전체에서 사용할 수 있는 것 지정

  • Role 과 SA 를 연결하기 위해서는 RoleBinding 이 필요하다
    • ClusterRole 의 경우 ClusterRoleBinding 이 필요하다

SA 생성하기 및 삭제하기

  • create 로 SA 를 생성하자
  • delete 로 SA 삭제도 가능하다

SA 권한

  • defualt 계정은 모든 K8S 명령이 가능하다
root@manager:~/k8slab# k get svc --as system:serviceaccount:default:testuser
Error from server (Forbidden): services is forbidden: User "system:serviceaccount:default:testuser" cannot list resource "services" in API group "" in the namespace "default"
  • user1 의 권한을 일시적으로 주어 명령 실행할 경우, 해당 명령 실행에 대한 권한이 없으므로 실행이 되지 않는다
    • as system:serviceaccount 을 통해 default ns 의 testuser 의 권한을 일시적으로 주어 명령을 실행하였다

      401 error : 인증 에러 - authentication - username/password 문제
      403 error : 인가 에러 - authorization - 인증에 성공한 사용자에게 부여된 권한 문제

Role 생성하기

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: testuser
rules:
- apiGroups: [""]
  resources: ["services", "pods"]
  verbs: ["get", "list", "watch"]
  • list 는 전체, get 은 특정을 지정하는 것이다. watch 는 실시간 확인이다
root@manager:~/k8slab/sa# k apply -f role.yaml 
role.rbac.authorization.k8s.io/testuser created
  • 배포해주자

RoleBinding 생성 및 확인

  • 생성한 Role 과 SA 를 연결해보자
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: testuserrb
subjects:
- kind: ServiceAccount
  name: testuser
  namespace: default
roleRef:
  kind: Role
  name: testuser
  apiGroup: rbac.authorization.k8s.io
  • 연결한 SA 와 Role 을 정의해준다
    • 이를 통해 다수의 사용자에게 똑같은 Role 을 적용시킬 수 있다
root@manager:~/k8slab/sa# k apply -f rolebinding.yaml 
rolebinding.rbac.authorization.k8s.io/testuserrb created
root@manager:~/k8slab/sa# k get svc --as system:serviceaccount:default:testuser
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   6d
root@manager:~/k8slab/sa# k get pod --as system:serviceaccount:default:testuser
NAME                                  READY   STATUS    RESTARTS   AGE
nfs-nginx-854db57786-sml9w            1/1     Running   2          4d23h
nfs-pod-provisioner-98bd4898f-gqx2f   1/1     Running   2          4d23h
testpod                               1/1     Running   2          4d18h
root@manager:~/k8slab/sa# k get deploy --as system:serviceaccount:default:testuser
Error from server (Forbidden): deployments.apps is forbidden: User "system:serviceaccount:default:testuser" cannot list resource "deployments" in API group "apps" in the namespace "default"
  • RoleBinding 을 배포 후 확인해보자
    • svc 와 pod 는 get , list 권한을 주었으므로 확인이 가능하다
    • 허나, deploy 는 권한을 주지 않았으므로 error 가 발생한다

2. Api Server 접속

K8S 는 각 오브젝트에 대한 접근이 가능하도록 Rest Api 가 제공된다. 접근을 위해서는 Header 에 별도의 Token 을 첨부하여야 한다

접근 경로를 먼저 확인해보고, 생성한 SA 의 Token 을 이용하여 웹으로 접근했을 때, svc 와 pod 는 웹 상에서 결과를 확인할 수 있는지 여부를 살펴보자

Token 없이 Api Server 접속

  • 웹 브라우저에서 Api Server 에 접속해보자
    • 권한 문제가 생긴다. 이는 토큰 정보 없이 접속했으므로 403 error 가 발생한다
root@manager:~/k8slab# curl https://localhost:6443 -k
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {
    
  },
  "status": "Failure",
  "message": "forbidden: User \"system:anonymous\" cannot get path \"/\"",
  "reason": "Forbidden",
  "details": {
    
  },
  "code": 403
}
  • 로컬 환경에서 접속시 우리는 https 인증을 위한 공인 인증서가 없으므로, -k 옵션을 통해 접속한다. 아직 토큰 정보를 전달하지 않았으므로 403 error 가 발생한다

Proxy 를 통한 Api Server 접속

  • proxy 를 열어두자
  • 해당 주소로 들어가자. proxy 를 열면 누구나 해당 주소에 인증 정보 상관없이 접근할 수 있다
root@manager:~/k8slab/sa# curl http://localhost:8001/apis/node.k8s.io
{
  "kind": "APIGroup",
  "apiVersion": "v1",
  "name": "node.k8s.io",
  "versions": [
    {
      "groupVersion": "node.k8s.io/v1",
      "version": "v1"
    },
    {
      "groupVersion": "node.k8s.io/v1beta1",
      "version": "v1beta1"
    }
  ],
  "preferredVersion": {
    "groupVersion": "node.k8s.io/v1",
    "version": "v1"
  }
}
  • 이를 통해 인증 정보 없이 api server 의 정보를 불러올 수 있다
    • 허나, 이 방법은 보안상 안 좋은 방법이다. 누구든지 접근할 수 있기 때문이다

Token 확인

root@manager:~/k8slab/sa# k get secret
NAME                                 TYPE                                  DATA   AGE
default-token-229bg                  kubernetes.io/service-account-token   3      6d
nfs-pod-provisioner-sa-token-kb7v5   kubernetes.io/service-account-token   3      4d23h
testuser-token-r6bnm                 kubernetes.io/service-account-token   3      50m
  • Secret 리스트를 확인하자
  • 해당 user 의 Secret 의 상세 정보를 확인하면, Token 을 확인할 수 있다. 이는 base64 로 암호화 된 Token 이기에 복호화 후 사용해야 한다
export SECTOEKN=$(k get secret $SEC -o jsonpath='{.data.token}' | base64 -d )
  • 해당 Secret 의 Token 을 복호화 후 전역 변수에 저장하였다

Token 을 통한 Api Server 접속

curl https://localhost:6443/apis --header "Authorization: Bearer $SECTOEKN" -k

  • header 에 Token 을 넣어주면, 접속이 가능하다. Token 타입이 Bearer 임을 지정해줘야 한다
  • 위와 같이 Pod list 를 확인 가능 하다
  • Service list 도 확인 가능 하다
root@manager:~/k8slab/sa# curl https://localhost:6443/api/v1/namespaces/default/pods --header "Authorization: Bearer $SECTOEKN" -k
{
  "kind": "PodList",
  "apiVersion": "v1",
  "metadata": {
    "selfLink": "/api/v1/namespaces/default/pods",
    "resourceVersion": "143430"
  },
  "items": []
  • 모든 Pod 를 삭제하고, 다시 확인하면 items 가 비어있다
  • Pod 를 생성하면, 위와 같이 items 에 정보가 추가되어진다
curl https://localhost:6443/api/v1/namespaces/default/pods/testpod1 --header "Authorization: Bearer $SECTOEKN" -k

curl -X GET https://localhost:6443/api/v1/namespaces/default/pods/testpod1 --header "Authorization: Bearer $SECTOEKN" -k
  • 생성한 Pod 의 상세 정보를 확인해보자
    • GET 이 기본값이기에 따로 명시하지 않아도 GET 이 된다
curl -X DELETE  https://localhost:6443/api/v1/namespaces/default/pods/testpod1 --header "Authorization: Bearer $SECTOEKN" -k
  • DELETE 를 통해 삭제도 가능하다

3. Api Server 활용

watch 로 확인하기

root@manager:~/k8slab/sa# curl https://localhost:6443/api/v1/namespaces/default/pods?watch=true --header "Authorization: Bearer $SECTOEKN" -k &
[2] 249333
  • watch=true 를 하면, 실시간으로 pod 의 상태를 확인한다. 허나, 이 명령을 백그라운드에서 실행하지 않으면, 해당 명령이 계속 실행되어 프롬프트가 돌아오지 않아 추가 명령을 내리지 못하므로, 뒤에 & 를 붙여서 백그라운드에서 실행하게 한다
  • Pod 를 배포하면, 실시간으로 상태 정보를 모니터링 할 수 있다
  • 삭제시에도 상태 정보를 출력해준다
ps -ef | grep curl # 실행중인 프로세스 확인, curl 프로세스 ID 를 확인하자
kill -9 249333 # curl 프로세스를 바로 종료 시켰다
  • 백그라운드에서 실행중인 curl 명령을 종료시키자

이는 우리가 user1 에게 watch 권한을 주었기에 가능하다

DELETE 권한 주기

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: testuser
rules:
- apiGroups: [""]
  resources: ["services", "pods"]
  verbs: ["get", "list", "watch","delete"]
  • 위와 같이 verbs 에 delete 를 추가하자
root@manager:~/k8slab/sa# k apply -f role.yaml
role.rbac.authorization.k8s.io/testuser configured
  • role 을 재배포하자
curl -X DELETE https://localhost:6443/api/v1/namespaces/default/pods/testpod1 --header "Authorization: Bearer $SECTOEKN" -k
  • 이제 Pod 삭제 명령을 내리면
root@manager:~/k8slab/sa# k get pod
No resources found in default namespace.
  • Pod 가 삭제된다. 성공적으로 Delete 권한을 주었다
profile
멋진 엔지니어가 될 때까지

0개의 댓글