Skip to content
ioob.dev
Go back

ArgoCD 7편 — RBAC과 SSO: 팀 단위 접근 제어

· 8분 읽기

Table of contents

모두가 admin이면 벌어지는 일

ArgoCD를 처음 설치하면 admin 계정 하나로 모든 걸 한다. 설정도 하고, 앱도 만들고, 싱크도 누른다. 팀원이 두세 명일 때는 이게 크게 문제가 안 되지만, 조직이 커지면 이야기가 달라진다.

백엔드 팀이 프론트엔드 팀의 Application을 실수로 삭제하거나, 인턴이 프로덕션에 싱크를 눌러버리는 상황은 충분히 일어날 수 있다. “누가 어디에 무엇을 할 수 있는가”를 명확하게 정의하지 않으면, GitOps의 장점인 추적 가능성과 안정성이 무너진다.

ArgoCD의 접근 제어는 세 가지 축으로 이루어진다. AppProject가 리소스 경계를 나누고, RBAC이 역할별 권한을 정의하며, SSO가 실제 사용자를 인증한다. 이 세 축을 하나씩 살펴보자.

AppProject — 리소스 경계 나누기

AppProject는 Application들을 논리적으로 묶는 단위다. 기본으로 존재하는 default 프로젝트는 모든 소스 레포와 모든 대상 클러스터에 접근할 수 있어서 편하지만, 그만큼 제약이 없다는 뜻이기도 하다.

팀별 프로젝트를 만들어보자. 백엔드 팀이 접근할 수 있는 소스 레포, 배포 가능한 클러스터와 네임스페이스, 사용 가능한 리소스 종류를 제한한다.

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: backend-team
  namespace: argocd
spec:
  description: "백엔드 팀 프로젝트"

  # 허용된 소스 레포지토리
  sourceRepos:
    - "https://github.com/my-org/backend-*"
    - "https://github.com/my-org/shared-libs.git"

  # 배포 가능한 대상
  destinations:
    - server: https://kubernetes.default.svc
      namespace: backend-*
    - server: https://10.0.1.100:6443
      namespace: backend-*

  # 배포 가능한 리소스 종류
  clusterResourceWhitelist:
    - group: ""
      kind: Namespace

  namespaceResourceWhitelist:
    - group: "apps"
      kind: Deployment
    - group: "apps"
      kind: StatefulSet
    - group: ""
      kind: Service
    - group: ""
      kind: ConfigMap
    - group: ""
      kind: Secret
    - group: "networking.k8s.io"
      kind: Ingress

  # Orphaned Resource 모니터링
  orphanedResources:
    warn: true

sourceRepos에 와일드카드를 쓸 수 있어서 backend-*처럼 패턴 매칭이 가능하다. destinations에서도 네임스페이스에 와일드카드를 써서 backend- 접두사가 붙은 네임스페이스만 허용할 수 있다.

clusterResourceWhitelistnamespaceResourceWhitelist는 배포 가능한 리소스 종류를 제한한다. 이걸 설정하지 않으면 해당 프로젝트에서는 어떤 리소스도 배포할 수 없으니, 필요한 리소스 종류를 명시적으로 열어줘야 한다.

반대로 특정 리소스만 차단하고 싶다면 블랙리스트 방식도 가능하다.

namespaceResourceBlacklist:
  - group: ""
    kind: ResourceQuota
  - group: ""
    kind: LimitRange

프론트엔드 팀의 프로젝트도 비슷한 구조로 만들되, 소스 레포와 네임스페이스 범위만 달리하면 된다.

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: frontend-team
  namespace: argocd
spec:
  description: "프론트엔드 팀 프로젝트"
  sourceRepos:
    - "https://github.com/my-org/frontend-*"
  destinations:
    - server: https://kubernetes.default.svc
      namespace: frontend-*
  clusterResourceWhitelist: []
  namespaceResourceWhitelist:
    - group: "apps"
      kind: Deployment
    - group: ""
      kind: Service
    - group: ""
      kind: ConfigMap
    - group: "networking.k8s.io"
      kind: Ingress

프론트엔드 팀은 clusterResourceWhitelist를 빈 배열로 두었다. Namespace 같은 클러스터 수준 리소스를 생성할 필요가 없는 팀이라면 아예 막아두는 게 안전하다.

RBAC — 역할과 권한 정의

AppProject가 “어떤 리소스에 접근할 수 있는가”를 정의한다면, RBAC은 “누가 어떤 동작을 할 수 있는가”를 정의한다. ArgoCD의 RBAC은 Casbin 기반이며, argocd-rbac-cm ConfigMap에서 관리한다.

