Cluster Management
OrbStack
OrbStack · Fast, light, simple Docker & Linux
Say goodbye to slow, clunky containers and VMs. The fast, light, and easy way to run containers and Linux. Develop at lightspeed with our Docker Desktop alternative.
orbstack.dev
원활한 테스트를 위해 OrbStack을 설치해줍니다 (mac)
아래 실습에서는 도커 데스크탑 대신 OrbStack을 사용합니다.

네이티브 macOS 앱이며 Docker Desktop에 비해 CPU와 메모리 사용량이 적습니다.
아래는 공식 웹사이트의 Benchmark 입니다.

아래 실습간 로컬에서 컨테이너 ip로 직접 접근해야되는 부분이 있습니다.
OrbStack은 컨테이너 네트워크 대역 인터페이스를 macOS 시스템 네트워크에 직접 노출시켜줍니다.
kind 클러스터 생성 시 mac 로컬에서 접근 가능한 네트워크 인터페이스가 노출됩니다. (ex. bridge102)

따라서 포트포워딩 없이도 컨테이너 내부 서비스에 접근이 가능합니다.
그 외에도 https 기능, 쿠버네티스, 리눅스 등이 있습니다.
다만 Docker Desktop과 마찬가지로 개인용은 무료이나 상업용은 비용을 지불해야합니다.
테스트
실습을 위해 kind mgmt k8s와 ingress nginx, Argo CD를 배포합니다.
enable-ssl-passthrough 옵션을 통해 Argo CD가 tls 종료를 하도록합니다.
Argo CD tls 인증서 구성
https://argo-cd.readthedocs.io/en/stable/operator-manual/tls/#tls-certificates-used-by-argocd-serverhttps://argo-cd.readthedocs.io/en/stable/operator-manual/tls/
argocd-server는 기본적으로 네임스페이스 내 argocd-server-tls 라는 이름의 Secret tls.crt 와 tls.key로 사용합니다.
해당 방식은 공식문서에서도 권장하는 방식입니다.
- Secret 이름: argocd-server-tls (네임스페이스: argocd)
- 필드: tls.crt (인증서), tls.key (비밀키)
- Secret 타입: kubernetes.io/tls 또는 일반 Opaque여도 OK
- 자동 감지됨 (재시작 없이 적용됨)
kubectl create -n argocd secret tls argocd-server-tls \
--cert=/path/to/cert.pem \
--key=/path/to/key.pem
구버전으로는 argocd-server 였지만 지금은 사용되지 않습니다.
둘다 없으면 Argo CD가 자체 서명 인증서(Self-Signed) 를 생성해서 argocd-server secret에 저장합니다.
# kind k8s 배포
kind create cluster --name mgmt --image kindest/node:v1.32.8 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
labels:
ingress-ready: true
extraPortMappings:
- containerPort: 80
hostPort: 80
protocol: TCP
- containerPort: 443
hostPort: 443
protocol: TCP
- containerPort: 30000
hostPort: 30000
EOF
# NGINX ingress 배포
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
KUBE_EDITOR="nano" kubectl edit -n ingress-nginx deployments/ingress-nginx-controller
...
- --enable-ssl-passthrough
혹은
kubectl get deployment ingress-nginx-controller -n ingress-nginx -o yaml \
| sed '/- --publish-status-address=localhost/a\
- --enable-ssl-passthrough' | kubectl apply -f -
#
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout argocd.example.com.key \
-out argocd.example.com.crt \
-subj "/CN=argocd.example.com/O=argocd"
#
kubectl create ns argocd
# tls 시크릿 생성
kubectl -n argocd create secret tls argocd-server-tls \
--cert=argocd.example.com.crt \
--key=argocd.example.com.key
#
cat <<EOF > argocd-values.yaml
global:
domain: argocd.example.com
server:
ingress:
enabled: true
ingressClassName: nginx
annotations:
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
tls: true
EOF
# 설치 : Argo CD v3.1.9
helm repo add argo https://argoproj.github.io/argo-helm
helm install argocd argo/argo-cd --version 9.0.5 -f argocd-values.yaml --namespace argocd
# 도메인 설정
## macOS의 /etc/hosts 파일 수정
echo "127.0.0.1 argocd.example.com" | sudo tee -a /etc/hosts
cat /etc/hosts
## C:\Windows\System32\drivers\etc\hosts 관리자모드에서 메모장에 내용 추가
127.0.0.1 argocd.example.com
# 접속 확인
curl -vk https://argocd.example.com/
# 최초 접속 암호 확인
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d ;echo
38L2ZmXne7jIaRSZ
ARGOPW=<최초 접속 암호>
ARGOPW=YYpjg453yyKi4HdK
# argocd 서버 cli 로그인
argocd login argocd.example.com --insecure --username admin --password $ARGOPW
# 확인
argocd cluster list
argocd proj list
argocd account list
# admin 계정 암호 변경 : qwe12345
argocd account update-password --current-password $ARGOPW --new-password qwe12345
# Argo CD 웹 접속 주소 확인 : admin 계정 / qwe12345
open "http://argocd.example.com"
open "https://argocd.example.com"

