
접근 제어
1·2장에서 GitOps와 Argo CD의 기본 원리를 살펴보고,
3장에서는 고가용성과 실전 운영 전략을 다뤘다.
이제부터는 “누가 Argo CD에 접근해서 무엇을 할 수 있는가?”를 다루는 접근 제어 챕터다.
특히 다음 네 가지 축을 중심으로 정리해본다.
- 선언적 사용자 관리 (admin, 로컬 계정)
- RBAC 정책
- 서비스 어카운트 (CI/CD용 계정)
- SSO 및 Keycloak 연동
접근 제어는 “보안”만의 이야기가 아니라, 운영상 안정성과 책임의 경계(블레임 라인)를 분리하는 핵심 요소다.
1. 접근 제어 개요
Argo CD의 접근 제어는 크게 이렇게 구성된다.
| 구분 | 역할 |
| 로컬 사용자 / admin | 설치 직후 접근 가능한 계정, 최소 권한 운영용 로컬 계정 |
| RBAC 정책 (argocd-rbac-cm) | 사용자·그룹이 어떤 리소스에 어떤 동작을 할 수 있는지 정의 |
| AppProject 역할 | 특정 프로젝트에 속한 애플리케이션에 대한 세밀한 권한 제어 |
| 서비스 어카운트 | CI/CD 파이프라인 등 자동화에서 사용하는 계정/토큰 |
| SSO (Dex, Keycloak 등) | 외부 IdP와 연동하여 조직 계정 기반으로 접근 제어 |
3장에서 인프라 레벨의 HA를 다뤘다면, 4장은 그 위에서 “사람과 시스템이 어떻게 안전하게 Argo CD를 사용할 것인지”를 설계하는 이야기라고 보면 된다.
2. 선언적 사용자 – admin과 로컬 계정
2.1 기본 admin 계정과 초기 비밀번호
Argo CD를 설치하면 기본적으로 admin 계정이 생성된다.
- 시스템 전체에 대한 슈퍼유저 권한 보유
- 초기 비밀번호는 argocd-initial-admin-secret 시크릿에 저장
kubectl get secret -n argocd argocd-initial-admin-secret \
--context kind-myk8s \
-o jsonpath='{.data.password}' | base64 -d
# 출력 값이 초기 admin 비밀번호
이 비밀번호로 UI 또는 CLI에 로그인한 뒤, 반드시 비밀번호를 변경해야 한다.
argocd account update-password
# Enter password of currently logged in user (admin): <기존 비번>
# Enter new password for user admin: <새 비번>
# Confirm new password for user admin: <새 비번>
# Password updated
비밀번호를 분실했을 때는 FAQ에 따라 시크릿의 bcrypt 해시를 초기화하거나 수정해서 복구 가능하다.
운영 환경에서는 admin 계정을 장기간 쓰지 않고, 초기 구성 후 비활성화하는 것이 일반적인 패턴이다.
2.2 admin 계정 비활성화
argocd-cm ConfigMap에서 admin 계정을 비활성화할 수 있다.
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
admin.enabled: "false"
- 설치 직후: admin 계정으로 Argo CD 초기 설정 및 로컬 계정/SSO 구성
- 이후: admin 계정 비활성화, 실제 운영은 로컬 사용자 또는 SSO 기반 계정 사용
관리자를 “비밀번호를 아는 소수”에서 “조직 계정/그룹”으로 옮겨가는 과정이기 때문에, 장기적으로는 반드시 거쳐야 할 단계라고 보는 게 맞다.
2.3 최소 권한 로컬 사용자 – alice 생성
일상적인 작업(애플리케이션 조회, 동기화 등)을 위한 로컬 사용자 alice를 선언적으로 생성해보자.
- argocd-cm에 사용자 추가
KUBE_EDITOR="nano" kubectl edit cm -n argocd argocd-cm
data:
# alice 사용자 추가
# - apiKey : API 키 발급 가능
# - login : UI/CLI 로그인 가능
accounts.alice: apiKey, login
# 계정 비활성화 예시
# accounts.alice.enabled: "false"
- 계정 생성 확인
argocd account list
# NAME ENABLED CAPABILITIES
# admin true login
# alice true apiKey, login
- 비밀번호 설정
argocd account update-password \
--account alice \
--current-password qwe12345 \
--new-password alice12345
- 시크릿에 저장된 계정 정보 확인
kubectl get secret -n argocd argocd-secret \
-o jsonpath='{.data}' | jq
여기에 accounts.alice.password, accounts.alice.passwordMtime, accounts.alice.tokens 등이 bcrypt 및 base64 형태로 저장된다.
2.4 권한이 없을 때의 모습 – Guestbook 예제
관리자가 guestbook Helm 예제 애플리케이션을 생성했다고 하자.
cat <https://github.com/argoproj/argocd-example-apps
targetRevision: HEAD
syncPolicy:
automated:
enabled: true
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
destination:
namespace: guestbook
server: https://kubernetes.default.svc
EOF
이 상태에서 alice로 로그인하면, RBAC 기본 정책에 따라 애플리케이션이나 클러스터가 보이지 않을 수 있다.
즉:
- “사용자를 만들었다고 해서 자동으로 권한이 생기는 것은 아니다”
- “사용자 관리”와 “권한 관리(RBAC)”는 별개의 단계다
라는 것을 직관적으로 보여주는 예제다.
3. RBAC: 정책으로 권한 부여하기
Argo CD의 RBAC는 크게 두 레벨에서 구성된다.
- 전역 RBAC: argocd-rbac-cm ConfigMap
- AppProject 단위 역할: AppProject.spec.roles
3.1 전역 RBAC 설정 – argocd-rbac-cm
argocd-rbac-cm 기본 값은 다음과 같이 비어 있다.
kubectl get cm -n argocd argocd-rbac-cm -o jsonpath='{.data}' | jq
# {
# "policy.csv": "",
# "policy.default": "",
# "policy.matchMode": "glob",
# "scopes": "[groups]"
# }
여기서 중요한 필드:
- policy.csv : 역할 정의(p) + 사용자/그룹 매핑(g)
- policy.default : 별도 매핑이 없는 사용자가 부여받는 기본 역할
Argo CD 내장 역할 두 가지:
| 역할 | 설명 |
| role:readonly | 모든 리소스 읽기 전용 |
| role:admin | 모든 리소스에 대한 무제한 접근 |
3.2 기본 정책을 읽기 전용으로 변경
운영에서 가장 안전한 기본값은 “읽기 전용”이다.
KUBE_EDITOR="nano" kubectl edit cm -n argocd argocd-rbac-cm
data:
policy.csv: ""
policy.default: role:readonly
이렇게 설정하면:
- 모든 사용자는 최소한 “읽기 전용”으로 Argo CD를 사용할 수 있다.
- 쓰기/동기화/삭제 등은 추가 역할 매핑을 통해서만 허용된다.
alice 계정으로 다시 로그인해서:
argocd login argocd.example.com --insecure --username alice
# Password: alice12345
argocd app list
# guestbook 앱이 보이고 상태 조회 가능 (Synced/Healthy 등)
UI에서도 Application / Cluster 목록이 보이지만, 삭제나 수동 sync 같은 쓰기 동작은 제한된다.
운영 관점에서 보면, **“기본은 다 읽을 수 있지만, 바꾸려면 명시적인 권한이 필요하다”**라는 정책이 장애 대응과 감사(감사 로그 추적)에 모두 유리하다.
3.3 AppProject 단위 역할
전역 RBAC 외에도, 프로젝트 단위로 역할을 정의할 수 있다.
대표적인 필드:
- spec.sourceRepos : 어떤 Git repo에서만 가져올 수 있는지
- spec.destinations : 어느 클러스터/네임스페이스로 배포 가능한지
- spec.roles : 해당 프로젝트에 속한 애플리케이션에 대한 역할과 정책
3장의 “App of Apps” 패턴과 결합하면, 플랫폼 팀이 “프로젝트 단위 샌드박스”를 만들어 각 팀에 할당하는 구조를 만들 수 있다.
4. 서비스 어카운트 – 자동화를 위한 계정
4.1 서비스 어카운트 개념
여기서 말하는 서비스 어카운트는 Argo CD 내부 계정 기준이다.
- CI/CD 파이프라인, 배치 작업, 외부 시스템에서 Argo CD API를 호출할 때 사용하는 계정
- 실제 사용자에게 연결된 계정을 그대로 쓰면:
- 계정 비활성화/퇴사/팀 변경 시 파이프라인 장애
- 감사 관점에서 “사람이 한 것인지, 자동화가 한 것인지” 경계가 흐려짐
- 따라서 “사람 계정”과 “서비스 계정”은 명확히 분리하는 것이 좋다.
Argo CD에서 서비스를 위한 계정을 만드는 방법은 두 가지다.
- 로컬 사용자 + apiKey만 활성화
- AppProject 역할에 토큰을 발급해서 사용
4.2 로컬 서비스 계정 – gitops-ci
1) apiKey만 허용된 계정 생성
KUBE_EDITOR="nano" kubectl edit cm -n argocd argocd-cm
data:
accounts.gitops-ci: apiKey
확인:
argocd account list
# NAME ENABLED CAPABILITIES
# admin false login
# alice true apiKey, login
# gitops-ci true apiKey
- gitops-ci는 UI/CLI 로그인 기능이 없고, API 키만 사용할 수 있는 계정이다.
2) 토큰 생성 권한 부여 – role:user-update
기본적으로 다른 계정의 토큰을 생성하려면 권한이 필요하다.
실습에서는 alice에게 계정 업데이트 권한을 주기 위해 role:user-update를 추가한다.
KUBE_EDITOR="nano" kubectl edit cm -n argocd argocd-rbac-cm
data:
policy.csv: |
# p : 정책 정의
p, role:user-update, accounts, update, *, allow
p, role:user-update, accounts, get, *, allow
# g : 사용자 → 역할 매핑
g, alice, role:user-update
이제 alice로 로그인해서 서비스 계정 토큰을 생성할 수 있다.
argocd account generate-token -a gitops-ci
# eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.... 형태의 JWT 토큰 출력
argocd account get-user-info --auth-token <위 토큰>
# Logged In: true
# Username: gitops-ci
이 토큰을 CI/CD 파이프라인에서 Authorization: Bearer <TOKEN> 형태로 사용하면 된다.
현재는 policy.default = role:readonly이기 때문에, 이 토큰은 기본적으로 “읽기 전용 권한을 가진 서비스 계정 토큰”이다.
- 상태 조회, 앱 리스트, 클러스터 목록 조회 등은 가능
- 동기화, 삭제, 프로젝트 변경 등은 불가
실무에서는 이 토큰에 필요한 최소 권한만 추가 부여해서 사용하는 것이 이상적이다.
4.3 프로젝트 역할과 토큰 – proj:sample-apps:read-sync
두 번째 방식은 프로젝트 역할(Role)에 토큰을 부여하는 것이다.
1) 샘플 프로젝트 생성 – sample-apps
cat <https://kubernetes.default.svc
sourceRepos:
- https://github.com/argoproj/argocd-example-apps.git
EOF
이 프로젝트의 특징:
- destinations : test 네임스페이스, 해당 클러스터로만 배포 가능
- sourceRepos : 지정된 Git repo에서만 가져올 수 있음
- roles.read-sync : sample-apps 프로젝트에 속한 앱에 대해서만 get/sync 허용
2) 프로젝트에 애플리케이션 연결 – pre-post-sync
cat <https://github.com/argoproj/argocd-example-apps
targetRevision: master
destination:
namespace: test
server: https://kubernetes.default.svc
syncPolicy:
automated:
enabled: false
syncOptions:
- CreateNamespace=true
EOF
alice 계정에서 다음을 실행하면:
argocd app sync argocd/pre-post-sync
# permission denied: applications, sync, sample-apps/pre-post-sync, sub: alice
동기화 권한이 없으므로 실패한다.
3) 프로젝트 역할 토큰 생성
먼저 alice에게 프로젝트 업데이트 권한을 추가로 부여한다.
KUBE_EDITOR="nano" kubectl edit cm -n argocd argocd-rbac-cm
data:
policy.csv: |
p, role:user-update, accounts, update, *, allow
p, role:user-update, accounts, get, *, allow
p, role:user-update, projects, update, sample-apps, allow
g, alice, role:user-update
그 다음 alice가 프로젝트 역할 토큰을 생성한다.
argocd proj role create-token sample-apps read-sync
# Create token succeeded for proj:sample-apps:read-sync.
# Token: <JWT 토큰 출력>
이제 이 토큰을 사용해서 동기화를 수행하면 된다.
TOKEN=<위에서 발급된 토큰>
argocd app sync argocd/pre-post-sync --auth-token $TOKEN
이 토큰의 특성:
- 주체(subject)는 proj:sample-apps:read-sync
- sample-apps 프로젝트에 속한 앱에 대해서만 get/sync 가능
- 다른 프로젝트/앱에는 권한 없음
즉, “이 파이프라인은 sample-apps 프로젝트 안에서만 동작한다”는 강력한 보안 경계를 토큰 하나로 표현할 수 있다.
5. SSO – Dex와 Keycloak
5.1 SSO 개념
SSO(Single Sign-On)는 다음과 같은 역할을 한다.
- 애플리케이션(Argo CD)은 사용자 인증을 직접 처리하지 않는다.
- 대신 외부 IdP(예: Keycloak, Google, 회사 SSO 등)에 인증을 위임한다.
- 사용자는 한 번만 로그인하면 여러 애플리케이션에 접근 가능하다.
- 권한(그룹, 역할)은 중앙에서 관리하고, 각 애플리케이션에서는 토큰의 클레임(roles, groups 등)에 따라 권한을 부여한다.
Argo CD는 SSO를 두 가지 방법으로 제공한다.
- 내장 Dex OIDC 공급자 사용
- Dex 없이, 외부 OIDC 공급자(예: Keycloak)를 직접 사용
SSO가 활성화되고 로컬 계정/관리자가 비활성화되면, Argo CD UI에서 ID/PW 입력창은 사라지고 “SSO 로그인 버튼”만 남는다.
5.2 Keycloak 개요
Keycloak은 애플리케이션에 초점을 맞춘 오픈 소스 ID 및 접근 관리 도구다.
주요 특징:
- 로그인 UI, 비밀번호 재설정, 2FA, 약관 동의 등 인증 관련 기능 제공
- OAuth 2.0, OpenID Connect, SAML 2.0 지원
- 자체 사용자 DB + 소셜 로그인 + 기업 디렉터리(AD/LDAP) 연동
- 세션/SSO/로그아웃 관리
- 확장 가능한 구조 (커스텀 인증 플로우, 사용자 스토어, 토큰 변환 등)
Argo CD 같은 애플리케이션 입장에서는 “Keycloak이 인증/인가의 허브 역할을 해 주고, 자신은 토큰만 검증하면 되는 구조”라서 구현 부담이 크게 줄어든다.
5.3 Keycloak Dev 모드 실행 (Docker)
docker run -d \
-e KEYCLOAK_ADMIN=admin \
-e KEYCLOAK_ADMIN_PASSWORD=admin \
--net host \
--name dev-keycloak \
quay.io/keycloak/keycloak:22.0.0 start-dev
- 관리자 콘솔: http://localhost:8080/admin
- 초기 관리자 계정: admin / admin
5.4 Realm / User / Group / Role 구성
- Realm 생성
- 이름: myrealm
- Realm Settings → Display name 설정
- User 생성
- Users → Add user
- Username: keycloak
- Email: keycloak@keycloak.org
- First name: Ola
- Last name: Nordmann
- Credentials 탭에서 패스워드 설정 (Temporary: Off)
- Group 생성 및 사용자 그룹 조인
- Groups → Create group → mygroup
- Users → 해당 user → Groups → mygroup Join
- Realm Role 생성 및 사용자 매핑
- Realm roles → Create role → myrole
- Users → Role mapping → myrole Assign
이 구조는 이후 Argo CD RBAC에서 groups 클레임을 이용해 권한을 부여하는 기반이 된다.
5.5 Argo CD용 Keycloak 클라이언트 생성
Keycloak 관리자 콘솔에서:
- Clients → Create client
- Client ID: argocd
- Name: argocd client
- Client authentication: ON (Confidential)
- 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: +
생성 후 Credentials 탭에서 Client Secret을 복사해 둔다.
예: mV3IZO3nmHoZr3BBC37UpdrMSMkF9Umt
5.6 Argo CD OIDC 설정
1) clientSecret을 Argo CD 시크릿에 저장
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": "..."
2) argocd-cm에 OIDC 설정 추가
KUBE_EDITOR="nano" kubectl edit cm -n argocd argocd-cm
data:
url: https://argocd.example.com
oidc.config: |
name: Keycloak
issuer: http://192.168.254.110:8080/realms/master
clientID: argocd
clientSecret: mV3IZO3nmHoZr3BBC37UpdrMSMkF9Umt
requestedScopes: ["openid", "profile", "email"]
- issuer: Keycloak Realm의 Issuer URL
- requestedScopes: 토큰에 포함하고 싶은 기본 정보 범위
그룹 정보를 RBAC에 활용하고 싶다면, groups 스코프를 추가한다.
requestedScopes: ["openid", "profile", "email", "groups"]
3) Argo CD 서버 재시작
kubectl rollout restart deploy argocd-server -n argocd
이제 Argo CD 로그인 화면에 “SSO 버튼”이 보이고, 해당 버튼을 누르면 Keycloak 로그인 페이지로 리다이렉트된다.
5.7 그룹 기반 RBAC – Keycloak groups → Argo CD roles
Keycloak 그룹과 Argo CD 역할을 매핑하면, 조직의 그룹 구조를 그대로 가져와서 쓸 수 있다.
예)
KUBE_EDITOR="nano" kubectl edit cm -n argocd argocd-rbac-cm
data:
policy.default: role:readonly
policy.csv: |
g, keycloak-admin, role:admin
g, keycloak-dev, role:developer
- Keycloak에서 keycloak-admin, keycloak-dev 그룹을 만들고
- 각 그룹에 사용자를 할당
- OIDC 토큰에 groups 클레임이 포함되도록 설정
→ 이렇게 하면 Argo CD에서는 “사용자가 어떤 그룹에 속해 있느냐”에 따라 역할이 자동 할당된다.
플랫폼 팀 입장에서는 그룹만 관리해도 권한 구조가 따라오므로 운영 비용이 크게 줄어든다.
6. OAuth 2.0 / OpenID Connect / JWT 빠른 정리
4장에서는 Keycloak을 OIDC 공급자로 썼기 때문에, 배경에 깔린 프로토콜을 간단히 짚고 넘어가면 전체 구조가 더 잘 보인다.
6.1 OAuth 2.0 – 인가 프레임워크
OAuth 2.0은 “권한 위임”을 위한 프레임워크다.
| 역할 | 설명 |
| Resource Owner | 보통 사용자 (본인 데이터의 주인) |
| Client | 사용자를 대신해 리소스에 접근하려는 애플리케이션 |
| Authorization Server | 인증/인가를 담당, Access Token 발급 (Keycloak) |
| Resource Server | 실제 보호된 리소스를 제공하는 API 서버 |
Authorization Code Flow의 핵심 흐름:
- Client가 사용자에게 “Authorization Server로 로그인해 달라”고 리다이렉트
- 사용자가 Authorization Server에서 로그인 및 동의
- Authorization Server가 Client에게 Authorization Code 전달
- Client가 Authorization Code로 Access Token(필요시 Refresh Token 포함)을 발급받음
- Client는 Access Token을 붙여 Resource Server에 접근
Argo CD + Keycloak 시나리오에서는:
- 브라우저(사용자)가 Keycloak에 로그인
- Keycloak이 Argo CD에게 ID/Access Token을 발급
- Argo CD는 이 토큰을 기반으로 사용자 세션/권한을 관리한다.
6.2 OpenID Connect – OAuth 위에 얹은 “인증” 계층
- OAuth 2.0은 “인가(Authorization)” 프로토콜이지, 인증(Authentication)을 직접 정의하지 않는다.
- OpenID Connect는 OAuth 2.0 위에 “사용자 인증” 계층을 추가한 표준.
- scope=openid를 포함하면 “인증 요청”이 되며, ID Token(JWT 형식)을 반환한다.
- ID Token에는 sub, email, name, groups 등의 클레임이 포함될 수 있다.
Argo CD 입장에서는:
- Access Token: API 호출 권한
- ID Token: 사용자 정보 / 그룹 정보 기반으로 RBAC 역할 부여
6.3 JWT – 토큰 형식
Keycloak이 발급하는 토큰은 대부분 JWT(JSON Web Token)이다.
- 헤더(header).페이로드(payload).서명(signature) 형식
- Base64URL 인코딩
- 페이로드에 클레임(roles, groups, email 등)을 담을 수 있음
- 서명은 Authorization Server의 비밀/키를 이용해 생성되며, Resource Server에서 검증 가능
리소스 서버(예: Argo CD API 서버)는:
- issuer/키 정보를 Discovery/JWKS로 확인
- JWT 서명 검증
- 만료 시간/발행자/대상(clientID) 등을 검증
- 페이로드에 있는 roles/groups를 읽어 권한을 판단
결국 4장의 접근 제어는 “누가 어떤 JWT를 들고 왔고, 그 JWT 안에 어떤 클레임이 들어 있는가”를 기준으로 동작한다고 볼 수 있다.
7. 정리
| 항목 | 내용 |
| 선언적 사용자 | admin 계정은 초기 구성에만 사용하고, 이후에는 로컬 사용자/SSO 계정으로 전환 |
| RBAC 전역 정책 | argocd-rbac-cm의 policy.csv, policy.default로 기본 역할 및 사용자/그룹 매핑 |
| 기본 권장 정책 | policy.default = role:readonly로 두고, 쓰기 권한은 명시적으로 할당 |
| 서비스 어카운트 | 로컬 계정에 apiKey만 부여하거나, 프로젝트 역할에 토큰을 생성해 CI/CD에서 사용 |
| 프로젝트 역할 | 특정 프로젝트 내부 애플리케이션에 대한 read/sync 등의 권한을 세밀하게 제어 |
| SSO | Dex 또는 Keycloak 같은 외부 OIDC 공급자와 연동해 조직 계정 기반으로 접근 제어 |
| Keycloak 연동 | Realm/User/Group/Role/Client → ArgoCD OIDC 설정 → groups 기반 RBAC |
개인적인 인사이트
- 접근 제어는 “나중에 보안팀에서 하라고 하는 것”이 아니라, 처음부터 구조적으로 설계해야 하는 운영 기능에 가깝다.
- admin 계정을 언제, 어떤 기준으로 비활성화할지 명확히 정해두는 것만으로도 사고 위험이 크게 줄어든다.
- 프로젝트 역할 + 토큰 조합은 “파이프라인의 공격 범위를 프로젝트 단위로 잘라내는 칼” 같은 역할을 한다.
- SSO와 그룹 기반 RBAC를 붙이면, “사람이 소속된 팀”이 곧 “권한 경계”가 되기 때문에, 조직이 커질수록 효과가 기하급수적으로 커진다.
'스터디(Study) > CI·CD Study' 카테고리의 다른 글
| Jenkins · Argo CD · Keycloak · OpenLDAP로 Kubernetes SSO + RBAC 구성하기 [부록 실습] (0) | 2025.11.22 |
|---|---|
| 예제로 배우는 Argo CD 5장: Argo CD로 쿠버네티스 클러스터 부트스트랩 (0) | 2025.11.22 |
| 예제로 배우는 Argo CD 3장: Argo CD 운영 (1) | 2025.11.08 |
| 예제로 배우는 Argo CD 2장: Argo CD 시작하기 (0) | 2025.11.08 |
| 예제로 배우는 Argo CD 1장: 깃옵스와 쿠버네티스 (0) | 2025.11.08 |
댓글