일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- c
- 기계학습#인공지능#AI#ML
- https
- Ai
- 쿠버네티스 #도커 #MSA #Istio #Service Mesh
- rest proxy
- 1*1
- Kubernetes
- rolebinding
- 컴파일러
- NFA #DFA #컴파일러 #Lexical
- Linear Regression #AI #기계학습 #인공지능 #Lasso #Ridge
- Datamining
- 인공지능 #AI #ML #기계학습 #Lasso #Ridge #Regularization #Linear Regression
- datascience
- linux
- dadtascience
- k9s
- embedded rest proxy
- Data # datamining #datascience #AI #ML
- 알고리즘
- CKA
- ML
- OS
- xff
- TLS
- AI #ML #Data #datascience #data mining
- k8s
- Linear Regression #AI #ML #기계학습 #인공지능 #선형회귀
- dadtamining
- Today
- Total
solve-my-curiosity
TLS handshake + ServiceAccount 본문
목적 : TLS 핸드쉐이크 과정을 통해 https 개념을 알아보고 더 나아가 k8s에서 ServiceAccount의 역할을 알아보자.
TLS 핸드쉐이크는 TCP 3-way handshake를 한 후 TLS handshake를 하고 HTTPS통신을 하는 과정이다.
TCP 3-way handshake는 SYN / SYN+ACK / ACK 이 3과정으로 알 수 있고
TLS handshake는
1) Client Hello
2) Server Hello (+ cert.pem)
3) 인증서 검증 (ca.crt)
4) 키 교환 (공개키 암호화)
5) 세션키 설정
6) Secure 통신 시작
이 과정으로 이루어진다.
2)에서 서버가 주는 cert.pem은 서버의 인증서이고
3)에서 클라이언트의 ca.crt는 CA기관의 공개키이다. ca.crt로 cert.pem을 검증해보는 것이고 그 안에서 서버의 공개키를 꺼내서
4) 클라이언트의 대칭키를 서버의 공개키로 암호화 후 보낸다.
5) 서버는 서버의 비밀키로 클라이언트의 대칭키를 복호화 하고 세션키를 설정하게 된다.
이것이 TLS 핸드쉐이크라고 할 수 있다.
하지만 이건 구식 방식이고
💡 참고: 현대적 TLS에서는
- 키는 서로 협상해서 공유된 비밀로 만든다 (ECDHE)
- 서버의 cert.pem은 인증만 한다 (진짜 서버 맞는지)
- 서버의 공개키로는 직접 암호화 안 한다
라고 한다...
이제는 k8s의 serviceaccount에 대해 알아보자
serviceaccount의 의미를 계속 헷갈렸었는데 한마디로 말하면 `Pod에게 인격을 주는 것(?)`라고 생각할 수 있을 것 같다.
User가 kube API 서버에 인증을 하고 요청을 하는 것인데 그것이 User가 Pod로 변한다면
그때 부여하는 것이 serviceaccount이기 때문이다.
이제 실습을 해보자
NS : test-ns이다.
1) serviceaccount 생성
k create serviceaccount my-sa
2) Pod 생성 (serviceAccountName을 적어주는게 포인트이다)
apiVersion: v1
kind: Pod
metadata:
name: curl-test-pod
namespace: test-ns
spec:
serviceAccountName: my-sa
containers:
- name: curl
image: curlimages/curl
command: ["sleep", "3600"]
3) Pod 안에 접속해서 API 서버에 curl 날려보기
k exec curl-test-pod -it -- sh
~ $ TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
~ $ cat /var/run/secrets/kubernetes.io/serviceaccount/token
eyJhbGciOiJSUzI1NiIsImtpZCI6ImtHd0hEc2doZGo1ZWNOX2psaFI0RFVsTzE2eEFscG9DV0c0TVhieGhiREkifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzgyMjE4OTc3LCJpYXQiOjE3NTA2ODI5NzcsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwianRpIjoiNzc3NDAyZTctYWRkYy00MTEzLWE3MGEtNzMwYjhhMGI2ZDFmIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJ0ZXN0LW5zIiwibm9kZSI6eyJuYW1lIjoibG9jYWwtY2x1c3Rlci1jb250cm9sLXBsYW5lIiwidWlkIjoiMTE4YjUwYmYtMzg0Ni00Mzk0LWJmZTMtMTg2YzcwZWEwNWFlIn0sInBvZCI6eyJuYW1lIjoiY3VybC10ZXN0LXBvZCIsInVpZCI6IjY1N2RjZmMwLTE1OTYtNDdlMC05NDAzLTQ3OWM4NmIxYThjNCJ9LCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoibXktc2EiLCJ1aWQiOiJhOTQ5ZmU2NC0xYmM2LTRlYzAtOTM5Mi05YTQzNWE0Y2FjMjEifSwid2FybmFmdGVyIjoxNzUwNjg2NTg0fSwibmJmIjoxNzUwNjgyOTc3LCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6dGVzdC1uczpteS1zYSJ9.A5k-RYz3OMxMFjwtKCKHBOFKz_2PrhXQGdjIQwzUg0op4b4e7AmIjddCrubKl_8WjorfVhAkaMd2XkCKv_S6CsdQpfgIwxdsn2GcZ6vyHEWiiKcBFNnoZIumt3wBZv6Eg0HKuR0gSOY3qdzwDcIuvAfOF2jIMPKR7RpC8-_MN7fCYdp1zxMMyxQWumc8974yrWqUEFjq2uQKKjnRgEqP1Nz0NYUzcXLNUjMbniemh_nbGeR97Etu7ktq2U04pRMnQJEg3qhVkoBwAxGk3AGRyeWkKUH-1Xzh3-vwVao4-PykEiacylgBfP6UvVHu5WSK4Q8jRf_r43TtnhHfBnC55A~ $ echo $KUBERNETES_SERVICE_HOST
10.96.0.1
~ $ curl -sSk -H "Authorization: Bearer $TOKEN" \
> https://$KUBERNETES_SERVICE_HOST/api/v1/pods
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "pods is forbidden: User \"system:serviceaccount:test-ns:my-sa\" cannot list resource \"pods\" in API group \"\" at the cluster scope",
"reason": "Forbidden",
"details": {
"kind": "pods"
},
"code": 403
message를 잘 보면 나오지만 serviceaccount:my-sa는 pods를 나열할 수 없다 403 에러 뜬다. 이렇게 나온다.
serviceaccount를 부여했지만 그 serviceaccount에 아무것도 권한을 주지 않았기 때문에 에러가 뜬다.
이제는 권한을 주자.
4) Role 생성
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: test-ns
name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]
Role을 만들었으니 이제 이 Role을 serviceaccount에 부여하자
5) RoleBinding 생성
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods-binding
namespace: test-ns
subjects:
- kind: ServiceAccount
name: my-sa
namespace: test-ns
roleRef:
kind: Role #this must be Role or ClusterRole
name: pod-reader
apiGroup: rbac.authorization.k8s.io
Rolebinding을 통해서 ServiceAccount와 Role을 매핑시켜주었다.
6) 다시 되는지 확인
https://$KUBERNETES_SERVICE_HOST/api/v1/namespaces/test-ns/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "1129322"
},
"items": [
{
"metadata": {
"name": "curl-test-pod",
"namespace": "test-ns",
"uid": "657dcfc0-1596-47e0-9403-479c86b1a8c4",
"resourceVersion": "1128647",
"creationTimestamp": "2025-06-23T12:49:37Z",
"annotations": {
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"curl-test-pod\",\"namespace\":\"test-ns\"},\"spec\":{\"containers\":[{\"command\":[\"sleep\",\"3600\"],\"image\":\"curlimages/curl\",\"name\":\"curl\"}],\"serviceAccountName\":\"my-sa\"}}\n"
},
~~~~~~
"startTime": "2025-06-23T12:49:37Z",
"containerStatuses": [
{
"name": "curl",
"state": {
"running": {
"startedAt": "2025-06-23T12:49:44Z"
}
},
"lastState": {},
"ready": true,
"restartCount": 0,
"image": "docker.io/curlimages/curl:latest",
"imageID": "docker.io/curlimages/curl@sha256:9a1ed35addb45476afa911696297f8e115993df459278ed036182dd2cd22b67b",
"containerID": "containerd://b28cf33345df3545fb88c11f0d9ce1c682eda86ec3c775cb320385dfddd906f2",
"started": true
}
],
"qosClass": "BestEffort"
}
}
]
이렇게 잘 되었다.
여기서 알 수 있는 점은 Pod안의 Token을 이용한다는 점이고 kube API 서버의 위치가 자동으로 환경변수로 들어가있다는 점이다.
ServiceAccount를 사용하게 되면 Pod안에 Token이 /var/run/secrets/kubernetes.io/serviceaccount/token 안에 생기고
KUBERNETES_HOST / KUBERNETES_PORT 값들이 자동으로 박히게 된다.
경로 내용
/var/run/secrets/kubernetes.io/serviceaccount/token | 📌 ServiceAccount 토큰 (JWT 형식) |
/var/run/secrets/kubernetes.io/serviceaccount/ca.crt | 📌 API 서버의 CA 인증서 |
/var/run/secrets/kubernetes.io/serviceaccount/namespace | 📌 이 Pod가 속한 네임스페이스 |
그럼 이 ServiceAccount로 API 서버에 "무엇을 하려고" 통신을 하는걸까?
대답은 GPT가 너무 잘 대답해주어서 가져왔다.
1. 🔁 Controller나 Operator가 리소스를 감시할 때
예: ReplicaSet, Deployment, Custom Operator 등
- 컨트롤러는 "지금 있는 Pod 개수" 를 주기적으로 조회해서,
부족하면 새로 만들고, 많으면 삭제함 - 이때 API 서버에서 pods를 list/get/watch 해야 하니까
→ ServiceAccount가 필요함
2. 🧠 앱이 자기 주변 상태를 파악하려 할 때
예: 클러스터 내 다른 서비스가 몇 개 있는지 알고 싶을 때
- 서비스 디스커버리
- 메트릭 수집기 (Prometheus exporter, FluentBit)
- 모니터링 대상 찾기
→ Pod 목록을 읽어서 어떤 앱이 실행 중인지 확인함
→ pods를 list하거나 endpoints를 조회하는 권한이 필요함
3. 📦 CI/CD Agent가 리소스를 배포·관리할 때
예: ArgoCD, Tekton, Jenkins
- Pod 내부에서 Deployment를 생성하거나 삭제해야 함
- kubectl apply 하는 것처럼 실제 리소스를 API로 보냄
→ 이때도 ServiceAccount가 API를 호출함
→ 그래서 그 계정에 Role/ClusterRole을 연결해줘야 함
4. 🧪 애플리케이션 테스트/자기관리 목적
예:
- 스스로 “지금 내 Pod의 상태가 뭔지”, “내가 속한 네임스페이스의 자원은 어떤지” 확인
- 예: downwardAPI나 fieldRef로는 부족할 때
보면볼수록 k8s 진짜 잘 만든것 같다.
'K8S' 카테고리의 다른 글
Cert-Manager Mini Project (1) (2) | 2025.06.12 |
---|---|
X-Forwarded-For + Ingress(K8S) (0) | 2025.06.08 |
Kubernetes의 Log System 를 알아보자 (0) | 2025.06.01 |
인턴 트러블슈팅 후기 2 (2) | 2025.01.12 |
인턴 트러블슈팅 후기 1 (1) | 2025.01.08 |