crowdsecurity/crowdsec · error

failed to load client cert/key pair: %w

Error message

failed to load client cert/key pair: %w

What it means

When both ssl_client_cert and ssl_client_key are configured for MySQL, ConnectionString loads them with tls.LoadX509KeyPair. Any failure (unreadable files, mismatched pair, bad PEM) is wrapped as 'failed to load client cert/key pair: %w'.

Source

Thrown at pkg/csconfig/database.go:184

		if d.SSLCACert != "" {
			caCert, err := os.ReadFile(d.SSLCACert)
			if err != nil {
				return "", fmt.Errorf("failed to read CA cert file %s: %w", d.SSLCACert, err)
			}
			if tlsConfig.RootCAs == nil {
				tlsConfig.RootCAs = x509.NewCertPool()
			}
			if !tlsConfig.RootCAs.AppendCertsFromPEM(caCert) {
				return "", fmt.Errorf("failed to append CA cert file %s: %w", d.SSLCACert, err)
			}
			params.Set("tls", "custom")
		}

		if d.SSLClientCert != "" && d.SSLClientKey != "" {
			cert, err := tls.LoadX509KeyPair(d.SSLClientCert, d.SSLClientKey)
			if err != nil {
				return "", fmt.Errorf("failed to load client cert/key pair: %w", err)
			}
			tlsConfig.Certificates = []tls.Certificate{cert}
			params.Set("tls", "custom")
		}

		if params.Get("tls") == "custom" {
			// Register the custom TLS config
			err := mysql.RegisterTLSConfig("custom", tlsConfig)
			if err != nil {
				return "", fmt.Errorf("failed to register custom TLS config: %w", err)
			}
		}
		connString = fmt.Sprintf("%s?%s", connString, params.Encode())
	case "postgres", "postgresql", "pgx":
		if d.isSocketConfig() {
			connString = fmt.Sprintf("host=%s user=%s dbname=%s password=%s", d.DbPath, d.User, d.DbName, d.Password)
		} else {
			connString = fmt.Sprintf("host=%s port=%d user=%s dbname=%s password=%s", d.Host, d.Port, d.User, d.DbName, d.Password)

View on GitHub (pinned to 909b515798)

Solutions

  1. Verify both files are readable and PEM-encoded (`openssl x509 -in cert.pem -noout`, `openssl rsa -in key.pem -check`)
  2. Confirm cert and key match: compare `openssl x509 -noout -modulus` and `openssl rsa -noout -modulus` hashes
  3. Decrypt the key if needed (`openssl rsa -in key.pem -out key-nocrypt.pem`) or fix the pair files

Example fix

// before
ssl_client_cert: /etc/crowdsec/db/client-new.pem
ssl_client_key: /etc/crowdsec/db/client-old.key  # mismatched
// after
ssl_client_cert: /etc/crowdsec/db/client.pem
ssl_client_key: /etc/crowdsec/db/client.key  # matching pair, chmod 600 owned by crowdsec
Defensive patterns

Strategy: validation

Validate before calling

if _, err := tls.LoadX509KeyPair(certPath, keyPath); err != nil { return fmt.Errorf("client tls pair invalid: %w", err) }

Try / catch

if _, err := dbCfg.ConnectionString(); err != nil { if strings.Contains(err.Error(), "client cert/key pair") { log.Fatalf("TLS client pair invalid: %v", err) } }

Prevention

When it happens

Trigger: Client cert or key path wrong/unreadable; cert and key belong to different pairs; key encrypted or in unsupported format; invalid PEM content.

Common situations: Rotating client certs and mismatching cert with an old key; missing intermediate cert in chain file; key file with restrictive permissions (0600 root) while crowdsec runs as another user.

Related errors


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