dev/prd 배포
테스트를 위해 두 클러스터를 더 배포합니다.
kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* kind-mgmt kind-mgmt kind-mgmt
# 도커 네트워크 확인 : mgmt 컨테이너 IP 확인
docker network ls
docker network inspect kind | jq
# kind k8s 배포
kind create cluster --name dev --image kindest/node:v1.32.8 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 31000
hostPort: 31000
EOF
kind create cluster --name prd --image kindest/node:v1.32.8 --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 32000
hostPort: 32000
EOF
설치후 context를 변경해 보면서 잘 설치되었는지 확인합니다.
# 설치 후 확인
kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
kind-dev kind-dev kind-dev
kind-mgmt kind-mgmt kind-mgmt
* kind-prd kind-prd kind-prd
# mgmt k8s 자격증명 변경
kubectl config use-context kind-mgmt
kubectl config get-contexts
#
kubectl get node -v=6 --context kind-mgmt
kubectl get node -v=6 --context kind-dev
kubectl get node -v=6 --context kind-prd
cat ~/.kube/config
kubectl get pod -A --context kind-mgmt
kubectl get pod -A --context kind-dev
kubectl get pod -A --context kind-prd
# alias 설정
alias k8s1='kubectl --context kind-mgmt'
alias k8s2='kubectl --context kind-dev'
alias k8s3='kubectl --context kind-prd'
# 확인
k8s1 get node -owide
k8s2 get node -owide
k8s3 get node -owide
클러스터 등록
# 기본 cluster 확인
argocd cluster list
argocd cluster list -o json | jq
kubectl get secret -n argocd
kubectl get secret -n argocd argocd-secret -o jsonpath='{.data}' | jq
#
k8s2 get sa -n kube-system
k8s3 get sa -n kube-system
이제 Argo CD에 다른 k8s 클러스터를 등록합니다.
https://argo-cd.readthedocs.io/en/stable/operator-manual/cluster-management/
클러스터를 등록하기 전 ~/.kube/config 를 확인하면 클러스터 정보가
127.0.0.1:49440 과 같이 포트포워딩된 포트로 잡혀있는 것을 확인할 수 있습니다.

Argo CLI는 로컬에서 수행되기 때문에 로컬과 mgmt (ArgoServer) 모두 바라볼수있는 IP대역으로 설정되어야합니다.
docker network 를 통해 클러스터의 IP 대역을 확인합니다.
# docker network inspect kind | grep -E 'Name|IPv4Address'
"Name": "kind",
"Name": "mgmt-control-plane",
"IPv4Address": "192.168.97.2/24",
"Name": "prd-control-plane",
"IPv4Address": "192.168.97.4/24",
"Name": "dev-control-plane",
"IPv4Address": "192.168.97.3/24",
해당 대역은 컨테이너 대역이지만 처음 설치한 OrbStack은 로컬에 해당 대역으로 접근할 수 있는 인터페이스를 오픈시킵니다.
로컬에서 ping 을 시도하면 정상적으로 가는 것을 확인할 수 있습니다.

이제 vi ~/.kube/config 에서 kind-prd, kind-dev를 도커 네트워크에 설정된 대역으로 변경해줍니다.
각각 192.168.97.4:6443 192.168.97.3:6443 으로 변경합니다.
# dev/prd k8s 에 api server 주소 컨테이너 IP로 변경
cp ~/.kube/config ./kube-config.bak
vi ~/.kube/config
...
server: https://192.168.97.3:6443
name: kind-dev
...
server: https://192.168.97.4:6443
name: kind-prd
...
# 확인
kubectl get node -v=6 --context kind-dev
kubectl get node -v=6 --context kind-prd
ArgoCD에 다른 k8s 클러스터 등록
# dev k8s 등록
argocd cluster add kind-dev --name dev-k8s
WARNING: This will create a service account `argocd-manager` on the cluster referenced by context `kind-dev` with full cluster level privileges. Do you want to continue [y/N]? y
{"level":"info","msg":"ServiceAccount \"argocd-manager\" already exists in namespace \"kube-system\"","time":"2025-11-15T16:37:59+09:00"}
{"level":"info","msg":"ClusterRole \"argocd-manager-role\" updated","time":"2025-11-15T16:37:59+09:00"}
{"level":"info","msg":"ClusterRoleBinding \"argocd-manager-role-binding\" updated","time":"2025-11-15T16:37:59+09:00"}
{"level":"info","msg":"Using existing bearer token secret \"argocd-manager-long-lived-token\" for ServiceAccount \"argocd-manager\"","time":"2025-11-15T16:37:59+09:00"}
Cluster 'https://192.168.97.3:6443' added
#
k8s2 get sa -n kube-system argocd-manager
kubectl rolesum -n kube-system argocd-manager --context kind-dev
• [CRB] */argocd-manager-role-binding ⟶ [CR] */argocd-manager-role
Resource Name Exclude Verbs G L W C U P D DC
*.* [*] [-] [-] ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔
dev 클러스터에는 argo-manager 라는 서비스 어카운트가 생성됩니다.
이 SA가 클러스터롤바인딩을 통해 *.* (모든 API 그룹의 모든 리소스) 에 대해 거의 모든 권한을 가진것을 확인가능합니다.
CRB = ClusterRoleBinding
CR = ClusterRole
# 클러스터 자격증명은 시크릿에 저장하고, 해당 시크릿에 반드 시 argocd.argoproj.io/secret-type=cluster 라벨 필요
kubectl get secret -n argocd -l argocd.argoproj.io/secret-type=cluster
NAME TYPE DATA AGE
cluster-192.168.97.3-3897021443 Opaque 3 12m
mgmt 클러스터에서는 위 시크릿을 통해 외부 클러스터 접속 정보를 확인합니다.
# k9s 에서 data 내용 확인
k9s -> : secret argocd -> 아래 secret 에서 d (Describe) -> x (Toggle Decode) 로 확인
#
argocd cluster list -o json | jq
argocd cluster list
SERVER NAME VERSION STATUS MESSAGE PROJECT
https://192.168.97.3:6443 dev-k8s Unknown Cluster has no applications and is not being monitored.
https://kubernetes.default.svc in-cluster Unknown Cluster has no applications and is not being monitored.
# prd k8s 등록
argocd cluster add kind-prd --name prd-k8s --yes
k8s3 get sa -n kube-system argocd-manager
kubectl get secret -n argocd -l argocd.argoproj.io/secret-type=cluster
argocd cluster list
SERVER NAME VERSION STATUS MESSAGE PROJECT
https://192.168.97.3:6443 dev-k8s Unknown Cluster has no applications and is not being monitored.
https://192.168.97.4:6443 prd-k8s Unknown Cluster has no applications and is not being monitored.
https://kubernetes.default.svc in-cluster Unknown Cluster has no applications and is not being monitored.
ArgoCD에 정상적으로 연결된 것을 확인할 수 있습니다.


