crowdsecurity/crowdsec · error

user/password authentication and TLS authentication are mutu

Error message

user/password authentication and TLS authentication are mutually exclusive

What it means

The LAPI client supports either username/password authentication or TLS mutual (certificate) authentication, not both. Load() rejects a configuration that sets client TLS cert/key auth while a login is present, because the two credential mechanisms are mutually exclusive by design.

Source

Thrown at pkg/csconfig/api.go:187

		if strings.HasPrefix(l.Credentials.URL, "http") && !strings.HasSuffix(l.Credentials.URL, "/") {
			l.Credentials.URL += "/"
		}
	}

	// is the configuration asking for client authentication via TLS?
	credTLSClientAuth := l.Credentials.CertPath != "" || l.Credentials.KeyPath != ""

	// is the configuration asking for TLS encryption and server authentication?
	credTLS := credTLSClientAuth || l.Credentials.CACertPath != ""

	credSocket := strings.HasPrefix(l.Credentials.URL, "/")

	if credTLS && credSocket {
		return errors.New("cannot use TLS with a unix socket")
	}

	if credTLSClientAuth && l.Credentials.Login != "" {
		return errors.New("user/password authentication and TLS authentication are mutually exclusive")
	}

	if l.InsecureSkipVerify == nil {
		apiclient.InsecureSkipVerify = false
	} else {
		apiclient.InsecureSkipVerify = *l.InsecureSkipVerify
	}

	if l.Credentials.CACertPath != "" {
		caCert, err := os.ReadFile(l.Credentials.CACertPath)
		if err != nil {
			return fmt.Errorf("failed to load cacert: %w", err)
		}

		caCertPool, err := x509.SystemCertPool()
		if err != nil {
			log.Warningf("Error loading system CA certificates: %s", err)
		}

View on GitHub (pinned to 909b515798)

Solutions

  1. Remove the login (and password) entries when authenticating with a client certificate
  2. Or remove the client cert/key and ca_cert_path entries and keep login/password
  3. Restart crowdsec after cleaning the credentials block

Example fix

// before
api:
  client:
    credentials:
      login: myuser
      cert_path: /etc/crowdsec/ssl/client.crt
      key_path: /etc/crowdsec/ssl/client.key
// after
api:
  client:
    credentials:
      login: myuser
      password: mypassword
      url: https://lapi.example.com:8080
Defensive patterns

Strategy: validation

Validate before calling

if l.Credentials.Login != "" && (l.Credentials.CertPath != "" || l.Credentials.KeyPath != "") {
    return errors.New("choose either login/password or TLS client cert auth")
}
if err := l.Load(); err != nil { ... }

Type guard

func usesTLSClientAuth(cred Credentials) bool { return cred.CertPath != "" && cred.KeyPath != "" }

Try / catch

if err := clientCfg.Load(); err != nil {
    return fmt.Errorf("lapi client config: %w", err)
}

Prevention

When it happens

Trigger: api.client.credentials contains login (non-empty) together with client cert/key paths that enable credTLSClientAuth; LocalApiClientCfg.Load() raises the error during config load.

Common situations: Merging a bouncer-style cert config with an agent-style login/password config; leftovers from a previous auth scheme after migrating from TLS certs to password auth; copy-pasted credentials blocks from two different hosts.

Understand the failure class

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/ab0328c8a0e19964. Report an issue: GitHub.