k8s 에서 1.24 이전 버전에는 service account secret token이 자동으로 생성 되었지만,
이후 버전 부터는 직접 생성하고 관리해주어야 한다.
특히 토큰에는 수명주기가 있으며 이를 관리해주어야 한다.
임시 기간 토큰 생성 및 영구 생성, Refresh를 통한 토큰 관리가 있다.
1. 임시 기간 토큰 생성
kubectl create token 명령어를 통해 토큰 생성이 가능하며, --duration 옵션을 통해 시간 지정 가능하다.
duration 옵션이 없을 경우 기본적으로 1시간으로 세팅된다.
또한, 해당 명령어로 토큰을 생성할 경우 생성할 때 조회 가능하고 더 이상 생성한 토큰에 대해 조회가 불가능하다.
# 임시 계정 생성
kubectl create sa temp-sa
# create token 명령어를 통해 임시 생성
kubectl create token temp-sa --duration 30m
# result
eyJhbGciOiJSUzI1NiIsImtpZCI6ImU1Mnp2SFpHYS1RN2dXaElkV0tEZC1nemlxeTFhdWQiGE5ZC1hM2E3LTQ4OGYtOTM3OS1iYzc0MGU1ZjUyMDkifX0sIm5iZiI6MTczNDQzOTY4MCwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6dGVtcC1zYSJ9.Ya83wdlUMifQww_XUmK2rEfxkAMqueDT6QeYiQqwXlWYnUIq4YaCZDbo7XZz8xW3W-_efpx1-7n9dHkUMzk88LvCCS5C0S6J89hGGAI4T_nhyTfIhj4AbC_hhLdZR3b9pSuh7a0xY_CiD
{
"aud": [
"https://kubernetes.default.svc.cluster.local"
],
"exp": 1734441480,
"iat": 1734439680,
"iss": "https://kubernetes.default.svc.cluster.local",
"jti": "360425d7-587d-44ca-8633-67e5e07ac9e5",
"kubernetes.io": {
"namespace": "default",
"serviceaccount": {
"name": "temp-sa",
"uid": "34bd8a9d-a3a7-488f-9379-bc740e5f5209"
}
},
"nbf": 1734439680,
"sub": "system:serviceaccount:default:temp-sa"
}
2. 영구 토큰 생성
영구 토큰은 Service Account 생성 후 Secret을 따로 생성해주면 된다.
하지만, 권장하지는 않는다.
# 계정 생성
kubectl create sa permanent-sa
# secret 생성
vi secret.yaml
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: permanent-sa-secret
annotations:
kubernetes.io/service-account.name: permanent-sa
# 적용
kubectl apply -f secret.yaml
# 조회
kubectl get secret
NAME TYPE DATA AGE
permanent-sa-secret kubernetes.io/service-account-token 3 4s
# 토큰 조회
kubectl describe secret apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: permanent-sa-secret
annotations:
kubernetes.io/service-account.name: permanent-apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: permanent-sa-secret
annotations:
kubernetes.io/service-account.name: permanent-sa
root@master:~/account# kubectl describe secret permanent-sa
Name: permanent-sa-secret
Namespace: default
Labels: <none>
Annotations: kubernetes.io/service-account.name: permanent-sa
kubernetes.io/service-account.uid: 349d3c79-1180-4cea-9357-5169a7a88d4c
Type: kubernetes.io/service-account-token
Data
====
token: eyJhbGciOiJSUzI1NiIsImtpZCI6ImU1Mnp2SFpHYS1RN2dXXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3V
ca.crt: 1107 bytes
namespace: 7 bytes
3. Service Account Mount를 통한 갱신
3.1 기본적인 Mount 를 통한 갱신
기본적으로 pod yaml 설정시 Service Account를 적용하게되면 1시간마다 토큰이 갱신된다. (확인하려면 1시간 후 pod 에 접속해서 확인 가능, 공식문서에서도 1시간마다 kubelet이 갱신한다고 나와 있음)
# 토큰 생성
kubectl create sa auto-sa
# deploy.yaml 내 serviceAccount 적용
...
spec:
template:
spec:
serviceAccount: auto-sa
containers:
...
...
# 토큰 조회를 위해 pod 접속
kubectl exec -it stdout-node-869cff8b95-cxqf2 -- sh
# 경로
pwd
/var/run/secrets/kubernetes.io/serviceaccount
ls
ca.crt namespace token
# 토큰 조회
# 토큰이 변경되는걸 확인하려면 1시간 후에 해당 pod 접속해서 똑같이 확인하면 됨.
cat token
eyJhbGciOiJSUzI1NiIsImtpZCI6ImU1Mnp2SFpHYS1RN2dXaElkV0tEZC1nemlxeTFMclJubTVTaFhoVkZIY2sifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzY1OTc2NzIxLCJpYXQiOjE3MzQ0NDA3MjEsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwianRpIjoiNjQ3ZDZmYWMtODc
3.2 Volume Project 를 통한 관리
위 방법 말고 Volume Project를 통한 시간 설정 및 갱신이 가능하다.
automountServiceAccountToken 옵션을 false 로 주어야하므로 yaml로 생성 기본적으로 ServiceAccount 생성시 true 로 생성 됨.
해당 예제는 2시간으로 설정
(2시간뒤 자동 갱신됨)
# automountServiceAccountToken 옵션을 false 로 주어야하므로 yaml로 생성
# 기본적으로 ServiceAccount 생성시 true 로 생성 됨.
vi passive-sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: passive-sa
namespace: default
automountServiceAccountToken: false
# deploy.yaml 내 serviceAccount volume project 적용
...
spec:
template:
spec:
serviceAccount: passive-sa
volumes:
- name: project-passive-sa
projected:
sources:
- serviceAccountToken:
path: passive-account-file
expirationSeconds: 7200
containers:
volumeMounts:
- mountPath: /tmp/token
name: project-passive-sa
...
# 토큰 조회를 위해 pod 접속
kubectl exec -it stdout-node-7fcc7ff87-tjfjf -- sh
# 경로
# 위에서 /tmp/token 에 설정했음
pwd
/tmp/token
# 위에서 passive-sa-file 로 설정했음
ls
passive-sa-file
# 토큰 조회
# 토큰이 변경되는걸 확인하려면 2시간으로 설정했으므로 2시간 후에 해당 pod 접속해서 똑같이 확인하면 됨.
cat passive-sa-file
eyJhbGciOiJSUzI1NiIsImtpZCI6ImU1Mnp2SFpHY
3.3 TokenRequest API 이용
API 호출용, 일반 Service Account 2개를 만들어, 하나는 Token 갱신을 위해 사용하는 방법으로 사용한다.
Containerd 에서 인증서 에러 발생시 인증서가 있는 경우와 없는 경우 설정하는 방법이다.
참고로 containerd 를 설정했다고 ctr 명령어 까지 같이 적용되는건 아니다. crictl 만 적용된다.
ctr 의 경우 인증서가 있으면 --tlscacert, --tlscrt, --tlskey 3개옵션을 적용하여 사용하면 되며
인증서가 없을 경우 --skip-verify 옵션을 사용하면된다.
1. containerd 설정파일을 수정한다.
$ vi /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d"
2. certs.d 폴더를 생성한다.
$ cd /etc/containerd/
$ mkdir certs.d
3. 내부에 인증서 연결할 서버 폴더생성
$ cd certs.d
$ mkdir registry.wky.kr
$ cd registry.wky.kr
$ pwd
/etc/containerd/certs.d/registry.wky.kr
4. hosts.toml 파일 생성
인증서가 있는 경우.
$ vi hosts.toml
server = "https://registry.wky.kr"
[host."https://registry.wky.kr"]
capabilities = ["pull", "resolve"]
# pemfile 이 있는 경로 및 파일 입력
ca = pemfile.pem
# crt, key, pem 파일이 있는 경로 및 파일 입력
client = [[crtfile.crt, keyfile.key], [pemfile.pem]]
인증서가 없는 경우
$ vi hosts.toml
server = "https://registry.wky.kr"
[host."https://registry.wky.kr"]
capabilities = ["pull", "resolve"]
skip_verify = true
'ctr image mount imagename:tag 폴더' 명렁어를 통해 확인할 수 있다.
먼저 이미지가 서버 내에 있어야함.
$ crictl images
IMAGE TAG IMAGE ID SIZE
docker.io/library/busybox latest 63cd0d5fb10d7 1.86MB
$ mkdir busybox
$ ctr -n=k8s.io image mount docker.io/library/busybox:latest ./busybox/
sha256:66ccab9b46d8f9daffd6e24c69ab2d6c5a5b44e9d0e39991985a910a2775755e
./busybox/
$ ls busybox/
bin dev etc home lib lib64 root tmp usr var
사설 인증서를 생성하고, 사설인증서이기 때문에 해당 registry를 실제 사용할 서버를 위해 ca파일도 생성한다.
# 사설 인증서 생성
$ openssl req -newkey rsa:4096 -nodes -sha256 -keyout domain.key -subj "/CN=registry.wky.kr" -addext "subjectAltName=DNS:registry.wky.kr" -x509 -days 365 -out domain.crt
# 이미지 push 또는 pull 위한 ca 파일 생성
$ cat domain.crt domain.key > domain.pem
$ helm install opensearch-dashboards opensearch-dashboards-2.24.1.tgz --create-namespace --namespace logging
# 실행 후 확인
$ kubectl get pods -n logging
NAME READY STATUS RESTARTS AGE
opensearch-dashboards-649d556895-r4vwn 1/1 Running 0 2m13s
Host는 oepnsearch가 statefulset으로 동작하므로 opensearch service의 headless service로 연결한다.
$ kubectl edit cm fluent-bit
# [OUTPUT] 에 stdout이 있으면 해당 부분 제거 후 아래 부분 추가
[OUTPUT]
Name opensearch
Match kube.*
Host opensearch-cluster-master-headless.logging
Port 9200
tls On
tls.verify Off
HTTP_User admin
HTTP_Passwd wkyKr!2024
Retry_Limit False
Suppress_Type_Name On
fluent-bit 의 config map hot reload 를 설정하지 않았으므로, fluent-bit pod를 전체 재기동한다.
11. 연동 후 OpenSearch에서 확인을 위해 서비스를 통한 로깅 테스트 후 Fluent-Bit 확인
$ kubectl apply -f k8s.yaml
deployment.apps/stdout-node created
service/stdout-node-service created
ingress.networking.k8s.io/stdout-node-ingress created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
stdout-node-6f945d7989-6xjp2 1/1 Running 0 20s
3. fluent-bit install
$ helm repo add fluent https://fluent.github.io/helm-charts
$ helm upgrade --install fluent-bit fluent/fluent-bit
# namespace 를 주지않으면 default namespace에 생성된다
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
fluent-bit-67blm 0/1 ContainerCreating 0 5s
fluent-bit-vvt7c 0/1 ContainerCreating 0 5s
4. 현재 elasticsearch 나 opensearch 를 설치하지 않았으므로 stdout테스트를 진행한다. (테스트 후 opensearch 설치 예정)
기존에 있던 OUTPUT인 elasticsearch를 삭제하고 [OUTPUT]으로 stdout 을 추가한다.
(해당 Name의 경우 이름이 정해져있으며, 이름마다 사용할 수 있는 변수?가 다르다. 공식 가이드에서 확인 가능하다.)
$ kubectl edit cm fluent-bit
기존에 있던 elasticsearch OUTPUT 삭제
[OUTPUT]
Name es
Match host.*
Host elasticsearch-master
Logstash_Format On
Logstash_Prefix node
Retry_Limit False
아래 stdout OUTPUT 추가
[OUTPUT]
Name stdout
Match kube.*
# config map 수정 후 fluent-bit pod 삭제를 통해 재기동한다.
$ kubectl delete pods fluent-bit-67blm fluent-bit-vvt7c
pod "fluent-bit-67blm" deleted
pod "fluent-bit-vvt7c" deleted
5. 1번에서 설치한 테스트 pod 위치를 확인 후 같은 위치의 fluent-bit pod 의 로그를 f option을 통해 확인한다.