{"record":{"id":"6d77b1443698bc81","repo":"crowdsecurity/crowdsec","slug":"failed-to-load-client-cert-key-pair-w","errorCode":null,"errorMessage":"failed to load client cert/key pair: %w","messagePattern":"failed to load client cert/key pair: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/csconfig/database.go","lineNumber":184,"sourceCode":"\n\t\tif d.SSLCACert != \"\" {\n\t\t\tcaCert, err := os.ReadFile(d.SSLCACert)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"failed to read CA cert file %s: %w\", d.SSLCACert, err)\n\t\t\t}\n\t\t\tif tlsConfig.RootCAs == nil {\n\t\t\t\ttlsConfig.RootCAs = x509.NewCertPool()\n\t\t\t}\n\t\t\tif !tlsConfig.RootCAs.AppendCertsFromPEM(caCert) {\n\t\t\t\treturn \"\", fmt.Errorf(\"failed to append CA cert file %s: %w\", d.SSLCACert, err)\n\t\t\t}\n\t\t\tparams.Set(\"tls\", \"custom\")\n\t\t}\n\n\t\tif d.SSLClientCert != \"\" && d.SSLClientKey != \"\" {\n\t\t\tcert, err := tls.LoadX509KeyPair(d.SSLClientCert, d.SSLClientKey)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"failed to load client cert/key pair: %w\", err)\n\t\t\t}\n\t\t\ttlsConfig.Certificates = []tls.Certificate{cert}\n\t\t\tparams.Set(\"tls\", \"custom\")\n\t\t}\n\n\t\tif params.Get(\"tls\") == \"custom\" {\n\t\t\t// Register the custom TLS config\n\t\t\terr := mysql.RegisterTLSConfig(\"custom\", tlsConfig)\n\t\t\tif err != nil {\n\t\t\t\treturn \"\", fmt.Errorf(\"failed to register custom TLS config: %w\", err)\n\t\t\t}\n\t\t}\n\t\tconnString = fmt.Sprintf(\"%s?%s\", connString, params.Encode())\n\tcase \"postgres\", \"postgresql\", \"pgx\":\n\t\tif d.isSocketConfig() {\n\t\t\tconnString = fmt.Sprintf(\"host=%s user=%s dbname=%s password=%s\", d.DbPath, d.User, d.DbName, d.Password)\n\t\t} else {\n\t\t\tconnString = fmt.Sprintf(\"host=%s port=%d user=%s dbname=%s password=%s\", d.Host, d.Port, d.User, d.DbName, d.Password)","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/csconfig/database.go#L166-L202","documentation":"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'.","triggerScenarios":"Client cert or key path wrong/unreadable; cert and key belong to different pairs; key encrypted or in unsupported format; invalid PEM content.","commonSituations":"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.","solutions":["Verify both files are readable and PEM-encoded (`openssl x509 -in cert.pem -noout`, `openssl rsa -in key.pem -check`)","Confirm cert and key match: compare `openssl x509 -noout -modulus` and `openssl rsa -noout -modulus` hashes","Decrypt the key if needed (`openssl rsa -in key.pem -out key-nocrypt.pem`) or fix the pair files"],"exampleFix":"// before\nssl_client_cert: /etc/crowdsec/db/client-new.pem\nssl_client_key: /etc/crowdsec/db/client-old.key  # mismatched\n// after\nssl_client_cert: /etc/crowdsec/db/client.pem\nssl_client_key: /etc/crowdsec/db/client.key  # matching pair, chmod 600 owned by crowdsec","handlingStrategy":"validation","validationCode":"if _, err := tls.LoadX509KeyPair(certPath, keyPath); err != nil { return fmt.Errorf(\"client tls pair invalid: %w\", err) }","typeGuard":null,"tryCatchPattern":"if _, err := dbCfg.ConnectionString(); err != nil { if strings.Contains(err.Error(), \"client cert/key pair\") { log.Fatalf(\"TLS client pair invalid: %v\", err) } }","preventionTips":["Keep cert and key files as an exact matching pair; rotate them together","Ensure key files are unencrypted PEM and readable by the service user","Verify pair match via modulus comparison before deployment"],"tags":["database","mysql","tls","certificate"],"backgroundTag":"invalid-certificate-format","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}