ArgoCD의 ApplicationSet에 대해서 그동안 다뤄봤습니다.

이번에는 추가적으로 OpenLDAP, KeyCloak, Jenkins, ArgoCD를 통합 설정하여 CI/CD 플랫폼을 관리하기 위한 구성을 해보겠습니다.

해당 구현으로 다 수의 사용자 인증 부터 권한관리 까지 체계적으로 구성할 수 있어 미승인 사용자를 차단하고 권한부여된 사용자가 적절한 액션을 취할 수 있도록 할 수 있습니다.

 

Cluster 구성

이전 블로그에 있는 멀티 클러스터환경에 이어서 진행하겠습니다.

https://hanship.tistory.com/5 포스팅을 참조해서 클러스터 구성을 해줍니다.

 

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

# 확인
kubectl get deploy,svc,ep keycloak
kubectl get ingress keycloak
NAME       CLASS   HOSTS                  ADDRESS   PORTS   AGE
keycloak   nginx   keycloak.example.com             80      19s

# 도메인 설정
## macOS의 /etc/hosts 파일 수정
echo "127.0.0.1 keycloak.example.com" | sudo tee -a /etc/hosts

# keycloak 웹 접속 : admin / admin
open "http://keycloak.example.com/admin"

keycloak realms과 users를 생성합니다.

realms 생성 user 생성, 현재 realms 확인 비밀번호 설정(Credential에서 확인) 비밀번호 설정
  • realms 생성 : myrealm
  • users 생성 : alice - 암호 alice123

keycloak에서 argocd 를 위한 client을 생성합니다.

  • client id : argocd
  • name : argocd client
  • client auth : ON
  • 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 : 메모 해두기 3QhTVm6g4Bp3EOJGDyCII4XEwITJxXwn

위 설정을 한 후 아래의 명령어를 통해 잘 설정되었는 지 확인해봅니다.

curl -s http://keycloak.example.com/realms/myrealm/.well-known/openid-configuration> | jq
...
  "mtls_endpoint_aliases": {
    "token_endpoint": "<http://keycloak.example.com/realms/myrealm/protocol/openid-connect/token>",
    "revocation_endpoint": "<http://keycloak.example.com/realms/myrealm/protocol/openid-connect/revoke>",
    "introspection_endpoint": "<http://keycloak.example.com/realms/myrealm/protocol/openid-connect/token/introspect>",
    "device_authorization_endpoint": "<http://keycloak.example.com/realms/myrealm/protocol/openid-connect/auth/device>",
    "registration_endpoint": "<http://keycloak.example.com/realms/myrealm/clients-registrations/openid-connect>",
    "userinfo_endpoint": "<http://keycloak.example.com/realms/myrealm/protocol/openid-connect/userinfo>",
    "pushed_authorization_request_endpoint": "<http://keycloak.example.com/realms/myrealm/protocol/openid-connect/ext/par/request>",
    "backchannel_authentication_endpoint": "<http://keycloak.example.com/realms/myrealm/protocol/openid-connect/ext/ciba/auth>"
  },
  "authorization_response_iss_parameter_supported": true
...

ArgoCD OIDC 설정을 진행합니다. (클라이언트 시크릿 설정)

# oidc.keycloak.clientSecret 에서 메모해둔 Credentials 입력
kubectl -n argocd patch secret argocd-secret --patch='{"stringData": { "oidc.keycloak.clientSecret": "3QhTVm6g4Bp3EOJGDyCII4XEwITJxXwn" }}'

# 확인
kubectl get secret -n argocd argocd-secret -o jsonpath='{.data}' | jq
...
  "oidc.keycloak.clientSecret": "M1FoVFZtNmc0QnAzRU9KR0R5Q0lJNFhFd0lUSnhYd24=",
...

argocd 에서 keycloak authentication 를 활성화 할 수 있도록 설정해줍니다.

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: 3QhTVm6g4Bp3EOJGDyCII4XEwITJxXwn
    requestedScopes: ["openid", "profile", "email"]
'

# 확인
kubectl get cm -n argocd argocd-cm -o yaml | grep oidc.config: -A5

argocd server를 재시작 해줍니다.

kubectl rollout restart deploy argocd-server -n argocd

