kubectl "You must be logged in to the server (Unauthorized)" 해결 6가지
어제까지 멀쩡히 돌아가던 kubectl get pods가 오늘 갑자기 이렇게 뱉어냅니다.
error: You must be logged in to the server (Unauthorized)손에 땀이 나죠. 하지만 결론부터 말하면 이건 "권한이 없다(403)"가 아니라 "당신이 누구인지 클러스터가 증명하지 못했다(401)" 라는 인증(authentication) 영역의 문제입니다. 즉 RBAC 설정을 뒤지기 전에 내 신분증(토큰·인증서)이 유효한지부터 봐야 합니다.
이 시리즈(K8s_Troubleshooting_Guide)의 앞 편들이 스케줄링·이미지·네트워크 같은 워크로드 영역을 다뤘다면, 12편인 이번 글은 authn/authz 영역으로 넘어옵니다. 에러 문구를 그대로 검색해서 들어오셨다면, 5분 안에 원인을 특정하고 복붙 명령으로 복구하는 것을 목표로 갑니다.
401 vs 403: 가장 먼저 잡고 가야 할 개념
트러블슈팅의 절반은 "어느 동네 문제인지" 구분하는 데서 끝납니다.
| 에러 메시지 | HTTP 코드 | 의미 | 원인 영역 | 1차 점검 대상 |
|---|---|---|---|---|
You must be logged in to the server (Unauthorized) | 401 | 내가 누구인지 증명 실패 (인증) | authn | 토큰/인증서 만료, context, 클라우드 자격증명 |
Forbidden ... cannot list resource ... | 403 | 누군지는 알지만 권한 없음 (인가) | authz | RBAC Role/RoleBinding |
핵심 비유: 401은 출입증 자체가 만료·분실된 상태, 403은 출입증은 있는데 그 방에 들어갈 권한이 없는 상태입니다. 이 글은 401에 집중하고, 403(RBAC)은 아래 5번 원인에서 경계선만 짚어줍니다.
비슷해 보이지만 원인이 다른 문구도 함께 구분해 두세요.
| 실제 출력 문구 | 유력 원인 | 1차 조치 |
|---|---|---|
You must be logged in to the server (Unauthorized) | 토큰·자격증명 만료(kubeadm이면 client 인증서 만료 포함), 잘못된 user | 아래 (1)~(4) |
You must be logged in to the server (the server has asked for the client to provide credentials) | 자격증명이 비었거나 exec 플러그인 실패 | kubeconfig의 exec 블록, AWS_PROFILE 점검 |
Unable to connect to the server: x509: certificate has expired or is not yet valid | 대개 API 서버의 serving 인증서 만료 또는 클라이언트·서버 시계 오차. client 인증서 만료는 보통 이 문구가 아니라 Unauthorized로 나타남 | 서버 인증서 만료일, kubeadm certs check-expiration, timedatectl |
Error from server (Forbidden): ... cannot ... | 인증은 성공, 인가(RBAC) 실패 | (5) |
Unable to connect to the server: dial tcp ... | 엔드포인트·네트워크 문제 | 클러스터 엔드포인트 확인 |
원인별 진단·해결 6가지 (복붙 명령 위주)
(1) kubeconfig 토큰/인증서 만료
가장 흔한 범인입니다. 단기 만료(STS) 토큰이 보편화되면서 "몇 시간 뒤 갑자기" 패턴이 잦아졌습니다.
# 진단: 현재 사용자에 박힌 token / 인증서 정보 확인
kubectl config view --raw --minify출력에서 user: 아래 token:이 있거나 exec: 블록이 있는지 봅니다. 정적 토큰이 박혀 있다면 만료됐을 가능성이 큽니다. 해결은 발급처에서 토큰을 재발급받아 갱신하는 것입니다(클라우드면 3번으로).
⚠️ --raw는 토큰과 인증서 원문을 그대로 출력합니다. 화면 공유나 이슈·채팅에 붙여넣을 때는 반드시 가리세요. 구조만 볼 때는 --raw 없이 kubectl config view --minify로 충분합니다.
(2) 잘못된 context/cluster 지정
멀티 클러스터 환경에서 dev 자격증명으로 prod를 찌르는 사고가 의외로 많습니다.
# 진단
kubectl config current-context # 지금 어디를 보고 있나
kubectl config get-contexts # * 표시가 현재 context
# 해결
kubectl config use-context <원하는-context-이름>get-contexts 출력의 CLUSTER/AUTHINFO 컬럼이 의도한 값인지 확인하세요. 엉뚱한 context였다면 이것만으로 끝납니다.
(3) 클라우드 IAM 토큰 만료 (EKS / GKE)
EKS는 aws-iam-authenticator 또는 aws eks get-token(exec credential plugin)으로 STS 단기 토큰을 발급합니다. AWS 세션이 만료되면 토큰 발급 단계에서 AWS CLI 에러가 나거나 곧바로 401이 뜹니다.
# EKS: kubeconfig 자격증명 갱신
aws eks update-kubeconfig --region <리전> --name <클러스터명>
# 프로파일을 따로 쓴다면
aws eks update-kubeconfig --region <리전> --name <클러스터명> --profile <프로파일>
# GKE
gcloud container clusters get-credentials <클러스터명> --region <리전>EKS에서 가장 흔한 함정: aws sts get-caller-identity로 AWS 자격증명 자체가 유효한지 먼저 확인하세요. AWS 세션이 죽어 있으면 update-kubeconfig를 해도 토큰 발급 단계에서 똑같이 401이 납니다.
aws sts get-caller-identity # 여기서 에러나면 AWS 자격증명부터 갱신자격증명은 유효한데도 401이라면 그 IAM 신원이 클러스터에 매핑돼 있는지 확인합니다. EKS는 aws-auth ConfigMap이나 EKS Access Entry에 등록된 신원만 받아들입니다. 클러스터 관리자에게 aws sts get-caller-identity의 ARN(역할을 맡았다면 역할 ARN)이 등록돼 있는지 확인을 요청하세요.
# 관리자 권한이 있는 쪽에서 확인
aws eks list-access-entries --cluster-name <클러스터명>
kubectl -n kube-system get configmap aws-auth -o yaml(4) client-certificate 권한·만료 확인
온프레미스 kubeadm 클러스터는 보통 client certificate 인증을 씁니다. 인증서는 기본 1년 만료라 까먹기 딱 좋습니다.
# 인증서 만료일 디코딩
openssl x509 -in ~/.kube/client.crt -noout -enddate
# 출력 예) notAfter=Jun 16 09:00:00 2026 GMT
# kubeconfig에 base64로 박혀 있다면
kubectl config view --raw -o jsonpath='{.users[0].user.client-certificate-data}' | base64 -d | openssl x509 -noout -enddatenotAfter가 지났다면 만료입니다. 인증서 파일 경로/권한(ls -l로 600 권장)도 함께 점검하고, kubeadm이라면 kubeadm certs renew 계열로 갱신합니다.
x509: certificate has expired or is not yet valid가 나온다면 client 인증서보다 API 서버 인증서와 시계를 먼저 봅니다. kubectl이 서버가 내민 인증서를 검증하다 실패했다는 뜻이기 때문입니다.
# API 서버가 내미는 인증서의 유효기간 (kubeadm 기본 포트 6443)
echo | openssl s_client -connect <apiserver-host>:6443 2>/dev/null | openssl x509 -noout -dates
# 컨트롤 플레인 노드에서 전체 인증서 점검·갱신
sudo kubeadm certs check-expiration
sudo kubeadm certs renew all
# 갱신한 인증서는 컨트롤 플레인 static Pod를 재시작해야 반영됨:
# /etc/kubernetes/manifests/의 매니페스트를 잠시 다른 곳으로 옮겼다가 Pod가 내려간 뒤 되돌림
# 갱신된 admin.conf를 kubeconfig로 복사
sudo cp /etc/kubernetes/admin.conf $HOME/.kube/config(5) RBAC 미부여 — 여기서 401이 아니라 403이 뜬다
여기가 401과 403의 경계선입니다. 인증은 됐는데 권한이 없으면 401이 아니라 403이 떠야 정상입니다. 즉 401이라면 RBAC는 보통 범인이 아닙니다.
# 내가 특정 동작을 할 수 있는지 확인
kubectl auth can-i list pods
kubectl auth can-i get pods --namespace prod출력이 no면 403(인가) 문제, 그런데도 메시지가 401이라면 인증 단계에서 이미 막힌 것이니 1~4번으로 돌아가세요.
kubectl auth whoami # 클러스터가 나를 누구로 인식하는지 (kubectl 1.28+)whoami가 예상과 다른 사용자라면 권한이 아니라 인증·context 문제입니다.
(6) 시스템 시계 오차
JWT/STS 토큰에는 NotBefore/Expiry가 박혀 있어, 클라이언트 시계가 어긋나면 멀쩡한 토큰도 "아직 유효하지 않음" 또는 "만료됨"으로 검증 실패합니다. VM·컨테이너 환경에서 의외로 자주 발생합니다.
# 진단
timedatectl # System clock synchronized: yes 인지 확인
# 해결 (NTP 동기화)
sudo timedatectl set-ntp true
sudo systemctl restart systemd-timesyncdSystem clock synchronized: no거나 실제 시각과 수 분 이상 차이 나면 동기화 후 재시도하세요.
5분 빠른 진단 플로우
막혔을 때 위에서 아래로 순서대로 내려가면 됩니다.
- context 확인 →
kubectl config current-context로 엉뚱한 곳을 보고 있는지 (원인 2) - 토큰/인증서 만료 확인 →
kubectl config view --raw --minify+openssl x509 -enddate(원인 1·4) - 클라우드면 자격증명 갱신 →
aws sts get-caller-identity→aws eks update-kubeconfig ...또는gcloud ... get-credentials(원인 3) - 시계 확인 →
timedatectl동기화 여부 (원인 6) - 여기까지 통과하면 권한 영역 →
kubectl auth can-i ...로 403 여부 확인 (원인 5)
실무 팁: 401 신고를 받으면 context 확인(원인 2)과
aws sts get-caller-identity(원인 3)부터 보는 습관을 들이면 복구가 빨라집니다.
예방이 곧 트러블슈팅 — 토큰 자동 갱신과 context 분리
복구도 중요하지만, 재발을 막는 게 진짜 실력입니다.
- exec credential plugin으로 자동 갱신: 정적 토큰을 박지 말고, kubeconfig의
user.exec로 매 요청 시 토큰을 새로 받게 하세요. EKS 권장 방식입니다.
users:
- name: my-eks
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: aws
args:
- eks
- get-token
- --cluster-name
- my-cluster
- --region
- ap-northeast-2-
클러스터별 context·kubeconfig 분리: prod와 dev를 한 파일에 섞지 말고
KUBECONFIG=~/.kube/prod:~/.kube/dev식으로 분리하거나, 셸 프롬프트에 현재 context를 노출(kube-ps1)해 오발사고를 줄이세요. -
KUBECONFIG 병합 우선순위 확인: 여러 파일을 병합하면 같은 이름의 user·context는 목록에서 먼저 나온 파일의 값이 채택됩니다. 재발급했는데도 401이면
echo $KUBECONFIG로 파일 순서를 보고,kubectl config view --minify로 실제 채택된 user를 대조하세요. -
CI/CD 러너는 단기 토큰으로: Kubernetes 1.24부터 ServiceAccount 토큰 Secret이 자동 생성되지 않고, Pod에는 만료가 있는 bound 토큰이 주입됩니다. 러너가 오래전에 복사해 둔 토큰에 의존하지 말고, 실행마다
kubectl create token <SA이름> --duration=1h(TokenRequest API)로 발급받거나 클라우드의 OIDC 연동을 쓰세요.
핵심 명령 요약: current-context로 위치 확인 → config view --raw/openssl x509로 만료 확인 → aws eks update-kubeconfig로 갱신 → timedatectl로 시계 점검 → auth can-i로 권한 구분.
다음 편 예고: K8s_Troubleshooting_Guide 13편 — 403 Forbidden과 RBAC 권한 설계 트러블슈팅에서 이번에 살짝 짚은 인가(authz) 영역을 본격적으로 파고듭니다.
참고: 공식 문서
이 글에서 다루는 동작·설정·에러의 1차 출처는 다음 공식 문서입니다. 버전별 옵션과 정확한 동작은 여기서 확인하세요.
자주 묻는 질문 (FAQ)
Q. aws eks update-kubeconfig를 했는데도 그대로 401이에요.
A. AWS 세션 자체가 만료된 경우입니다. aws sts get-caller-identity로 자격증명이 살아 있는지 먼저 확인하고, 만료됐으면 SSO 로그인(aws sso login)이나 키 갱신 후 다시 update-kubeconfig 하세요.
Q. 프로파일·리전이 여러 개라 헷갈립니다.
A. --profile과 --region을 명시하고, exec plugin args에도 동일한 값을 넣으세요. AWS_PROFILE 환경변수와 kubeconfig의 exec 설정이 다르면 엉뚱한 자격증명으로 토큰을 받아 401이 납니다.
Q. 401인데 RBAC 문제일 수도 있나요? A. 거의 아닙니다. RBAC 미부여는 인증을 통과한 뒤 발생하므로 보통 403으로 표시됩니다. 401이면 토큰·인증서·context·시계 문제일 확률이 높으니 5분 플로우의 1~4번부터 점검하세요.
글마다 출처와 확인 범위가 다릅니다. 아래에 확인일·확인 범위·출처가 기록된 글만 그 범위에서 확인된 것입니다. 기록이 없는 글은 적용 전 사용 중인 버전의 공식 문서로 직접 확인하고, 오류는 이메일로 알려주세요. 편집 정책 · 이메일로 제보
이 글에는 사람이 확인한 날짜·범위 기록이 아직 없습니다.
댓글
첫 번째 댓글을 남겨보세요.