nginx helm chart 생성
Argo CD 배포 테스트를 위해 nginx helm chart 를 작성합니다.
개인 Github 레포에 업로드 하겠습니다.
https://github.com/gnobaaaar/nginx-chart
GitHub - gnobaaaar/nginx-chart: nginx helmchart for cicd study
nginx helmchart for cicd study. Contribute to gnobaaaar/nginx-chart development by creating an account on GitHub.
github.com
아래에서처럼 로컬 경로에 helm 파일을 생성해주겠습니다.
#
mkdir nginx-chart
cd nginx-chart
mkdir templates
cat > templates/configmap.yaml <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}
data:
index.html: |
{{ .Values.indexHtml | indent 4 }}
EOF
cat > templates/deployment.yaml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ .Release.Name }}
spec:
containers:
- name: nginx
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
ports:
- containerPort: 80
volumeMounts:
- name: index-html
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
volumes:
- name: index-html
configMap:
name: {{ .Release.Name }}
EOF
cat > templates/service.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}
spec:
selector:
app: {{ .Release.Name }}
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: {{ .Values.nodePort }}
type: NodePort
EOF
cat > values.yaml <<EOF
indexHtml: |
<!DOCTYPE html>
<html>
<head>
<title>Welcome to Nginx!</title>
</head>
<body>
<h1>Hello, Kubernetes!</h1>
<p>Nginx version 1.26.1</p>
</body>
</html>
image:
repository: nginx
tag: 1.26.1
replicaCount: 1
nodePort: 30000
EOF
cat > values-dev.yaml <<EOF
indexHtml: |
<!DOCTYPE html>
<html>
<head>
<title>Welcome to Nginx!</title>
</head>
<body>
<h1>Hello, Dev - Kubernetes!</h1>
<p>Nginx version 1.26.1</p>
</body>
</html>
image:
repository: nginx
tag: 1.26.1
replicaCount: 1
nodePort: 31000
EOF
cat > values-prd.yaml <<EOF
indexHtml: |
<!DOCTYPE html>
<html>
<head>
<title>Welcome to Nginx!</title>
</head>
<body>
<h1>Hello, Prd - Kubernetes!</h1>
<p>Nginx version 1.26.1</p>
</body>
</html>
image:
repository: nginx
tag: 1.26.1
replicaCount: 2
nodePort: 32000
EOF
cat > Chart.yaml <<EOF
apiVersion: v2
name: nginx-chart
description: A Helm chart for deploying Nginx with custom index.html
type: application
version: 1.0.0
appVersion: "1.26.1"
EOF
#
git add . && git commit -m "Add sample yaml" && git push -u origin main
# 헬름 렌더링 확인
helm template mgmt-nginx . -f values.yaml
helm template dev-nginx . -f values-dev.yaml
helm template prd-nginx . -f values-prd.yaml
helm 정의
Chart.yaml
Helm Chart 메타데이터 정의
name: nginx-chart
version: 1.0.0
values.yaml
환경별로 nginx의 동작을 다르게 설정하였습니다.
| 파일 | nodePort | index.html | replicas |
| values.yaml | 30000 | “Hello, Kubernetes!” | 1 |
| values-dev.yaml | 31000 | “Hello, Dev - Kubernetes!” | 1 |
| values-prd.yaml | 32000 | “Hello, Prd - Kubernetes!” | 2 |
templates/configmap.yaml
Helm 템플릿 기능을 사용해서 index.html 내용을 Configmap으로 저장합니다.
templates/deployment.yaml
volumeMounts:
- name: index-html
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
configmap 으로 저장된 index.html을 마운트해서 사용합니다.
templates/service.yaml
type: NodePort
nodePort: {{ .Values.nodePort }}
values.yaml 에서 설정된 노드포트로 외부에 접근가능하게 노출시킵니다.
ArgoCD에 nginx 배포
배포를 위해 변수값을 잡고 갑니다.
docker network inspect kind | grep -E 'Name|IPv4Address'
DEVK8SIP=192.168.97.3
PRDK8SIP=192.168.97.4
echo $DEVK8SIP $PRDK8SIP
# argocd app 배포
cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: mgmt-nginx
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
helm:
valueFiles:
- values.yaml
path: nginx-chart
repoURL: https://github.com/gasida/cicd-study
targetRevision: HEAD
syncPolicy:
automated:
prune: true
syncOptions:
- CreateNamespace=true
destination:
namespace: mgmt-nginx
server: https://kubernetes.default.svc
EOF
cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: dev-nginx
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
helm:
valueFiles:
- values-dev.yaml
path: nginx-chart
repoURL: https://github.com/gasida/cicd-study
targetRevision: HEAD
syncPolicy:
automated:
prune: true
syncOptions:
- CreateNamespace=true
destination:
namespace: dev-nginx
server: https://$DEVK8SIP:6443
EOF
cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: prd-nginx
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
helm:
valueFiles:
- values-prd.yaml
path: nginx-chart
repoURL: https://github.com/gasida/cicd-study
targetRevision: HEAD
syncPolicy:
automated:
prune: true
syncOptions:
- CreateNamespace=true
destination:
namespace: prd-nginx
server: https://$PRDK8SIP:6443
EOF
#
argocd app list
kubectl get applications -n argocd dev-nginx
kubectl get applications -n argocd dev-nginx -o yaml
kubectl get applications -n argocd dev-nginx -o yaml | kubectl neat | yq
kubectl describe applications -n argocd dev-nginx
kubectl get applications -n argocd
NAME SYNC STATUS HEALTH STATUS
dev-nginx Synced Healthy
mgmt-nginx Synced Healthy
prd-nginx Synced Healthy
정상적으로 접근이 되는지 nodeport로 확인해봅니다.
# mgmt
kubectl get pod,svc,ep,cm -n mgmt-nginx
curl -s http://127.0.0.1:30000
# dev
kubectl get pod,svc,ep,cm -n dev-nginx --context kind-dev
curl -s http://127.0.0.1:31000
# prd
kubectl get pod,svc,ep,cm -n prd-nginx --context kind-prd
curl -s http://127.0.0.1:32000
# Argo CD App 삭제
kubectl delete applications -n argocd mgmt-nginx dev-nginx prd-nginx
ApplicationSet
따로 포스팅 정리합니다
OpenLDAP + KeyCloak + Argo CD + Jenkins
keycloak 배포
실습을 위해 keycloak을 파드로 배포해 보겠습니다.
#
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: keycloak
labels:
app: keycloak
spec:
replicas: 1
selector:
matchLabels:
app: keycloak
template:
metadata:
labels:
app: keycloak
spec:
containers:
- name: keycloak
image: quay.io/keycloak/keycloak:26.4.0
args: ["start-dev"] # dev mode 실행
env:
- name: KEYCLOAK_ADMIN
value: admin
- name: KEYCLOAK_ADMIN_PASSWORD
value: admin
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: keycloak
spec:
selector:
app: keycloak
ports:
- name: http
port: 80
targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: keycloak
namespace: default
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
ingressClassName: nginx
rules:
- host: keycloak.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: keycloak
port:
number: 8080
EOF
디플로이먼트와 서비스, 그리고 접근하는 ingress를 배포합니다.
args: ["start-dev"] 를 통해 개발자 모드로 실행합니다.
ingress의 annotation은 두가지가 쓰였습니다.
nginx.ingress.kubernetes.io/rewrite-target: /
이 설정이 있으면, /keycloak → / 로 바꿔서 백엔드(Keycloak 컨테이너)로 전달합니다.
즉, Keycloak 컨테이너는 원래 경로 /에서 동작하므로, rewrite를 하지 않으면 /keycloak이라는 경로를 처리 못합니다.
nginx.ingress.kubernetes.io/ssl-redirect: "false"
HTTP 요청을 HTTPS로 리다이렉트 하지않습니다.
http 접속접근도 허용해 줍니다.
# 확인
kubectl get deploy,svc,ep keycloak
kubectl get ingress keycloak
NAME CLASS HOSTS ADDRESS PORTS AGE
keycloak nginx keycloak.example.com localhost 80 91s
#
curl -s -H "Host: keycloak.example.com" http://127.0.0.1 -I
HTTP/1.1 302 Found
Location: http://keycloak.example.com/admin/
# 도메인 설정
## macOS의 /etc/hosts 파일 수정
echo "127.0.0.1 keycloak.example.com" | sudo tee -a /etc/hosts
cat /etc/hosts
## C:\Windows\System32\drivers\etc\hosts 관리자모드에서 메모장에 내용 추가
127.0.0.1 keycloak.example.com
# keycloak 웹 접속 : admin / admin
curl -s http://keycloak.example.com -I
open "http://keycloak.example.com/admin"
# 확인
kubectl get deploy,svc,ep keycloak
kubectl get ingress keycloak
NAME CLASS HOSTS ADDRESS PORTS AGE
keycloak nginx keycloak.example.com localhost 80 91s
#
curl -s -H "Host: keycloak.example.com" http://127.0.0.1 -I
HTTP/1.1 302 Found
Location: http://keycloak.example.com/admin/
# 도메인 설정
## macOS의 /etc/hosts 파일 수정
echo "127.0.0.1 keycloak.example.com" | sudo tee -a /etc/hosts
cat /etc/hosts
## C:\Windows\System32\drivers\etc\hosts 관리자모드에서 메모장에 내용 추가
127.0.0.1 keycloak.example.com
# keycloak 웹 접속 : admin / admin
curl -s http://keycloak.example.com -I
open "http://keycloak.example.com/admin"
/etc/hosts에 도메인을 넣어주고 접근하면 정상적으로 포털에 접근 가능합니다.