이렇게 한 후 argocd 에서 로그인을 해봅니다. LOG IN VIA KEYCLOAK 이 활성화 된 것 을 볼수 있습니다.

keycloak 으로 로그인하기를 클릭하면 아래와 같은 에러가 발생합니다.

failed to query provider "<http://keycloak.example.com/realms/myrealm>": Get "<http://keycloak.example.com/realms/myrealm/.well-known/openid-configuration>": dial tcp 127.0.0.1:80: connect: connection refused

keycloak으로 로그인 시 http://keycloak.example.com/realms/myrealm redirect 하는데 Host Mac에서는 해당 도메인이 접근되지만 kubernetes 환경에서는 해당 도메인에 대한 정보가 없기 때문에 접근을 할 수 없어 connect: connection refused 가 발생합니다.

ArgoCD가 **keycloak.example.com** 에 접근하지 못하는 경우, CoreDNS의 hosts 플러그인으로 클러스터 내부 IP로 매핑이 필요하기에 아래와 같이 설정을 해줍니다.

KEYCLOAK_IP=$(kubectl get svc -n default keycloak -o jsonpath='{.spec.clusterIP}' 2>/dev/null)
ARGOCD_IP=$(kubectl get svc -n argocd argocd-server -o jsonpath='{.spec.clusterIP}' 2>/dev/null)

kubectl patch cm coredns -n kube-system --type json -p="[
  {
    \"op\": \"replace\",
    \"path\": \"/data/Corefile\",
    \"value\": \".:53 {\\n    errors\\n    health {\\n       lameduck 5s\\n    }\\n    ready\\n    kubernetes cluster.local in-addr.arpa ip6.arpa {\\n       pods insecure\\n       fallthrough in-addr.arpa ip6.arpa\\n       ttl 30\\n    }\\n    hosts {\\n       ${KEYCLOAK_IP} keycloak.example.com\\n       ${ARGOCD_IP} argocd.example.com\\n       fallthrough\\n    }\\n    reload\\n    forward . /etc/resolv.conf {\\n       max_concurrent 1000\\n    }\\n    cache 30\\n    loop\\n    reload\\n    loadbalance\\n}\\n\"
  }
]"

# 확인
kubectl get cm coredns -n kube-system -o yaml
...
        hosts {
           10.96.201.45 keycloak.example.com
           10.96.74.42 argocd.example.com
           fallthrough
        }
...

위와 같이 설정 후 CoreDNS Pod가 자동으로 Reload 되며 다시 argocd에서 keycloak 으로 로그인하기를 누르면 아래와 같은 화면이 뜬다.

기존에 생성한 alice/alice123 비밀번호를 입력하고 접속한다.

Jenkins

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

# 도메인 설정
echo "127.0.0.1 **jenkins.example.com**" **| sudo tee -a /etc/hosts**

jenkins의 경우 nginx.ingress proxy body size를 무제한으로 설정해준다

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"

초기 암호를 확인한다.

kubectl exec -it -n jenkins deploy/jenkins -- **cat /var/jenkins_home/secrets/initialAdminPassword**
0ff6ec37578d420691e40a6bedc95a02

http://jenkins.example.com/ 에 접속하여 초기암호를 입력하고 설치를 진행해준다.

admin/qwe123 으로 암호를 설정한다.

jenkins도 동일하게 CoreDNS의 hosts 플러그인으로 클러스터 내부 IP 매핑을 해준다.

KEYCLOAK_IP=$(kubectl get svc -n default keycloak -o jsonpath='{.spec.clusterIP}' 2>/dev/null)
ARGOCD_IP=$(kubectl get svc -n argocd argocd-server -o jsonpath='{.spec.clusterIP}' 2>/dev/null)
JENKINS_IP=$(kubectl get svc -n jenkins jenkins-svc -o jsonpath='{.spec.clusterIP}' 2>/dev/null)

kubectl patch cm coredns -n kube-system --type json -p="[
  {
    \"op\": \"replace\",
    \"path\": \"/data/Corefile\",
    \"value\": \".:53 {\\n    errors\\n    health {\\n       lameduck 5s\\n    }\\n    ready\\n    kubernetes cluster.local in-addr.arpa ip6.arpa {\\n       pods insecure\\n       fallthrough in-addr.arpa ip6.arpa\\n       ttl 30\\n    }\\n    hosts {\\n       ${KEYCLOAK_IP} keycloak.example.com\\n       ${ARGOCD_IP} argocd.example.com\\n       ${JENKINS_IP} jenkins.example.com\\n       fallthrough\\n    }\\n    reload\\n    forward . /etc/resolv.conf {\\n       max_concurrent 1000\\n    }\\n    cache 30\\n    loop\\n    reload\\n    loadbalance\\n}\\n\"
  }
]"

