> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/argoproj/argo-cd/llms.txt
> Use this file to discover all available pages before exploring further.

# Secrets Management

> Best practices and approaches for managing secrets in Argo CD deployments

There are two general approaches to managing secrets in GitOps: on the destination cluster, or in Argo CD during manifest generation. **We strongly recommend the destination cluster approach** as it is more secure and provides a better user experience.

<Warning>
  Argo CD caches generated manifests (including injected secrets) in Redis as plaintext. Generation-based secret injection significantly increases security risk.
</Warning>

## Recommended: Destination Cluster Secret Management

In this approach, secrets are populated directly on the destination cluster, and Argo CD does not need to manage them.

### How It Works

<Steps>
  <Step title="Store Secrets Externally">
    Secrets are stored in external systems like AWS Secrets Manager, HashiCorp Vault, Azure Key Vault, or Google Secret Manager.
  </Step>

  <Step title="Deploy Operator">
    An operator runs on the destination cluster to sync secrets from the external system.
  </Step>

  <Step title="Application References Secrets">
    Applications reference Kubernetes Secrets that are automatically created and updated by the operator.
  </Step>
</Steps>

### Advantages

<CardGroup cols={2}>
  <Card title="Enhanced Security" icon="shield-check">
    Argo CD never has access to secrets, reducing risk of leakage through API, cache, or logs.
  </Card>

  <Card title="Decoupled Updates" icon="arrows-split-up-and-left">
    Secret updates are independent from app sync operations, avoiding unintended secret changes during releases.
  </Card>

  <Card title="Rendered Manifests Compatible" icon="file-code">
    Works with the "Rendered Manifests" GitOps pattern, an emerging best practice.
  </Card>

  <Card title="Zero Trust Architecture" icon="user-shield">
    Follows principle of least privilege—Argo CD has no secret access.
  </Card>
</CardGroup>

## Popular Solutions

### Sealed Secrets

[Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) encrypts secrets that can be stored safely in Git.

<CodeGroup>
  ```yaml SealedSecret Example theme={null}
  apiVersion: bitnami.com/v1alpha1
  kind: SealedSecret
  metadata:
    name: mysecret
    namespace: default
  spec:
    encryptedData:
      password: AgBy3i4OJSWK+PiTySYZZA9rO43cGDEq...
  ```

  ```bash Create Sealed Secret theme={null}
  # Install kubeseal CLI
  kubeseal --fetch-cert > pub-cert.pem

  # Encrypt a secret
  echo -n mypassword | kubeseal \
    --cert pub-cert.pem \
    --scope namespace-wide \
    --namespace default \
    --name mysecret
  ```
</CodeGroup>

<Info>
  The controller running on the cluster decrypts SealedSecrets and creates corresponding Kubernetes Secrets.
</Info>

### External Secrets Operator

