k8s SA

이진욱·2024년 10월 30일

k8s

목록 보기
1/1
post-thumbnail

Service Account

Kubernetes에서 SA (Service Account)는 Pod가 API 서버와 통신할 때 사용하는 자격 증명입니다.

root@master:~/lab5# k get sa
NAME      SECRETS   AGE
default   0         6d16h

root@master:~/lab5# k get sa -n kube-system
NAME                                   SECRETS   AGE
attachdetach-controller                0         6d16h
bootstrap-signer                       0         6d16h
calico-cni-plugin                      0         6d16h
calico-kube-controllers                0         6d16h
calico-node                            0         6d16h
certificate-controller                 0         6d16h
clusterrole-aggregation-controller     0         6d16h
coredns                                0         6d16h
cronjob-controller                     0         6d16h
csi-nfs-controller-sa                  0         20h
csi-nfs-node-sa                        0         20h

Kubernetes 클러스터를 생성하면, 전체 클러스터를 관리할 수 있는 권한을 부여하기 위해 default라는 Service Account(SA)가 생성됩니다. Kubernetes에서 root 사용자(또는 kubernetes-admin 사용자)는 클러스터 관리에 필요한 인증서를 발급받아 내부 클러스터에 접근할 수 있습니다.
이 과정에서 root 사용자에게 cluster-admin이라는 역할이 부여되며, 이는 ClusterRole과 ClusterRoleBinding을 통해 설정됩니다. ClusterRoleBinding은 누구에게(subjects) 어떤 권한을 줄지 (roleRef) 정의합니다.
즉, root 사용자에게는 클러스터 전체를 관리할 수 있는 cluster-admin 역할이 부여되어, 클러스터에서 다양한 명령어를 실행할 수 있는 권한이 주어집니다.

