앞서 작성한 글인 인증/인가에 대하여.. 와 OIDC(로컬환경실습)에서 인증/인가와 `OIDC`의 개념에 대해서는 충분히 알아보았습니다.
하지만 앞에서 진행한 실습이 local 환경이다보니 실무에서 사용하듯이 외부 `idP`를 통한 인증/인가가 불가능했는데요. 이번 포스팅에서는 `AWS EKS` 환경에서 `OIDC`를 설정하여 사용자(개발자)가 `kubectl` 명령어로 `EKS Cluster`에 접근할 때에 허용된 리소스에 접근할 수 있는 실습을 진행해보겠습니다.
실습
실습 환경 다이어그램

전체적인 다이어그램은 위와 같습니다.
1. `kubectl get nodes` 실행
2. `kubelogin`이 `Dex`에 `Authorization Request` 전송 (`client_id`, `redirect_uri`, `scope`)
3. `Dex`가 `GitHub OAuth`로 리다이렉트
4. 개발자가 `GitHub` 로그인 & 권한 승인
5. `Dex`가 `Authorization Code` + `org/team` 정보 수신
6. `Dex`가 `ID Token(JWT)` 발급 -> `sub`, `email`, `groups=[org:team]` 포함
7. `kubelogin`이 `Bearer Token`을 포함해 `EKS API Server`에 요청
8. `EKS`가 `OIDC Discovery` (`/.well-known/openid-configuration`) 조회
9. `JWKS`(공개키) 수신
10. `Token` 서명 검증
11. `groups=[org:team]` 정보를 `RBAC`에 전달
12. `ClusterRoleBinding` 조회
13. 권한 확인 완료
14. 응답 반환
15. `kubectl get nodes` 결과 출력
AWS VPC 및 EKS Cluster 생성

VPC는 서울 리전에 `192.168.0.0/16` 대역으로 생성하며, 2개 가용 영역(2a, 2c)에 Public과 Private 서브넷을 각각 구성하고, public subnet에 ALB를 배치했습니다.
EKS는 1.32 버전을 사용하였고, 워커노드는 `t3.medium` 2대로 구성하였습니다.
kubeconfig 등록
aws eks update-kubeconfig --region ap-northeast-2 --name temp-eks
생성된 cluster 확인
kubectl get po -A

kubectl get node

`pod 조회` 및 `node 조회` 명령어를 통해 `EKS cluster`가 생성되었는지 확인합니다.
AWS Load Balancer Controller 설치
`Dex`는 외부에서 `HTTPS`로 접근 가능해야 합니다. 그렇기 떄문에 `Load Balancer Controller`를 통해 `ALB Ingress`를 생성하여 `Dex`를 외부에 노출합니다.
Helm repo 추가
helm repo add eks https://aws.github.io/eks-charts
helm repo update
설정 파일
serviceAccount:
create: true
name: aws-load-balancer-controller
annotations:
eks.amazonaws.com/role-arn: # AWS IAM ARN(iara)
배포
helm upgrade --install aws-load-balancer-controller eks/aws-load-balancer-controller \
--namespace kube-system \
--values values.yaml \
--wait \
--timeout 3m

배포 확인
kubectl get po -n kube-system

Github OAuth 설정
Github Organization 생성 및 Team 생성

OIDC 실습을 위해 인증으로 활용할 Github Organization을 생성하고, 권한에 따른 인가 실습을 위해 `devops` 팀과 `backend` 팀을 생성합니다. (현재는 `devops`팀으로 설정했습니다.)
Github OAuth App 생성

github organization에서 `/settings/applications`에 접근한 뒤 OAuth APP을 생성합니다.
이때, `Authorization callback URL` 에 접근할 `Dex`의 `URL`을 입력합니다. (`redirectURL`와 일치해야 합니다.)