# 확인
kubectl get cm coredns -n kube-system -o yaml
...
        hosts {
           10.96.201.45 keycloak.example.com
           10.96.74.42 argocd.example.com
           10.96.95.174 jenkins.example.com
           fallthrough
        }
...

jenkins도 keycloak을 통해서 사용자 인증처리하여 로그인 할 수 있도록 keycloak에 접속하여 아래의 정보로 client를 생성해준다.(argocd client 생성 화면 참조)

keycloak 에 jenkins 를 위한 client 생성

http://jenkins.example.com/manage/pluginManager/available 에 접속하여 OpenID Connect Authentication plugins을 설치해준다**.**

재시작은 진행할 필요는 없다.

그런 다음 http://jenkins.example.com/manage/configureSecurity/ 으로 접속하여 keycloak 설정을 jenkins에 해준다.

  • Login with Openid Connect
  • Client id : jenkins
  • Client secret : <keycloak 에서 jenkins client 에서 credentials>
  • Configuration mode : Discovery…
  • Well-know configuration endpoint http://keycloak.example.com/realms/**myrealm**/.well-known/openid-configuration
  • Override scopes : openid email profile
  • Logout from OpenID Provider : Check
  • Security configuration
    • Disable ssl verification : Check

Jenkisn Logout을 하고 다시 접속시 keycloak 로그인으로 redirect된다. keycloak user/password인 alice/alice123 을 입력하면 jenkins에 로그인이 된다.

Jenkins와 ArgoCD 두 군데에 로그인 하면 keycloak session에서 두 군데에 로그인된 것을 확인할 수 있다.

LADP 구성하기

LDAP 이란 사용자·그룹·권한 정보를 계층적으로 보관하는 “주소록/조직도” 이다. 사내에서 구성원 정보를 계층적으로 관리하는데 많이 사용된다.

실습으로는 OPEN LDAP을 설치한다. 아래 예제를 참조해서 설치해본다.

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
NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/openldap   1/1     1            1           31s

NAME                            READY   STATUS    RESTARTS   AGE
pod/openldap-54857b746c-t2rf2   2/2     Running   0          31s

NAME               TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                                    AGE
service/openldap   NodePort   10.96.232.206   <none>        80:30000/TCP,389:31842/TCP,636:31803/TCP   31s

NAME                 ENDPOINTS                                        AGE
endpoints/openldap   10.244.0.31:80,10.244.0.31:389,10.244.0.31:636   31s

# 기본 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 krew install stern
kubectl stern -n openldap openldap-54857b746c-ch9g4

http://127.0.0.1:30000/ 로 접속하여 위와 같이 로그인한다.

만약 로그인이 안된다면 deployment를 삭제하고 재배포 해본다.

로그인이 성공하면 아래와 같은 화면을 볼 수 있다.

openldap 을 cli에서 구성해본다.

# ldap cli 접속
kubectl -n openldap exec -it deploy/openldap -c openldap -- bash

# pstree 출력
pstree -aplpst
run,1 -u /container/tool/run
  └─slapd,433 -h ldap://openldap-54857b746c-t2rf2:389 ldaps://openldap-54857b746c-t2rf2:636 ldapi:/// -u openldap -g openldap -d 256
      ├─{slapd},436
      ├─{slapd},437
      └─{slapd},438

# 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
  • user는 alice, bob을 사용합니다.
  • group은 devs, admins 그룹을 사용합니다.
  • ou(organizationalUnit) 은 people, groups 입니다.

위에 명시된 정보를 ldap에 생성하는 작업을 아래 스크립트에서 진행합니다. 기존에 접속한 ldap bash 환경에서 이어서 작업합니다.

# 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 UI에서 Refresh 버튼을 클릭하면 아래와 같이 볼 수 있습니다.

Keycloak에서 LDAP 구성하기