ls 내용에는 각 파일들은 Kubernetes 구성 요소에 대한 인증서들입니다. 대부분의 인증서는 1년의 만료기간을 가지며, 적절한 시기에 갱신이 필요합니다. kubeadm으로 생성된 인증서들은 재발급이 가능하며, 만료 기간이 긴 인증서를 받기 위해서는 OpenShift와 같은 플랫폼 또는 하드웨어 보안 모듈(HSM)을 활용한 방법을 고려할 수 있습니다.

  1. Rule (규칙):
    내용: 리소스(Resource)와 이를 다룰 수 있는 작업(Verb)으로 구성됩니다. 예를 들어, 리소스는 Pod 또는 Service일 수 있고, 작업은 "Get", "List"와 같은 동작을 의미합니다.
    역할: 특정 리소스에 대해 어떤 작업을 수행할 수 있는지를 정의합니다.
  2. Role (역할):
    내용: 네임스페이스 내에서 적용되는 규칙들의 모음입니다. 여러 개의 규칙을 묶어서 특정 리소스에 대한 작업 권한을 정의합니다.
    역할: 한 네임스페이스 내에서 리소스에 대한 접근 권한을 관리합니다.
  3. Role Binding (역할 바인딩):
    내용: Role이나 Cluster Role을 특정 사용자(User), 그룹(Group), 또는 서비스 계정(Service Account, SA)에 바인딩합니다.
    역할: 정의된 Role의 규칙들을 사용자나 서비스 계정에게 연결하여 권한을 부여합니다.
  4. (Aggregated) Cluster Role (집계된 클러스터 역할):
    내용: 클러스터 전반에 적용되는 규칙들의 모음입니다. 네임스페이스에 국한되지 않고 클러스터 전체에 적용되는 글로벌 권한을 정의합니다.
    역할: 클러스터 레벨에서 리소스에 대한 권한을 관리합니다.
  5. Cluster Role Binding (클러스터 역할 바인딩):
    내용: Cluster Role을 특정 사용자, 그룹, 또는 서비스 계정에 바인딩하여 클러스터 전체에서 권한을 부여합니다.
    역할: 클러스터 전반에서 권한이 필요한 사용자나 서비스 계정에게 Cluster Role의 규칙들을 할당합니다.
  6. Service Account (서비스 계정):
    내용: 클러스터 내에서 동작하는 프로세스를 위해 사용하는 Kubernetes 계정입니다. Pod는 이 서비스 계정의 자격 증명을 사용하여 API 서버와 상호작용합니다.
    역할: 클러스터 내에서 자동으로 관리되는 프로세스들이 인증된 사용자처럼 동작할 수 있도록 지원합니다.
  7. Pod:
    내용: Kubernetes의 기본 컴퓨팅 유닛입니다. 서비스 계정의 자격 증명을 사용하여 API 서버와 통신하고, 정의된 작업을 수행합니다.
    역할: 클러스터에서 정의된 리소스를 실제로 실행하는 주체로서, 서비스 계정을 통해 권한을 갖고 API 서버와 상호작용합니다.
  8. User (사용자):
    내용: Kubernetes API 서버에 인증하는 실제 사용자입니다. Kubernetes 클러스터 내에서 역할(Role)을 부여받아 리소스에 접근할 수 있습니다.
    역할: API 서버에 접속하여 정의된 권한 내에서 리소스를 관리합니다.
  9. Group (그룹):
    내용: 여러 사용자를 하나의 그룹으로 묶어 관리하는 개념입니다. Role 또는 Cluster Role을 그룹에 할당하여 여러 사용자에게 권한을 부여할 수 있습니다.
    역할: 여러 사용자에게 동일한 권한을 한 번에 할당할 때 사용됩니다.
    전체적인 흐름:
    Rule은 리소스와 이에 대한 작업(verbs)을 정의합니다.
    Role은 이러한 규칙들의 모음이며, 네임스페이스 내에서 사용됩니다.
    Role Binding은 Role을 사용자, 그룹 또는 서비스 계정과 연결하여 권한을 부여합니다.
    (Aggregated) Cluster Role은 클러스터 전체에서 사용할 수 있는 권한 모음입니다.
    Cluster Role Binding은 Cluster Role을 사용자나 서비스 계정에 바인딩하여 클러스터 전반에 권한을 부여합니다.
    Service Account는 클러스터 내에서 Pod와 같은 자원이 사용할 수 있는 계정입니다.
    Pod는 실제로 컴퓨팅 작업을 수행하는 유닛이며, 서비스 계정을 통해 API 서버와 상호작용합니다.
    User는 Kubernetes API 서버에 인증하는 실제 사용자입니다.
    Group은 여러 사용자를 묶어 한 번에 권한을 부여할 때 사용됩니다.

root 사용자에게 cluster-admin이라는 역할이 부여되며, 이는 ClusterRole과 ClusterRoleBinding을 통해 설정됩니다. ClusterRoleBinding은 누구에게(subjects) 어떤 권한을 줄지 (roleRef) 정의합니다.
root는 cluster,admin 권한으로 모든 object 의 리소스와,명령어를 실행 할 수 있다.
(보안취약)

  1. apiGroups:
    설명: apiGroups는 Kubernetes 리소스 그룹을 지정하는 필드입니다. API 리소스는 여러 그룹으로 나뉘며, 각 그룹은 특정한 리소스 타입들을 관리합니다.
    예시: ""(빈 문자열)은 코어 API 그룹을 의미하며, apps, rbac.authorization.k8s.io와 같은 값이 다른 API 그룹을 나타냅니다.
  2. resources:
    설명: resources는 접근할 수 있는 리소스 유형을 정의합니다. Kubernetes에서 관리하는 다양한 리소스(예: pods, services, nodes 등)에 대해 권한을 설정할 수 있습니다.
    예시:
    "pods": Pod 리소스에 대한 접근 권한을 의미합니다.
    "services": 서비스 리소스에 대한 접근을 허용합니다.
    '*': 모든 리소스에 대한 접근을 허용합니다.
  3. verbs:
    설명: verbs는 해당 리소스에 대해 수행할 수 있는 작업(권한)을 지정합니다. 일반적으로 읽기, 쓰기, 삭제와 같은 작업들이 포함됩니다.
    예시:
    "get": 리소스를 조회하는 권한을 의미합니다.
    "list": 여러 리소스를 목록으로 조회하는 권한을 의미합니다.
    "create": 새로운 리소스를 생성할 수 있는 권한을 의미합니다.
    "update": 기존 리소스를 수정할 수 있는 권한을 의미합니다.
    "delete": 리소스를 삭제할 수 있는 권한을 의미합니다.
    '*': 모든 작업을 허용합니다.
  4. nonResourceURLs:
    설명: nonResourceURLs는 Kubernetes API에서 리소스 기반이 아닌 URL 경로에 대한 접근을 제어합니다. 일반적으로 /healthz나 /metrics 같은 경로에 대한 접근 권한을 설정할 때 사용됩니다.
    예시:
    "/healthz": 클러스터 상태를 확인하는 경로에 대한 접근을 허용합니다.
    "*": 모든 URL 경로에 대한 접근을 허용합니다.

