Skip to content
Published on

ArgoCD 보안 모델: 인증, 인가, 시크릿 관리

공유하기
Authors

1. ArgoCD 보안 아키텍처 개요

ArgoCD는 Kubernetes 환경에서 GitOps를 구현하는 도구이므로, 클러스터와 Git 저장소에 대한 광범위한 접근 권한을 보유합니다. 따라서 보안은 ArgoCD 운영의 핵심입니다.

보안 계층

Layer 1: 인증 (Authentication)
  - 누가 접근하는가?
  - Local Users, SSO (OIDC/SAML/LDAP via Dex)

Layer 2: 인가 (Authorization)
  - 무엇을 할 수 있는가?
  - RBAC Policies, AppProject Scoping

Layer 3: 자격 증명 관리 (Credential Management)
  - Git 저장소, 클러스터 접근 자격 증명
  - Kubernetes Secrets로 안전하게 저장

Layer 4: 시크릿 관리 (Secret Management)
  - 애플리케이션 시크릿의 안전한 처리
  - Sealed Secrets, External Secrets, Vault

Layer 5: 네트워크 보안 (Network Security)
  - TLS, Network Policy, 접근 제한

2. 인증 (Authentication)

Local Users

ArgoCD는 내장 사용자 계정을 제공합니다:

# argocd-cm ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  # 로컬 사용자 정의
  accounts.alice: apiKey, login
  accounts.bob: login
  accounts.ci-bot: apiKey # CI/CD 전용 (API 키만)

계정 기능:

기능설명
loginWeb UI 및 CLI 로그인 가능
apiKeyAPI 토큰 생성 가능 (자동화용)

비밀번호 관리:

# 사용자 비밀번호 변경
argocd account update-password --account alice

# API 토큰 생성 (CI/CD용)
argocd account generate-token --account ci-bot

SSO via Dex

Dex는 ArgoCD에 내장된 OIDC Identity Provider입니다:

# argocd-cm ConfigMap
data:
  url: https://argocd.example.com
  dex.config: |
    connectors:
      - type: github
        id: github
        name: GitHub
        config:
          clientID: YOUR_CLIENT_ID
          clientSecret: $dex.github.clientSecret
          orgs:
            - name: my-org
              teams:
                - platform-team
                - dev-team

OIDC 직접 연동 (Dex 없이)

Okta, Auth0, Keycloak 등과 직접 OIDC 연동도 가능합니다:

# argocd-cm ConfigMap
data:
  oidc.config: |
    name: Okta
    issuer: https://my-org.okta.com/oauth2/default
    clientID: YOUR_CLIENT_ID
    clientSecret: $oidc.okta.clientSecret
    requestedScopes:
      - openid
      - profile
      - email
      - groups
    requestedIDTokenClaims:
      groups:
        essential: true

SAML 연동

data:
  dex.config: |
    connectors:
      - type: saml
        id: saml
        name: SAML SSO
        config:
          ssoURL: https://idp.example.com/sso
          caData: BASE64_ENCODED_CA_CERT
          redirectURI: https://argocd.example.com/api/dex/callback
          entityIssuer: https://argocd.example.com/api/dex/callback
          usernameAttr: email
          emailAttr: email
          groupsAttr: groups

LDAP 연동

data:
  dex.config: |
    connectors:
      - type: ldap
        id: ldap
        name: LDAP
        config:
          host: ldap.example.com:636
          insecureNoSSL: false
          insecureSkipVerify: false
          rootCAData: BASE64_ENCODED_CA
          bindDN: cn=admin,dc=example,dc=com
          bindPW: $dex.ldap.bindPW
          userSearch:
            baseDN: ou=users,dc=example,dc=com
            filter: "(objectClass=person)"
            username: uid
            idAttr: uid
            emailAttr: mail
            nameAttr: cn
          groupSearch:
            baseDN: ou=groups,dc=example,dc=com
            filter: "(objectClass=groupOfNames)"
            userMatchers:
              - userAttr: DN
                groupAttr: member
            nameAttr: cn

인증 흐름 상세

