Ssoon
Argo CD in Practice – 4) 접근 제어 : 서비스 계정 본문
🔐 Argo CD Service Accounts
- Argo CD에서 Service Account는 자동화된 프로세스(CI/CD 파이프라인 등)가 시스템에 접근할 수 있도록 해주는 중요한 인증 수단입니다.
이 계정은 실제 사용자의 계정과 분리되어야 하며, 최소 권한 원칙(Principle of Least Privilege)을 반드시 지켜야 합니다.
🧩 Service Account란?
- 자동화 도구나 파이프라인이 Argo CD에 접근할 때 사용하는 계정입니다.
이 계정은 실제 사용자 계정이 아니기 때문에, 특정 사용자가 비활성화되거나 권한이 변경되더라도 파이프라인이 중단되지 않습니다.
“Service Account는 사용자 계정과 분리되어야 하며, 필요한 권한만 부여해야 한다.”
- Argo CD에서 Service Account를 만드는 방법은 두 가지입니다.
- Local User 기반 Service Account (apiKey 사용)
- Project Role 기반 Service Account (token 사용)
🧰 Local Service Account 만들기
- Local Service Account는 UI나 CLI 로그인을 위한 비밀번호 없이, API Key로만 인증하는 계정입니다.
예를 들어, 파이프라인에서 특정 Application의 Sync 작업만 수행할 수 있도록 제한할 수 있습니다.
⚙️ Step 1. argocd-cm 수정
- 아래처럼 ConfigMap을 수정하여 새로운 로컬 계정을 추가합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ KUBE_EDITOR="vi" kubectl edit cm -n argocd argocd-cm
configmap/argocd-cm edited
apiVersion: v1
data:
accounts.alice: apiKey,login
accounts.gitops-ci: apiKey
admin.enabled: "false"
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ argocd account list
NAME ENABLED CAPABILITIES
admin false login
alice true apiKey, login
gitops-ci true apiKey
“accounts.gitops-ci: apiKey 설정으로 로그인 불가능한 API 전용 계정을 만든다.”
⚙️ Step 2. Token 생성 권한 부여
- 문제는 alice 사용자에게는 다른 계정의 토큰을 생성할 권한이 없다는 점입니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ argocd account generate-token -a gitops-ci
{"level":"fatal","msg":"rpc error: code = PermissionDenied desc = permission denied: accounts, update, gitops-ci, sub: alice, iat: 2025-11-12T09:30:57Z","time":"2025-11-12T18:58:42+09:00"}
- admin 계정을 다시 활성화할 수도 있지만, 이는 보안상 권장되지 않습니다.
- 이를 해결하기 위해 argocd-rbac-cm.yaml에 새로운 Role을 추가합니다.
| policy.csv | 실제 RBAC 정책 정의. 형식: p, <role>, <resource>, <action>, <scope>, <effect> |
| p, role:user-update, accounts, update, *, allow | role:user-update가 accounts 리소스에 대해 update 권한을 모든 범위(*)에 허용 |
| p, role:user-update, accounts, get, *, allow | role:user-update가 accounts 리소스를 조회(get)할 수 있음 |
| g, alice, role:user-update | alice 계정에 role:user-update를 부여 |
| policy.default: role:readonly | 지정되지 않은 계정/리소스는 기본적으로 읽기 전용 |
| policy.matchMode: glob | 패턴 매칭 모드. * 같은 와일드카드 사용 가능 |
| scopes: '[groups]' | 정책 적용 범위를 그룹 단위로 설정 (여기서는 그룹 기반 적용) |
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ KUBE_EDITOR="vi" kubectl edit cm -n argocd argocd-rbac-cm
configmap/argocd-rbac-cm edited
apiVersion: v1
data:
policy.csv: |
p, role:user-update, accounts, update, *, allow
p, role:user-update, accounts, get, *, allow
g, alice, role:user-update
policy.default: role:readonly
policy.matchMode: glob
scopes: '[groups]'
“alice에게 계정 업데이트 및 조회 권한(role:user-update)을 부여한다.”
⚙️ Step 3. Token 생성
- 권한이 부여된 alice 사용자로 CLI에서 아래 명령어를 실행합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ argocd account generate-token -a gitops-ci
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhcmdvY2QiLCJzdWIiOiJnaXRvcHMtY2k6YXBpS2V5IiwibmJmIjoxNzYyOTQxNjMyLCJpYXQiOjE3NjI5NDE2MzIsImp0aSI6IjcwNzFhN2U1LTg1ZDQtNDU0OC1iZjI1LTZhZDhkNzYzYjIyMCJ9.K5ngFnJe-8liatLgKqv6ixgBwt2u1igx68AMyDxXxeI
⚙️ Step 4. Token 검증
- 생성된 토큰이 잘 동작하는지 확인하기 위해 다음 명령을 실행합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhcmdvY2QiLCJzdWIiOiJnaXRvcHMtY2k6YXBpS2V5IiwibmJmIjoxNzYyOTQxNjMyLCJpYXQiOjE3NjI5NDE2MzIsImp0aSI6IjcwNzFhN2U1LTg1ZDQtNDU0OC1iZjI1LTZhZDhkNzYzYjIyMCJ9.K5ngFnJe-8liatLgKqv6ixgBwt2u1igx68AMyDxXxeI
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ argocd account get-user-info --auth-token $TOKEN
Logged In: true
Username: gitops-ci
Issuer: argocd
Groups:
“API Key 기반 계정은 UI 로그인이 불가능하며, CLI 또는 API를 통해서만 접근할 수 있다.”
⚙️ Step 5. 권한 부여
- 현재 상태에서는 기본적으로 read-only 권한만 있습니다.
- Service Account가 특정 Application을 sync하거나 create, delete 등의 작업을 수행하려면 argocd-rbac-cm에 추가 정책을 명시해야 합니다.
“Local Account는 group 기반 권한 설정이 불가능하며, 오직 role을 통해 권한을 부여할 수 있다.”
🧭 Project Role 기반 Service Account
- 두 번째 방식은 AppProject의 Role과 Token을 이용하는 것입니다.
- AppProject는 Application이 어떤 리소스, 네임스페이스, 클러스터에서 동작할 수 있는지를 제한하는 기능입니다.
- 여기에 Role을 추가하고 Token을 발급하면, 해당 Role이 가진 권한 범위 내에서만 동작하는 Service Account를 만들 수 있습니다.
- Argo CD가 설치되면 default 라는 기본 프로젝트가 제공되는데, 기본 프로젝트는 애플리케이션에 대한 제한 사항이 설정돼 있지 않다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ kubectl get appprojects.argoproj.io -n argocd default -o yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
creationTimestamp: "2025-11-12T08:17:25Z"
generation: 1
name: default
namespace: argocd
resourceVersion: "4561"
uid: c1c76e2d-c341-4951-8187-9a5af07f7cad
spec:
clusterResourceWhitelist:
- group: '*'
kind: '*'
destinations:
- namespace: '*'
server: '*'
sourceRepos:
- '*'
status: {}
⚙️ Step 1. AppProject 신규 생성
- 프로젝트를 토큰과 함께 사용하는 방법을 확인하기 위해 새 프로젝트를 만들고 기존 argocd 애플리케이션에 사용해볼 것이다.
- 일단 새 프로젝트를 만들면 프로젝트에 사용할 역할을 생성하고 역할에 권한을 할당하고 토큰을 생성해야 한다.
| p | policy type (권한 부여) |
| proj:sample-apps:read-sync | 역할 이름 지정 (위에서 만든 read-sync 역할) |
| applications | 권한이 적용될 리소스 타입 |
| get | 허용되는 액션 (조회) |
| sample-apps/* | 적용 범위 (이 프로젝트 내 모든 애플리케이션) |
| allow | 허용 여부 |
- clusterResourceWhitelist
- 이 프로젝트에서 허용된 클러스터 리소스를 정의합니다.
- group: '*', kind: '*' → 모든 그룹과 모든 종류의 클러스터 리소스 접근 허용
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: sample-apps
namespace: argocd
spec:
roles:
- name: read-sync
description: read and sync privileges
policies:
- p, proj:sample-apps:read-sync, applications, get, sample-apps/*, allow
- p, proj:sample-apps:read-sync, applications, sync, sample-apps/*, allow
clusterResourceWhitelist:
- group: '*'
kind: '*'
description: Project to configure argocd self-manage application
destinations:
- namespace: test
server: https://kubernetes.default.svc
sourceRepos:
- https://github.com/argoproj/argocd-example-apps.git
EOF
appproject.argoproj.io/sample-apps created
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ kubectl get appproject -n argocd
NAME AGE
default 108m
sample-apps 11s

“read-sync Role은 Application에 대한 get/sync 권한만 가진다.”
⚙️ Step 2. 해당 프로젝트에 app 배포
- 애플리케이션 생성
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ cat <<EOF | kubectl apply -f -
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: pre-post-sync
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: sample-apps
source:
path: pre-post-sync
repoURL: 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
Warning: metadata.finalizers: "resources-finalizer.argocd.argoproj.io": prefer a domain-qualified finalizer name including a path (/) to avoid accidental conflicts with other finalizer writers
application.argoproj.io/pre-post-sync created
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ argocd app list
NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET
argocd/guestbook https://kubernetes.default.svc guestbook default Synced Healthy Auto-Prune <none> https://github.com/argoproj/argocd-example-apps helm-guestbook HEAD
argocd/pre-post-sync https://kubernetes.default.svc test sample-apps OutOfSync Missing Manual <none> https://github.com/argoproj/argocd-example-apps pre-post-sync master
- 동기화 실행 시 실패!
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ argocd app sync argocd/pre-post-sync
{"level":"fatal","msg":"rpc error: code = PermissionDenied desc = permission denied: applications, sync, sample-apps/pre-post-sync, sub: alice, iat: 2025-11-12T09:30:57Z","time":"2025-11-12T19:11:17+09:00"}

⚙️ Step 3. Role Token 생성 권한 추가
- 이제 alice 가 Role Token을 생성할 수 있도록 RBAC 설정을 업데이트합니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ KUBE_EDITOR="vi" kubectl edit cm -n argocd argocd-rbac-cm
configmap/argocd-rbac-cm edited
apiVersion: v1
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
“특정 프로젝트(argocd)에 대해서만 업데이트 권한을 허용한다.”
⚙️ Step 4. Token 생성
- 이제 Token을 생성할 수 있습니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ argocd proj role create-token sample-apps read-sync
Create token succeeded for proj:sample-apps:read-sync.
ID: 5a26c1a3-659e-4e60-b638-05a62a4d6913
Issued At: 2025-11-12T19:14:30+09:00
Expires At: Never
Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhcmdvY2QiLCJzdWIiOiJwcm9qOnNhbXBsZS1hcHBzOnJlYWQtc3luYyIsIm5iZiI6MTc2Mjk0MjQ3MCwiaWF0IjoxNzYyOTQyNDcwLCJqdGkiOiI1YTI2YzFhMy02NTllLTRlNjAtYjYzOC0wNWE2MmE0ZDY5MTMifQ.RSWvFO_IDr8ZcwXljvq7CkIN7RAunK7qDJ4Cqi1ADIM
⚙️ Step 5. Token 사용
- 이 Token으로 sync 작업을 실행할 수 있습니다.
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhcmdvY2QiLCJzdWIiOiJwcm9qOnNhbXBsZS1hcHBzOnJlYWQtc3luYyIsIm5iZiI6MTc2Mjk0MjQ3MCwiaWF0IjoxNzYyOTQyNDcwLCJqdGkiOiI1YTI2YzFhMy02NTllLTRlNjAtYjYzOC0wNWE2MmE0ZDY5MTMifQ.RSWvFO_IDr8ZcwXljvq7CkIN7RAunK7qDJ4Cqi1ADIM
(⎈|kind-myk8s:N/A) ssoon@DESKTOP-72C919S:~$ argocd app sync argocd/pre-post-sync --auth-token $TOKEN
TIMESTAMP GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
2025-11-12T19:15:32+09:00 Service test pre-post-sync-kustomize-guestbook-ui OutOfSync Missing
2025-11-12T19:15:32+09:00 apps Deployment test pre-post-sync-kustomize-guestbook-ui OutOfSync Missing
2025-11-12T19:15:32+09:00 Namespace test Running Synced namespace/test created
2025-11-12T19:15:32+09:00 batch Job test pre-post-sync-before Progressing
2025-11-12T19:15:34+09:00 batch Job test pre-post-sync-before Running Synced PreSync job.batch/pre-post-sync-before created
2025-11-12T19:15:50+09:00 Service test pre-post-sync-kustomize-guestbook-ui Synced Healthy
2025-11-12T19:15:50+09:00 apps Deployment test pre-post-sync-kustomize-guestbook-ui Synced Progressing
2025-11-12T19:15:50+09:00 apps Deployment test pre-post-sync-kustomize-guestbook-ui Synced Healthy
2025-11-12T19:15:52+09:00 batch Job test pre-post-sync-before Succeeded Synced PreSync Reached expected number of succeeded pods
2025-11-12T19:15:52+09:00 Service test pre-post-sync-kustomize-guestbook-ui Synced Healthy service/pre-post-sync-kustomize-guestbook-ui created
2025-11-12T19:15:52+09:00 apps Deployment test pre-post-sync-kustomize-guestbook-ui Synced Healthy deployment.apps/pre-post-sync-kustomize-guestbook-ui created
2025-11-12T19:15:52+09:00 batch Job test pre-post-sync-after Running Synced PostSync job.batch/pre-post-sync-after created
2025-11-12T19:16:10+09:00 batch Job test pre-post-sync-after Succeeded Synced PostSync Reached expected number of succeeded pods
Name: argocd/pre-post-sync
Project: sample-apps
Server: https://kubernetes.default.svc
Namespace: test
URL: https://argocd.example.com/applications/argocd/pre-post-sync
Source:
- Repo: https://github.com/argoproj/argocd-example-apps
Target: master
Path: pre-post-sync
SyncWindow: Sync Allowed
Sync Policy: Manual
Sync Status: Synced to master (0d521c6)
Health Status: Healthy
Operation: Sync
Sync Revision: 0d521c6e049889134f3122eb32d7ed342f43ca0d
Phase: Succeeded
Start: 2025-11-12 19:15:32 +0900 KST
Finished: 2025-11-12 19:16:10 +0900 KST
Duration: 38s
Message: successfully synced (no more tasks)
GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
Namespace test Running Synced namespace/test created
batch Job test pre-post-sync-before Succeeded PreSync Reached expected number of succeeded pods
Service test pre-post-sync-kustomize-guestbook-ui Synced Healthy service/pre-post-sync-kustomize-guestbook-ui created
apps Deployment test pre-post-sync-kustomize-guestbook-ui Synced Healthy deployment.apps/pre-post-sync-kustomize-guestbook-ui created
batch Job test pre-post-sync-after Succeeded PostSync Reached expected number of succeeded pods
- 결과로 Application의 리소스 상태가 동기화되며, UI에서도 “Sync Status” 버튼을 통해 동기화 상태를 확인할 수 있습니다.

“Project Role Token은 해당 Project의 Application에만 접근 가능하다.”
💡 Token 관리 팁
- 모든 Token은 생성된 Project Role에 저장되며,사용 이력 및 만료 시간(expiresAt)을 설정할 수 있습니다.
보안을 강화하기 위해 정기적인 Token Rotation을 권장합니다.
“Pipeline 실패를 방지하려면 Token 만료를 자동화하거나 주기적으로 갱신해야 한다.”
⚡️ Token을 이용한 Sync의 유용성
- Argo CD Application에 자동 동기화(auto-sync) 기능이 있더라도,Token 기반 수동 Sync를 허용하는 것은 여전히 유용합니다.
- 예를 들어,
- auto-sync 주기를 10~15분으로 늘려 시스템 부하를 줄이고,
- Git Commit 시점에 파이프라인에서 sync 명령을 직접 호출할 수 있습니다.
“자동 동기화를 유지하면서도, Pipeline에서 Token으로 수동 Sync를 트리거할 수 있다.”
📌 핵심 요약
- Service Account는 자동화를 위한 비사용자 계정이며, 최소 권한 원칙을 적용해야 함
- Local Account 방식은 apiKey로 인증하고, UI 로그인 불가
- Project Role 방식은 특정 AppProject 내 Role과 Token을 이용하여 제한된 권한 부여
- RBAC 설정은 argocd-rbac-cm에서 Casbin 정책(p, g)을 사용
- Token Rotation과 만료 관리를 통해 보안 유지
- Token 기반 Sync는 auto-sync와 병행하여 파이프라인 유연성을 확보
“Service Account는 자동화를 위한 핵심 구성요소이며, 보안과 최소 권한 설정이 무엇보다 중요하다.”
'CICD Study [1기]' 카테고리의 다른 글
| Argo Rollouts - Kubernetes 점진적 배포 컨트롤러 (0) | 2025.10.19 |
|---|---|
| Argo CD in Practice – 4) 접근 제어 : 단일 로그인 (0) | 2025.10.19 |
| Argo CD in Practice – 4) 접근 제어 : 선언적 사용자 (0) | 2025.10.19 |
| Argo CD in Practice – 3) Argo CD 운영 : 가시성 활성화 (0) | 2025.10.19 |
| Argo CD in Practice – 3) Argo CD 운영 : 재해 복구 계획 수립 (0) | 2025.10.19 |
Comments