생성이 완료되면 `ClientID`와 `ClientSecretID`를 얻을 수 있습니다.
Github OAuth ClientID와 ClientSecretID도 다시 사용하니 저장해두세요!
Dex 배포
secret 및 pod 배포
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: dex-github-secret
namespace: dex
type: Opaque
stringData:
GITHUB_CLIENT_ID: # 실제 GITHUB OAuth CLIENT ID
GITHUB_CLIENT_SECRET: #실제 GITHUB OAuth CLIENT SECRET ID
먼저 dex용 secret을 먼저 생성합니다. 여기에는 위에서 생성한 Github OAuth의 clientID와 ClientSecretID를 넣어줍니다.
config:
issuer: "https://dex.lakescript.net"
storage:
type: kubernetes
config:
inCluster: true
web:
http: 0.0.0.0:5556
oauth2:
skipApprovalScreen: true
responseTypes:
- code
connectors:
- type: github
id: github
name: GitHub
config:
clientID: $GITHUB_CLIENT_ID
clientSecret: $GITHUB_CLIENT_SECRET
redirectURI: "https://dex.lakescript.net/callback"
orgs:
- name: eks-oidc
staticClients:
- id: kubectl
name: kubectl
public: true
redirectURIs:
- http://localhost:8000
- http://localhost:18000
enablePasswordDB: false
# GitHub OAuth 자격증명은 Secret으로 주입
envFrom:
- secretRef:
name: dex-github-secret
# ALB를 통해 외부 노출 → ClusterIP로 변경
service:
type: ClusterIP
ports:
http:
port: 5556
# ALB Ingress
ingress:
enabled: true
className: alb
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS": 443}]'
alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
alb.ingress.kubernetes.io/healthcheck-path: /healthz
hosts:
- host: dex.lakescript.net
paths:
- path: /
pathType: Prefix
`Dex` 의 공식 helm을 참고하여 `values.yaml`을 작성하는데, 위에서 생성한 `secret`을 참고하여 `GithubOAuth`에서 발급받은 `ClientID`와 `SecretID`를 가져오게 됩니다.
또한 `Dex issuer URL`은 반드시 `HTTPS`여야 합니다. `EKS`가 `OIDC Provider`를 등록할 때 `issuer URL`의 `TLS` 인증서를 검증하기 때문에, `ACM`에서 `dex.lakescript.net`에 대한 인증서를 발급받아 `ARN`에 지정합니다. (후에 `Route53`에서 해당 경로에 대한 `record`를 추가해주셔야 합니다.)
dex 배포 확인
kubectl get po,secret,ing -n dex
생성된 `pod`와 `secret`, `ingress`를 확인합니다.

브라우저에서 dex 접근

위와 같이 생성한 `ingress`으로 접근했을 때 정상적으로 접근이 되는 것을 확인하실 수 있습니다.
EKS 설정
EKS OIDC 설정
`Dex` 배포를 완료했고, 접근까지 확인했으면 이제 `EKS Cluster`에 `OIDC` 설정을 진행합니다.
variable "oidc_client_id" {
type = string
default = "kubectl"
description = "Dex static client ID"
}
resource "aws_eks_identity_provider_config" "dex" {
cluster_name = var.cluster_name
oidc {
identity_provider_config_name = "dex"
issuer_url = "https://dex.lakescript.net"
client_id = var.oidc_client_id
username_claim = "email"
username_prefix = "oidc:"
groups_claim = "groups"
groups_prefix = "oidc:"
}
}
위의 `tf` 값을 통해 `Dex`용 `EKS OIDC Identity Provider`를 등록합니다.

