/인프라/kubectl Unauthorized 원인별 3분 진단·복구 런북 (EKS 재발급)
인프라kubectl UnauthorizedEKS kubeconfig

kubectl Unauthorized 원인별 3분 진단·복구 런북 (EKS 재발급)

kubectl 'You must be logged in to the server (Unauthorized)' 에러를 토큰·인증서 만료, context·RBAC·엔드포인트 5가지로 분기 진단하고, aws eks update-kubeconfig 재발급과 openssl 만료 확인까지 복붙으로 3분 내 복구하세요.

kubectl Unauthorized 원인별 3분 진단·복구 런북 (EKS 재발급)

kubectl "Unauthorized" 원인별 3분 진단·복구 런북 (EKS 재발급 포함)

K8s Troubleshooting Guide 22편

어제까지 잘 되던 kubectl이 갑자기 막혔다

배포하려고 kubectl get pods를 쳤는데 이런 문구가 뜬 경험, 인프라 하다 보면 반드시 한 번은 겪습니다.

CODE
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)토큰/자격증명 만료 또는 잘못된 userEKS면 aws eks update-kubeconfig 재발급, config current-context 확인
Unable to connect to the server: x509: certificate has expiredclient-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을 쓰는지 봐야 합니다.

Bash
# 지금 활성화된 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%는 이 한 줄로 끝납니다.

Bash
aws eks update-kubeconfig --region ap-northeast-2 --name my-cluster

재발급 후에도 안 되면 ~/.kube/configexec 블록을 확인하세요. EKS 1.24+는 아래처럼 aws eks get-token을 씁니다(구버전은 aws-iam-authenticator).

YAML
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가 됩니다.

Bash
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/온프렘)

인증서 방식이라면 만료일부터 확인합니다.

Bash
# 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 환경에서는 이렇게 점검·갱신합니다.

Bash
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이 떴다면 인증은 통과한 겁니다. 권한만 확인하면 됩니다.

Bash
# 내가 지금 누구로 인식되는지 (Kubernetes 1.28+)
kubectl auth whoami

# 특정 동작 가능 여부
kubectl auth can-i create deployments -n prod
kubectl auth can-i '*' '*' --all-namespaces   # 관리자급인지

can-ino면 RoleBinding/ClusterRoleBinding을 추가해야 하고, kubectl auth whoami가 예상과 다른 신원이면 (B)의 프로파일·context 문제로 돌아갑니다.

실무 한마디

재발급까지 했는데도 Unauthorized가 안 풀리는 케이스의 대부분은 KUBECONFIG 환경변수에 여러 파일이 병합되어 있고, 우선순위 높은 파일의 옛 user가 그대로 살아있는 경우였습니다. echo $KUBECONFIG부터 찍어보고, 병합 파일 중 어느 것이 실제로 채택되는지 kubectl config view --minify로 대조하는 습관이 시간을 아껴줍니다. CI에서만 실패한다면 러너의 ServiceAccount bound 토큰 만료를 의심하세요.

Unauthorized 3분 복구 체크리스트

  1. 에러 원문 읽기 → 401(Unauthorized)인지 403(Forbidden)인지 구분
  2. kubectl config current-context / get-contexts로 context·user 짝 확인
  3. EKS면 aws eks update-kubeconfig + aws sts get-caller-identity로 신원·프로파일 대조
  4. 인증서 방식이면 openssl x509 -noout -enddate로 만료 확인
  5. 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로 단기 토큰을 매 실행마다 발급받도록 파이프라인을 수정하세요.

✦ ✦ ✦
편집 검토 · Editorial Review

이 글은 AI 에이전트가 자료 조사와 1차 초안 작성을 담당하고, 사람 편집자가 사실관계·출처·톤과 맥락을 검토한 뒤 발행했습니다. 환경(OS·버전)에 따라 결과가 다를 수 있으니 적용 전 공식 문서를 함께 확인하세요. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

초안 · AI (Content Reviewer)·검토 · Nodelog 편집자·발행 ·

댓글

첫 번째 댓글을 남겨보세요.