keycloak과 ldap을 구성합니다. 유저를 keycloak이 아닌 ldap에서 생성하고 관리합니다. keycloak은 User Federation 으로 LDAP과 연동하여 사용자 정보를 동기화합니다.

설정 중간에 Test 버튼을 클릭하여 정상 연동됨을 확인합니다.

설정 값은 아래와 같습니다.

  • General
    • UI display name: ldap
    • Vendor: Other
  • Connection and authentication
    • Connection URL: ldap://openldap.openldap.svc:389 ⇒ Test connection
    • Bind DN: (= Login DN) cn=admin,dc=example,dc=org
    • Bind Credential: admin ⇒ Test authentication
  • LDAP searching and updating
    • Edit mode: WRITABLE
    • Users DN: ou=people,dc=example,dc=org
    • Username LDAP attribute: uid
    • RDN LDAP attribute: uid
    • UUID LDAP attribute: uid
    • User Object Classes: inetOrgPerson
    • Search scope: Subtree (OU 하위 모두 탐색)
  • Synchronization settings
    • Import Users: On (LDAP → KeyCloak : Sync OK)
    • Sync Registrations: Off (KeyCloak → LDAP : Sync OK)

위와 같이 설정하고 Keycloak에서 Users에서 전체 검색 시 LDAP에 등록된 유저가 연동됨을 확인 할 수 있습니다.

Bob 유저의 상세정보를 아래와 같이 Federation link 가 LDAP으로 설정됨을 볼 수 있습니다.

 

만약 보이지 않는다면 User Federation → LDAP Provider 선택 → Settings → Action : Sync all users 를 해봅니다.

 

유저 연동됨을 확인했으니 ArgoCD와 Jenkins으로 이동하여 bob 유저로 로그인해봅니다.

bob(암호: bob123) 를 입력하고 정상적으로 로그인 되는지 확인합니다. 로그인 된다면 ldap → keycloak 연동이 완료됨을 확인할 수 있습니다.

alice(암호: alice123) 도 동일하게 테스트 해줍니다.

새로운 유저인 jack(암호: jack123) 도 추가해서 로그인 해봅니다.

cat <<EOF | ldapadd -x -D "cn=admin,dc=example,dc=org" -w admin
dn: uid=jack,ou=people,dc=example,dc=org
objectClass: inetOrgPerson
cn: Jack
sn: Hong
uid: jack
mail: jack@example.org
userPassword: jack123
EOF

위와 같이 ldap user를 생성하고 로그인하면 정상적으로 로그인 됨을 확인 할 수 잇습니다.

ArgoCD에 LDAP User 권한 연동

argocd 에 sample application을 배포하고 조회가 되는지 테스트 해보겠습니다. 아래 스크립트로 샘플 애플리케이션을 배포해줍니다.

cat https://github.com/hanship0530/Learning
        targetRevision: HEAD
        path: ci-cd-cookbook/6w/guestbook
      destination:
        server: '{{.server}}'
        namespace: guestbook
      syncPolicy:
        syncOptions:
          - CreateNamespace=true
EOF

# sync
argocd app sync -l managed-by=applicationset

# 생성된 application yaml 확인
kubectl get applications -n argocd in-cluster-guestbook -o yaml | k neat | yq
kubectl get applications -n argocd dev-k8s-guestbook -o yaml | k neat | yq
kubectl get applications -n argocd prd-k8s-guestbook -o yaml | k neat | yq

# 각 k8s 에 배포된 파드 정보 확인
k8s1 get pod -n guestbook
k8s2 get pod -n guestbook
k8s3 get pod -n guestbook

jack 유저로 로그인해서 확인해보겠습니다.

 

로그인 시 아무것도 보이지 않습니다. Cookie에 등록된 jwt 정보를 확인해봅니다.

https://www.jwt.io/ 해당 값을 입력해서 확인해보면 User는 Jack인것을 확인할 수 있습니다.

현재 배포된 애플리케이션이 안보이는 이유는 Keycloak에 아무런 Group 정보가 연동이 안되어서 그렇습니다.