deployment 에 설정했던 admin/admin 으로 접근합니다.
접속 했다면 realms와 users를 생성해줍니다.
- realms 생성 : myrealm
- users 생성 : alice - 암호 alice123


mgmt k8a in-cluster 내부 설정
mgmt k8a in-cluster 내부에서도 keycloak / argocd 도메인 호출 가능하게 설정해줍니다.
테스트를 위해 경량의 curl 파드를 배포합니다.
# 경량의 curl 테스트용 파드 생성
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: curl
namespace: default
spec:
containers:
- name: curl
image: curlimages/curl:latest
command: ["sleep", "infinity"]
EOF
배포된 keycloak과 argocd 정보를 확인합니다.
#
kubectl get pod -l app=keycloak -owide
kubectl get pod -l app=keycloak -o jsonpath='{.items[0].status.podIP}'
KEYCLOAKIP=$(kubectl get pod -l app=keycloak -o jsonpath='{.items[0].status.podIP}')
echo $KEYCLOAKIP
# 기본 통신 및 정보 확인 : ClusterIP 메모!
kubectl get svc keycloak
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
keycloak ClusterIP 10.96.58.66 <none> 80/TCP 25m
kubectl get svc -n argocd argocd-server
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
argocd-server ClusterIP 10.96.156.196 <none> 80/TCP,443/TCP 134m
예시처럼 값을 확인해보겠습니다.
keycloak pod ip : 10.244.0.17
keycloak svc cluster ip : 10.96.82.111
argocd svc cluster ip : 10.96.193.83

