안녕하세요. 저는 오픈소스컨설팅에서 고객사의 CI/CD 환경을 효율적으로 개선하고, Kubernetes 기반의 애플리케이션 배포를 자동화하는 방식에 대해 다양한 컨설팅을 진행하고 있는 DevOps Engineer 정광필입니다.
이번 기술 블로그에서는 여러 고객사 컨설팅을 진행하면서 가장 많은 문의를 받았던 사용자별 ArgoCD 권한 부여 방법을 Keycloak으로 설정하는 방식에 대해 설명드리려 합니다.
ArgoCD는 개발자, 운영자, DevOps 엔지니어들이 Kubernetes에 애플리케이션을 GUI 기반으로 손쉽게 배포할 수 있도록 돕는 강력한 도구입니다. 하지만 ArgoCD의 기본 설정은 로그인한 모든 사용자에게 전체 리소스에 대한 접근 권한을 부여합니다. 이 때문에 별도의 권한 분리 설정(RBAC)을 하지 않을 경우, 사용자 간 불필요한 리소스 노출이나 의도치 않은 접근으로 인한 설정 변경으로 인해 보안 사고나 서비스 운영에 문제가 발생할 수 있습니다.
이러한 문제를 해결하기 위해 Keycloak과 같은 인증 서버를 통해 SSO(Single-Sign On) 기반으로 로그인한 사용자에게 Role별로 ArgoCD에서 관리하는 리소스별로 권한을 부여하는 방식을 활용하면, 권한을 세부적으로 관리하고 보안을 강화할 수 있습니다.
Keycloak은 오픈소스 기반의 Identity and Access Management (IAM) 솔루션으로, 웹 애플리케이션과 API를 안전하게 보호하기 위한 다양한 기능을 제공합니다. 단순한 사용자 로그인 기능을 넘어, 엔터프라이즈 환경에서 요구되는 복잡한 인증 및 권한 관리 요구사항에 맞춰 설계되었습니다.
Keycloak은 애플리케이션과 분리된 독립적인 인증 서버 역할을 수행합니다. 애플리케이션 개발자는 인증 로직을 직접 구현하는 대신, Keycloak에 사용자를 리다이렉션하고 Keycloak으로부터 토큰(JWT)을 받아 인증 상태를 확인하는 방식으로 인증을 처리합니다. 이 방식은 애플리케이션 개발의 복잡성을 줄이고, 보안 취약점을 최소화하는 데 큰 도움을 줍니다.
결론적으로, Keycloak은 엔터프라이즈 환경에서 필요한 모든 인증 및 권한 관리 기능을 통합적으로 제공하는 강력한 도구이며, 개발자는 핵심 비즈니스 로직에 더 집중할 수 있게 해줍니다.
ArgoCD는 GitOps 방식을 채택한 쿠버네티스용 지속적 배포(CD) 도구입니다. 애플리케이션의 모든 상태를 Git 저장소에서 관리하고, 이를 쿠버네티스 클러스터에 자동으로 동기화하는 것을 핵심으로 합니다. 단순한 배포를 넘어, GitOps의 장점을 극대화하는 다양한 기능을 제공합니다.
ArgoCD는 GitOps 방식을 통한 배포를 진행합니다. GitOps는 애플리케이션 배포와 운영에 관련된 모든 요소를 Git에서 관리(Ops)하는 방법론입니다. ArgoCD는 GitOps 전략을 사용하여 다음과 같은 단계로 배포를 진행합니다.
이러한 방식 덕분에, K8s에 배포할 리소스를 서버에 직접 접근하여 배포할 필요가 없어집니다. 모든 변경 사항은 Git의 커밋 히스토리로 기록되므로, 롤백이나 Trouble Shooting시 문제 추적이 매우 쉬워집니다.
추가적으로 ArgoCD에서는 Git 저장소에 K8s Menifest 파일을 연동하여 사용하는 방법 외에도 Helm Repository를 바로 연동하여 Helm Chart를 통해 배포하는 방식도 가능합니다.
결론적으로, ArgoCD는 GitOps를 통해 K8s 애플리케이션 배포를 자동화하고, 안정적인 운영 환경을 구축하는 데 필수적인 도구입니다.
ArgoCD는 자체적인 사용자 관리 시스템을 가지고 있지 않기 때문에, argocd-rbac-cm
ConfigMap을 통해 RBAC 정책을 설정합니다. 이 정책은 특정 Group에 Role을 부여해서 그룹별 특정 리소스에 대한 권한을 부여하는 방식으로 동작합니다.
ArgoCD는 사용자의 인증을 위해 외부 OIDC(OpenID Connect) 공급자와의 연동을 지원합니다. Keycloak이 바로 이 OIDC 공급자 역할을 수행하는 것이죠. Keycloak과 ArgoCD를 연동하면 다음과 같은 이점을 얻을 수 있습니다.
argocd-admin
그룹의 사용자에게는 ArgoCD의 모든 권한을, argocd-developer
그룹의 사용자에게는 ArgoCD의 특정 프로젝트 조회 권한만 부여하는 방식이 가능해집니다.다음 챕터에서는 이와 같은 이점을 실제로 구현하기 위해 Keycloak과 ArgoCD를 어떻게 설정하는지 Tool 구축부터 연동 방식까지 구체적인 내용과 함께 설명하겠습니다.
Keycloak & ArgoCD는 MacOS의 Minikube Cluster 위에 Helm chart로 구축하였습니다.
MacOS Minikube Cluster 구축방식 및 ingress-controller 설정 방식은 아래 공식 문서를 참고해주세요.
ingress-controller는 IP:Port 방식이 아닌 도메인(Ex. argocd.cicd.test.com) 방식으로 Keycloak & ArgoCD에 접근할 수 있도록 도와주는 Minikube Addon입니다.
MacOS Minikube 구축방식 : minikube start
Minikube ingress-controller 구축방식 : Ingress DNS
# bitnami repository 추가하기
$ helm repo add bitnami https://charts.bitnami.com/bitnami
# bitnami repository가 잘 추가되었는지 확인하기
$ helm repo list | grep bitnami
bitnami https://charts.bitnami.com/bitnami
# bitnami repository에 keycloak helm chart 확인하기
$ helm search repo | grep keycloak
bitnami/keycloak 25.0.0 26.3.2 Keycloak is a high performance Java-based ident... Keycloak is a high performance Java-based ident...
values.yaml 설정은 서버 환경과 사용 방식에 따라 가변적으로 설정을 진행해야 하기 때문에 본 가이드에서는 values.yaml 설정에 대한 방식은 다루지 않습니다.
# keycloak 설정값이 포함된 values.yaml 추출하기
$ helm show values bitnami/keycloak > values.yaml
# values.yaml 설정하기
$ vi values.yaml
```
# Copyright Broadcom, Inc. All Rights Reserved.
# SPDX-License-Identifier: APACHE-2.0
## @section Global parameters
global:
## Global Docker image parameters
## Please, note that this will override the image parameters, including dependencies, configured to use the global value
## @param global.imageRegistry Global Docker Image registry
## @param global.imagePullSecrets Global Docker registry secret names as an array
##
imageRegistry: ""
imagePullSecrets: []
## @param global.defaultStorageClass Global default StorageClass for Persistent Volume(s)
##
defaultStorageClass: ""
## Security parameters
## @param global.security.allowInsecureImages Allows skipping image verification
##
```
3. keycloak을 생성할 namespace를 생성한 후, Helm install을 통해 keycloak을 생성한 namespace 위에 설치합니다.
# keycloak namespace 생성하기
$ kubectl create namespace keycloak
# keycloak namespace 위에 values.yaml 설정값을 참조하는 keycloak 설치하기
$ helm install keycloak bitnami/keycloak -n keycloak -f values.yaml
4. keycloak 리소스를 조회하여 클러스터 위에 설치가 된 모습을 확인합니다.
# keycloak 리소스 조회하기
$ kubectl get po,ing,svc -n keycloak
NAME READY STATUS RESTARTS AGE
pod/keycloak-0 1/1 Running 0 15h
pod/keycloak-postgresql-0 1/1 Running 0 15h
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress.networking.k8s.io/keycloak nginx your-keycloak-domain keycloak-IP 80, 443 15h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/keycloak ClusterIP 10.106.121.149 <none> 80/TCP 15h
service/keycloak-headless ClusterIP None <none> 8080/TCP 15h
service/keycloak-postgresql ClusterIP 10.98.128.138 <none> 5432/TCP 15h
service/keycloak-postgresql-hl ClusterIP None <none> 5432/TCP 15h
5. 브라우저로 keycloak 콘솔에 접속하여 keycloak을 확인합니다.
6. 구축한 Keycloak에 Realm, Client, User를 생성하는 방식은 아래 공식 문서를 참고해주세요.
User 생성 방법 : Server Administration Guide
Realm 생성 방법 : Server Administration Guide
Client 생성 방법 : Server Administration Guide
# argo repository 추가하기
$ helm repo add argo https://argoproj.github.io/argo-helm
# argo repository가 잘 추가되었는지 확인하기
$ helm repo list | grep argo
argo https://argoproj.github.io/argo-helm
# argo repository에 argo-cd helm chart 확인하기
$ helm search repo | grep argo-cd
argo/argo-cd 8.2.5 v3.0.12 A Helm chart for Argo CD, a declarative, GitOps...=
values.yaml 설정은 서버 환경과 사용 방식에 따라 가변적으로 설정을 진행해야 하기 때문에 본 가이드에서는 values.yaml 설정에 대한 방식은 다루지 않습니다.
# keycloak 설정값이 포함된 values.yaml 추출하기
$ helm show values argo/argo-cd > values.yaml
# values.yaml 설정하기
$ vi values.yaml
```
## Argo CD configuration
## Ref: https://github.com/argoproj/argo-cd
##
# -- Provide a name in place of `argocd`
nameOverride: argocd
# -- String to fully override `"argo-cd.fullname"`
fullnameOverride: ""
# -- Override the namespace
# @default -- `.Release.Namespace`
namespaceOverride: ""
# -- Override the Kubernetes version, which is used to evaluate certain manifests
kubeVersionOverride: ""
# Override APIVersions
# If you want to template helm charts but cannot access k8s API server
# you can set api versions here
apiVersionOverrides: {}
# -- Create aggregated roles that extend existing cluster roles to interact with argo-cd resources
```
3. argo-cd을 생성할 namespace를 생성한 후, Helm install을 통해 keycloak을 생성한 namespace 위에 설치합니다.
# argo-cd namespace 생성하기
$ kubectl create namespace argo-cd
# argo-cd namespace 위에 values.yaml 설정값을 참조하는 argo-cd 설치하기
$ helm install keycloak argo/argo-cd -n argo-cd -f values.yaml
4. argo-cd values.yaml에는 ingress 설정이 따로 없으므로 argo-cd-ing.yaml 파일을 생성한 후 apply 명령어로 ingress 명령어를 생성합니다.
# argo-cd ingress yaml 파일 생성
$ vi argo-cd-ing.yaml
```
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
nginx.ingress.kubernetes.io/ssl-redirect: "true"
name: argo-cd-argocd-server
namespace: argo-cd
spec:
ingressClassName: nginx
rules:
- host: your-argo-domain
http:
paths:
- backend:
service:
name: argo-cd-argocd-server
port:
number: 443
path: /
pathType: Prefix
tls:
- hosts:
- your-argo-domain
secretName: your-tls-secret-name
```
# argo-cd ingress 배포
$ kubectl apply -f argo-cd-ing.yaml
5. argo-cd 리소스를 조회하여 클러스터 위에 설치가 된 모습을 확인합니다.
$ kubectl get po,svc,ing -n argo-cd
NAME READY STATUS RESTARTS AGE
pod/argo-cd-argocd-application-controller-0 1/1 Running 0 15h
pod/argo-cd-argocd-applicationset-controller-b8f8c88b6-287mp 1/1 Running 0 15h
pod/argo-cd-argocd-dex-server-6c68c96f4f-wtbwm 1/1 Running 0 15h
pod/argo-cd-argocd-notifications-controller-c468d8dc8-w2p8w 1/1 Running 0 15h
pod/argo-cd-argocd-redis-6f6f6c4d54-h2kz5 1/1 Running 0 15h
pod/argo-cd-argocd-repo-server-777d9bd79d-hztdc 1/1 Running 0 15h
pod/argo-cd-argocd-server-5c8f57dfdb-zwdhh 1/1 Running 0 15h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/argo-cd-argocd-applicationset-controller ClusterIP 10.104.223.12 <none> 7000/TCP 15h
service/argo-cd-argocd-dex-server ClusterIP 10.110.45.249 <none> 5556/TCP,5557/TCP 15h
service/argo-cd-argocd-redis ClusterIP 10.100.24.28 <none> 6379/TCP 15h
service/argo-cd-argocd-repo-server ClusterIP 10.98.2.157 <none> 8081/TCP 15h
service/argo-cd-argocd-server ClusterIP 10.101.9.1 <none> 80/TCP,443/TCP 15h
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress.networking.k8s.io/argo-cd-argocd-server nginx your-argo-domain your-ingress-ip 80, 443 15h
6. 브라우저로 argo-cd에 접속해서 argo-cd를 확인합니다.
argocd-cm
ConfigMap을 수정하여 ArgoCD에 Keycloak을 연동합니다.# argocd-cm ConfigMap 수정
$ kubectl edit cm -n argocd argocd-cm
```
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
# Keycloak OIDC 설정
oidc.config: |
name: Keycloak
issuer: https://your-keycloak-url/realms/your-realm-name
clientID: argocd
clientSecret: your-keycloak-client-secret
requestedScopes: ['openid']
logoutURL: https://your-keycloak-url/realms/your-realm-name/protocol/openid-connect/logout?id_token_hint={{token}}&post_logout_redirect_uri=https://your-argocd-url
```
2. argocd-server deployment를 재시작하여 변경 사항을 적용합니다.
# argo-cd-argocd-server 재시작
$ kubectl rollout restart -n argo-cd deployment argo-cd-argocd-server
3. 브라우저로 ArgoCD에 접속하여 LOG IN VIA KEYCLOAK 버튼이 활성화 되어있는지 확인합니다.
4. LOG IN VIA KEYCLOAK 버튼을 클릭하여 keycloak 로그인 창으로 로그인을 진행하여 ArgoCD 홈 화면으로 접근합니다.
ArgoCD RBAC 설정은 Keycloak에서 Admin 유저, 일반 유저를 생성하고, ArgoCD에는 특정 Project, Repository, Application을 생성한 뒤, Admin 유저에게는 ArgoCD의 모든 리소스 및 설정에 접근할 수 있는 권한을 부여하고, 일반 유저에게는 ArgoCD의 특정 프로젝트, Cluster에만 접근할 수 있게 설정하는 방법을 설명합니다.
2. Users → 생성한 Admin 유저 사용자 → Groups → Join Group을 통해 생성한 admin Group에 Join 합니다.
argocd-rbac-cm
ConfigMap을 수정하여 admin 그룹에 admin role 권한을 부여합니다.policy.csv
는 쉼표로 구분된 정책 규칙들을 담고 있으며, 각 행은 특정 권한을 부여하는 역할을 합니다.g, admin, role:admin
의 의미는 admin
그룹에 속한 사용자는 Argo CD의 최고 권한을 가진 role:admin
역할을 부여받습니다. 이 역할은 기본적으로 모든 권한을 가진다는 의미입니다.# argocd-rbac-cm ConfigMap 수정
$ kubectl edit cm -n argo-cd argocd-rbac-cm
```
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-rbac-cm
namespace: argo-cd
data:
policy.csv: |
g, admin, role:admin
policy.default: ''
policy.matchMode: glob
scopes: '[groups]'
```
2. argocd-server deployment를 재시작하여 변경 사항을 적용합니다.
# argo-cd-argocd-server 재시작
$ kubectl rollout restart -n argo-cd deployment argo-cd-argocd-server
2. Settings → Repositories → CONNECT REPO를 통해 배포할 Application의 Menifest 파일이 들어있는 git repository를 연결합니다. 이때 Project는 앞서 생성한 project로 설정합니다.
3. Applications → +New App을 통해 아래 예시와 같이 설정합니다.
4. Application이 생성된 모습을 확인할 수 있습니다.
2. Groups → Create Group을 통해 일반 사용자가 포함될 그룹 하나를 생성합니다.
3. Users → 생성한 일반 유저 사용자 → Groups → Join Group을 통해 생성한 Group에 Join 합니다.
4.4 일반 유저로 ArgoCD 접근하기 단계에서 일반 유저로 로그인 시 아무런 권한이 없기 때문에 ArgoCD 리소스들을 확인할 수 없었습니다. 그렇기 때문에 이번 단계에서는 일반 사용자가 포함되어 있는 그룹인 testgroup에 특정 ArgoCD 프로젝트가 접근할 수 있는 Role을 생성하여 특정 프로젝트에 접근 가능하게끔 설정하는 방식을 예시와 함께 설명드리겠습니다.
argocd-rbac-cm
ConfigMap을 수정하여 testgroup 그룹에 특정 ArgoCD 프로젝트(testproj) role을 매핑합니다.p, role:test, ...
: test
라는 이름의 역할을 정의하는 규칙입니다.
p, role:test, applications, *, testproj/*, allow
: role:test
에 속한 사용자는 testproj
프로젝트에 속한 모든 애플리케이션에 대해 모든 작업()을 수행할 수 있습니다.p, role:test, repositories, *, testproj/*, allow
: role:test
는 testproj
프로젝트와 연결된 모든 Git 리포지토리에 대해 모든 작업을 할 수 있습니다.p, role:test, projects, *, testproj, allow
: role:test
는 testproj
라는 프로젝트 자체에 대해 모든 작업을 할 수 있습니다.p, role:test, clusters, *, <https://kubernetes.default.svc>, allow
: role:test
는 기본 쿠버네티스 클러스터(https://kubernetes.default.svc
)에 대해 모든 작업을 할 수 있습니다.g, testgroup, role:test
: 이는 testgroup
이라는 이름의 그룹을 role:test
역할에 연결합니다. 즉, testgroup
에 속한 모든 사용자는 role:test
가 가진 모든 권한을 상속받습니다.# argocd-rbac-cm ConfigMap 수정
$ kubectl edit cm -n argo-cd argocd-rbac-cm
```
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-rbac-cm
namespace: argo-cd
data:
policy.csv: |
p, role:test, applications, *, testproj/*, allow
p, role:test, repositories, *, testproj/*, allow
p, role:test, projects, *, testproj, allow
p, role:test, clusters, *, https://kubernetes.default.svc, allow
g, testgroup, role:test
g, admin, role:admin
policy.default: ''
policy.matchMode: glob
scopes: '[groups]'
```
2. argocd-server deployment를 재시작하여 변경 사항을 적용합니다.
# argo-cd-argocd-server 재시작
$ kubectl rollout restart -n argo-cd deployment argo-cd-argocd-server
3. 일반 유저로 ArgoCD에 로그인 하여 권한이 부여된 프로젝트(testproj)에 관련된 리소스가 보이는지 확인합니다.
이번 기술 블로그를 통해 Keycloak과 ArgoCD를 연동하여 RBAC(Role-Based Access Control) 기반의 접근 제어를 구현하는 방법을 단계별로 살펴보았습니다. 이를 통해 Keycloak을 활용하여 단순히 로그인 기능을 연동하는 수준을 넘어, 각 사용자의 역할과 권한을 세부적으로 관리하고, 이를 ArgoCD와 연동해 실 서비스 운영에 반영하는 과정까지 다루었습니다.
Keycloak을 통해 인증과 권한 부여를 일원화하면 조직 내 여러 서비스가 동일한 정책과 기준으로 운영될 수 있고, 사용자 관리가 분산되지 않아 보안 취약점을 줄일 수 있습니다. 특히 대규모 DevOps 환경에서는 프로젝트별 혹은 팀별 접근 권한을 체계적으로 제어할 수 있어, 운영 효율성과 감사 추적성(auditability)까지 강화되는 장점이 있습니다.
또한 ArgoCD와의 연동을 통해 GitOps 파이프라인에서 필요한 승인 절차나 배포 범위를 세밀하게 제어할 수 있으므로, 운영자는 시스템 전반을 더 안정적으로 관리할 수 있습니다. 이는 단순한 기술적 편리함을 넘어, 기업의 보안 정책 준수와 컴플라이언스 측면에서도 중요한 가치를 가집니다.
앞으로는 이 구성을 바탕으로, 예를 들어 특정 팀이 특정 네임스페이스만 배포할 수 있게 한다거나, 운영 환경에서는 이중 승인 체계를 적용하는 등, 더 현실적이고 맞춤화된 정책을 실험해보는 것도 좋은 방향이 될 것입니다.
결론적으로, Keycloak과 ArgoCD의 RBAC 연동은 단순한 기술 조합이 아니라, 안정적이고 확장 가능한 DevSecOps 문화를 구축하기 위한 핵심 구조 중 하나라고 생각합니다. 이 글이 실제 환경에 적용하는 데 있어 기초 가이드 역할을 하길 바라며, 앞으로도 꾸준히 다양한 시나리오와 적용 사례를 공유해드리겠습니다. 감사합니다.