kubectl "Unauthorized" 원인별 3분 진단·복구 런북 (EKS 재발급 포함)
K8s Troubleshooting Guide 22편
어제까지 잘 되던 kubectl이 갑자기 막혔다
배포하려고 kubectl get pods를 쳤는데 이런 문구가 뜬 경험, 인프라 하다 보면 반드시 한 번은 겪습니다.
error: You must be logged in to the server (Unauthorized)당황할 필요 없습니다. kubectl의 인증 컨텍스트(kubeconfig)는 토큰 → 인증서 → context 매핑 → RBAC → 엔드포인트 순으로 딱 5개 지점만 무너집니다. 대부분은 "단기 토큰이 만료됐다"거나 "가리키는 context가 틀렸다"입니다. 특히 EKS 1.24+부터 aws eks get-token 방식이 기본이 되고, Kubernetes 1.24부터 ServiceAccount의 영구 토큰이 폐지되면서 만료성(bound) 토큰으로 인한 Unauthorized가 눈에 띄게 늘었습니다.
이 글은 원리 강의가 아니라 복구 우선 런북입니다. 일단 명령부터 치고, 설명은 그다음에 읽으세요.
1. 에러 원문별 진단표 — 문구로 원인 즉시 분기
가장 먼저 할 일은 에러 원문을 그대로 읽는 것입니다. 문구만으로 원인 5개가 갈립니다.
| 실제 출력 문구 | 유력 원인 | 1차 조치 |
|---|---|---|
error: You must be logged in to the server (Unauthorized) | 토큰/자격증명 만료 또는 잘못된 user | EKS면 aws eks update-kubeconfig 재발급, config current-context 확인 |
Unable to connect to the server: x509: certificate has expired | client-certificate 만료 (kubeadm 등) | openssl x509 -enddate로 만료 확인 후 kubeadm certs renew |
You must be logged in to the server (the server has asked for the client to provide credentials) | 자격증명이 아예 비었거나 exec 플러그인 실패 | kubeconfig의 exec 블록·AWS_PROFILE 점검 |
Error from server (Forbidden): ... cannot ... in namespace "xxx" | 인증은 성공, 인가(RBAC) 실패 | kubectl auth can-i로 권한 점검, RoleBinding 확인 |
Unable to connect to the server: dial tcp ... | 엔드포인트 변경/네트워크 | 클러스터 엔드포인트 재확인 (다음 편 주제) |
핵심 구분: Unauthorized(401) 는 "네가 누군지 증명 못 했다", Forbidden(403) 은 "누군지는 알겠는데 권한이 없다"입니다. 방향이 완전히 다릅니다.
2. 현재 자격증명부터 3초 점검
원인을 좁히려면 지금 kubectl이 어떤 user/cert/token을 쓰는지 봐야 합니다.
# 지금 활성화된 context 이름
kubectl config current-context
# 전체 context 목록 — 별표(*)가 현재 사용 중
kubectl config get-contexts
# 현재 context의 cluster/user/endpoint 상세 (민감정보 주의!)
kubectl config view --minify⚠️ kubectl config view --minify --raw는 토큰과 인증서 원문을 그대로 노출합니다. 화면 공유·로그 붙여넣기 시 반드시 마스킹하세요.
여기서 자주 나오는 함정: context는 A 클러스터인데 user는 B 클러스터 것을 참조하는 매핑 오류입니다. get-contexts 출력의 CLUSTER, AUTHINFO 열이 서로 짝이 맞는지 확인하세요.
3. 원인별 복구 실전
(A) EKS — kubeconfig 재발급
EKS에서 Unauthorized가 뜨면 90%는 이 한 줄로 끝납니다.
aws eks update-kubeconfig --region ap-northeast-2 --name my-cluster재발급 후에도 안 되면 ~/.kube/config의 exec 블록을 확인하세요. EKS 1.24+는 아래처럼 aws eks get-token을 씁니다(구버전은 aws-iam-authenticator).
users:
- name: arn:aws:eks:ap-northeast-2:123456789012:cluster/my-cluster
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: aws
args:
- eks
- get-token
- --cluster-name
- my-cluster가장 흔한 진짜 원인은 프로파일 불일치입니다. kubeconfig를 만든 AWS 프로파일과 지금 셸의 프로파일이 다르면, 인증이 다른 IAM 신원으로 나가 Unauthorized가 됩니다.
aws sts get-caller-identity # 지금 내 IAM 신원
echo $AWS_PROFILE # 셸 프로파일
aws --version # 1.16 이하 구버전이면 get-token 미지원aws sts get-caller-identity 결과가 클러스터 aws-auth ConfigMap에 등록된 신원과 다르면 그게 원인입니다.
(B) client-certificate 만료 확인·갱신 (kubeadm/온프렘)
인증서 방식이라면 만료일부터 확인합니다.
# kubeconfig에서 client 인증서 추출 → 만료일 확인
kubectl config view --raw -o jsonpath='{.users[0].user.client-certificate-data}' \
| base64 -d | openssl x509 -noout -enddate
# 출력 예: notAfter=Jul 3 09:00:00 2026 GMT만료됐다면 kubeadm 환경에서는 이렇게 점검·갱신합니다.
kubeadm certs check-expiration # 전체 인증서 만료 현황
kubeadm certs renew admin.conf # admin kubeconfig 인증서 갱신
# 갱신 후 새 admin.conf를 ~/.kube/config로 복사
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config(C) RBAC — 401 vs 403 확실히 가르기
Forbidden이 떴다면 인증은 통과한 겁니다. 권한만 확인하면 됩니다.
# 내가 지금 누구로 인식되는지 (Kubernetes 1.28+)
kubectl auth whoami
# 특정 동작 가능 여부
kubectl auth can-i create deployments -n prod
kubectl auth can-i '*' '*' --all-namespaces # 관리자급인지can-i가 no면 RoleBinding/ClusterRoleBinding을 추가해야 하고, kubectl auth whoami가 예상과 다른 신원이면 (B)의 프로파일·context 문제로 돌아갑니다.
실무 한마디
재발급까지 했는데도 Unauthorized가 안 풀리는 케이스의 대부분은 KUBECONFIG 환경변수에 여러 파일이 병합되어 있고, 우선순위 높은 파일의 옛 user가 그대로 살아있는 경우였습니다. echo $KUBECONFIG부터 찍어보고, 병합 파일 중 어느 것이 실제로 채택되는지 kubectl config view --minify로 대조하는 습관이 시간을 아껴줍니다. CI에서만 실패한다면 러너의 ServiceAccount bound 토큰 만료를 의심하세요.
Unauthorized 3분 복구 체크리스트
- 에러 원문 읽기 → 401(Unauthorized)인지 403(Forbidden)인지 구분
kubectl config current-context/get-contexts로 context·user 짝 확인- EKS면
aws eks update-kubeconfig+aws sts get-caller-identity로 신원·프로파일 대조 - 인증서 방식이면
openssl x509 -noout -enddate로 만료 확인 - 403이면
kubectl auth can-i/auth whoami로 RBAC 점검
다음 23편에서는 The connection to the server ... was refused — API 서버 접근 자체가 막히는 엔드포인트/네트워크 문제를 다룹니다.
참고: 공식 문서
이 글에서 다루는 동작·설정·에러의 1차 출처는 다음 공식 문서입니다. 버전별 옵션과 정확한 동작은 여기서 확인하세요.
자주 묻는 질문 (FAQ)
Q. update-kubeconfig로 재발급했는데도 여전히 Unauthorized입니다.
A. 두 가지를 보세요. 첫째, KUBECONFIG에 여러 파일이 병합돼 옛 user가 우선 채택되는 경우입니다. 둘째, aws sts get-caller-identity의 신원이 클러스터 aws-auth ConfigMap(또는 EKS Access Entry)에 등록돼 있지 않은 경우입니다. 신원 자체가 클러스터에 매핑돼야 합니다.
Q. 여러 클러스터를 병합해 쓰는데 잘못된 context를 참조합니다.
A. kubectl config get-contexts로 별표(*) 위치를 확인하고 kubectl config use-context <이름>으로 전환하세요. AUTHINFO(user)와 CLUSTER 열이 같은 클러스터를 가리키는지 함께 점검해야 매핑 오류를 막습니다.
Q. CI/CD 러너에서만 Unauthorized가 납니다.
A. Kubernetes 1.24부터 ServiceAccount 영구 토큰이 폐지되고 bound(만료성) 토큰이 기본이라, 러너가 캐싱한 오래된 토큰이 만료됐을 가능성이 큽니다. TokenRequest API로 단기 토큰을 매 실행마다 발급받도록 파이프라인을 수정하세요.
이 글은 AI 에이전트가 자료 조사와 1차 초안 작성을 담당하고, 사람 편집자가 사실관계·출처·톤과 맥락을 검토한 뒤 발행했습니다. 환경(OS·버전)에 따라 결과가 다를 수 있으니 적용 전 공식 문서를 함께 확인하세요. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.
댓글
첫 번째 댓글을 남겨보세요.