ip나 서비스클러스터 주소를 사용한 파드간 통신은 가능하지만
도메인으로의 요청 접근은 불가합니다.
현재 도메인이 DNS에 없어서 추가가 필요합니다.
kubectl exec -it curl -- ping -c 1 $KEYCLOAKIP
kubectl exec -it curl -- curl -s http://keycloak.default.svc.cluster.local/realms/myrealm/.well-known/openid-configuration | jq
# 왜 호출이 되지 않을까?
kubectl exec -it curl -- curl -s http://keycloak.example.com -I
kubectl exec -it curl -- nslookup -debug keycloak.example.com
kubectl exec -it curl -- nslookup keycloak.example.com
# 해결해보자 : coredns 에 hosts 플러그인 활용
KUBE_EDITOR="nano" kubectl edit cm -n kube-system coredns
.:53 {
...
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
hosts {
<CLUSTER IP> keycloak.example.com
<CLUSTER IP> argocd.example.com
fallthrough
}
reload # cm 설정 변경 시 자동으로 reload 적용됨
...
# cm 설정 변경 시 자동으로 reload 적용 로그 확인
kubectl logs -n kube-system -l k8s-app=kube-dns --timestamps
# 도메인 질의 시, ClusterIP로 변경 확인 : 파드 내에 dns 쿼리 캐시는 없는 걸까요???
kubectl exec -it curl -- nslookup -debug keycloak.example.com
kubectl exec -it curl -- nslookup keycloak.example.com
위 예제처럼 CoreDNS에 hosts를 직접 넣어주겠습니다.

reload 옵션으로 인해 자동으로 적용됩니다 (파드 재기동 불필요)
이제 도메인질의를 하면 ClusterIP로 질의하는 것을 확인할 수 있습니다.
keycloak, ArgoCD 설정
keycloak 설정
keycloak에 Argo CD 를 위한 client 생성을 진행하겠습니다.
- client id : argocd
- name : argocd client


- Root URL : https://argocd.example.com/
- Home URL : /applications
- Valid redirect URIs : https://argocd.example.com/auth/callback
- Valid post logout redirect URIs : https://argocd.example.com/applications
- Web origins : +

생성된 client 에서 → Credentials : 메모 해둡니다.
ex. bVYzSVpPM25tSG9acjNCQkMzN1VwZHJNU01rRjlVbXQ
ArgoCD OIDC 구성
클라이언트 시크릿 설정
#
kubectl -n argocd patch secret argocd-secret --patch='{"stringData": { "oidc.keycloak.clientSecret": "<REPLACE_WITH_CLIENT_SECRET>" }}'
kubectl -n argocd patch secret argocd-secret --patch='{"stringData": { "oidc.keycloak.clientSecret": "mV3IZO3nmHoZr3BBC37UpdrMSMkF9Umt" }}'
# 확인
kubectl get secret -n argocd argocd-secret -o jsonpath='{.data}' | jq
...
"oidc.keycloak.clientSecret": "bVYzSVpPM25tSG9acjNCQkMzN1VwZHJNU01rRjlVbXQ=",

# 설정 추가
kubectl patch cm argocd-cm -n argocd --type merge -p '
data:
oidc.config: |
name: Keycloak
issuer: http://keycloak.example.com/realms/myrealm
clientID: argocd
clientSecret: mV3IZO3nmHoZr3BBC37UpdrMSMkF9Umt
requestedScopes: ["openid", "profile", "email"]
'
# 확인
kubectl get cm -n argocd argocd-cm -o yaml | grep oidc.config: -A5
oidc.config: |
name: Keycloak
issuer: http://keycloak.example.com/realms/myrealm
clientID: argocd
clientSecret: mV3IZO3nmHoZr3BBC37UpdrMSMkF9Umt
requestedScopes: ["openid", "profile", "email"]
설정되었다면 argocd를 재기동 해줍니다.
kubectl rollout restart deploy argocd-server -n argocd
ArgoCD 포털을 접근해서 로그아웃해주고 keycloak을 통해 로그인해줍니다.

로그인 과정에서, auth? 에서 페이로드 확인 : scope 에 openid profile email 범위 허용 확인할 수 있습니다.
따라서 처음 접근하려고 한다면 email 기입이 필요합니다.
모든 입력이 완료되면 정상적으로 포털에 keycloak을 통해 접근할 수 있습니다.

jenkins 직접 파드로 배포
젠킨스에도 keyclaok을 연동해보겠습니다.
#
kubectl create ns jenkins
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: jenkins-pvc
namespace: jenkins
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins
namespace: jenkins
spec:
replicas: 1
selector:
matchLabels:
app: jenkins
template:
metadata:
labels:
app: jenkins
spec:
securityContext:
fsGroup: 1000
containers:
- name: jenkins
image: jenkins/jenkins:lts
ports:
- name: http
containerPort: 8080
- name: agent
containerPort: 50000
volumeMounts:
- name: jenkins-home
mountPath: /var/jenkins_home
volumes:
- name: jenkins-home
persistentVolumeClaim:
claimName: jenkins-pvc
---
apiVersion: v1
kind: Service
metadata:
name: jenkins-svc
namespace: jenkins
spec:
type: ClusterIP
selector:
app: jenkins
ports:
- port: 8080
targetPort: http
protocol: TCP
name: http
- port: 50000
targetPort: agent
protocol: TCP
name: agent
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: jenkins-ingress
namespace: jenkins
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
spec:
ingressClassName: nginx
rules:
- host: jenkins.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: jenkins-svc
port:
number: 8080
EOF
# 확인
kubectl get deploy,svc,ep,pvc -n jenkins
kubectl get ingress -n jenkins jenkins-ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
jenkins-ingress nginx jenkins.example.com localhost 80 60s
# 도메인 설정
## macOS의 /etc/hosts 파일 수정
echo "127.0.0.1 jenkins.example.com" | sudo tee -a /etc/hosts
cat /etc/hosts
## C:\Windows\System32\drivers\etc\hosts 관리자모드에서 메모장에 내용 추가
127.0.0.1 jenkins.example.com
# 초기 암호 확인
kubectl exec -it -n jenkins deploy/jenkins -- cat /var/jenkins_home/secrets/initialAdminPassword
7521bc306a4049a6a0fd75391ae4b235
# 웹 접속 : 기본 설정 진행
curl -s http://jenkins.example.com -I
open "http://jenkins.example.com"
초기 패스워드로 접근합니다.

플러그인은 추천되는걸로 누르고 설치를 진행합니다.
- 관리자 계정 설정 : admin / qwe123
- in-cluster 호출을 위한 도메인 설정
젠킨스 포털에서 계정을 변경하고 나면 coreDNS에 host 를 추가해줍니다.
# 기본 통신 및 정보 확인 : ClusterIP 메모!
kubectl get svc -n jenkins
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins-svc ClusterIP 10.96.165.34 <none> 8080/TCP,50000/TCP 5m18s
kubectl get svc -n jenkins
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins-svc ClusterIP 10.96.241.201 <none> 8080/TCP,50000/TCP 62m
# 해결해보자 : coredns 에 hosts 플러그인 활용
KUBE_EDITOR="nano" kubectl edit cm -n kube-system coredns
.:53 {
...
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
hosts {
<CLUSTER IP> keycloak.example.com
<CLUSTER IP> argocd.example.com
<CLUSTER IP> jenkins.example.com
fallthrough
}
reload # cm 설정 변경 시 자동으로 reload 적용됨
...

keycloak 에 jenkins 를 위한 client 생성
- client id : jenkins
- name : jenkins client
- Client authentication : Check
- Authentication flow : Standard flow
- Root URL : http://jenkins.example.com/
- Home URL : http://jenkins.example.com/
- Valid redirect URIs : http://jenkins.example.com/securityRealm/finishLogin
- Valid post logout redirect URIs : http://jenkins.example.com
- Web origins : +
Jenkins OIDC 플러그인 설치
keycloak을 통한 OIDC 사용을 위해 Jenkins 포털에서 플러그인 설치를 진행합니다.


- 플러그인 설치 : OpenID Connect Authentication
- Manage Jenkins → Security : Security Realm 설정 → 하단 Save
- Login with Openid Connect
- Client id : jenkins
- Client secret : <keycloak 에서 jenkins client 에서 credentials>
- Configuration mode : Discovery via Well-know configuration endpoint
- http://keycloak.example.com/realms/myrealm/.well-known/openid-configuration
- Override scopes : openid email profile
- Logout from OpenID Provider : Check
- 젠킨스 로그아웃시 keycloak 도 함께 로그아웃됩니다 (SSO 세션)
- Security configuration
- Disable ssl verification : Check
- Keycloak이 HTTP 또는 자체 서명된 SSL 인증서를 사용할 때 필요
- Disable ssl verification : Check

새 창에서 jenkins 도메인으로 접근을 시도해봅니다.
302 redirect 되어 keycloak으로 이동하는 것을 확인할 수 있습니다.



LDAP
Lightweight Directory Access Protocol
사용자·그룹·권한 정보를 계층적으로 보관하는 주소록/조직도
디렉터리 서비스에 접근하기 위한 표준 프로토콜입니다.
트리 구조로 저장된 조직 내 사용자, 그룹, 권한 등의 정보를 저장하고 조회하는 시스템입니다.
dc=example,dc=org # Base DN(Root DN)
├── ou=people
│ ├── uid=alice
│ └── uid=bob
└── ou=groups
├── cn=devs
└── cn=admins
각 노드는 DN(Distinguished Name)으로 전체 경로를 식별됩니다.
DN은 하나의 엔트리(ex. alice)를 고유하게 식별하는 전체경로입니다.
RDN은 DN을 구성하는 한단계 (한 조각)을 의미합니다.
- 전체 경로의 단계는 여러 개의 RDN(Relative Distinguished Name)으로 구성
- 예시) 사용자 alice
- DN: uid=alice (사용자 식별자) ,ou=people (조직단위) ,dc=example,dc=org (도메인 컴포넌트)
- DN에 할당된 “uid=alice”, “ou=people”, “dc=example,dc=org”은 각 엔트리의 RDN
- 예시) 사용자 alice
# 파일시스템과 비유한다면
DN: uid=alice,ou=people,dc=example,dc=org
==> /org/example/people/alice ← 이런 느낌
- LDAP 서버 = 회사의 인사/보안부
- LDAP 서버도 마찬가지로, 사용자·그룹·권한 정보를 디렉터리라는 구조로 보관하는 중앙 관리소입니다.
- 회사에는 모든 직원의 정보(이름, 부서, 직급, 이메일 등)를 한 곳에 모아 관리하는 인사부가 있죠.
- 디렉터리 구조 = 회사 조직도
- LDAP도 “dc=company, ou=부서, cn=사용자” 같은 계층적 주소로 정보를 저장합니다.
- 회사에 “본사–부서–팀–직원”으로 이어지는 조직도가 있는 것처럼,
- 클라이언트(애플리케이션) = 직원 신분 확인 창구
- 인사부가 “맞다/아니다” 또는 “이 사람의 권한은 이런 것”을 알려주죠.
- 누군가 회사 시스템에 로그인하면, 시스템이 인사부(=LDAP 서버)에 “이 사람 우리 직원 맞나요?” 하고 묻습니다.
- 인증(Authentication) = 신분증 검사
- 시스템이 LDAP 서버에 아이디와 비밀번호를 보내 확인받습니다.
- 권한 부여(Authorization) = 출입증/권한 확인
- LDAP 서버가 “이 사람은 개발팀” “이 사람은 관리자”처럼 그룹 정보나 역할을 반환하면, 시스템이 그 정보에 따라 접근 권한을 부여합니다.

