Skip to content
Published on

[ArgoCD] Security Model: Authentication, Authorization, and Secret Management

Authors

1. ArgoCD Security Architecture Overview

ArgoCD holds broad access to clusters and Git repositories as a GitOps tool for Kubernetes. Security is therefore central to ArgoCD operations.

Security Layers

Layer 1: Authentication
  - Who is accessing?
  - Local Users, SSO (OIDC/SAML/LDAP via Dex)

Layer 2: Authorization
  - What can they do?
  - RBAC Policies, AppProject Scoping

Layer 3: Credential Management
  - Git repository, cluster access credentials
  - Stored securely as Kubernetes Secrets

Layer 4: Secret Management
  - Safe handling of application secrets
  - Sealed Secrets, External Secrets, Vault

Layer 5: Network Security
  - TLS, Network Policy, access restrictions

2. Authentication

Local Users

ArgoCD provides built-in user accounts:

# argocd-cm ConfigMap
data:
  accounts.alice: apiKey, login
  accounts.bob: login
  accounts.ci-bot: apiKey
CapabilityDescription
loginWeb UI and CLI login
apiKeyAPI token generation (for automation)

SSO via Dex

Dex is the built-in OIDC Identity Provider:

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

Direct OIDC Integration (Without Dex)

Connect directly to Okta, Auth0, Keycloak:

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

LDAP Integration

data:
  dex.config: |
    connectors:
      - type: ldap
        id: ldap
        name: LDAP
        config:
          host: ldap.example.com:636
          insecureNoSSL: false
          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

Authentication Flow

SSO Login:
  1. User accesses ArgoCD UI
  2. Clicks "Log in via SSO"
  3. API Server redirects to Dex authorization endpoint
  4. Dex redirects to external IdP (GitHub/Okta/LDAP)
  5. User authenticates at external IdP
  6. IdP redirects to Dex callback URL (auth code)
  7. Dex exchanges auth code for tokens
  8. Dex generates ID Token (user info + groups)
  9. API Server validates ID Token
  10. ArgoCD JWT issued (includes group info)
  11. JWT stored in browser cookie

3. Authorization - RBAC

RBAC Policy Structure

ArgoCD uses Casbin-based RBAC:

# argocd-rbac-cm ConfigMap
data:
  policy.default: role:readonly
  policy.csv: |
    # Admin role
    p, role:admin, applications, *, */*, allow
    p, role:admin, clusters, *, *, allow
    p, role:admin, repositories, *, *, allow
    p, role:admin, projects, *, *, allow

    # Developer role
    p, role:developer, applications, get, */*, allow
    p, role:developer, applications, sync, */*, allow
    p, role:developer, applications, action/*, */*, allow
    p, role:developer, logs, get, */*, allow

    # Read-only role
    p, role:readonly, applications, get, */*, allow
    p, role:readonly, projects, get, *, allow

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

    # Group mappings (SSO groups -> ArgoCD roles)
    g, platform-team, role:admin
    g, dev-team, role:developer
    g, viewers, role:readonly
    g, ci-bot, role:ci-bot

  scopes: '[groups, email]'

Resources and Actions

ResourceActionsDescription
applicationsget, create, update, delete, sync, override, action/*Application management
clustersget, create, update, deleteCluster management
repositoriesget, create, update, deleteRepository management
projectsget, create, update, deleteProject management
logsgetPod log viewing
execcreatePod exec execution

AppProject RBAC

Fine-grained RBAC within AppProjects:

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: team-alpha
spec:
  roles:
    - name: deployer
      description: 'Deployment permissions'
      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: 'View permissions'
      policies:
        - p, proj:team-alpha:viewer, applications, get, team-alpha/*, allow
      groups:
        - team-alpha-viewers

4. Repository Credential Management

HTTPS Credentials

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

SSH Credentials

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-----

Credential Templates

Apply common credentials to multiple repositories with the same pattern:

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
  username: git
  password: ghp_XXXXXXXXXXXX

5. Cluster Credential Management

Least Privilege Principle

For production, apply minimal permissions instead of 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. Secret Management Integration

Sealed Secrets

Encrypt secrets for safe Git storage:

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)

Integration with external secret management systems:

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'
---
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

SOPS Integration

SOPS selectively encrypts YAML values:

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:
  age:
    - recipient: age1...
  lastmodified: '2026-03-20T00:00:00Z'
  version: 3.7.3

7. Network Security

TLS Configuration

# argocd-cmd-params-cm ConfigMap
data:
  server.insecure: 'false'
  reposerver.tls.minversion: '1.2'

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: []

8. Audit Logging

ArgoCD API Server logs all user operations:

Log entries:
  - Timestamp: When the action occurred
  - User: Who performed the action (including SSO groups)
  - Action: What was done (sync, create, delete, etc.)
  - Resource: Target Application or resource
  - Result: Success/failure

Prometheus Metrics

ArgoCD exposes security-related metrics:

argocd_app_sync_total: Total sync count
argocd_app_info: Application state information
argocd_cluster_api_server_requests_total: Cluster API request count
argocd_redis_request_total: Redis request count

9. Security Best Practices

Authentication

  • Mandate SSO in production
  • Disable or rotate local admin account password
  • Set expiry on API tokens
  • Enable MFA (Multi-Factor Authentication)

Authorization

  • Set default policy to role:readonly
  • Apply Least Privilege principle
  • Isolate teams with AppProjects
  • Restrict sync permissions for production namespaces

Credentials

  • Prefer SSH keys over HTTPS tokens
  • Apply minimal scope to tokens
  • Implement periodic key rotation
  • Apply minimal RBAC for cluster access

Secrets

  • Never store plaintext secrets in Git
  • Use Sealed Secrets or External Secrets Operator
  • Implement auto-rotation mechanisms for secrets

Network

  • Apply TLS to all communications
  • Restrict ArgoCD component access with Network Policies
  • Limit ArgoCD UI access via VPN or IP whitelisting

10. Summary

Key elements of the ArgoCD security model:

  1. Authentication: SSO (OIDC/SAML/LDAP via Dex) + local users
  2. Authorization: Casbin RBAC + AppProject scoping
  3. Repository Credentials: Secure management via HTTPS/SSH Secrets
  4. Cluster Credentials: ServiceAccount + Least Privilege
  5. Secret Management: Sealed Secrets / ESO / AVP / SOPS
  6. Network Security: TLS + Network Policy
  7. Audit: API Server logs + Prometheus metrics

Properly configuring these security layers enables building a secure GitOps operational environment.