모든 쿠버네티스 클러스터의 진입점은 api-server이다. 사용자는 kubectl, 클라이언트 라이브러리 또는 REST 요청을 통해 API에 접근한다. 사용자와 쿠버네티스 서비스 어카운트 모두 API에 접근할 수 있다.
쿠버네티스는 일반적인 사용자 계정과 서비스 계정으로 인증을 요청한다.
kubectl api-resources | grep serviceaccounts(sa)
AWS에서의 IAM 인스턴스 프로파일: ec2 인스턴스에게 권한을 주면 ec2 인스턴스를 내에 있는 어플리케이션이 aws에 접근할때 권한을 받게 된다.
파드에 있는 어플리케이션이 API-Server에 접근하기 위해서는 다른 코드가 필요한데 지금은 없다. 따라서 파드 내에 kubectl 명령어는 api-server와 통신해서 쿠버네티스의 리소스를 관리하기때문에 이 명령이 있는 이미지를 사용해서 확인한다.
vi kubectl.yaml
apiVersion: v1
kind: Pod
metadata:
name: kubectl
spec:
container:
- name: kubectl
image: bitnami/kubectl:1.24.6
kubectl create -f kubectl.yaml
# 상태를 보면 Completed이 걸리면서 재시작 실행
kubectl get po
어플리케이션이 정상적으로 종료되었기 때문에 Completed이고 Exit code가 0임.
어떤 어플리케이션인지 확인하기 위해 이미지의 entrypoint나 cmd를 확인한다.
sudo docker pull bitnami/kubectl:1.24.6
sudo docker image inspect bitnami/kubectl:1.24.6
-> CMD: --help , entrypoint: kubectl
# help 화면이 나온다.
sudo docker run bitnami/kubectl:1.24.6
쿠버네티스는 디텍치 모드로 작동하는데 kubectl 명령은 이 모드로 사용할 수 없다. 따라서 꼼수로 디텍치 모드에서 계속해서 실행할수 있는 어플리케이션이 필요하다. 이 방법을 이용해 파드에 영구적으로 실행가능하다.
vi kubectl.yaml
apiVersion: v1
kind: Pod
metadata:
name: kubectl
spec:
containers:
- name: kubectl
image: bitnami/kubectl:1.24.6
command: ['sleep']
args: ['infinity']
kubectl create -f kubectl.yaml
kubectl get pod
kubectl exec -it kubectl -- sh
$ kubectl version
# 클러스터에 접근했지만 거부당해서 나온 오류
$ kubectl get pods
$ kubectl get nodes
# --v 디버깅 모드로는 접근 가능,
$ kubectl get pods --v=4
-> code: 403 # 기본적으로 http 통신을 하게됨
# api 서버에 접근했지만 거부당함
ctrl + d: bash 셀 종료
kubectl get serviceaccount(sa)
kubectl get pod kubectl -o jsonpath='{.spec.serviceAccountName}'
-> default로 나옴
모든 파드는 따로 설정하지 않으면 default라는 서비스 어카운트를 가짐.
TLS가 설정되면 HTTP 요청이 인증 단계로 넘어간다. 이는 다이어그램에 1단계로 표시되어 있다. 클러스터 생성 스크립트 또는 클러스터 관리자는 API 서버가 하나 이상의 인증기 모듈을 실행하도록 구성한다. 인증기에 대해서는 인증에서 더 자세히 서술한다.
인증 단계로 들어가는 것은 온전한 HTTP 요청이지만 일반적으로 헤더 그리고/또는 클라이언트 인증서를 검사한다.
인증 모듈은 클라이언트 인증서, 암호 및 일반 토큰, 부트스트랩 토큰, JWT 토큰(서비스 어카운트에 사용됨)을 포함한다.
요청을 인증할 수 없는 경우 HTTP 상태 코드 401과 함께 거부된다.
특정 사용자로부터 온 요청이 인증된 후에는 인가되어야 한다.
쿠버네티스는 ABAC(속성기반 접근제어, 잘 안씀), RBAC 모드(역할기반 접근제어)를 사용하여 인가 모듈을 지원한다. 관리자가 클러스터를 생성할 때 API 서버에서 사용해야 하는 인가 모듈을 구성했다. 인가 모듈이 2개 이상 구성되면 쿠버네티스가 각 모듈을 확인하고, 어느 모듈이 요청을 승인하면 요청을 진행할 수 있다. 모든 모듈이 요청을 거부하면 요청이 거부된다(HTTP 상태 코드 403).
kubectl api-resousrces | grep rbac
어드미션 제어 모듈은 요청을 수정하거나 거부할 수 있는 소프트웨어 모듈이다. 인가 모듈에서 사용할 수 있는 속성 외에도 어드미션 제어 모듈은 생성되거나 수정된 오브젝트 내용에 접근할 수 있다. 요청이 모든 어드미션 제어 모듈을 통과하면 유효성 검사 루틴을 사용하여 해당 API 오브젝트를 검증한 후 오브젝트 저장소에 기록된다.
유효성 검사
yaml 파일을 만들어서 생성하거나 삭제하거나를 하는데, 이 yaml 파일에 대한 유효성을 검사한다.
기본값 세팅
우리가 지정하지 않은 값들을 default 값으로 설정해주는 역할을 한다.
전체 흐름: 일반 사용자나 서비스 계정을 가지고 있는 앱이 -> 인증서(사람 계정) 기반, 패스워드, 토큰 기반(서비스 계정)의 인증 -> RBAC 인가 -> 어드미션 제어 -> etcd에 정보 저장
롤: 특정 API나 자원사용 권한들은 명시해둔 규칙의 집합
롤바인딩: 사용자(SA나 Human)와 롤을 연결시켜줌
-> Role로 시작하는 것들은 네임 스페이스를 사용
클러스터롤: 네임스페이스에 상관없이 클러스터 전체의 역할
클러스터롤바인딩: 클러스터 역할과 사용자를 연결시켜줌
-> Cluster로 시작하는 것들은 네임스페이스를 사용하지 않음
# 둘의 필드가 같음, 기본적으로 권한을 부여하는 것, 다른 점은 네임스페이스 사용여부
kubectl explain roles.rules
kubectl explain clusterRoles.rules
vi role-read-pod.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: read-pod
rules:
- apiGroups: [""] # 그룹 지정
resources: ["pods"] # 자원 지정
verbs: ["get", "list"] # 명령 지정
파드 리소스에 대한 get과 list만 가능함
vi crole-read-pod.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: read-pod
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get","list"]
위의 롤과 큰 차이가 없음, 네임스페이스를 지정하지 못함
vi rbind-myuser1.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: myuser1-read-pod
namespace: default
subjects: # 사용자 지정
- kind: ServiceAccount
name: myuser1
apiGroup: "" # 선택사항
namespace: default
roleRef: # 역할 지정
kind: Role
name: read-pod
apiGroup: rbac.authorization.k8s.io # 필수로 지정
default 네임스페이스에 있는 read-pod와 myuser1를 연결해준 것이다. myuser1는 default 네임스페이스 내에 있는 파드 리소스에 대해서만 get, list를 할 수 있는 권한을 부여받음
vi sa-myuser1.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: myuser1
namespace: default
kubectl create -f sa-myuser1.yaml
kubectl create -f 02_service_account/
vi crbind-myadmin.yaml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: myadmin-admin
subjects:
- kind: ServiceAccount
name: myadmin
namespace: default
apiGroup: ""
roleRef:
kind: ClusterRole
name: admin
apiGroup: "rbac.authorization.k8s.io"
# 기본 제공되는 클러스터롤 확인
kubectl get clusterroles
admin은 기본으로 제공되는 클러스터롤이다. 클러스터 전체의 admin권한을 가짐(EndPoints, ClusterRole, ClusterRoleBinding 제외)
FC(full control): 모든 권한을 다 가지고 있음. 우리가 실습하면서 기본적으로 사용했던 권한이 cluster-admin으로 이것이 FC이다.
vi crbind-myuser2.yaml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: myuser2-read-pod
subjects:
- kind: ServiceAccount
name: myuser2
namespace: default
apiGroup: ""
roleRef:
kind: ClusterRole
name: read-pod
apiGroup: "rbac.authorization.k8s.io"
read-pod라는 클러스터와 myuser2를 연결해준 것이다. myuser2는 네임스페이스에 상관없이 클러스터 전체의 파드 리소스에 대해서만 get, list를 할 수 있는 권한을 부여받음
# 하위 디렉터리까지 전체 실핼
cd ~/goorm-8th-k8s/manifests/12_authentication/03_rbac
kubectl create -R -f .
# 서비스 계정과 rbac 모두 실행
kubectl create -f 02_service_account/
kubectl create -R -f 03_rbac/
vi kubectl.yaml
apiVersion: v1
kind: Pod
metadata:
name: kubectl
spec:
serviceAccountName: myuser1
containers:
- name: kubectl
image: bitnami/kubectl:1.24.6
command: ['sleep']
args: ['infinity']
kubectl create -f kubectl.yaml
kubectl get po kubectl -o jsonpath='{.spec.serviceAccountName}'
kubectl get pod
# 실행
kubectl exec -it kubectl -- sh
$ kubectl get pods
# 만들수 있는 권한이 없어서 안만들어짐
$ kubectl run myweb --image nginx
myuser1에 파드를 볼 수있는 권한이 롤바인딩으로 주어졌기 때문에 지금은 파드 확인가능
kubectl exec -it kubectl -- sh
$ kubectl get rs -A
$ kubectl get deploy
# 클러스터 이름이 들어간 것 이외에는 다 실행가능
$ kubectl get clusterroles
# 생성 가능
$ kubectl run myweb --image nginx
$ kubectl get po
vi myedit-myview.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: myedit
namespace: default
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: myview
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: myedit-edit
subjects:
- kind: ServiceAccount
name: myedit
apiGroup: ""
namespace: default
roleRef:
kind: ClusterRole
name: edit
apiGroup: "rbac.authorization.k8s.io"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: myedit-view
subjects:
- kind: ServiceAccount
name: myview
apiGroup: ""
namespace: default
roleRef:
kind: ClusterRole
name: view
apiGroup: "rbac.authorization.k8s.io"
# 생성
kubectl create -f myedit-myview.yaml
# 기존 것 삭제, --force 옵션을 붙여줘야 한다.
kubectl delete -f kubectl.yaml --force
# kubectl.yaml 내용에서 서비스 어카운트를 myview와 myedit로 바꾸면서 권한 확인
view < edit < admin < cluster-admin: 상위 권한을 가지고 있는 애들은 하위 명령을 다 사용가능
LDAP
경량 디렉터리 액세스 프로토콜(영어: Lightweight Directory Access Protocol; LDAP)은 TCP/IP 위에서 디렉터리 서비스를 조회하고 수정하는 응용 프로토콜이다.
디렉터리는 논리, 계급 방식 속에서 조직화된, 비슷한 특성을 가진 객체들의 모임이다. 가장 일반적인 예로는 전화 번호부(telephone directory)가 있는데 가나다 순의 일련의 이름을 가지고 있고, 이름마다 전화 번호와 주소가 포함되어 있다. 이러한 기본 설계 때문에 LDAP는 인증을 위한 다른 서비스에 의해 자주 사용된다.
우리가 사용하는 인증서들은 전부 x509라는 표준으로 만들어져 있다.
인증서의 서명된 토큰이나 인증서를 사용해서 인증을 해야되는데 쿠버네티스에서는 자체적으로 pki키를 가지고 있다. ca.crt와 ca.key가 존재한다.
# pki키 위치
cd /etc/kubernetes/pki
ls
# 인증서를 넣으면 현재는 cat과 다름이 없다.
openssl x509 -in ca.crt
# 인증서를 디코딩해서 내용을 보여준다.
# https의 인증서의 세부정보가 구조가 같다.
openssl x509 -in ca.crt -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 0 (0x0)
Signature Algorithm: sha256WithRSAEncryption # sha256해쉬랑 RSA 방식 사용
Issuer: CN = kubernetes # 발급자
Validity
Not Before: Feb 13 05:28:00 2023 GMT # 유효기간
Not After : Feb 10 05:28:00 2033 GMT # 10년의 유효기간 전에 갱신을 해줘야 쿠버네티스를 계속 사용가능
Subject: CN = kubernetes # 발급대상
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
...
자체서명 인증서이기에 발급자와 발급 대상이 같다. Root CA는 더이상 상위구조가 없기 때문에 제 3자가 인증해줄 수 없다.
apiserver.crt를 확인해보면 유효기간이 1년짜리인데 1년동안 인증서 갱신을 하지 않으면 클러스터가 정지된다.
cd ~/.kube
# 내가 사용하고 있는 인증서의 내용
cat config
client-certificate-data # 인증서의 내용부분 복사
# 인증서 내용 파일로 저장
echo 인증서 내용 복붙 | base64 -d > ~/my.crt
# 쿠버네티스 SA가 인증서를 우리에게 준 것임을 확인
openssl x509 -in my.crt -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2861070825632837409 (0x27b490c1df142f21)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = kubernetes # 발급자: 쿠버네티스
Validity
Not Before: Feb 13 05:28:00 2023 GMT
Not After : Feb 13 05:28:01 2024 GMT
Subject: O = system:masters, CN = kubernetes-admin # 발급대상은 우리의 현재 사용하고 있는계정이름(kubernetes-admin)이다.
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
DN, CN 등은 이름이다.
클라이언트 -> x509 인증서 키 생성 -> 자체서명 인증서가 아니기에 키를 가지고 csr(인증서명요청) 생성 -> csr를 Root CA에게 보냄 -> RootCA가 키(ca.key)와 인증서(ca.crt)를 가지고 있기 때문에 이를 결합을 시켜서 우리의 인증서를 만들어줌 -> 우리는 이 인증서를 가지고 인증을 해야댐
kubectl api-resources | grep certificate(csr)
# 새로운 유저의 키 생성
openssl genrsa -out myuser3.key 2048
# 인증서 생성
openssl req -new -key myuser3.key -out myuser3.csr -subj "/CN=myuser3"
# csr 인코딩
base64 myuser3.csr -w 0
# csr 리소스 만들기
vi myuser3-csr.yaml
apiVersion: certificates.k8s.io/v1 # 리소스를 보면서 버전 확인
kind: CertificateSigningRequest
metadata:
name: myuser3
spec:
request: <BASE64 ENCODED VALUE> # 서명하기 위한 csr의 인코딩한 내용 복붙
signerName: kubernetes.io/kube-apiserver-client
usages:
- client auth # 클라이언트 인증용이라 명시
kubectl create -f myuser3-csr.yaml
# condition이 pending 상태임.
kubectl get csr
# 문제가 없다고 판단되면 실행, csr을 승인할 것을 명령
kubectl certificate approve myuser3
# 발급되었다고 condition 바뀜
kubectl get csr
# status의 certificate 부분이 인증서의 내용 디코딩하여 crt 파일로 저장
kubectl get csr myuser3 -o jsonpath='{.status.certificate}' | base64 -d > myuser3.crt
cat myuser3.crt
# 발급자와 주체 확인
openssl x509 -in myuser3.crt -text -noout
# 기본적인 모든 작업 가능하게 구성
vi role-admin-pod.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default
name: admin-pod
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["create", "get", "list", "update", "delete"]
vi rbind-myuser3.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: myuser3-admin-pod
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: admin-pod
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: myuser3
kubectl create -f rbind-myuser3.yaml -f role-admin-pod.yaml
kubeconfig 파일들을 사용하여 클러스터, 사용자, 네임스페이스 및 인증 메커니즘에 대한 정보를 관리할 수 있다. kubectl 커맨드라인 툴은 kubeconfig 파일을 사용하여 클러스터의 선택과 클러스터의 API 서버와의 통신에 필요한 정보를 찾는다.
kubeconfig 파일은 우리가 처음에 쿠버네티스를 설치할때 만들어주었던 것이다.자격증명 가져오기 확인
kubectl 컨텍스트와 설정 확인: kubectl 치트 시트
cd ~/.kube
cat config
# 홈디렉터리 밑에 kubecinfg파일 보는 명령
kubectl config view
apiVersion: v1
clusters: # 쿠버네티스 클러스터를 의미
- cluster:
certificate-authority-data: DATA+OMITTED # ca.crt 인증서
server: https://127.0.0.1:6443 # IP서버
name: cluster.local # 현재 우리가 사용하고 있는 클러스터의 이름
contexts: # 클러스터와 사용자를 결합한 개념
- context:
cluster: cluster.local
namespace: default
user: kubernetes-admin
name: kubernetes-admin@cluster.local # 관습적으로 사용자 이름@클러스터 이름
current-context: kubernetes-admin@cluster.local
kind: Config
preferences: {}
users: # 로그인할 사용자(human) 지정
- name: kubernetes-admin # 우리 계정
user: # 사용자 인증 방법
client-certificate-data: REDACTED # 인증서
client-key-data: REDACTED # 키
우리의 계정은 my.crt 파일을 보면 CN이 설정되어있는데 이로 인해 실제 계정의 이름이 정해진다.
kubectl config get-users
kubectl config get-clusters
kubectl config get-contexts
# contexts의 네임스페이스를 바꿔줌
kebens kube-system
kubectl config get-contexts
# 기본 인증을 지원하는 새로운 사용자를 kubeconf에 추가
kubectl config set-credentials (tab)(tab) # 가능한 옵션 확인
# 사용자 이름은 crt 인증서 파일을 기준으로 지정해줘야됨
# 위치는 crt와 key가 있는 곳에서 진행, 아니면 경로 지정해줘야댐
kubectl config set-credentials myuser3 --client-certificate=myuser3.crt --client-key=myuser3.key
# 추가된 사용자 확인
kubectl config view
#파일의 내용을 내장시킴
kubectl config set-credentials myuser3 --client-certificate=myuser3.crt --client-key=myuser3.key --embed-certs
# 추가된 사용자 확인
kubectl config view
# 사용자와 클러스터 연결, 이름은 관습적으로 사용자 이름@클러스터 이름
kubectl config set-context myuser3@cluster.local --cluster=cluster.local --user=myuser3 --namespace=default
kubectl config get-context
# 사용
kubectl config use-context myuser3@cluster.local
# * 표시가 바뀜
kubectl config get-context
사용자가 바뀌었기때문에 myuser3에게 주어진 권한만 사용 가능.
# 실행 안됨
kubectl get deploy
# 실행됨
kubectl get po
현재 사용하는 컨텍스트 확인하기 위한 명령 설정
kubectx# 파일 불러오기 wget https://github.com/ahmetb/kubectx/releases/download/v0.9.4/kubectx sudo install kubectx /usr/local/bin # kubectl config use-context XXX와 같은 명령 kubectx