SSO 로그인:
  1. 사용자가 ArgoCD UI 접속
  2. "Log in via SSO" 클릭
  3. API Server -> Dex authorization endpoint로 리다이렉트
  4. Dex -> 외부 IdP(GitHub/Okta/LDAP)로 리다이렉트
  5. 사용자가 외부 IdP에서 인증
  6. IdP -> Dex callback URL리다이렉트 (인증 코드)
  7. Dex가 인증 코드로 토큰 교환
  8. Dex가 ID Token 생성 (사용자 정보 + 그룹)
  9. API Server가 ID Token 검증
  10. ArgoCD JWT 발급 (그룹 정보 포함)
  11. JWT를 브라우저 쿠키에 저장

3. 인가 (Authorization) - RBAC

RBAC 정책 구조

ArgoCD는 Casbin 라이브러리 기반의 RBAC을 사용합니다:

# argocd-rbac-cm ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-rbac-cm
  namespace: argocd
data:
  policy.default: role:readonly
  policy.csv: |
    # 역할 정의
    p, role:admin, applications, *, */*, allow
    p, role:admin, clusters, *, *, allow
    p, role:admin, repositories, *, *, allow
    p, role:admin, projects, *, *, allow

    # 개발팀 역할
    p, role:developer, applications, get, */*, allow
    p, role:developer, applications, sync, */*, allow
    p, role:developer, applications, action/*, */*, allow
    p, role:developer, logs, get, */*, allow

    # 읽기 전용 역할
    p, role:readonly, applications, get, */*, allow
    p, role:readonly, projects, get, *, allow
    p, role:readonly, clusters, get, *, allow
    p, role:readonly, repositories, get, *, allow

    # CI/CD 봇 역할
    p, role:ci-bot, applications, sync, ci-project/*, allow
    p, role:ci-bot, applications, get, ci-project/*, allow

    # 그룹 매핑 (SSO 그룹 -> ArgoCD 역할)
    g, platform-team, role:admin
    g, dev-team, role:developer
    g, viewers, role:readonly
    g, ci-bot, role:ci-bot

  scopes: '[groups, email]'

정책 문법

# 권한 정책 (p)
p, SUBJECT, RESOURCE, ACTION, OBJECT, EFFECT

# 그룹 매핑 (g)
g, GROUP, ROLE

리소스와 액션

리소스액션설명
applicationsgetApplication 조회
applicationscreateApplication 생성
applicationsupdateApplication 수정
applicationsdeleteApplication 삭제
applicationssyncApplication 동기화
applicationsoverrideApplication 파라미터 오버라이드
applicationsaction/*커스텀 액션 (restart 등)
clustersget/create/update/delete클러스터 관리
repositoriesget/create/update/delete저장소 관리
projectsget/create/update/delete프로젝트 관리
logsgetPod 로그 조회
execcreatePod exec 실행

AppProject RBAC

AppProject 내에서 더 세밀한 RBAC을 적용할 수 있습니다:

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: team-alpha
spec:
  roles:
    - name: deployer
      description: '배포 권한'
      policies:
        - p, proj:team-alpha:deployer, applications, sync, team-alpha/*, allow
        - p, proj:team-alpha:deployer, applications, get, team-alpha/*, allow
      groups:
        - team-alpha-deployers
    - name: viewer
      description: '조회 권한'
      policies:
        - p, proj:team-alpha:viewer, applications, get, team-alpha/*, allow
      groups:
        - team-alpha-viewers

RBAC 디버깅

# 특정 사용자의 권한 확인
argocd admin settings rbac can role:developer get applications '*/*'

# 정책 검증
argocd admin settings rbac validate --policy-file policy.csv

4. 저장소 자격 증명 관리

HTTPS 자격 증명

apiVersion: v1
kind: Secret
metadata:
  name: repo-creds
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: repository
type: Opaque
stringData:
  type: git
  url: https://github.com/my-org/my-repo.git
  username: git
  password: ghp_XXXXXXXXXXXX # GitHub Personal Access Token

SSH 자격 증명

apiVersion: v1
kind: Secret
metadata:
  name: repo-creds-ssh
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: repository
type: Opaque
stringData:
  type: git
  url: git@github.com:my-org/my-repo.git
  sshPrivateKey: |
    -----BEGIN OPENSSH PRIVATE KEY-----
    ...
    -----END OPENSSH PRIVATE KEY-----