[External Secrets Operator](https://github.com/external-secrets/external-secrets) syncs secrets from external secret management systems.

<Tabs>
  <Tab title="AWS Secrets Manager">
    ```yaml theme={null}
    apiVersion: external-secrets.io/v1beta1
    kind: ExternalSecret
    metadata:
      name: aws-secret
      namespace: default
    spec:
      refreshInterval: 1h
      secretStoreRef:
        name: aws-secretsmanager
        kind: SecretStore
      target:
        name: database-credentials
      data:
      - secretKey: username
        remoteRef:
          key: prod/database/credentials
          property: username
      - secretKey: password
        remoteRef:
          key: prod/database/credentials
          property: password
    ```
  </Tab>

  <Tab title="HashiCorp Vault">
    ```yaml theme={null}
    apiVersion: external-secrets.io/v1beta1
    kind: ExternalSecret
    metadata:
      name: vault-secret
      namespace: default
    spec:
      refreshInterval: 15m
      secretStoreRef:
        name: vault-backend
        kind: SecretStore
      target:
        name: api-credentials
      data:
      - secretKey: token
        remoteRef:
          key: secret/data/api
          property: token
    ```
  </Tab>

  <Tab title="Google Secret Manager">
    ```yaml theme={null}
    apiVersion: external-secrets.io/v1beta1
    kind: ExternalSecret
    metadata:
      name: gcp-secret
      namespace: default
    spec:
      refreshInterval: 1h
      secretStoreRef:
        name: gcpsm-secretstore
        kind: SecretStore
      target:
        name: application-secrets
      data:
      - secretKey: api-key
        remoteRef:
          key: projects/123456/secrets/api-key/versions/latest
    ```
  </Tab>
</Tabs>

### Kubernetes Secrets Store CSI Driver

[Secrets Store CSI Driver](https://github.com/kubernetes-sigs/secrets-store-csi-driver) mounts secrets from external stores as volumes.

```yaml theme={null}
apiVersion: v1
kind: Pod
metadata:
  name: app-pod
spec:
  containers:
  - name: app
    image: myapp:latest
    volumeMounts:
    - name: secrets-store
      mountPath: "/mnt/secrets"
      readOnly: true
  volumes:
  - name: secrets-store
    csi:
      driver: secrets-store.csi.k8s.io
      readOnly: true
      volumeAttributes:
        secretProviderClass: "aws-secrets"
```

### Other Solutions

<CardGroup cols={2}>
  <Card title="AWS Secret Operator" icon="aws" href="https://github.com/mumoshu/aws-secret-operator">
    Kubernetes operator for AWS Secrets Manager
  </Card>

  <Card title="Vault Secrets Operator" icon="vault" href="https://developer.hashicorp.com/vault/docs/platform/k8s/vso">
    Official HashiCorp Vault operator for Kubernetes
  </Card>
</CardGroup>

## Not Recommended: Manifest Generation-Based

<Warning>
  **We strongly caution against this approach** due to security and operational risks.
</Warning>

In this approach, Argo CD uses a [Config Management Plugin](https://argo-cd.readthedocs.io/en/stable/operator-manual/config-management-plugins/) to inject secrets during manifest generation.

### Disadvantages

<AccordionGroup>
  <Accordion title="Security Risks">
    * Argo CD needs access to secrets, increasing attack surface
    * Generated manifests with secrets stored in plaintext in Redis cache
    * Secrets exposed via repo-server API (gRPC service)
    * Anyone with Redis or repo-server access can view secrets
  </Accordion>

  <Accordion title="Operational Risks">
    * Secret updates coupled with application sync operations
    * Risk of unintentional secret changes during unrelated releases
    * Difficult to audit when secrets were actually updated
  </Accordion>

  <Accordion title="Compatibility Issues">
    * Incompatible with "Rendered Manifests" pattern
    * Limits adoption of emerging GitOps best practices
    * May complicate future migrations
  </Accordion>
</AccordionGroup>

### Mitigating Risks (If You Must Use This Approach)

<Note>
  Many users have already adopted generation-based solutions. Argo CD will continue to support this approach, but will not prioritize new features that solely support this style.
</Note>

If you must use secret-injection plugins, implement these mitigations:

<Steps>
  <Step title="Network Policies">
    Set up network policies to prevent direct access to Redis and repo-server.

    ```yaml theme={null}
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: argocd-redis-network-policy
      namespace: argocd
    spec:
      podSelector:
        matchLabels:
          app.kubernetes.io/name: argocd-redis
      policyTypes:
      - Ingress
      ingress:
      - from:
        - podSelector:
            matchLabels:
              app.kubernetes.io/part-of: argocd
    ```

    <Warning>
      Verify your cluster supports NetworkPolicies and can enforce them (not all CNI plugins do).
    </Warning>
  </Step>

  <Step title="Dedicated Cluster">
    Run Argo CD on its own cluster with no other applications.

    * Reduces blast radius if secrets are compromised
    * Limits potential lateral movement
    * Simplifies security auditing
  </Step>

  <Step title="Redis Encryption">
    Enable Redis TLS and authentication:

    ```yaml theme={null}
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: argocd-cmd-params-cm
      namespace: argocd
    data:
      redis.server: "argocd-redis:6379"
      redis.use.tls: "true"
    ```
  </Step>

  <Step title="Access Controls">
    Strictly limit RBAC permissions for accessing:

    * Redis pods and services
    * repo-server pods and services
    * argocd namespace resources
  </Step>

  <Step title="Audit Logging">
    Enable comprehensive audit logging:

    ```yaml theme={null}
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: argocd-cm
      namespace: argocd
    data:
      # Log all API requests
      server.log.level: "debug"
      # Enable audit logging
      server.audit.log.enabled: "true"
    ```
  </Step>
</Steps>

### Popular Plugin: argocd-vault-plugin

[argocd-vault-plugin](https://github.com/argoproj-labs/argocd-vault-plugin) is a popular Config Management Plugin for secret injection.

<Warning>
  This plugin requires Argo CD to have access to your secret backend, increasing security risk.
</Warning>

<CodeGroup>
  ```yaml Plugin Configuration theme={null}
  apiVersion: v1
  kind: ConfigMap
  metadata:
    name: argocd-cm
    namespace: argocd
  data:
    configManagementPlugins: |
      - name: argocd-vault-plugin
        generate:
          command: ["argocd-vault-plugin"]
          args: ["generate", "./"]
  ```

  ```yaml Application Manifest theme={null}
  apiVersion: v1
  kind: Secret
  metadata:
    name: example-secret
  type: Opaque
  stringData:
    # Plugin will replace this with actual value from Vault
    password: <path:secret/data/myapp#password>
  ```
</CodeGroup>

## Migration Strategy

If you're currently using manifest generation-based secrets, consider migrating:

<Steps>
  <Step title="Audit Current Usage">
    Identify all applications using secret injection plugins:

    ```bash theme={null}
    kubectl get applications -A -o json | \
      jq '.items[] | select(.spec.source.plugin != null) | .metadata.name'
    ```
  </Step>

  <Step title="Choose Destination Approach">
    Select an operator-based solution:

    * External Secrets Operator (multi-cloud)
    * Sealed Secrets (Git-native)
    * Cloud-specific operators
  </Step>

  <Step title="Deploy Operator">
    Install chosen operator on destination clusters:

    ```bash theme={null}
    # Example: External Secrets Operator
    helm repo add external-secrets https://charts.external-secrets.io
    helm install external-secrets \
      external-secrets/external-secrets \
      -n external-secrets-system \
      --create-namespace
    ```
  </Step>

  <Step title="Migrate Incrementally">
    Migrate applications one at a time:

    1. Create ExternalSecret/SealedSecret resources
    2. Update application to reference new Secrets
    3. Remove plugin configuration
    4. Test thoroughly
  </Step>

  <Step title="Remove Plugin">
    Once all applications are migrated, remove the plugin from Argo CD configuration.
  </Step>
</Steps>

## Comparison Table

| Feature               | Destination Cluster | Manifest Generation |
| --------------------- | ------------------- | ------------------- |
| Argo CD Secret Access | ❌ No                | ✅ Yes (High Risk)   |
| Secret in Redis Cache | ❌ No                | ✅ Yes (Plaintext)   |
| Update Coupling       | ✅ Decoupled         | ❌ Coupled with Sync |
| Rendered Manifests    | ✅ Compatible        | ❌ Incompatible      |
| Security Posture      | ✅ Strong            | ⚠️ Weak             |
| Complexity            | ⚠️ Medium           | ✅ Simple            |
| Argo CD Version       | Any                 | Any                 |

## Best Practices

<CardGroup cols={2}>
  <Card title="Principle of Least Privilege" icon="user-lock">
    Argo CD should only have permissions it absolutely needs—not secret access
  </Card>

  <Card title="Secret Rotation" icon="rotate">
    Use operators that support automatic secret rotation from external systems
  </Card>

  <Card title="Separate Concerns" icon="diagram-project">
    Decouple secret management from application deployment workflows
  </Card>

  <Card title="Audit Trail" icon="clipboard-list">
    Leverage external secret manager audit logs for compliance
  </Card>
</CardGroup>

## Related Resources

<CardGroup cols={2}>
  <Card title="Security Overview" icon="shield" href="/security/overview">
    Comprehensive Argo CD security architecture
  </Card>

  <Card title="TLS Configuration" icon="lock" href="/security/tls">
    Secure inter-component communication
  </Card>

  <Card title="RBAC Configuration" icon="users" href="/configuration/rbac">
    Control access to Argo CD resources
  </Card>

  <Card title="Config Management Plugins" icon="plug" href="/developers/config-management-plugins">
    Learn about plugin architecture
  </Card>
</CardGroup>