Keycloak에서 admin으로 접속하여 Group를 연동해줍니다.

  • User Federation → LDAP Provider 선택 → Mappers → Add mapper → 아래 설정 후 Save
    • name : ldap-groups
    • Mapper type: group-ldap-mapper
    • LDAP Groups DN : ou=groups,dc=example,dc=org
    • Group Name LDAP Attribute: cn
    • Group Object Classed: groupOfNames
    • Membership LDAP attribute: member
    • Membership attribute type: DN
    • Mode: READ_ONLY

위와 같이 설정하고 User federations → LDAP → Mappers → ldap-groups 선택 → Action → Sync LDAP groups to Keycloak 클릭해줍니다. 그리고 Group을 확인합니다.

그런 다음 Keycloak 에서 토큰에 Group 전달을 위한 설정 : ArgoCD Client 설정을 해줍니다.

  • Client Scoups 생성 : Name (groups) , 나머지는 기본값

그런 다음 해당 client scopes 에서 mappers 클릭 → [Configure a new mapper] 클릭 한 후 mapper 리스트가 나타나면 'Group Membership' 선택 후 Name, Token Claim Name 에 groups 입력

 

 

argocd client 에서 groups 전달을 위한 설정을 합니다. : client 에서 argocd 클릭

  • [Client scopes] 탭 이동 후, Add client scope 클릭 후 생성한 groups를 선택합니다. 이때, [Add] 선택 후 드롭다운의 Default를 선택.

 

위와 같이 설정 이후 Argo CD에 scope 에 groups 추가 설정을 진행하고 나서 로그아웃 후 로그인 시도를 해봅니다. (적용을 위해서 15초 정도 후에 아래 로그인 진행 합니다.)

Keycloak → Sessions → jack signout 을 해줍니다.

kubectl edit cm -n argocd argocd-cm
...
    requestedScopes: ["openid", "profile", "email" , "groups"]
...

 

scope에 groups가 추가되었습니다.

 

로그인 후 auth? 에서 scope에 groups가 추가된것을 확인합니다.

그런 다음 jack 계정으로 app 조회를 하기 위해 아래의 작업을 진행해줍니다.

Argo CD RBAC 할당 합니다. (Keycloak 그룹 ArgoCDAdmins에 ArgoCD 권한을 매핑하기 위해 argocd-rbac-cm 컨피그맵을 업데이트)

kubectl edit cm argocd-rbac-cm -n argocd
...
data:
  policy.csv: |
    g, devs, role:admin
...

해당 설정 후 bob으로 로그인 시 app이 보이지만 jack의 경우 안보입니다. Keycloak 을 확인해보면 Jack은 dev group에 추가가 안된 것을 볼 수 있습니다.

Ldap에서 추가해줍니다.

# ldap cli 접속
kubectl -n openldap exec -it deploy/openldap -c openldap -- bash
cat <<EOF | ldapmodify -x -D "cn=admin,dc=example,dc=org" -w admin
dn: cn=devs,ou=groups,dc=example,dc=org
changetype: modify
add: member
member: uid=jack,ou=people,dc=example,dc=org
EOF

위와 같이 한 후 User federation → ldap → Mappers → ldap-groups → Action → Sync LDAP groups to Keycloak 을 클릭하여 동기화를 진행해줍니다.

위와 같이 한 후 User federation → ldap → Settings → Action → Sync all users 을 클릭하여 동기화를 진행해줍니다.

이후 Keyclaok Groups에 devs 의 Members를 확인해보면 jack 추가된 것을 볼 수 있습니다. Jack User 정보에서도 Group에 추가됬는지 확인을 해줍니다.

 

devs 그룹에 jack 이 추가되었습니다.

Session에서 Jack을 Sign out 시킨 후 다시 로그인을 하면 dev-k8s-guestbook을 확인 할 수 있습니다.

 

LDAP + Keyclaok 으로 사용자 인증을 구현하고 Jenkins, ArgoCD에 접근을 제어하는 설정을 진행해보았습니다.

실습한 모든 클러스터를 삭제합니다.

kind get clusters | xargs -I {} kind delete cluster --name {}

'스터디 > [gasida] ci-cd 스터디 1기' 카테고리의 다른 글

Image Build  (0) 2025.12.05
Vault  (0) 2025.11.26
ArgoCD ApplicationSet  (0) 2025.11.23
Arocd Rollout  (0) 2025.11.16
ArgoCD + Ingress + Self Managed  (0) 2025.11.16

+ Recent posts