학습일지/kubernetes

CKA 대비 kubernetes 스터디 - 6. Security (2)

inspirit941 2022. 3. 30. 08:52
반응형

API Group - prerequisite for Authorization

스크린샷 2022-03-20 오후 1 16 44

 

스크린샷 2022-03-20 오후 1 19 37

  • version: 클러스터 버전 확인용.
  • health / monitor: checking health를 위해 사용함.
  • logs : 3rd party 프로덕트와 통신할 목적으로 사용함
  • API - cluster functionality를 위한 API라서 좀더 상세히 다룬다.

 

api : Core Group. k8s 자체의 핵심 기능을 주로 담당한다. Namespace, node, Persistent Volumes 등등

스크린샷 2022-03-20 오후 1 20 37

apis : Named Group. more organized / newer features are available.

 

스크린샷 2022-03-20 오후 1 36 00

특정 리소스를 docs에서 선택하면, 어떤 API에서 호출할 수 있는지 확인해준다.

 

스크린샷 2022-03-20 오후 1 38 17

아니면 클러스터에 별다른 path 없이 직접 호출해보면 된다. 사용할 수 있는 api 목록을 알 수 있다.

 

스크린샷 2022-03-20 오후 1 39 25


 

스크린샷 2022-03-20 오후 1 41 58

 

스크린샷 2022-03-20 오후 1 49 21

  • 클러스터에 api를 요청하려면, 앞서 언급한 cert와 key가 있어야 한다. 없을 경우 403 forbidden이 발생함.
  • 인증서와 key값을 curl에 넣고 바로 전송하는 방법도 있고, kubectl proxy 명령어를 사용해 접근할 수도 있다.
    • proxy를 사용할 경우, proxy에서 kubeconfig 파일을 확인해서 apiserver로 요청을 전달한다.

cf. kube proxy != kubectl proxy.

스크린샷 2022-03-20 오후 1 50 15

  • kube-proxy : services, pods의 across different node 통신을 가능하게 해 주는 k8s component
  • kubectl proxy: kube-apiserver에 접근할 목적으로 kubectl이 생성한 http proxy.

Authorization

Authenticated된 사용자가 클러스터에 들어와서 무엇을 할 것인가? 를 결정하는 영역.

스크린샷 2022-03-20 오후 1 59 43

  • 일반적으로 admin은 모든 권한을 가지고 있어야 한다.
  • 하지만 developer라면, 예컨대 조회는 가능해도 삭제는 불가능하게 만든다거나
  • jenkins같은 프로덕트에서 접근할 때에는 로직을 다른 식으로 적용하고 싶을 수 있다.

Namespace별로 logical partitioning을 구현하면, 각 ns별로 접근할 수 있는 주체의 권한을 지정할 수 있다.

 

스크린샷 2022-03-20 오후 3 17 02

구체적인 Authorization 방법은 크게 네 가지.

 

스크린샷 2022-03-20 오후 3 44 55

kube-apiserver는 사용자에게도 요청을 받고, kubelet을 통해 각 노드를 관리한다.

  • kubelet은 kube api에서 service / endpoints / nodes / pods 관련 정보를 읽고
  • node / pod status, events를 쓸 수 있어야 한다.

Kubelet에서 필요로 하는 위 작업의 Authorization 담당은 Node Authorizer 라는 형태로 존재한다.

  • kubelet으로 certificate 발급할 때 system:nodes 라는 group으로 생성했었다.
  • node authorizer는 이 system:node 그룹에 적용된다. 필요한 권한을 지정해줌.

 

스크린샷 2022-03-20 오후 6 55 20

ABAC : User 또는 Group of Users에 permission을 연결하기 위해 사용함.

  • policy를 적용한 policy file를 json 포맷으로 만들어서 apiserver에 pass the file.
  • 새로운 사용자나 그룹이 추가될 때마다 policy file을 직접 수정해주고, apiserver를 재시작해야 함.
    • 관리가 어렵기 때문에 잘 안씀

스크린샷 2022-03-20 오후 7 21 55

RBAC : user / userGroup을 직접 연결하는 대신 Role 형태로 binding하는 것.

  • 여러 권한을 role로 묶은 뒤, 해당 role에 사용자 / 그룹을 연결한다.
  • 권한의 변경이 필요한 경우 role 단위로 변경한다. role이 부여된 사용자는 변경사항이 즉시 반영된다.
  • Managing Access 측면에서 좀더 표준에 가까운 형태.

 

스크린샷 2022-03-20 오후 9 55 19

