테스트용 EC2에서 EKS 쪽 작업할 게 생겨 IAM Role 할당 -> ~/.kube/config 설정 후
API 요청을 보냈더니 에러가 났다.
평소 쿠버네티스 세팅은
- EC2에 IAM Role 할당 (Administrator 혹은 최소한의 Node Role)
- aws eks update-kubeconfig
- aws-auth configmap에 IAM Role 추가 (혹은 IAM Access Entries에 Role 추가)
이 세 가지만 하면 문제 없었는데,, 다 돼있는데도 안돼서 당황했다.
그래서 이번 글에서는 겉핡기식으로 알고 있던 쿠버네티스 인증에 대해 조금 자세히 다뤄보고 왜 저런 이슈가 발생했는지 기록해놔야겠다 라는 생각이 들었다.
쿠버네티스 인증
Kubernetes uses client certificates, bearer tokens, or an authenticating proxy to authenticate API requests through authentication plugins. (Link)
쿠버네티스 공식문서를 보면 인증 방식으로 크게 세 가지를 지원한다.
- Client Certificates (X.509)
- Bearer Tokens
- Authenticating Proxy
이 중에서 EKS 인증에서 활용되는 Token 방식에 대해 알아보자.
EKS는 Webhook Token, Service Account Token과 더불어 2021년 2월부터 OIDC 인증도 지원한다.
Webhook Token Authentication
우리는 쿠버네티스 API 서버와 통신하기 위해 최초 로컬 혹은 특정 서버에 클러스터를 등록해주는 과정을 거친다.
이때 aws eks update-kubeconfig 명령어를 사용하게 되는데 이건 단순히 kubectl과 EKS Cluster를 connect 시켜주기 위한 사전절차일 뿐이다.
[ec2-user@ip-172-20-10-116 ~]$ aws eks update-kubeconfig --region ap-northeast-2 --name jaejung-eks-cluster
Updated context arn:aws:eks:ap-northeast-2:123456789012:cluster/jaejung-eks-cluster in /home/ec2-user/.kube/config
자동으로 home 디렉토리 하위 .kube/config 파일을 업데이트 해주기 때문에 사용하기 간편하지만 eks api를 호출하기 때문에
폐쇄망의 경우 eks용 interface endpoint를 생성하거나 직접 config 파일을 업데이트 해줘야 한다.
물론 IAM 주체에 eks:DescribeCluster 권한이 할당되어 있어야 하며 aws sts get-caller-identity 입력 시 표시되는 자격 증명을 사용한다고 보면 된다.
이때 호출되는 자격증명이 IAM Role이 맞는지, Access key가 입력돼있는 건 아닌지 꼭 확인해야 한다. (이 글을 쓰는 이유이기도 함)
이제 Webhook Authentication이 어떻게 동작하는지 살펴보자.
1. Client가 kubectl을 입력하면 bearer token이 생성된다.
kubectl을 입력하면 어떻게 token이 생성될까?
답은 ~/.kube/config에 있다.
kubectl은 기본적으로 $Home/.kube/config 파일에서 클러스터, 인증, 컨텍스트 정보를 읽어들인다.
그리고 config 파일 하단을 보면 이런 값이 들어가있다.
- name: arn:aws:eks:ap-northeast-2:123456789012:cluster/jaejung-eks-cluster
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
args:
- --region
- ap-northeast-2
- eks
- get-token
- --cluster-name
- jaejung-eks-cluster
- --output
- json
command: aws
결론적으로 kubectl을 입력하면 이 명령어가 자동으로 실행된다고 보면 된다.
aws --region ap-northeast-2 eks get-token --cluster-name jaejung-eks-cluster --output json
직접 실행해보면 굉장히 긴 토큰값이 반환되는 것을 볼 수 있다.
명령어를 실행할 때마다 새로운 토큰값이 생성되고 이 토큰의 만료 기간은 15분이다.
관련 re:Post를 보면 만료 시간은 수정할 수 없다고 한다.
이 토큰값은 base64로 인코딩된 문자열이라서 디코딩해보면 이런 값이 된다.
https://sts.ap-northeast-2.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIA2B6Y4IBCUSBQBF7W%2F20240926%2Fap-northeast-2%2Fsts%2Faws4_request&X-Amz-Date=20240926T073528Z&X-Amz-Expires=60&X-Amz-SignedHeaders=host%3Bx-k8s-aws-id&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEMj%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaDmFwLW5vcn.............
- https://sts.ap-northeast-2.amazonaws.com/
- Action=GetCallerIdentity
- Version=2011-06-15
- X-Amz-Algorithm=AWS4-HMAC-SHA256
- X-Amz-Credential=ASIA2B6Y4IBCUSBQBF7W
- ...
정리해보면
1. eks get-token을 통해 response로 token을 전달받고
2. 이 token은 base 64로 Encoding 되어있고
3. Decoding 해보면 AWS STS(Secure Token Service)의 GetCallerIdentity API를 호출하는 Pre-Signed URL 값이 된다.
2. 이제 사용자 인증을 받아보자.
그럼 인증은 어떤 방식으로 진행될까?
우선 위에서 생성된 토큰이 EKS API 서버로 전송된다.
(kubectl <-> Kubernetes API 서버간 통신은 client-go 라이브러리를 통해 이루어진다.)
API 서버는 전달받은 Token을 aws-iam-authenticator server에 전달한다.
aws-iam-authenticator server는 Token Authentication Webhook 호출 -> sts get-caller-identity 호출 과정을 통해
IAM으로부터 UserID, 사용자에 대한 ARN을 반환받는다.
그 다음으로 aws-auth configmap이 쿠버네티스 보안 주체를 리턴한다.
youtube 영상에서 이 부분이 뭔 뜻인지 이해가 안갔는데
그냥 IAM 사용자와 Kubernetes 사용자를 매핑시켜둔 게 aws-auth configmap 이니까 IAM으로부터 반환 받은 사용자 정보가 aws-auth에 존재하는지 확인하는 절차 정도로 이해했다.
이후 aws-iam-authenticator server는 Kubernetes API 서버에게 TokenReview 라는 데이터 타입으로 username, group을 반환한다.
tokenreview 데이터는 대충 이렇게 생겼다.
{
"kind": "TokenReview",
"apiVersion": "authentication.k8s.io/v1beta1",
"metadata": {
"creationTimestamp": null
},
"spec": {
"token": "$BEARER_TOKEN"
}
}
이 데이터를 가지고서 Kubernetes RBAC 체계에서 요청에 대해 Allow / Deny를 결정짓게 된다.
쉽게 말하면 결국 인증을 요청한 사용자에 대한 정보가 여러 api 호출을 거쳐 configmap에 매핑돼있는 게 확인이 됐을 때 '인증 완료' 가 찍히는 것이다.
이제 돌고돌아 couldn't get current server API group list 오류는 왜 났을까?
aws sts get-caller-identity를 호출했더니 내가 EC2에 할당해놓은 IAM Role이 아니라 예전에 등록해둔 Access key, Secret key로 인해 IAM User가 반환되었다.
결국 EKS에는 IAM Role을 등록해두고 인증을 요청한 주체는 엉뚱한 사용자라서 오류가 났었다.
끝.
참고자료
https://coffeewhale.com/kubernetes/authentication/x509/2020/05/02/auth01/
https://seungjjun.tistory.com/m/313
https://www.youtube.com/watch?v=d16UXBthfYQ&t=656s&ab_channel=AmazonWebServicesKorea
'AWS' 카테고리의 다른 글
AWS Lambda@Edge를 활용한 실시간 이미지 리사이징 (0) | 2023.12.01 |
---|---|
Session Manager를 통해 EC2 인스턴스 접속하기(feat. CentOS) (0) | 2022.09.14 |
Openswan을 활용한 AWS Site-to-Site VPN 구성하기 (0) | 2022.08.02 |
EC2에 Jenkins 구축하기 (0) | 2022.05.03 |
EC2에 harbor 설치하기 (0) | 2022.05.02 |