Service account token Volume Projection
BoundServiceAccountTokenVolume
이 v1.21 버전 부터 Default로 추가됩니다.
이제 모든 쿠버네티스 서비스 어카운트(ServiceAccount)의 토큰(Token)은 1시간의 만료시간을 가지게 되었습니다. 기존 서비스 어카운트 토큰은 만료기간이 없어서 문제가 있었거든요.
그 말은 즉, 나쁜 사람이 토큰을 탈취했다면 만료시간 없이 계속 사용이 가능했다 라는 이야기입니다. 하지만 Kubernetes v1.21부터 BoundServiceAccountTokenVolume
이 기본으로 활성화가 되기 때문에 해당 이슈는 해결이 됩니다.
ServiceAccount의 Token 만료시간(Expiration Time)
아래에서 보시는 것처럼 서비스 어카운트 토큰에는 이제 "exp" claim이 있습니다. exp 시간이 생각보다 긴 이유는 아래에 후술하겠습니다.
* Header
{
"alg":"RS256",
"kid":"f35415113bde44b7855fcb8b15cbb5ee65d3db8"
}
* Payload
{
"aud":[
"https://kubernetes.default.svc"
],
"exp":1687703452,
"iat":1656167452,
"iss":"https://oidc.eks.ap-northeast-2.amazonaws.com/id",
"kubernetes.io":{
"namespace":"any commerce",
"pod":{
"name":"order-84b5d545bd-nknns",
"uid":"215f207b-b396-4953-9ff9-74f9b8c66b1a"
},
"serviceaccount":{
"name":"order",
"uid":"7b083c6e-3616-4067-a906-92509390156b"
},
"warnafter":1656171059
},
"nbf":1656167452,
"sub":"system:serviceaccount:any commerce:order"
}
iat: 1656167452 2022. 6. 25. 오후 11:30:52
nbf: 1656167452 2022. 6. 25. 오후 11:30:52
exp: 1687703452 2023. 6. 25. 오후 11:30:52
Bound Service Account Token Volume
그렇다면 바로 이 Bound Service Account Token Volume이란 도대체 뭘까요? 기존 서비스 어카운트는 딱히 유효기간이라는게 없는 Secret 기반의 Volume을 사용하고 있었죠.
Bound Service Account Token Volume은 Secret기반 Volume이 아닌 Projected Volume을 사용합니다.
https://kubernetes.io/docs/concepts/storage/projected-volumes/
Projected Volume은 다음 4가지 타입을 지원합니다. Projected Volume은 All-in-One 컨셉의 볼륨으로, 여러 소스들을 하나의 볼륨에 담아서 쓸 수 있게 해줍니다.
그중 우리가 주목해야할 것은 가장 마지막의 serviceAccountToken입니다.
실제 fluent-bit pod의 볼륨을 살펴보면, 아래와같이 projected volume 소스들 중에 serviceAccountToken
을 확인 할 수 있습니다.
- name: kube-api-access-j5mwt
projected:
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
name: kube-root-ca.crt
items:
- key: ca.crt
path: ca.crt
- downwardAPI:
items:
- path: namespace
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
defaultMode: 420
Bound Service Account Token Volume의 핵심은 /var/run/secrets/kubernetes.io/serviceaccount/token
에 있는 token 파일 내용이 1시간마다 바뀐다는 것입니다. (time-limited, auto-refreshed, and invalidated when the containing pod is deleted.)
해당 볼륨은 아래와 같은 mountPath에 mount가 될 것이기 때문입니다.
volumeMounts:
- name: kube-api-access-j5mwt
readOnly: true
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
그런데 말입니다
이 문제는 쉬운 문제가 아닙니다. 서비스 어카운트를 사용하는 Kubernetes 내의 클라이언트들은 이제 1시간마다 토큰을 리프레시 해주어야 하는 것이죠.
Kubernetes SDK의 경우 다음 버전 이상에서 토큰 리프레시 기능을 지원합니다. 이 SDK를 사용하면 일반적으로 문제는 없습니다.
- Go version 0.15.7 and later
- Python version 12.0.0 and later
- Java version 9.0.0 and later
- JavaScript version 0.10.3 and later
- Ruby master branch
- Haskell version 0.3.0.0
- C# version 7.0.5 and later
그 외의 클라이언트는 디스크(/var/run/secrets/kubernetes.io/serviceaccount/token
)에서 주기적으로 토큰을 가져와야합니다. 권장사항은 1분 간격입니다.
하지만 어떤 Application은 Kubernetes의 버전 업그레이드 속도를 따라가지 못하는 경우도 발생할 수 있겠죠. 여기서 유효기간이 만료된 Token을 Application이 사용하고, 요청이 거절되면서 이제 장애가 발생하는 케이스가 생겨나게 됩니다.
EKS의 경우
그래서 AWS와 같은 Public Cloud 벤더의 경우, Smooth한 마이그레이션을 위해 유효기간이 지난 Token으로 요청을 보내도 괜찮도록 설정을 해 두었습니다. AWS의 경우 90일까지는 유효기간이 지난 Token을 사용해도 요청을 허용합니다. exp 기간이 길었던 이유가 바로 이것 때문인 것이죠.
참고로 EKS에서 어떤 Application 들이 유효기간이 지난 요청을 보내고 있는지는 다음과 같은 방법을 통해 확인이 가능합니다.
1. 컨트롤 플레인 로깅을 EKS 클러스터에서 활성화 (특히 Audit log)
2. Cloudwatch Log Insights 쿼리에서 "유효기간이 지난 토큰"을 쓰는 앱들을 아래와 같이 검색:
fields @timestamp
| filter @logStream like /kube-apiserver-audit/
| filter @message like /seconds after warning threshold/
| parse @message "subject: *, seconds after warning threshold:*\"" as subject, elapsedtime
EKS가 아닌 경우
EKS가 아닌 온프레미스 등에서 직접 운영하시는 k8s는 kube-apiserver에 --service-account-extend-token-expiration=false
옵션을 줘서 유효기간을 지난 요청을 받도록 하는 옵션을 끄실 수 있습니다.
GKE는 Secret기반 SA token도 일단은 남아있다고 하고, AKS의 경우 서비스 계정 토큰 볼륨 프로젝션을 별도로 활성화 하시지 않으면 딱히 영향을 받으실 부분이 없으실 것 같은데, 이부분은 추가적으로 확인이 필요할 것 같습니다.
혹시 궁금한 점이 있다면 댓글로 남겨주세요.
감사합니다.
'Container > Kubernetes' 카테고리의 다른 글
Kubernetes Ephemeral container 란? (0) | 2022.08.15 |
---|---|
containerd를 위한 fluent-bit config 설정 (0) | 2022.06.26 |
댓글