keduit 라는 네임스페이스를 관리하는 팀장~! 의 SA 를 생성해 보자~!

root@master:~# # keduit ns에 sa 생성하기
root@master:~# k create sa eng1 -n keduit
serviceaccount/eng1 created

root@master:~# k get sa -n keduit
NAME      SECRETS   AGE
default   0         5d18h
eng1      0         14s
root@master:~# k get svc -n keduit
NAME               TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)           AGE
keduit-mariadb     LoadBalancer   10.99.29.12     211.183.3.201   3306:30418/TCP    5d17h
mariadb-service    LoadBalancer   10.111.74.173   211.183.3.202   3306:32675/TCP    5d17h
svc-blog           ClusterIP      10.97.140.223   <none>          80/TCP            18h
svc-main           NodePort       10.111.55.83    <none>          80:30005/TCP      18h
svc-shop           NodePort       10.97.55.91     <none>          80:30006/TCP      18h

root@master:~# k get svc --as system:serviceaccount:keduit:eng1 -n keduit
Error from server (Forbidden): services is forbidden: User "system:serviceaccount:keduit:eng1" cannot list resource "services" in API group "" in the namespace "keduit"

root@master:~# #""포함된 리스트 확인불가하다. 권한이 없기때문... role, rolebinding 하기 위한 작업이 필요하다.

eng1.yml 파일 생성후 아래 내용추가

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: keduit-eng1
  namespace: keduit
rules:
- apiGroups: ["", "apps"]
  resources: ["pods", "deployments", "services"]
  verbs: ["get", "create", "update", "patch", "delete", "list", "watch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: keduit-eng1
  namespace: keduit
roleRef:
  kind: Role
  name: keduit-eng1
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: eng1
  namespace: keduit

k apply -f eng1.yml

get은 한 개만,list는 모두 볼 수 있다.
eng1에게 권한부여 (role,rolebinding)
k get clusterrole cluster-admin –o yaml 참고
k api-resources 참고

root@master:~/lab5# k get svc --as system:serviceaccount:keduit:eng1 -n keduit
NAME               TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)           AGE
keduit-mariadb     LoadBalancer   10.99.29.12     211.183.3.201   3306:30418/TCP    5d18h
mariadb-service    LoadBalancer   10.111.74.173   211.183.3.202   3306:32675/TCP    5d18h
svc-blog           ClusterIP      10.97.140.223   <none>          80/TCP            19h
svc-main           NodePort       10.111.55.83    <none>          80:30005/TCP      19h
svc-shop           NodePort       10.97.55.91     <none>          80:30006/TCP      19h

Quiz. keduit 에 속해있는 eng1 은 keduit 네임스페이스의 팀장이다. 해당 sa 를 이용하여 eng2 를 생성해 보자. eng2 는 kediut 네임스페이스의 일반 엔지니어이다. 해당 엔지니어는 오직 Pod, Deployment 에 대한 목록 확인만 가능하다. 다른건 못한다.

k create sa eng2 --as system:serviceaccount:keduit:eng1 –n keduit => eng1.yml에서 eng2생성 eng2의 role,rolebinding 추가한다 .