- LDAP 디렉터리에서 표현하는 정보 구조 2가지
- Entry : 디렉토리에서 정보를 표현하는 기본 단위이다. Entry는 다수의 attribute로 구성됩니다.
- Atribute : Entry의 각 타입을 저장하는 공간으로 1개의 Attribute에 하나, 또는 다수의 값을 담을 수 있습니다.
- 도구 : Windows AD, OpenLDAP - Home 등등
OpenLDAP 작업전 아래 삭업을 수행합니다.
사전 작업 : Keycloak 에 alice sign out 및 alice 사용자 제거
OpenLDAP

OpenLDAP 서버 배포
#
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
name: openldap
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: openldap
namespace: openldap
spec:
replicas: 1
selector:
matchLabels:
app: openldap
template:
metadata:
labels:
app: openldap
spec:
containers:
- name: openldap
image: osixia/openldap:1.5.0
ports:
- containerPort: 389
name: ldap
- containerPort: 636
name: ldaps
env:
- name: LDAP_ORGANISATION # 기관명, LDAP 기본 정보 생성 시 사용
value: "Example Org"
- name: LDAP_DOMAIN # LDAP 기본 Base DN 을 자동 생성
value: "example.org"
- name: LDAP_ADMIN_PASSWORD # LDAP 관리자 패스워드
value: "admin"
- name: LDAP_CONFIG_PASSWORD
value: "admin"
- name: phpldapadmin
image: osixia/phpldapadmin:0.9.0
ports:
- containerPort: 80
name: phpldapadmin
env:
- name: PHPLDAPADMIN_HTTPS
value: "false"
- name: PHPLDAPADMIN_LDAP_HOSTS
value: "openldap" # LDAP hostname inside cluster
---
apiVersion: v1
kind: Service
metadata:
name: openldap
namespace: openldap
spec:
selector:
app: openldap
ports:
- name: phpldapadmin
port: 80
targetPort: 80
nodePort: 30000
- name: ldap
port: 389
targetPort: 389
- name: ldaps
port: 636
targetPort: 636
type: NodePort
EOF
#
kubectl get deploy,pod,svc,ep -n openldap
# 기본 LDAP 정보 : 아래 Bind DN과 PW로 로그인
## Base DN: dc=example,dc=org
## Bind DN: cn=admin,dc=example,dc=org
## Password: admin
open http://127.0.0.1:30000
# phpLDAPadmin 로그인
kubectl stern -n openldap openldap-54857b746c-ch9g4