그 후 `terraform apply` 하게 되면 위와 같이 정상적으로 `EKS`에 `OIDC` 설정이 완료된 것을 확인하실 수 있습니다.
RBAC 설정
이제 `Github`의 팀별로 권한을 다르게 설정하기 위해 `RBAC`를 설정하도록 하겠습니다.
# devops 팀
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: oidc-github-team-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: Group
name: "oidc:eks-oidc:devops"
apiGroup: rbac.authorization.k8s.io
`devops` 팀의 경우 `admin` 권한을 부여하는 `RBAC`를 생성합니다.
# backend 팀
apiVersion: v1
kind: Namespace
metadata:
name: backend
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
namespace: backend
rules:
- apiGroups: ["", "apps", "batch"]
resources: ["pods", "pods/log", "deployments", "services", "configmaps", "replicasets"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: backend-team-binding
namespace: backend
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: developer
subjects:
- kind: Group
name: "oidc:eks-oidc:backend"
apiGroup: rbac.authorization.k8s.io
`backend` 팀의 경우 `backend` 네임스페이스에서만 조회할 수 있는 권한만 부여하도록 `RBAC`를 생성합니다.
kubeconfig 생성
일반적으로 기본 `kubeconfig`는 `AWS IAM`을 통해 인증합니다. 하지만 OIDC로 인증하려면 `Dex issuer`와 `kubelogin`을 사용하는 별도의 `kubeconfig`가 필요합니다.
kubelogin 설치에 대해서는 이전 블로그 글(링크) 참고해주세요.
CLUSTER_NAME="temp-eks"
REGION="ap-northeast-2"
OIDC_ISSUER="https://dex.lakescript.net"
CLIENT_ID="kubectl"
OUTPUT="oidc-kubeconfig.yaml"
먼저 원활하게 명령어를 실행할 수 있게 환경변수를 등록합니다.
# EKS 클러스터 정보 조회
EKS_API=$(aws eks describe-cluster --name ${CLUSTER_NAME} --region ${REGION} \
--query "cluster.endpoint" --output text)
EKS_CA=$(aws eks describe-cluster --name ${CLUSTER_NAME} --region ${REGION} \
--query "cluster.certificateAuthority.data" --output text)
`EKS API Server` 주소와 `CA` 인증서를 자동으로 조회하여 각각 `EKS_API`와 `EKS_CA` 변수에 저장합니다.
cat > oidc-kubeconfig.yaml << EOF
apiVersion: v1
kind: Config
clusters:
- name: ${CLUSTER_NAME}-oidc
cluster:
server: ${EKS_API}
certificate-authority-data: ${EKS_CA}
users:
- name: oidc-user
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: kubectl
args:
- oidc-login
- get-token
- --oidc-issuer-url=${OIDC_ISSUER}
- --oidc-client-id=${CLIENT_ID}
- --oidc-extra-scope=groups
- --oidc-extra-scope=email
contexts:
- name: ${CLUSTER_NAME}-oidc
context:
cluster: ${CLUSTER_NAME}-oidc
user: oidc-user
current-context: ${CLUSTER_NAME}-oidc
EOF
그 후 지정한 변수들을 인증에 사용하기 위한 `OIDC Kubeconfig` 파일을 생성합니다.
인증/인가 확인
kubeconfig 환경변수 등록
export KUBECONFIG=~/.kube/config:oidc-kubeconfig.yaml
실습을 위해 임시로 `KUBECONFIG` 환경변수에 위에서 생성한 `oidc-kubeconfig`를 지정합니다.
kubectl config use-context temp-eks-oidc
이때 `aws eks update-kubeconfig`로 만든 기본 `context` 이름이 `temp-eks` 이기 때문에 원활한 실습을 위해 `temp-eks-oidc`로 `context`를 지정합니다.
kubectl 명령 실행
kubectl get po
이제 `kubectl` 명령어를 실행합니다.

위와 같이 인증을 하는 브라우저가 보이게 됩니다.
time=2026-04-02T06:39:37.760Z level=INFO msg="login successful" connector_id=github username=lake preferred_username=leehosu email=hosu4549@gmail.com groups=[eks-oidc:devops[] request_id=ba6f508d-7b94-442d-bd08-a089b1cf48a3
인증을 완료하고 dex의 로그를 확인하면 위와 같이 확인할 수 있습니다.
groups_prefix("oidc:") + GitHub Org("eks-oidc") + Team("devops")
→ "oidc:eks-oidc:devops"
즉, `devops` 팀으로 매핑된 것을 확인할 수 있습니다.

그 후 `kubectl` 을 통해 조회가 완료된 것을 알 수 있습니다.

추가적으로 pod를 생성해봤을 때 현재 devops 팀은 admin 권한이기 때문에 pod 생성도 완료되는 것을 확인할 수 있습니다.
팀 변경

이제 backend 팀으로 팀을 변경합니다.
rm -rf ~/.kube/cache/oidc-login/
그 후 `kubelogin`이 토큰을 캐싱하고 있어서 기존 토큰에는 변경 전 그룹 정보가 담겨 있기에 위의 명령어를 통해 캐시를 지우고 다시 인증합니다.
kubectl get po
다시 pod 조회 명령을 실행해보겠습니다.

이번엔 인가 결과가 실패했다는 `Forbidden`에러가 발생한 것을 확인할 수 있습니다.
time=2026-04-02T06:47:51.235Z level=INFO msg="login successful" connector_id=github username=lake preferred_username=leehosu email=hosu4549@gmail.com groups=[eks-oidc:backend[] request_id=391a5247-5563-4b53-9841-0c30071e19b1
그 후 `Dex` 로그를 확인해보면 아까와 달리 `backend` 팀으로 매핑된 것을 알 수 있습니다.
kubectl get po -n backend

`backend` 네임스페이스 내의 pod 목록을 조회하는 명령어는 정상적으로 실행되는것을 알 수 있습니다.
kubectl run nginx --image=nginx -n backend

추가로 `backend` 네임스페이스에서도 `create` 되지 않는 것을 확인할 수 있습니다. (의도한대로!)
'데브옵스 이야기 > Kubernetes' 카테고리의 다른 글
| kubernetes 인증/인가 - OIDC (로컬 환경 실습) (0) | 2026.03.13 |
|---|---|
| 쿠버네티스 인증인가에 대하여... (0) | 2026.03.06 |
| 쿠버네티스 장애 원인 분석을 Slack으로 받아보기 (feat. K8sGPT) (0) | 2026.01.10 |
| stakater/Reloader 사용시 configmap, secret 변경할 시에 감지 안되는 이슈 (0) | 2025.12.22 |