---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: keduit-eng2
namespace: keduit
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: keduit-eng2
namespace: keduit
roleRef:
kind: Role
name: keduit-eng2
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: eng2
namespace: keduit
root@master:~/lab5# k get deploy --as system:serviceaccount:keduit:eng2 -n keduit
NAME                READY   UP-TO-DATE   AVAILABLE   AGE
blog                1/1     1            1           19h
keduit-mariadb      1/1     1            1           5d18h
main                1/1     1            1           19h
mariadb-deployment  1/1     1            1           5d19h
shop                1/1     1            1           19h

root@master:~/lab5# k get svc --as system:serviceaccount:keduit:eng2 -n keduit
Error from server (Forbidden): services is forbidden: User "system:serviceaccount:keduit:eng2" cannot list resource "services" in API group "" in the namespace "keduit"

eng1,eng2의 권한 비교

root@master:~/lab5# k run pod nginx --image=nginx --port=80 -n keduit --as system:serviceaccount:keduit:eng2 -n keduit
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:keduit:eng2" cannot create resource "pods" in API group "" in the namespace "keduit"

root@master:~/lab5# k run pod nginx --image=nginx --port=80 -n keduit --as system:serviceaccount:keduit:eng1 -n keduit
pod/nginx created

Node에 라벨 부여하기

Node 확인

root@master:~/lab5# k get node
NAME     STATUS   ROLES           AGE     VERSION
master   Ready    control-plane   6d21h   v1.29.10
node1    Ready    <none>          6d21h   v1.29.10
node2    Ready    <none>          6d21h   v1.29.10
node3    Ready    <none>          6d21h   v1.29.10
root@master:~/lab5# k describe node node3
Name:               node3
Roles:              <none>
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/os=linux
                    kubernetes.io/arch=amd64 #범용 cpu가 탑재 (intel,amd)
                    kubernetes.io/hostname=node3
                    kubernetes.io/os=linux
                    zone=seoul # 추가하여 지정가능 


root@master:~/lab5# #각 Node에 라벨 부여하기
root@master:~/lab5# k label node node1 region=seoul 
node/node1 labeled
root@master:~/lab5# k label node node2 region=seoul 
node/node2 labeled
root@master:~/lab5# k label node node3 region=jeju
node/node3 labeled
root@master:~/lab5# 

root@master:~/lab5# k label node node3 region- # 라벨 삭제 
node/node3 unlabeled

root@master:~/lab5# k describe node node3 | head
Name:               node3
Roles:              <none>
Labels:             beta.kubernetes.io/arch=amd64
                    beta.kubernetes.io/os=linux
                    kubernetes.io/arch=amd64
                    kubernetes.io/hostname=node3
                    kubernetes.io/os=linux
Annotations:        csi.volume.kubernetes.io/nodeid: {"nfs.csi.k8s.io":"node3"}
                    kubeadm.alpha.kubernetes.io/cri-socket: /var/run/cri-dockerd.sock
                    node.alpha.kubernetes.io/ttl: 0
root@master:~/lab5# 

root@master:~/lab5# k get no --selector region #특정 라벨을 보유한 노드 출력 
NAME    STATUS   ROLES    AGE     VERSION
node1   Ready    <none>   6d21h   v1.29.10
node2   Ready    <none>   6d21h   v1.29.10

root@master:~/lab5# k get no --selector region=seoul
NAME    STATUS   ROLES    AGE     VERSION
node1   Ready    <none>   6d21h   v1.29.10
node2   Ready    <none>   6d21h   v1.29.10

노드에게 name,selector를 추가하여 배치해보기

touch pod-nodename.yml

apiVersion: v1
kind: Pod
metadata:
  name: myapp1
  labels:
    name: myapp1
spec:
  containers:
  - name: myapp1
    image: nginx
    resources:
      limits:
        memory: "128Mi"
        cpu: "500m"
    ports:
      - containerPort: 80
  nodeName: node2 #node2 에게 배치된다 


root@master:~/lab5# k get pod -o wide
myapp1                  1/1     Running   0               7s    192.168.104.5     node2   <none>           <none>

touch pod-nodeselector.yml

apiVersion: v1
kind: Pod
metadata:
  name: myapp2
  labels:
    name: myapp2