OpenLDAP 구성
OpenLDAP을 쿠버네티스 환경에서 배포하고 사용자·그룹 엔트리를 구성하며, 인증/검색 테스트까지 진행해보겠습니다.
# 파드 내부로 접근
kubectl -n openldap exec -it deploy/openldap -c openldap -- bash
----------------------------------------------------
# slapd 프로세스가 실행 중임을 확인 (LDAP 서버 데몬)
pstree -aplpst
run,1 -u /container/tool/run
└─slapd,433 -h ldap://openldap-54857b746c-ch9g4:389 ldaps://openldap-54857b746c-ch9g4:636 ldapi:/// -u openldap -g openldap -d 256
├─{slapd},436
└─{slapd},437
# LDAP 관리자 인증 테스트 : 정상일 경우 LDAP 기본 엔트리 출력
ldapsearch -x -H ldap://localhost:389 -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin
# 실습 사용 최종 트리 구조
dc=example,dc=org
├── ou=people
│ ├── uid=alice
│ │ ├── cn: Alice
│ │ ├── sn: Kim
│ │ ├── uid: alice
│ │ └── mail: alice@example.org
│ └── uid=bob
│ ├── cn: Bob
│ ├── sn: Lee
│ ├── uid: bob
│ └── mail: bob@example.org
└── ou=groups
├── cn=devs
│ └── member: uid=bob,ou=people,dc=example,dc=org
└── cn=admins
└── member: uid=alice,ou=people,dc=example,dc=org
# ldapadd로 ou 추가 (organizationalUnit)
cat <<EOF | ldapadd -x -D "cn=admin,dc=example,dc=org" -w admin
dn: ou=people,dc=example,dc=org
objectClass: organizationalUnit
ou: people
dn: ou=groups,dc=example,dc=org
objectClass: organizationalUnit
ou: groups
EOF
adding new entry "ou=people,dc=example,dc=org"
adding new entry "ou=groups,dc=example,dc=org"
# ldapadd로 users 추가 (inetOrgPerson) : alice , bob
cat <<EOF | ldapadd -x -D "cn=admin,dc=example,dc=org" -w admin
dn: uid=alice,ou=people,dc=example,dc=org
objectClass: inetOrgPerson
cn: Alice
sn: Kim
uid: alice
mail: alice@example.org
userPassword: alice123
dn: uid=bob,ou=people,dc=example,dc=org
objectClass: inetOrgPerson
cn: Bob
sn: Lee
uid: bob
mail: bob@example.org
userPassword: bob123
EOF
adding new entry "uid=alice,ou=people,dc=example,dc=org"
adding new entry "uid=bob,ou=people,dc=example,dc=org"
# ldapadd로 groups 추가 (groupOfNames) : devs, admins
cat <<EOF | ldapadd -x -D "cn=admin,dc=example,dc=org" -w admin
dn: cn=devs,ou=groups,dc=example,dc=org
objectClass: groupOfNames
cn: devs
member: uid=bob,ou=people,dc=example,dc=org
dn: cn=admins,ou=groups,dc=example,dc=org
objectClass: groupOfNames
cn: admins
member: uid=alice,ou=people,dc=example,dc=org
EOF
adding new entry "cn=devs,ou=groups,dc=example,dc=org"
adding new entry "cn=admins,ou=groups,dc=example,dc=org"
# ldapsearch 검색 : ou
ldapsearch -x -D "cn=admin,dc=example,dc=org" -w admin \
-b "dc=example,dc=org" "(objectClass=organizationalUnit)" ou
# ldapsearch 검색 : 사용자
ldapsearch -x -D "cn=admin,dc=example,dc=org" -w admin \
-b "ou=people,dc=example,dc=org" "(uid=*)" uid cn mail
# ldapsearch 검색 : 그룹/멤버 확인
ldapsearch -x -D "cn=admin,dc=example,dc=org" -w admin \
-b "ou=groups,dc=example,dc=org" "(objectClass=groupOfNames)" cn member
# LDAP 사용자 인증 테스트 : 정상일 경우 LDAP 기본 엔트리 출력
ldapwhoami -x -D "uid=alice,ou=people,dc=example,dc=org" -w alice123
dn:uid=alice,ou=people,dc=example,dc=org
----------------------------------------------------
하나씩 나눠서 정리해보겠습니다.
LDAP 관리자 인증테스트
ldapsearch -x -H ldap://localhost:389 -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin
- 관리자 계정으로 LDAP에 인증(bind) 후 전체 트리 검색 시도
- 정상 연결되면 LDAP 루트 엔트리(dc=example,dc=org) 이하가 출력됨
- -b는 어디서부터 검색할지 (Base DN)
- -D는 로그인 계정
- -w는 비밀번호
목표 LDAP 구조는 아래와 같습니다.
dc=example,dc=org
├── ou=people ← 사용자
│ ├── uid=alice
│ └── uid=bob
└── ou=groups ← 그룹
├── cn=devs
└── cn=admins
조직 단위(ou) 추가
ldapadd -x -D "cn=admin,dc=example,dc=org" -w admin <<EOF
...
EOF
- ou=people, ou=groups 두 조직 단위를 추가 (objectClass: organizationalUnit)
- 조직 구조의 컨테이너 생성
사용자 추가 (alice, bob)
| cn | 전체 이름 (common name) |
| sn | 성 (surname) |
| uid | 고유 사용자 ID |
| 이메일 주소 | |
| userPassword | 로그인 비밀번호 (LDAP bind에 사용됨) |
그룹 추가 (devs, admins)
- cn=devs, cn=admins 그룹 생성
- member 속성은 DN 경로로 지정
member: uid=alice,ou=people,dc=example,dc=org
KeyCloak에서 LDAP 설정 실습
실습해보면서 조금씩 이해해보겠습니다.
Keycloak은 User Federation으로 LDAP과 연동하여 사용자 정보를 동기화합니다.
admin Console
[Realm] myrealm → User Federation → Add LDAP providers

