crowdsecurity/crowdsec · error

while opening cert file: %w

Error message

while opening cert file: %w

What it means

GetTLSConfig, when a client-auth mode stricter than RequestClientCert is set and CACertPath is non-empty, reads the CA certificate bundle with os.ReadFile to build the trust pool. Any read failure (missing file, permission denied, is-a-directory) is wrapped as 'while opening cert file'. Without the CA the server cannot verify client certificates, so startup fails fast.

Source

Thrown at pkg/csconfig/tls.go:75

	}

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

	if caCertPool == nil {
		caCertPool = x509.NewCertPool()
	}

	// the > condition below is a weird way to say "if a client certificate is required"
	// see https://pkg.go.dev/crypto/tls#ClientAuthType
	if clientAuthType > tls.RequestClientCert && t.CACertPath != "" {
		log.Infof("(tls) Client Auth Type set to %s", clientAuthType.String())

		caCert, err := os.ReadFile(t.CACertPath)
		if err != nil {
			return nil, fmt.Errorf("while opening cert file: %w", err)
		}

		caCertPool.AppendCertsFromPEM(caCert)
	}

	return &tls.Config{
		ServerName: t.ServerName, //should it be removed ?
		ClientAuth: clientAuthType,
		ClientCAs:  caCertPool,
		MinVersion: tls.VersionTLS12, // TLS versions below 1.2 are considered insecure - see https://www.rfc-editor.org/rfc/rfc7525.txt for details
	}, nil
}

View on GitHub (pinned to 909b515798)

Solutions

  1. Verify the file exists at the configured path: `ls -l <ca_cert_path>` and fix the path in the tls config if it doesn't.
  2. Fix permissions/ownership so the crowdsec process user can read it: `chown crowdsec:crowdsec ca.pem && chmod 644 ca.pem`.
  3. Ensure the path points to a PEM CA bundle (not a directory, not the private key): check `head -1` shows '-----BEGIN CERTIFICATE-----'.
  4. In containers, confirm the CA file is mounted into the container at the exact configured path.
  5. If client cert verification is not intended, set client_verification: NoClientCert and remove ca_cert_path.

Example fix

// before (config.yaml)
tls:
  ca_cert_path: /etc/crowdsec/ssl/ca.crt   # file does not exist
// after
tls:
  ca_cert_path: /etc/crowdsec/ssl/ca.pem   # existing PEM bundle
# or:
$ sudo chown crowdsec:crowdsec /etc/crowdsec/ssl/ca.pem && sudo chmod 644 /etc/crowdsec/ssl/ca.pem
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(tlsCfg.CACertPath)
if err != nil {
    return fmt.Errorf("ca_cert_path %q: %w", tlsCfg.CACertPath, err)
}
if info.IsDir() {
    return fmt.Errorf("ca_cert_path %q is a directory", tlsCfg.CACertPath)
}
if f, err := os.Open(tlsCfg.CACertPath); err == nil {
    defer f.Close() // readable by current user
}

Try / catch

if _, err := tlsCfg.GetTLSConfig(); err != nil {
    var perr *fs.PathError
    if errors.As(err, &perr) {
        log.Fatalf("CA cert unreadable: %s -> %v", perr.Path, perr.Err)
    }
    return err
}

Prevention

When it happens

Trigger: client_verification is set to RequireAndVerifyClientCert / VerifyClientCertIfGiven (anything > RequestClientCert) and tls.ca_cert_path points to a nonexistent, unreadable, or wrong file.

Common situations: CA path typo in config.yaml, CA file not mounted/copied into a container, wrong ownership so the crowdsec user cannot read it, or pointing at a directory or key file instead of the CA PEM bundle.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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