spec:
  containers:
  - name: myapp1
    image: nginx
    resources:
      limits:
        memory: "128Mi"
        cpu: "500m"
    ports:
      - containerPort: 80
  nodeSelector:
    region: seoul

root@master:~/lab5# k get pod -o wide
myapp2                  1/1     Running   0               6s      192.168.166.135   node1   <none>           <none>

imagepull 관련 imagePullPolicy -> Alway, Never, IfNotPresent

Always #기본값
kubelet이 컨테이너를 기동할 때마다, kubelet이 컨테이너 이미지 레지스트리에 이름과 이미지의 다이제스트가 있는지 질의한다. 일치하는 다이제스트를 가진 컨테이너 이미지가 로컬에 있는 경우, kubelet은 캐시된 이미지를 사용한다. 이외의 경우, kubelet은 검색된 다이제스트를 가진 이미지를 내려받아서 컨테이너를 기동할 때 사용한다.
#repo에가서 먼저 이미지를 찾아본다 .. 있다면 최신버전의 해쉬코드를 달라고함 만약 로컬에 있는 이미지와 해쉬코드를 비교해본다 repo에 있는 버전이 더 최신이라면 로컬의 이미지와 덮어 씌운다 .

IfNotPresent
이미지가 로컬에 없는 경우에만 내려받는다.

Never
kubelet은 이미지를 가져오려고 시도하지 않는다. 이미지가 어쨌든 이미 로컬에 존재하는 경우, kubelet은 컨테이너 기동을 시도한다. 이외의 경우 기동은 실패한다. 보다 자세한 내용은 미리 내려받은 이미지를 참조한다.

statefulset p348

deployment(젖소)와 비슷한 개념이다
statefulset(애완동물)을 구성하는 파드들은 서로 동일한 스펙이라고 하더라도 각 파드마다 독자성을 유지한다
스케줄링을 다시할 때도 유지된다.

헤드리스서비스

파드들의 개별 네트워크 식별을 위해
특징은 cluster-ip가 없다.

metadata:
  name: sfs-service01
spec:
  selector:
    app.kubernetes.io/name: web-sfs01
  type: ClusterIP
  clusterIP: None
ports:
  - protocol: TCP
    port: 80

스테이트풀셋과 헤드리스 생성

touch statefulset-web01.yml 스테이트풀셋

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: sfs-test01
spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: web-sfs01
  serviceName: sfs-service01
  template:
    metadata:
      labels:
        app.kubernetes.io/name: web-sfs01
    spec:
      containers:
      - name: nginx 
        image: nginx:latest
      

touch statefulset-service.yml 헤드리스

apiVersion: v1
kind: Service
metadata:
  name: sfs-service01
spec:
  selector:
    app.kubernetes.io/name: web-sfs01
  ports:
  - protocol: TCP
    port: 80

결과확인

pod/sfs-test01-0            1/1     Running   0               12s
pod/sfs-test01-1            1/1     Running   0               8s
pod/sfs-test01-2            1/1     Running   0               4s

service/sfs-service01   ClusterIP   10.97.161.219    <none>        80/TCP           16s
#헤드리스 서비스의 cluster-ip는 none이다

statefulset.apps/sfs-test01   3/3     12s

스테이트풀셋 접속 테스트

touch nginx-test01.yml #nginx pod 생성

apiVersion: v1
kind: Pod
metadata:
  name: nginx01  
spec:
  containers:
  - name: nginx-test01
    image: nginx:latest
  
nginx01                 1/1     Running   0               60s     192.168.135.61    node3   <none>           <none>
sfs-test01-0            1/1     Running   0               8m30s   192.168.135.56    node3   <none>           <none>
sfs-test01-1            1/1     Running   0               8m26s   192.168.166.185   node1   <none>           <none>
sfs-test01-2            1/1     Running   0               8m22s   192.168.104.55    node2   <none>           <none>
  

root@master:~/lab5# k exec -it nginx01 -- /bin/bash
root@nginx01:/# curl 192.168.166.185 
#nginx 파드에 접속
#curl 이용한 테스트 노트1 ip 접속 

root@nginx01:/# curl 192.168.166.185 
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
profile
클라우드 엔지니어가 되어보자!

0개의 댓글