Add LDAP Provider Sections
- General options - LDAP 연결 기본 정보
- UI display name : Admin Console에서 표시될 LDAP 이름.
- Vendor : LDAP 서버 유형 선택 (Active Directory, RHDS 등).
- Connection and authentication settings - LDAP 접속 방법과 인증 방법 정의
- Connection URL : ldap:// 또는 ldaps:// 주소 (예: ldap://10.0.0.10:389)
- Enable StartTLS : 일반 포트(389)에서 TLS로 보안 연결(636)할 때 사용.
- Test connection : 연결 사전 검증.
- Bind type : 인증 방식(simple, none).
- Bind DN / Bind credentials : LDAP에 접근할 계정과 비밀번호.
- Test authentication : 계정 인증을 사전 검증.
- LDAP searching and updating - 사용자를 찾고 업데이트하는 방식
- Edit mode : 데이터 수정 권한.
- READ_ONLY : LDAP 데이터는 읽기 전용.
- WRITABLE : Keycloak 변경 내용이 LDAP에 반영됨.
- UNSYNCED : Keycloak 로컬 데이터로만 사용.
- Users DN : 사용자 검색의 루트 DN(Distinguished Name - 식별 이름) (예: OU=Users,DC=example,DC=com)
- Username LDAP attribute : 로그인 시 식별할 속성
- Search scope : 검색 범위(One Level (하위 1단계), Subtree (하위 전체)).
- Edit mode : 데이터 수정 권한.
- Synchronization settings - LDAP 사용자 데이터를 Keycloak으로 동기화하는 주기를 정의
- Import users : LDAP 사용자 정보를 Keycloak DB에 임포트할지 여부.
- Sync Registrations : Keycloak에서 새로 생성한 사용자를 LDAP에 동기화할지 여부.
- Periodic full sync / Periodic changed users sync : 자동 동기화 주기 설정.
- Kerberos integration - Kerberos 통합에 대한 옵션
- Cache settings - LDAP 요청 결과 캐싱 정책 설정
- Advanced settings - LDAP 고급 기능
- Enable the LDAPv3 password modify extended operation : LDAP 비밀번호 변경 확장 기능 활성화.
- Validate password policy : Keycloak의 비밀번호 정책을 LDAP 사용자에게도 적용.
- Trust email : LDAP에서 가져온 이메일을 신뢰할지 여부.
필드값 최소 설정
- General
- UI display name: ldap
- admin 콘솔에 표시될 이름
- Vendor: Other
- UI display name: ldap
- Connection and authentication
- Connection URL: ldap://openldap.openldap.svc:389 ⇒ Test connection
- LDAP 서버 주소 입력
- Bind DN: (= Login DN) cn=admin,dc=example,dc=org
- 로그인 계정정보
- Bind Credential: admin ⇒ Test authentication
- Connection URL: ldap://openldap.openldap.svc:389 ⇒ Test connection
- LDAP searching and updating
- Edit mode: WRITABLE
- keycloak에서 LDAP 수정가능여부
- Users DN: ou=people,dc=example,dc=org
- 사용자들이 저장된 위치
- Username LDAP attribute: uid
- RDN LDAP attribute: uid
- UUID LDAP attribute: entryUUID
- User Object Classes: inetOrgPerson
- Search scope: Subtree (OU 하위 모두 탐색)
- Edit mode: WRITABLE
- Synchronization settings
- Import Users: On (LDAP → KeyCloak : Sync OK)
- LDAP -> keycloak 동기화 여부
- Sync Registrations: Off (KeyCloak → LDAP : Sync OK)
- Import Users: On (LDAP → KeyCloak : Sync OK)
- Save

[KeyCloak] LDAP Mapper 확인
admin Console
User Federation → LDAP Provider 선택 → Mappers: user에 대한 Mappers가 기본 존재
[KeyCloak] LDAP -> KeyCloak 동기화
admin Console
User Federation → LDAP Provider 선택 → Settings → Action : Sync all users ⇒ 실패 시, 다시 한번 더 시도!
- 처음 LDAP 연동 후 사용자 전부 불러올 때 : LDAP의 전체 사용자를 Keycloak DB에 동기화(기존 데이터 덮어씀)

admin Console
- Users → Default search → * : user 바로 보이지 않고, 해당 user 나 혹은 * 검색 시 출력

접근테스트
ArgoCD에 bob으로 접근테스트 해보겠습니다.

keycloak의 session 에서도 확인이 가능합니다.

'devops > cicd' 카테고리의 다른 글
| [CI/CD] 7주차 - Vault (2) (1) | 2025.12.03 |
|---|---|
| [CI/CD] 7주차 - Vault (1) (0) | 2025.11.29 |
| keycloak - Oauth - OIDC (0) | 2025.11.16 |
| [CI/CD] 5주차 - Argo CD 2/3 (0) | 2025.11.16 |
| [CI/CD] 4주차 - Argo CD 1/3 (1) (0) | 2025.11.09 |