eks csr, tls 인증 오류
부제 : cluster creator와 node role의 인증자를 동일하게 구성 시 일어나는 일에 대해서.
eks를 도입 하기 전에 사전 구축을 하고 테스트를 하는 과정에서 발생 된 일이다. 특정 상황에서 pod의 shell을 접속 하거나 로그를 보려고 하면 아래와 같은 TLS 오류가 발생 하였다.
Copy Error from server: Get "https://10.10.20.xxx:10250/containerLogs/game-2048/deployment-2048-74cdf7657b-jshqz/app-2048": remote error: tls: internal error
csr을 확인 해보니 아래와 같이 csr 승인을 받으려고 대기 중이 었다.
Copy > kubectl get csr -A |more
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
csr-22wz5 179m kubernetes.io/kubelet-serving kubernetes-admin <none> Pending
csr-268mq 12h kubernetes.io/kubelet-serving kubernetes-admin <none> Pending
csr-27jv2 3h30m kubernetes.io/kubelet-serving kubernetes-admin <none> Pending
csr-28z9s 163m kubernetes.io/kubelet-serving kubernetes-admin <none> Pending
csr-2925l 17h kubernetes.io/kubelet-serving kubernetes-admin <none> Pending
csr-299p4 14h kubernetes.io/kubelet-serving kubernetes-admin <none> Pending
csr-2b6m8 7h37m kubernetes.io/kubelet-serving kubernetes-admin <none> Pending
Approve,Issued 상태의 csr 상태 정보[정상]
kubectl get csr csr-ok -o json
Copy
{
"apiVersion": "certificates.k8s.io/v1",
"kind": "CertificateSigningRequest",
"metadata": {
"creationTimestamp": "2023-06-15T08:42:56Z",
"generateName": "csr-",
"name": "csr-mwg9m",
"resourceVersion": "1436",
"uid": "60c56b9c-6d85-41f9-ae09-a242dbb76688"
},
"spec": {
"extra": {
"accessKeyId": [
"ASIA5ISTH5MDxxxxx"
],
"arn": [
"arn:aws:sts::xxxxx:assumed-role/devops-role-20230614/i-0d53c8xxxxx3dd9"
],
"canonicalArn": [
"arn:aws:iam::xxxx:role/devops-role-20230614"
],
"principalId": [
"AROA5ISTH5MDNI6xxxxx"
],
"sessionName": [
"i-0d53c871axxxxx"
]
},
"groups": [
"system:bootstrappers",
"system:nodes",
"system:authenticated"
],
"request": "LS0tLS1CRUdJTiBDRVJUSUZJxxxxxxJQmJEQ0NBUklDQVFBd1hURVZNQk1HQTFVRUNoTU1jM2x6ZEdWdE9tNXZaR1Z6TVVRd1FnWURWUVFERXp0egplWE4wWlcwNmJtOWtaVHBwY0MweE1DMHhNQzB4TmkweE1qRXVZWEF0Ym05eWRHaGxZWE4wTFRJdVkyOXRjSFYwClpTNXBiblJsY201aGJEQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJQNjc4VFMrUTduVFlvdUUKcFpHQmxaYTRSR0puRlI0ZW9mZ29BTlZ0T1k3OG9SUkdyQ3p1OGZLYVpia09sNnpoU3RnVTYxTktLaHdWekhXSApJVDlHdlk2Z1V6QlJCZ2txaGtpRzl3MEJDUTR4UkRCQ01FQUdBMVVkRVFRNU1EZUNMMmx3TFRFd0xURXdMVEUyCkxURXlNUzVoY0MxdWIzSjBhR1ZoYzNRdE1pNWpiMjF3ZFhSbExtbHVkR1Z5Ym1Gc2h3UUtDaEI1TUFvR0NDcUcKU000OUJBTUNBMGdBTUVVQ0lRQ3RJaG85YzRhQlIrVVo0bnphY3AvZjhGNWtHSTgrOTViQU5ZWEVDMWYrWkFJZwpCa2VqWHNTVHNRcEJsalNieGJ6d3ZPY056SWQwVE9ST0M4OWhMR0UxZ0tJPQotLS0tLUVORCBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K",
"signerName": "kubernetes.io/kubelet-serving",
"uid": "aws-iam-authenticator:xxxxx:AROA5ISTH5xxxx",
"usages": [
"digital signature",
"key encipherment",
"server auth"
],
"username": "system:node:ip-10-10-xxx-xxxx.ap-northeast-2.compute.internal"
},
"status": {
"certificate": "LS0tLS1CRUdJTiBDRVJxxxxxxx1JSUM3akNDQWRhZ0F3SUJBZ0lVYXg4OXo4VU5ueXJJOGl3NDZlaGJlVG0za0JZd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZURVRNQkVHQTFVRUF4TUthM1ZpWlhKdVpYUmxjekFlRncweU16QTJNVFV3T0RNNE1EQmFGdzB5TkRBMgpNVFF3T0RNNE1EQmFNRjB4RlRBVEJnTlZCQW9UREhONWMzUmxiVHB1YjJSbGN6RkVNRUlHQTFVRUF4TTdjM2x6CmRHVnRPbTV2WkdVNmFYQXRNVEF0TVRBdE1UWXRNVEl4TG1Gd0xXNXZjblJvWldGemRDMHlMbU52YlhCMWRHVXUKYVc1MFpYSnVZV3d3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVQrdS9FMHZrTzUwMktMaEtXUgpnWldXdUVSaVp4VWVIcUg0S0FEVmJUbU8vS0VVUnF3czd2SHltbVc1RHBlczRVcllGT3RUU2lvY0ZjeDFoeUUvClJyMk9vNEc0TUlHMU1BNEdBMVVkRHdFQi93UUVBd0lGb0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREFUQU0KQmdOVkhSTUJBZjhFQWpBQU1CMEdBMVVkRGdRV0JCVHBzeTBFdENkLzhmUEwzeTBUQWx4eTdpcm1XVEFmQmdOVgpIU01FR0RBV2dCUUhaeHREdnlzbEhYZURHaTY2SHNpV0VDb0cvakJBQmdOVkhSRUVPVEEzZ2k5cGNDMHhNQzB4Ck1DMHhOaTB4TWpFdVlYQXRibTl5ZEdobFlYTjBMVEl1WTI5dGNIVjBaUzVwYm5SbGNtNWhiSWNFQ2dvUWVUQU4KQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBTDhSQUlUM2JUZnRuWmwyUWhhTWlkRUdBWkRlbXYvVmhCVU9SMVdldQp5TGsvVEZCMFBTMkNqQjByVkc1blVTc21pK2VIa0huaE9pMEtFOGFmWVkzUi9SMWZCZnZDVEs2Q3JvdjM2OTBaCnV4U2dESklEeUhBSEk3YjNJTzhsVnJTd3J6VFphQUtZMytPNTA1U1FpYmNUY1VMNGk4UXJoWkZod1dpSGdhRUcKNTJvbkFkWVl0RUtBc3NBbGJXTWpKMnhZaW80M25nQmVsaGtUTzNFOFJhVmlzNDkwbllIZjRLUkdETDl0SytlUwpzdXpMYzZ0M1UwTU1NcFUzcWthYXl3cUg0ckdJMkVYdC8veTQ0WU1kVy8vSk5WYzdFYk1GaHR4ZW9BUVUxdjFiCmVNTGdBRmQzOHEyYzBER3NCZlJXQ21YV2pibCs2RWxVQ1NYeXpGbks4Mm1pcFE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==",
"conditions": [
{
"lastTransitionTime": "2023-06-15T08:43:13Z",
"lastUpdateTime": "2023-06-15T08:43:13Z",
"message": "Auto approving self kubelet server certificate after SubjectAccessReview.",
"reason": "AutoApproved",
"status": "True",
"type": "Approved"
}
]
}
}
<Pending 상태의 csr 상태정보>
kubectl get csr csr-not-ok -o json
Copy
{
"apiVersion": "certificates.k8s.io/v1",
"kind": "CertificateSigningRequest",
"metadata": {
"creationTimestamp": "2023-06-15T09:08:51Z",
"generateName": "csr-",
"name": "csr-7rnjv",
"resourceVersion": "255226",
"uid": "37395e40-caef-4d21-8ff2-1f132c5b040b"
},
"spec": {
"extra": {
"accessKeyId": [
"ASIA5ISTH5xxxxxx"
],
"arn": [
"arn:aws:sts::xxxx:assumed-role/devops-role/i-xxxx"
],
"canonicalArn": [
"arn:aws:iam::9117813xxxxxx:role/devops-role"
],
"principalId": [
"AROA5ISTH5Mxxxx"
],
"sessionName": [
"i-07c45ea1exxxxx"
]
},
"groups": [
"system:masters",
"system:authenticated"
],
"request": "LS0tLS1xxxxxURSBSRVFVRVNULS0tLS0KTUlJQmFqQ0NBUkFDQVFBd1hERVZNQk1HQTFVRUNoTU1jM2x6ZEdWdE9tNXZaR1Z6TVVNd1FRWURWUVFERXpwegplWE4wWlcwNmJtOWtaVHBwY0MweE1DMHhNQzB4TmkwNU15NWhjQzF1YjNKMGFHVmhjM1F0TWk1amIyMXdkWFJsCkxtbHVkR1Z5Ym1Gc01Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRVo4SVNROFdwN0dkYjBpdjIKVGpSNkdBM0dxc1NCVXVDalllb0FqVWM2UmhSMUdLNDZrWEE4RW1lOUZQc0hTRWlZblZZcTU5Sk1BMnJHOWYyeQpPc25kSjZCU01GQUdDU3FHU0liM0RRRUpEakZETUVFd1B3WURWUjBSQkRnd05vSXVhWEF0TVRBdE1UQXRNVFl0Ck9UTXVZWEF0Ym05eWRHaGxZWE4wTFRJdVkyOXRjSFYwWlM1cGJuUmxjbTVoYkljRUNnb1FYVEFLQmdncWhrak8KUFFRREFnTklBREJGQWlFQXhWWUFrcVJCbFpKOEdjbmNhd2h3aWw5VE1ld3lrZnhaMVl6ZEk3dTZoeW9DSUZTawprZFdZN2MrUW5VaXVDZHhIUEdlU1czdCthbytmRER6N1JEUjB2VStTCi0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=",
"signerName": "kubernetes.io/kubelet-serving",
"uid": "aws-iam-authenticator:xxxx:AROA5ISTH5MDxxxxx",
"usages": [
"digital signature",
"key encipherment",
"server auth"
],
"username": "kubernetes-admin"
},
"status": {}
}
확인 결과 인증서의 내용은 모두 동일 하다
다른 점은 아래와 같다.
Copy pending
"usages": [
"digital signature",
"key encipherment",
"server auth"
],
"username": "kubernetes-admin"
-------------------------------------------------------------------------------
issued , aprover
"usages": [
"digital signature",
"key encipherment",
"server auth"
],
"username": "system:node:ip-10-10-16-121.ap-northeast-2.compute.internal"
현상은 pending이 걸리는 csr은 devops-role로 만든 node의 것이고 issued , approver 로 잘 처리가 된 csr은 신규로 만든 iam role 정도의 차이밖에 없었다.
당연 하겠지만 두 role의 policy는 최대한 동일하게 셋팅 하였다.
그럼 여기서 부터 나오는 의문점이 몇 가지 생긴다.
role 외에는 같은 yaml파일로 install 하였는데 왜 csr의 username이 다른 것일까?
같은 policy의 role을 사용 하였는데 왜 csr에서 이슈가 생긴 것일까?
하나씩 풀어보자
💡 Amazon EKS 클러스터를 생성할 경우 클러스터를 생성하는 [IAM 보안 주체](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html)에게는 Amazon EKS 제어 영역의 클러스터 역할 기반 액세스 제어(RBAC) 구성에 `system:masters` 권한이 자동으로 부여됩니다. 이 보안 주체는 표시되는 구성에 나타나지 않으므로 클러스터를 원래 생성한 보안 주체를 추적해야 합니다. 추가 IAM 보안 주체에 클러스터와 상호 작용할 수 있는 기능을 부여하려면 Kubernetes 내에서 `aws-auth` `ConfigMap`을 편집하고 `aws-auth` `ConfigMap`에 지정하는 `group`의 이름으로 Kubernetes `rolebinding` 또는 `clusterrolebinding`을 생성해야 합니다.
사실 이 문구도 많이 봤었지만 그렇게 크게 신경을 쓰고 있지 않았고 결국 이 문제로 인하여 이슈가 발생 되었다고 봐도 무방하다. 이에 원인파악에 시간을 많이 소모 하였고 문제를 찾지 못하고 있다가 우연히 원인을 찾게 되었다.
당시 devops 팀은 aws sso로 login을 한 뒤에 devops-role 을 assume 하여 클러스터를 생성한 상황 이었다. 그러다 eks & k8s 구축을 위해서 테스트 겸 다수의 cluster를 생성 & 삭제를 진행 하였고
우연히 configmap 에 등록이 안된 상태에서도 kubectl get pods 가 동작 되는 현상을 발견 하였다.
k get configmaps -n kube-system aws-auth -o yaml
Copy apiVersion: v1
data:
mapRoles: |
- groups:
- system:masters
- system:bootstrappers
- system:nodes
rolearn: arn:aws:iam::xxxxxx:role/eksFullAccessRole
username: system:node:{{SessionName}}
#username: system:node:{{EC2PrivateDNSName}}
- groups:
- system:masters
- system:bootstrappers
- system:nodes
rolearn: arn:aws:iam::xxxxxxxxx:role/AWSReservedSSO_xxxx_devops_1c74128xxxx
username: system:node:{{SessionName}}
위의 configmap을 보면 devops-role이 없는 상태임에도 불구하고 api 동작에 이상이 없었다.
그러고 원인을 찾던 도중 whoami라는 툴을 찾았다. 바로 시험 해보자
aws sts get-caller-identity |jq
Copy {
"UserId": "AROA5ISTH5xxxxxxx:xxxx@xxxxxx.co.kr",
"Account": "91178xxxxx",
"Arn": "arn:aws:sts::9117xxx:assumed-role/AWSReservedSSO_xxxxd_devops_xxxxx"
}
> kubectl rbac-tool whoami
{Username: "system:node:xxxxxx.co.kr",
UID: "aws-iam-authenticator:9117xxx:AROA5ISTH5Mxxxx",
Groups: ["system:masters",
"system:bootstrappers",
"system:nodes",
"system:authenticated"],
Extra: {accessKeyId: ["ASIA5Ixxxx"],
arn: ["arn:aws:sts::9117xxxxx:assumed-role/AWSReservedSSO_xxxx_devops_xxx3bb9822e/dorian@.co.kr"],
canonicalArn: ["arn:aws:iam::9117xxxxx:role/AWSReservedSSO_xxxx_devops_1c74128b3bb9822e"],
principalId: ["AROAxxxDMSX3GGZA4"],
sessionName: ["dorian.kim@xxx.co.kr"]}}
aws sts get-caller-identity |jq
Copy {
"UserId": "AROA5ISTxxxxxVQHL:devops-session",
"Account": "911xxxx",
"Arn": "arn:aws:sts::9117xxxx:assumed-role/devops-role/devops-session"
}
> kubectl rbac-tool whoami
```json
{Username: "kubernetes-admin",
UID: "aws-iam-authenticator:9xxx110:AROA5ISTH5xxxxVQHL",
Groups: ["system:masters",
"system:authenticated"],
Extra: {accessKeyId: ["ASIA5ISTH5MDNL5UZ3KW"],
arn: ["arn:aws:sts::911xxx10:assumed-role/devops-role/devops-session"],
canonicalArn: ["arn:aws:iam::911xxxx0:role/devops-role"],
principalId: ["AROA5IxxxxxxVQHL"],
sessionName: ["devops-session"]}}
내가 어떤 user로 접근 하고 있는지 상세 정보가 출력이 된다.
비교를 해 보면 Username: "kubernetes-admin” 의 원인과 configmap에 등록이 되어 있지 않은 role도 Groups: ["system:masters", "system:authenticated"] 권한을 부여
받아 api 동작이 잘 되었던 것이다.
참고로 eks생성자를 확인 하려면 aws cloud trail 을 확인 하자
일단 첫 번째 의문은 해소 되었다.
그럼 두번째 의문도 풀어보자
username과 csr은 무슨관계 일까?
일단 helm 으로 apache를 대충 설치 한 뒤에 pod 정보를 조금 살펴보자
Copy k get po apache-devopsrole-certm1-6d85486d-zpr6r -o yaml | vi -
여러가지 설정이 있겠지만 먼저 봐야 할 것은 두 가지 이다.
Copy volumes:
- name: kube-api-access-w8q5s
projected:
defaultMode: 420
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace
-------------------------------------------------------------------
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: kube-api-access-w8q5s
readOnly: true
위의 설정은 k8s-api에서 인증서를 생성하고 생성한 인증서 secrtet에 보관 이후 node(kublet)가
볼륨 마운트를 하여 pod에도 동일한 인증서로 서명 하여 tls 통신을 시도 하기 위한 설정이다.
실제 node 서버에 ssh로 접속 해서 인증서가 제대로 있는지 확인해보자
Copy [root@ip-10-xx-xx-13 kube-api-access-58vk5]# pwd
/var/lib/kubelet/pods/c2a616be-11a7-465b-93ae-609dffb18a51/volumes/kubernetes.io~projected/kube-api-access-58vk5
[root@ip-10-xx-xx-13 kube-api-access-58vk5]# ls
ca.crt namespace token
그럼 인증서도 완벽하게 다 있는데 kubernetes-api 놈이 승인을 안해주는 이유는 뭘까?
Copy
1. 신뢰 배포: kubelet에 대한 연결을 종료하려면 API 서버에서 서명된 인증서를 유효한 인증서로 인식해야 합니다. CA 번들은 다른 방법으로 배포되지 않습니다.
2. **허용되는 주제 - 조직은 정확히, 일반 이름은 ""로 시작합니다.**`["system:nodes"]system:node:`
3. 허용된 x509 확장 - 키 사용 및 DNSName/IPAddress subjectAltName 확장을 적용하고 EmailAddress 및 URI subjectAltName 확장은 다른 확장을 삭제합니다. 하나 이상의 DNS 또는 IP subjectAltName이 있어야 합니다.
4. 허용된 키 사용 - 또는 .`["key encipherment", "digital signature", "server auth"]["digital signature", "server auth"]`
5. 만료/인증서 수명 - 이 서명자의 kube-controller-manager 구현의 경우, 최소값으로 설정 옵션 또는 CSR 객체의 필드(지정된 경우)를 선택합니다.`-cluster-signing-durationspec.expirationSeconds`
6. CA 비트 허용/허용되지 않음 - 허용되지 않습니다.
허용되는 주제 - 조직은 정확히, 일반 이름은 ""로 시작합니다.["system:nodes"]system:node:
의 조건이 맞지 않아 결국 승인이 되지 않는 것으로 보인다.
그래서 어떻게 하라고?
cluster 생성자의 role과 다른 role로 node를 구성 하세요, 메뉴얼에 써 있습니다.
마무리
삽질을 하긴 했지만 덕분에 IAM 으로 CSR을 발급 받는 과정과 원리를 알게 되어 유익한 경험을 한것 같다.
Last updated 4 months ago