자격 증명 템플릿

같은 패턴의 여러 저장소에 공통 자격 증명을 적용합니다:

apiVersion: v1
kind: Secret
metadata:
  name: repo-creds-template
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: repo-creds
type: Opaque
stringData:
  type: git
  url: https://github.com/my-org # 이 URL로 시작하는 모든 저장소에 적용
  username: git
  password: ghp_XXXXXXXXXXXX

5. 클러스터 자격 증명 관리

클러스터 등록

# CLI로 클러스터 추가
argocd cluster add my-cluster-context --name production

ServiceAccount 토큰 방식

ArgoCD가 대상 클러스터에 접근할 때 사용하는 ServiceAccount:

# 대상 클러스터에 생성되는 리소스
apiVersion: v1
kind: ServiceAccount
metadata:
  name: argocd-manager
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: argocd-manager-role
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin # 주의: 프로덕션에서는 최소 권한 적용
subjects:
  - kind: ServiceAccount
    name: argocd-manager
    namespace: kube-system

최소 권한 원칙 적용

프로덕션 환경에서는 cluster-admin 대신 최소 권한을 적용합니다:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: argocd-manager-minimal
rules:
  - apiGroups: ['*']
    resources: ['*']
    verbs: ['get', 'list', 'watch']
  - apiGroups: ['apps']
    resources: ['deployments', 'statefulsets', 'daemonsets', 'replicasets']
    verbs: ['get', 'list', 'watch', 'create', 'update', 'patch', 'delete']
  - apiGroups: ['']
    resources: ['services', 'configmaps', 'secrets', 'serviceaccounts', 'namespaces', 'pods']
    verbs: ['get', 'list', 'watch', 'create', 'update', 'patch', 'delete']
  - apiGroups: ['networking.k8s.io']
    resources: ['ingresses', 'networkpolicies']
    verbs: ['get', 'list', 'watch', 'create', 'update', 'patch', 'delete']
  - apiGroups: ['batch']
    resources: ['jobs', 'cronjobs']
    verbs: ['get', 'list', 'watch', 'create', 'update', 'patch', 'delete']

6. 시크릿 관리 통합

Sealed Secrets

Sealed Secrets를 사용하면 암호화된 시크릿을 Git에 저장할 수 있습니다:

# 시크릿을 SealedSecret으로 암호화
kubeseal --format yaml --cert sealed-secrets-cert.pem \
  < my-secret.yaml > sealed-secret.yaml
# Git에 저장되는 SealedSecret (암호화됨)
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: my-secret
  namespace: default
spec:
  encryptedData:
    password: AgBy3i4OJSWK+... # 암호화된 값
  template:
    metadata:
      name: my-secret
      namespace: default

External Secrets Operator (ESO)

외부 시크릿 관리 시스템과 연동합니다:

# SecretStore 설정 (Vault 예시)
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: vault-backend
spec:
  provider:
    vault:
      server: 'https://vault.example.com'
      path: 'secret'
      auth:
        kubernetes:
          mountPath: 'kubernetes'
          role: 'argocd'
---
# ExternalSecret 정의
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: my-app-secrets
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: my-app-secrets
    creationPolicy: Owner
  data:
    - secretKey: database-password
      remoteRef:
        key: my-app/database
        property: password

ArgoCD Vault Plugin (AVP)

ArgoCD의 Config Management Plugin으로 Vault와 직접 통합:

# AVP를 사용한 매니페스트 예시
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
  annotations:
    avp.kubernetes.io/path: 'secret/data/my-app'
type: Opaque
stringData:
  password: <password> # Vault에서 자동으로 치환
  api-key: <api-key>

SOPS (Secrets OPerationS)

SOPS로 YAML 값만 선택적으로 암호화:

# SOPS로 암호화된 파일 (키는 평문, 값은 암호화)
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
stringData:
  password: ENC[AES256_GCM,data:...,iv:...,tag:...,type:str]
  api-key: ENC[AES256_GCM,data:...,iv:...,tag:...,type:str]