RBAC 정책의 기본 형식은 다음과 같다.

p, <subject>, <resource>, <action>, <object>, <effect>

subject는 역할이나 사용자, resource는 ArgoCD 리소스 종류(applications, repositories, clusters 등), action은 수행할 동작(get, create, update, delete, sync, override, action), object는 대상 범위, effect는 allow 또는 deny이다.

실제 설정을 보면 더 명확해진다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-rbac-cm
  namespace: argocd
data:
  policy.default: role:readonly
  policy.csv: |
    # 백엔드 팀 개발자 역할
    p, role:backend-dev, applications, get, backend-team/*, allow
    p, role:backend-dev, applications, sync, backend-team/*, allow
    p, role:backend-dev, applications, action/*, backend-team/*, allow
    p, role:backend-dev, logs, get, backend-team/*, allow

    # 백엔드 팀 리더 역할 (생성/삭제 권한 추가)
    p, role:backend-lead, applications, *, backend-team/*, allow
    p, role:backend-lead, repositories, get, *, allow
    p, role:backend-lead, clusters, get, *, allow
    p, role:backend-lead, logs, get, backend-team/*, allow

    # 프론트엔드 팀 개발자 역할
    p, role:frontend-dev, applications, get, frontend-team/*, allow
    p, role:frontend-dev, applications, sync, frontend-team/*, allow
    p, role:frontend-dev, logs, get, frontend-team/*, allow

    # 인프라 팀 (전체 관리)
    p, role:infra-admin, *, *, *, allow

    # 역할과 그룹 연결
    g, backend-devs, role:backend-dev
    g, backend-leads, role:backend-lead
    g, frontend-devs, role:frontend-dev
    g, infra-team, role:infra-admin

policy.default: role:readonly는 명시적으로 역할이 배정되지 않은 사용자에게 읽기 전용 권한을 부여한다. 기본값을 role:''(권한 없음)으로 바꾸면 더 엄격하게 관리할 수 있다.

g 라인은 그룹과 역할을 연결하는 부분이다. backend-devs라는 그룹에 속한 사용자는 자동으로 role:backend-dev 권한을 가진다. 이 그룹 이름은 SSO 연동 시 IdP에서 넘어오는 그룹 정보와 매칭된다.

backend-team/*에서 backend-team은 AppProject 이름이다. RBAC에서 object 필드의 형식은 <project>/<application> 이므로, backend-team/*은 backend-team 프로젝트의 모든 Application을 의미한다. 특정 Application만 지정하고 싶으면 backend-team/my-api처럼 쓰면 된다.

Dex를 이용한 SSO 연동

ArgoCD는 자체적으로 로컬 사용자를 관리할 수 있지만, 팀원이 많아지면 별도 인증 시스템과 연동하는 게 현실적이다. ArgoCD에는 Dex가 내장되어 있어서 다양한 IdP(Identity Provider)와 연결할 수 있다.

Dex는 OIDC(OpenID Connect) 브로커 역할을 하는 경량 인증 서비스다. GitHub, GitLab, Google, LDAP, SAML 등 여러 인증 소스를 지원한다.

GitHub OAuth를 이용한 SSO 연동을 설정해보자. 먼저 GitHub에서 OAuth App을 만들어야 한다. Authorization callback URL은 https://argocd.example.com/api/dex/callback으로 설정한다.

OAuth App에서 받은 Client ID와 Secret을 ArgoCD 설정에 넣는다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  url: https://argocd.example.com
  dex.config: |
    connectors:
      - type: github
        id: github
        name: GitHub
        config:
          clientID: $dex.github.clientID
          clientSecret: $dex.github.clientSecret
          orgs:
            - name: my-org
              teams:
                - backend-devs
                - backend-leads
                - frontend-devs
                - infra-team

Client ID와 Secret은 직접 ConfigMap에 넣지 않는다. $dex.github.clientID 형식으로 참조하면 ArgoCD가 argocd-secret Secret에서 해당 키의 값을 가져온다.

kubectl -n argocd patch secret argocd-secret -p \
  '{"stringData": {
    "dex.github.clientID": "실제-Client-ID",
    "dex.github.clientSecret": "실제-Client-Secret"
  }}'

orgsteams 설정이 핵심이다. GitHub 조직의 특정 팀에 속한 사용자만 로그인할 수 있도록 제한하며, 이 팀 이름이 RBAC 정책의 그룹 이름과 매칭된다. 예를 들어 GitHub의 my-org/backend-devs 팀에 속한 사용자는 자동으로 role:backend-dev 권한을 갖게 된다.

OIDC 직접 연동

Dex 없이 OIDC를 직접 연동할 수도 있다. 조직에서 이미 Keycloak, Okta, Azure AD 같은 IdP를 운영하고 있다면 이 방식이 더 간결하다.

Keycloak을 예로 들어보자. Keycloak에서 ArgoCD 클라이언트를 만들고 필요한 정보를 설정한다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  url: https://argocd.example.com
  oidc.config: |
    name: Keycloak
    issuer: https://keycloak.example.com/realms/my-realm
    clientID: argocd
    clientSecret: $oidc.keycloak.clientSecret
    requestedScopes:
      - openid
      - profile
      - email
      - groups

requestedScopesgroups를 포함시키는 게 중요하다. IdP에서 사용자가 속한 그룹 정보를 JWT 토큰에 담아 보내야 ArgoCD의 RBAC에서 그룹 기반 권한 매칭이 동작하기 때문이다.

Keycloak 쪽에서는 Client Scope에 groups 매퍼를 추가해서 토큰에 그룹 클레임이 포함되도록 설정해야 한다. IdP마다 그룹 클레임의 이름이 다를 수 있는데, ArgoCD에서는 이를 매핑할 수 있다.

oidc.config: |
  name: Keycloak
  issuer: https://keycloak.example.com/realms/my-realm
  clientID: argocd
  clientSecret: $oidc.keycloak.clientSecret
  requestedScopes:
    - openid
    - profile
    - email
    - groups
  requestedIDTokenClaims:
    groups:
      essential: true

로컬 사용자 관리

SSO 도입 전이나, CI 파이프라인용 서비스 계정이 필요할 때는 로컬 사용자를 쓰기도 한다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  accounts.ci-bot: apiKey,login
  accounts.ci-bot.enabled: "true"

apiKey는 API 토큰 생성 권한, login은 UI 로그인 권한이다. CI 봇은 UI 로그인이 필요 없으니 apiKey만 줘도 된다.

계정을 만든 뒤 비밀번호를 설정하고 토큰을 발급한다.

argocd account update-password --account ci-bot --new-password '새비밀번호'
argocd account generate-token --account ci-bot

이 로컬 사용자에게도 RBAC 정책을 적용할 수 있다.

p, ci-bot, applications, sync, */*, allow
p, ci-bot, applications, get, */*, allow

CI 봇에게는 싱크와 조회 권한만 주고, 생성이나 삭제 권한은 주지 않는 것이 일반적이다.

접근 제어 설계 원칙

지금까지 살펴본 내용을 정리하면, ArgoCD의 접근 제어는 계층적으로 동작한다.

  1. SSO/Dex가 “이 사람이 누구인지” 확인한다 (인증)
  2. RBAC이 “이 사람이 무엇을 할 수 있는지” 결정한다 (인가)
  3. AppProject가 “이 Application이 어디에 접근할 수 있는지” 제한한다 (리소스 경계)

설계할 때 몇 가지 원칙을 기억해두면 좋다. 먼저 최소 권한 원칙을 따른다. 기본 정책은 role:readonly나 빈 역할로 두고, 필요한 권한만 명시적으로 부여한다. 다음으로 그룹 기반으로 관리한다. 개별 사용자에게 직접 역할을 배정하면 사람이 바뀔 때마다 수정해야 하니, IdP의 그룹을 활용하는 편이 훨씬 관리하기 쉽다. 마지막으로 프로덕션 접근은 한 단계 더 제한한다. 프로덕션 프로젝트에 대한 싱크 권한은 시니어 이상에게만 부여하거나, 수동 승인 프로세스를 추가하는 것을 고려해볼 만하다.


RBAC과 SSO를 잘 구성하면 누가 어떤 작업을 했는지 추적할 수 있고, 실수로 인한 사고를 예방할 수 있다. 다음 편에서는 ArgoCD를 실전에서 운영할 때 자주 쓰이는 패턴들, 즉 App of Apps, 레포 전략, CI 연동, 그리고 트러블슈팅 노하우를 다룬다.

8편: 실전 패턴


Share this post on:

Comments

Loading comments...


Previous Post
ArgoCD 8편 — 실전 패턴: App of Apps, CI 연동, 트러블슈팅
Next Post
ArgoCD 6편 — 멀티 클러스터와 ApplicationSet