Authentication¶
This document explains how to configure authentication between the agent and principal components. Authentication ensures that only authorized agents can connect to the principal and that the principal can verify agent identities.
Authentication Methods Overview¶
argocd-agent supports three authentication methods:
| Method | Security Level | Use Case | Status |
|---|---|---|---|
| mTLS | High | Direct agent-to-principal connections | Recommended |
| mTLS + SPIRE | High | Multi-cluster with automated cert management | Recommended for SPIRE environments |
| Header-based | High | Service mesh deployments (Istio, Linkerd) | Recommended for mesh |
| UserPass | Low | Development only | Deprecated |
mTLS Authentication (Recommended)¶
Mutual TLS (mTLS) authentication uses client certificates to authenticate agents. This is the recommended method for most deployments.
How It Works¶
- The agent presents a client certificate when connecting to the principal
- The principal validates the certificate against its CA
- The principal extracts the agent identity from the certificate using one of:
- Subject DN (default): Extract from Common Name (CN) or other subject fields
- URI SANs: Extract from SPIFFE URIs in Subject Alternative Names
sequenceDiagram
participant Agent
participant Principal
Agent->>Principal: TLS handshake with client certificate
Principal->>Principal: Validate cert against CA
Principal->>Principal: Extract agent ID from CN
Principal-->>Agent: Connection accepted
Principal Configuration¶
Configure the principal to require and validate client certificates:
Option 1: Extract from Subject DN (default)
# ConfigMap (argocd-agent-params)
principal.auth: "mtls:subject:CN=([^,]+)"
principal.tls.client-cert.require: "true"
principal.tls.client-cert.match-subject: "true"
principal.tls.server.root-ca-secret-name: "argocd-agent-ca"
Or via command line:
argocd-agent principal \
--auth="mtls:subject:CN=([^,]+)" \
--require-client-certs=true \
--client-cert-subject-match=true
Option 2: Extract from URI SANs
Agent identity can also be extracted from URI Subject Alternative Names (SANs) in the certificate. The regex is matched against each URI SAN until a match is found.
# ConfigMap (argocd-agent-params)
principal.auth: "mtls:uri:spiffe://example\\.com/ns/argocd-agent/sa/(.+)"
principal.tls.client-cert.require: "true"
principal.tls.server.root-ca-secret-name: "argocd-agent-ca"
Or via command line:
argocd-agent principal \
--auth="mtls:uri:spiffe://example\\.com/ns/argocd-agent/sa/(.+)" \
--require-client-certs=true
Auth Format:
| Format | Identity Source | Example |
|---|---|---|
mtls:<regex> |
Subject DN | mtls:CN=([^,]+) (deprecated) |
mtls:subject:<regex> |
Subject DN (explicit) | mtls:subject:CN=([^,]+) |
mtls:uri:<regex> |
URI SANs (first match) | mtls:uri:spiffe://[^/]+/ns/[^/]+/sa/(.+) |
Parameter Explanation:
principal.auth: "mtls:..."- Use mTLS authentication with a regex to extract agent ID. The first capture group becomes the agent ID. For URI mode, all URIs are checked until one matches.principal.tls.client-cert.require: "true"- Require agents to present a client certificateprincipal.tls.client-cert.match-subject: "true"- Validate that the certificate CN matches the registered agent name (only relevant for subject-based auth)
Agent Configuration¶
Configure the agent to use mTLS:
# ConfigMap (argocd-agent-params)
agent.creds: "mtls:"
agent.tls.secret-name: "argocd-agent-client-tls"
agent.tls.root-ca-secret-name: "argocd-agent-ca"
agent.tls.client.insecure: "false"
Or via command line:
argocd-agent agent \
--creds="mtls:" \
--tls-secret-name=argocd-agent-client-tls \
--root-ca-secret-name=argocd-agent-ca
Certificate Requirements¶
For mTLS to work properly:
- Agent certificates must be signed by the same CA configured on the principal
- Identity field must contain an extractable agent ID:
- For subject-based auth: Certificate CN (or other DN field) should match the agent's registered name
- For URI-based auth: Certificate must include a URI SAN matching your regex pattern
- Certificate must include
clientAuthin extended key usage
Example cert-manager Certificate for SPIFFE URI:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: argocd-agent
namespace: argocd-agent
spec:
secretName: argocd-agent-client-tls
commonName: argocd-agent # May be constrained by policy
uris:
- "spiffe://example.com/ns/argocd-agent/sa/cluster-west-1"
usages:
- client auth
issuerRef:
name: your-issuer
kind: ClusterIssuer
See TLS & Certificates for detailed certificate setup instructions.
Header-Based Authentication (Service Mesh)¶
When running behind a service mesh like Istio or Linkerd, the mesh handles mTLS at the sidecar level. In this case, use header-based authentication to extract the agent identity from headers injected by the mesh.
How It Works¶
- The service mesh sidecar terminates mTLS
- The mesh injects identity information into HTTP headers (e.g.,
x-forwarded-client-cert) - The principal extracts the agent ID from the configured header using a regex
sequenceDiagram
participant Agent
participant AgentSidecar as Agent Sidecar
participant PrincipalSidecar as Principal Sidecar
participant Principal
Agent->>AgentSidecar: Plaintext gRPC
AgentSidecar->>PrincipalSidecar: mTLS (mesh-managed)
PrincipalSidecar->>Principal: Plaintext + identity headers
Principal->>Principal: Extract agent ID from header
Principal-->>Agent: Connection accepted
Principal Configuration for Istio¶
# ConfigMap (argocd-agent-params)
principal.listen.host: "127.0.0.1"
principal.tls.insecure-plaintext: "true"
principal.auth: "header:x-forwarded-client-cert:^.*URI=spiffe://[^/]+/ns/[^/]+/sa/([^,;]+)"
Or via command line:
argocd-agent principal \
--listen-host=127.0.0.1 \
--insecure-plaintext=true \
--auth="header:x-forwarded-client-cert:^.*URI=spiffe://[^/]+/ns/[^/]+/sa/([^,;]+)"
Parameter Explanation:
principal.listen.host: "127.0.0.1"- Only accept connections from localhost (the sidecar)principal.tls.insecure-plaintext: "true"- Disable TLS on the principal (the sidecar handles it)principal.auth: "header:..."- Extract agent ID from the specified header using the regex
Header Format:
The header name and regex depend on your service mesh:
| Service Mesh | Header | Example Regex |
|---|---|---|
| Istio | x-forwarded-client-cert |
^.*URI=spiffe://[^/]+/ns/[^/]+/sa/([^,;]+) |
| Linkerd | l5d-client-id |
^(.+)\.serviceaccount\.identity |
| Custom | Your header | Your regex (first capture group = agent ID) |
Agent Configuration for Service Mesh¶
# ConfigMap (argocd-agent-params)
agent.creds: "header:"
Or via command line:
argocd-agent agent --creds="header:"
Security Requirements¶
Critical Security Requirements
When using header-based authentication with --insecure-plaintext:
- Never expose the principal's plaintext port outside the service mesh
- Always bind to localhost (
--listen-host=127.0.0.1) - Use network policies to restrict access to the principal pod
- Verify mesh configuration - ensure the mesh properly injects identity headers
Valid Authentication Pairings¶
| Principal Config | Agent Config | Valid | Notes |
|---|---|---|---|
--insecure-plaintext=true + --auth=header:... |
--creds=header: |
Yes | Service mesh handles mTLS |
--insecure-plaintext=false + --auth=mtls:... |
--creds=mtls: |
Yes | Direct mTLS to principal |
--spire-agent-socket=... + --spire-auth-method=jwt |
--spire-agent-socket=... + --spire-auth-method=jwt |
Yes | SPIRE JWT-SVID authentication |
--spire-agent-socket=... + --spire-auth-method=mtls |
--spire-agent-socket=... + --spire-auth-method=mtls |
Yes | SPIRE X.509-SVID mTLS authentication |
--spire-agent-socket=... (no --spire-auth-method) |
Any | No | --spire-auth-method is required when SPIRE is enabled |
--insecure-plaintext=true + --auth=mtls:... |
Any | No | No client certs in plaintext mode |
--insecure-plaintext=false + --auth=header:... |
Any | No | Headers not injected without mesh |
Authentication with SPIRE¶
When SPIRE is enabled (--spire-agent-socket), TLS is handled by SPIRE-issued X.509 SVIDs. The --spire-auth-method flag controls how agents authenticate to the principal. Two methods are supported:
JWT mode (--spire-auth-method jwt)¶
Agent fetches a JWT-SVID from its local SPIRE Agent and sends it as a bearer token. Principal validates the JWT using its SPIRE JWT bundle source. Use this when each cluster has its own SPIRE Server and trust domain (federated setup).
Principal Configuration:
# ConfigMap (argocd-agent-params)
principal.spire.socket-path: "unix:///run/spire/agent-sockets/spire-agent.sock"
principal.spire.auth-method: "jwt"
# Auth defaults to spiffe-jwt:spiffe://[^/]+/(.+)
Agent Configuration:
# ConfigMap (argocd-agent-params)
agent.spire.socket-path: "unix:///run/spire/agent-sockets/spire-agent.sock"
agent.spire.auth-method: "jwt"
# Creds defaults to spiffe-jwt:
mTLS mode (--spire-auth-method mtls)¶
Agent presents its X.509-SVID as a TLS client certificate. Principal verifies the cert against the SPIRE trust bundle and extracts identity from the SPIFFE URI in the certificate SAN. Use this when all clusters share a single SPIRE Server (centralized setup), or when your SPIFFE provider doesn't support JWT-SVIDs.
Principal Configuration:
# ConfigMap (argocd-agent-params)
principal.spire.socket-path: "unix:///run/spire/agent-sockets/spire-agent.sock"
principal.spire.auth-method: "mtls"
# Auth defaults to mtls:uri:spiffe://[^/]+/(.+)
Agent Configuration:
# ConfigMap (argocd-agent-params)
agent.spire.socket-path: "unix:///run/spire/agent-sockets/spire-agent.sock"
agent.spire.auth-method: "mtls"
# Creds defaults to mtls:
Self-registration (required with SPIRE)¶
With static certificates, agent registration happens when you run argocd-agentctl pki issue agent <name> — this creates the agent's cluster secret on the principal. With SPIRE, there are no per-agent certificate steps, so self-registration must be enabled on the principal. When an agent connects for the first time, the principal automatically creates the cluster secret.
# Environment variables on the principal
ARGOCD_PRINCIPAL_ENABLE_SELF_CLUSTER_REGISTRATION: "true"
ARGOCD_PRINCIPAL_SELF_REGISTRATION_CLIENT_CERT_SECRET: "argocd-agent-shared-client-tls"
The shared client certificate must be created beforehand using argocd-agentctl pki issue shared-client. See TLS & Certificates for the complete setup steps.
No static certificate secrets are needed on the agent cluster. SPIRE provides all credentials automatically.
UserPass Authentication (Deprecated)¶
Deprecation Notice
The userpass authentication method is deprecated and not suited for use outside development environments. Use mTLS authentication for production deployments.
UserPass authentication uses username/password credentials stored in a file.
Principal Configuration¶
# ConfigMap (argocd-agent-params)
principal.auth: "userpass:/app/config/creds/userpass.creds"
Agent Configuration¶
# ConfigMap (argocd-agent-params)
agent.creds: "userpass:/app/config/creds/userpass.creds"
Credentials File Format¶
<agent-name>:<password>
Migration from UserPass to mTLS¶
- Generate client certificates for all agents (see TLS & Certificates)
- Deploy certificates to agent clusters
- Update agent configuration:
agent.creds: "mtls:" - Update principal configuration:
principal.auth: "mtls:CN=([^,]+)" - Enable client certificate requirement:
principal.tls.client-cert.require: "true" - Remove userpass secrets from all clusters
Authentication Troubleshooting¶
mTLS Authentication Failures¶
Symptom: "authentication failed" or "certificate required" errors
Check:
-
Verify client certificate exists:
kubectl get secret argocd-agent-client-tls -n argocd -
Verify certificate is signed by correct CA:
# Get CA cert kubectl get secret argocd-agent-ca -n argocd -o jsonpath='{.data.ca\.crt}' | base64 -d > ca.crt # Get client cert kubectl get secret argocd-agent-client-tls -n argocd -o jsonpath='{.data.tls\.crt}' | base64 -d > client.crt # Verify chain openssl verify -CAfile ca.crt client.crt -
Verify certificate CN matches agent name:
kubectl get secret argocd-agent-client-tls -n argocd -o jsonpath='{.data.tls\.crt}' | base64 -d | openssl x509 -noout -subject
Header Authentication Failures¶
Symptom: Agent connects but principal cannot extract identity
Check:
-
Verify the principal is receiving headers:
kubectl logs -n argocd deployment/argocd-agent-principal --tail=100 | grep -i header -
Test regex extraction:
# Example: Test Istio SPIFFE extraction echo "x-forwarded-client-cert: URI=spiffe://cluster.local/ns/argocd/sa/my-agent" | \ grep -oP '(?<=URI=spiffe://[^/]+/ns/[^/]+/sa/)[^,;]+' -
Verify service mesh is injecting headers:
# For Istio kubectl exec -it -n argocd deployment/argocd-agent-principal -c istio-proxy -- \ curl -s localhost:15000/config_dump | grep -i x-forwarded-client-cert
Connection Refused Errors¶
Symptom: Agent cannot establish connection
Check:
-
Verify principal is listening:
kubectl get svc -n argocd | grep principal kubectl logs -n argocd deployment/argocd-agent-principal | head -20 -
Test network connectivity:
kubectl run test --rm -it --image=busybox -- nc -zv <principal-service> <port> -
Check TLS configuration matches:
- If principal uses
--insecure-plaintext=false, agent must use TLS - If principal uses
--insecure-plaintext=true, agent should connect without TLS (mesh handles it)
Related Documentation¶
- TLS & Certificates - Certificate setup and management
- Networking - Service mesh integration, keepalives, and connection management
- Reference: Principal - All principal authentication parameters
- Reference: Agent - All agent authentication parameters