sops:
  kms: []
  age:
    - recipient: age1...
      enc: |
        -----BEGIN AGE ENCRYPTED FILE-----
        ...
        -----END AGE ENCRYPTED FILE-----
  lastmodified: '2026-03-20T00:00:00Z'
  version: 3.7.3

7. 네트워크 보안

TLS 설정

ArgoCD 컴포넌트 간 TLS 통신:

# argocd-cmd-params-cm ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cmd-params-cm
  namespace: argocd
data:
  server.insecure: 'false' # TLS 비활성화 금지
  reposerver.tls.minversion: '1.2'

Ingress TLS

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argocd-server
  namespace: argocd
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: 'true'
    nginx.ingress.kubernetes.io/backend-protocol: 'GRPC'
spec:
  tls:
    - hosts:
        - argocd.example.com
      secretName: argocd-tls
  rules:
    - host: argocd.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: argocd-server
                port:
                  number: 443

Network Policy

ArgoCD 네임스페이스에 Network Policy를 적용하여 접근을 제한합니다:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: argocd-server-policy
  namespace: argocd
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: argocd-server
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: ingress-nginx
      ports:
        - port: 8080
          protocol: TCP
        - port: 8083
          protocol: TCP
  egress:
    - to: [] # 모든 외부 접근 허용 (Git, 클러스터 등)

8. 감사 로깅 (Audit Logging)

ArgoCD 감사 로그

ArgoCD API Server는 모든 사용자 작업을 로그에 기록합니다:

로그 항목:
  - 시간: 작업 수행 시각
  - 사용자: 작업을 수행한 사용자 (SSO 그룹 포함)
  - 액션: 수행된 작업 (sync, create, delete)
  - 리소스: 대상 Application 또는 리소스
  - 결과: 성공/실패

로그 수집 설정

# API Server 로그에서 감사 이벤트 필터링
kubectl logs -n argocd deployment/argocd-server | grep "level=info"

Prometheus 메트릭

ArgoCD는 보안 관련 메트릭도 노출합니다:

argocd_app_sync_total: 총 동기화 횟수
argocd_app_info: 애플리케이션 상태 정보
argocd_cluster_api_server_requests_total: 클러스터 API 요청 수
argocd_redis_request_total: Redis 요청 수

9. 보안 모범 사례

인증

  • 프로덕션에서는 SSO를 필수로 사용
  • 로컬 admin 계정 비활성화 또는 비밀번호 주기적 변경
  • API 토큰에 만료 시간 설정
  • MFA(Multi-Factor Authentication) 활성화

인가

  • 기본 정책을 role:readonly로 설정
  • 최소 권한 원칙 적용 (Least Privilege)
  • AppProject로 팀별 격리
  • 프로덕션 네임스페이스에 대한 sync 권한 제한

자격 증명

  • SSH 키를 HTTPS 토큰보다 선호
  • 토큰에 최소 scope 적용
  • 주기적인 자격 증명 교체 (Key Rotation)
  • 클러스터 접근에 최소 권한 RBAC 적용

시크릿

  • 평문 시크릿을 Git에 절대 저장하지 않음
  • Sealed Secrets 또는 External Secrets Operator 사용
  • 시크릿 변경 시 자동 교체 메커니즘 구현

네트워크

  • 모든 통신에 TLS 적용
  • Network Policy로 ArgoCD 컴포넌트 접근 제한
  • ArgoCD UI에 대한 접근을 VPN 또는 IP 화이트리스트로 제한

10. 정리

ArgoCD 보안 모델의 핵심 요소:

  1. 인증: SSO(OIDC/SAML/LDAP via Dex) + 로컬 사용자
  2. 인가: Casbin RBAC + AppProject 스코핑
  3. 저장소 자격 증명: HTTPS/SSH Secret으로 안전하게 관리
  4. 클러스터 자격 증명: ServiceAccount + 최소 권한 원칙
  5. 시크릿 관리: Sealed Secrets / ESO / AVP / SOPS
  6. 네트워크 보안: TLS + Network Policy
  7. 감사: API Server 로그 + Prometheus 메트릭

이러한 보안 계층을 적절히 구성하면 안전한 GitOps 운영 환경을 구축할 수 있습니다.