Webhook : 3rd party와의 연결을 위해 사용함.

  • ex) Open policy agent라는 프로덕트와 연결할 경우
  • kube-apiserver로 요청이 들어왔을 때, 해당 요청을 한 사용자의 authorization을 전적으로 외부에 맡긴 뒤
  • 외부 프로덕트의 응답결과를 그대로 따르는 식.

이외에도 AlwaysAllow, AlwaysDeny 옵션이 있다.


스크린샷 2022-03-20 오후 9 58 40

Authorization 옵션은 kube-apiserver의 authorization-mode 옵션으로 설정 가능하다.

  • 디플트 옵션은 AlwaysAllow.
  • 여러 개의 Authorization 옵션을 주려면 위와 같이 하면 된다.

 

스크린샷 2022-03-20 오후 10 08 56

  • authorization-mode에 정의한 순서대로 authorization 로직을 타게 된다.
  • 예컨대 사용자의 요청이 들어오면, node가 제일 먼저 검증한다.
    • node의 로직에 걸리지 않으므로 deny -> 다음 로직으로 chaining하는 구조.
  • RBAC에서 적합한 authorize 로직을 찾으면, 해당 로직을 타고 사용자에게 권한 실행을 리턴하는 구조.
  • 한 모듈에서 approves the request -> 더 이상의 체크 없이 사용자는 grant the permission.

Role

스크린샷 2022-03-21 오후 9 28 43

Role도 하나의 k8s object이므로, yaml파일로 생성할 수 있다.

  • rules 필드에는 세 개의 값이 필요하다.
    • apiGroups : core group일 경우 공백으로 둬도 된다. 아니라면 그룹을 반드시 지정해야 함.
    • resources : 접근 가능한
    • verbs : 어떤 동작이 가능한지 정의.
  • 하나의 role에는 여러 rule을 정의할 수 있다. 예컨대 configmap을 생성하도록 하려면 configmap 리소스에 해당되는 verb를 추가하는 식.

 

스크린샷 2022-03-21 오후 9 31 03

  • User와 Role을 연결하기 위해 RoleBinding object를 생성한다.
  • Subjects : user 관련한 정보를 입력하는 란.
  • roleRef : 생성해둔 role의 정보를 입력하는 란.

role과 rolebinding은 namespace 범위의 영향을 받는다.

  • 위 에시의 경우 developer 사용자는 default 네임스페이스에 한해서만 role이 적용된다.
  • 특정 ns에 적용하려면 namespace를 지정하면 된다.

스크린샷 2022-03-21 오후 10 42 40스크린샷 2022-03-21 오후 10 42 55

 

스크린샷 2022-03-21 오후 10 44 00

 

스크린샷 2022-03-21 오후 10 44 25

  • 특정한 리소스에만 접근권한을 주고 싶다면, resourceName으로 해당 리소스를 지정할 수 있다.

Cluster Roles and Cluster Role Bindings

스크린샷 2022-03-21 오후 11 08 51

이전의 Role과 Rolebinding은 특정 namespace 내에서 이루어졌다.

  • 따로 ns를 정의하지 않으면 default ns를 기준으로 role의 boundary가 지정되었음.

하지만 namespace로 나뉘지 않는 영역은?

  • 예컨대 node는 namespace 범위로 한정할 수 있는 대상이 아니다. 얘는 클러스터 단위임.

 

스크린샷 2022-03-21 오후 11 14 19

  • namespace 리소스: 생성하거나 삭제할 때 해당 namespace를 반드시 명시해야 함.
  • cluster scope 리소스: 생성할 때 namespace를 요구하지 않음.

이 구분은 kubectl api-resources --namespaced=true / kubectl api-resources --namespaced=false 로 확인할 수 있다.

 

스크린샷 2022-03-21 오후 11 17 22

  • role과 마찬가지로 clusterRole을 생성하면 된다.
  • kubectl create -f cluster-admin-role.yaml 형태로 클러스터에 생성할 수 있다.

 

스크린샷 2022-03-21 오후 11 19 10

ClusterRolebinding도 문법은 앞서 설명한 roleBinding과 비슷하다.

  • subjects : 해당 role을 부여할 사용자
  • roleRef : 사용자에게 적용될 role

꼭 namespace기준으로 Strict하게 구분되는 건 아니다. ClusterRole로도 namespace 기반 리소스의 role을 정할 수 있다.

  • 이렇게 설정할 경우, 모든 namespace에서 적용할 수 있는 광역권한을 갖게 된다.

Service Account

스크린샷 2022-03-22 오전 7 00 08



k8s에는 두 종류의 Account가 있다. User / Service Account.

 

스크린샷 2022-03-22 오전 7 02 36

 

스크린샷 2022-03-22 오전 7 04 26

  • service account를 생성하면, 해당 계정에서 사용할 수 있는 토큰이 발급된다.
  • kubectl describe serviceaccount <이름> 으로 존재여부를 확인할 수 있다.
  • token은 secret으로 저장됨. Authentication Bearer Token으로 사용된다.

스크린샷 2022-03-22 오전 7 05 39

  • serviceaccount를 생성한다
  • 올바른 permission을 RBAC로 할당한다 (이 부분은 시험범위 아니라고 함)
  • get token -> web 3rd party application에서 사용하면 된다.

 

스크린샷 2022-03-22 오전 8 05 22

만약 3rd party 앱이 자체적으로 k8s hosting하고 있다면?

  • ex) k8s에 배포되어 있는 prometheus 같은 경우
    • Mounting the Servicetoken Secret inside the pod hosting 3rd party Application.
    • exporting the serviceAcount token + Configuring the app to use it 과정을 간소화할 수 잇다.
    • 애플리케이션이 쉽게 읽을 수 있고, cluster에도 secret이 이미 등록되어 있으므로 쉽게 사용할 수 있다.

 

스크린샷 2022-03-22 오전 8 16 50

 

스크린샷 2022-03-22 오전 8 17 49

모든 ns에는 default라는 serviceAccount가 기본적으로 생성되어 있다.

  • 새로운 Pod을 생성하면, default serviceAccount + token이 volumne mount 형태로 적용되어 있다.
  • 마운트된 경로로 가보면 crt, namespace, token 값이 있으며, 토큰은 k8s api를 사용하기 위한 값임.
  • default serviceAccount는 basic한 api query만 가능하도록 제한이 많이 걸려있는 account.



스크린샷 2022-03-22 오전 8 43 53

다른 serviceAccount를 적용하려면 serviceAccountName 필드를 사용해서 정의하면 된다.

  • 단, Pod의 경우 serviceAccount를 수정하면 반드시 새 pod를 생성해야 한다. Edit이 불가능.
  • Deployment의 경우, account를 변경하면 자동으로 rollout이 진행된다.
  • 만약 default serviceAccount 값을 설정하고 싶지 않다면 automaountServiceAccountToken:false 옵션을 spec 하위필드에 추가하면 된다.

Image Security

스크린샷 2022-03-22 오후 11 14 36

  • library: 이 영역에 user나 회사 등 특정 계정을 입력하지 않았을 경우 자동으로 입력되는 값. image: nginx 일 경우 자동으로 앞에 image: library/nginx 형태로 인식하는 식이다.
    • docker의 default account로, docker official image가 저장되어 있다. official image의 경우 전담 팀이 따로 관리하고 있는 이미지를 의미함.
  • docker.io: 별다른 입력을 하지 않았을 경우 디폴트로 간주되는 registry. docker의 기본 레지스트리 이기도 하다.

Private Repository를 사용할 경우... 보통 docker login으로 private registry에 로그인한 뒤 이미지를 pull할 수 있다.

스크린샷 2022-03-22 오후 11 19 27

  • k8s에서는 이 docker login으로 credential을 확보하는 과정을 어떻게 진행하나?
    • 이미지는 runtime 때 docker pull 형태로 가져오게 된다. 어떻게 credential pass를 할 수 있을까?

스크린샷 2022-03-22 오후 11 21 42

  • kubectl create secret docker-registry regcred ... 형태로 secret을 생성한다.
  • 이미지를 호출할 때 imagePullSecrets 옵션을 생성하고, secret값을 넣는다.

Security Context

스크린샷 2022-03-22 오후 11 38 35

docker에서는 container의 security 확보를 위한 여러 명령어들이 있다.

  • user id 제공하기. ex) --user=1001
  • linux capability that can be added / removed from the container. ex) --cap-add MAC_ADMIN

 

스크린샷 2022-03-22 오후 11 39 10

k8s에서도 동일한 기능이 있다. k8s는 container를 pod라는 개념으로 encapsulate했기 때문에, pod 안에 있는 여러 개의 container에 해당 옵션이 전부 적용될 수 있다. pod와 container에 다른 옵션이 적용되어 있을 경우 container will overwrite the settings on the pod.

 

스크린샷 2022-03-23 오전 12 22 13

  • spec 필드에 securityContext.runAsUser 옵션으로 user id를 제공할 수 있다.

 

스크린샷 2022-03-23 오전 12 21 54

  • 만약 pod가 아니라 container 단위로 security context를 걸고 싶다면, containers 내부에 정의하면 된다.
  • capability 옵션은 pod 레벨에서는 적용할 수 없다.

Network Policy

스크린샷 2022-03-23 오전 5 28 38

Ingress / Egress 구분 기준: 트래픽의 Originate를 기준으로 결정한다.

  • Web Client : 사용자의 요청이 ingress, api로 요청을 내보내는 게 egress.
  • API : web client로의 요청이 ingress, DB로 요청을 내보내는 게 egress.
  • DB : API로부터의 요청이 ingress.

 

스크린샷 2022-03-23 오전 5 28 46

따라서 위와 같이 rule을 구분할 수 있다.

  • Web Client
    • ingress rule : port 80으로 들어오는 http 트래픽 수용.
    • egress rule : api 서버에 port 5000으로 요청 전송.
  • API Server
    • ingress rule : port 5000으로 들어오는 http 트래픽 수용.
    • egress rule : DB 서버에 port 3306으로 요청 전송.
  • DB
    • ingress rule : port 3306으로 들어오는 트래픽 수용.

 

스크린샷 2022-03-23 오전 7 21 59

k8s에서 network의 중요한 원칙 중 하나

  • 클러스터 내 모든 pod는 route같은 추가처리 없이 통신이 가능해야 한다. default Rule = All allow임.
  • 예시의 경우 virtual private network -> 클러스터 전체에 적용되어 있음.
    • ip주소 / pod name / services 통해서 서로에게 접근 및 통신이 가능함.

스크린샷 2022-03-23 오전 7 24 57

  • 따라서, 위의 애플리케이션을 k8s pod로 대체할 경우 ingress / egress rule은 기본적으로 '누구와도 통신 가능' 이 된다.
  • 이 형태는 보안상 좋지 않기 때문에, Network Policy라는 k8s object를 사용해서 네트워크 ingress / egress 설정을 변경할 수 있다.

 

스크린샷 2022-03-23 오전 7 25 12

  • 위처럼 특정 Pod의 특정 port에서만 트래픽을 받도록 변경하면, 그 외의 나머지 요청은 전부 받지 않도록 설정한다.

스크린샷 2022-03-23 오전 9 01 26스크린샷 2022-03-23 오전 9 32 06

  • 구체적으로는 label / selector 사용해서 연결할 수 있음.

 

스크린샷 2022-03-23 오전 10 12 49

Network policy를 지원하는 / 지원하지 않는 솔루션들이 있다.

  • 지원하지 않는 것들도 policy 생성은 되지만, 실제로 적용이 되지 않는 형태임.

Network policy

DB를 외부에서 아무나 접근할 수 없고, 포트 3306으로만 트래픽을 받을 수 있도록 설정하려고 한다.

스크린샷 2022-03-23 오전 11 21 52

  • ingress.from 옵션으로 podselector에 특정 Label이 붙은 pod만 선택할 수 있다.
  • 단, 디폴트 옵션으로는 동일한 label이 붙은 모든 namespace의 pod가 해당된다.
    • 만약 namespace도 제한해야 한다면 namespaceSelector를 적용하면 된다.

스크린샷 2022-03-23 오후 12 30 49

  • 예컨대 DB를 위한 백업 서버를 따로 생성해서 사용한다고 하면, 백업 서버는 같은 namespace도 아니고 pod를 사용할 수도 없다.
  • 이 경우 ip주소를 토대로 ingress 옵션을 설정할 수 있다.

위 예시에서 최종적으로 rule의 개수는 총 2개로, 이 두 개의 rule은 OR 형태로 동작한다.

  • podSelector + namespaceSelector 두 개를 from에 묶어서 하나
    • 대신, from에 묶은 selector는 조건을 전부 충족해야만 ingress 조건을 충족한다.
  • ipBlock.cidr로 ip주소에 설정한 rlue 하나.

둘 중에 하나만 조건을 충족하면 연결 가능함.

스크린샷 2022-03-23 오후 12 39 01

  • 만약 이렇게 생성할 경우, rule의 개수는 3개.
  • 각 조건을 하나라도 만족할 경우 통신이 가능하다.
    • 따라서 오른쪽 그림처럼, prod Namespace에 있는 모든 pod / 다른 namespace이면서 podName이 api-pod인 경우 전부 DB와 연결할 수 있음.

스크린샷 2022-03-23 오후 12 42 54

Egress도 비슷하게 사용한다.

  • 예컨대 DB에서 외부 백업서버로 요청을 보낸다고 하면
    • policyType에 Egress 설정
    • egress.to 필드에 목적지 설정. 예시의 경우 Ip주소 지정방식을 사용했다.
반응형