istio/istio · error
failed to parse CRL: %w
Error message
failed to parse CRL: %w
What it means
verifyCert applies certificate revocation when configSource.tlsSettings.caCrl is set: it trims the string, optionally unwraps a PEM block, and calls x509.ParseRevocationList. Failure means the content is neither valid PEM-encoded nor raw DER CRL. Because the code ignores pem.Decode errors and falls through to parsing the raw bytes, both a mangled PEM header and non-CRL DER produce this error. The handshake is rejected.
Source
Thrown at pilot/pkg/bootstrap/configcontroller.go:509
sanMatchFound = true
break
}
}
}
if !sanMatchFound {
return fmt.Errorf("no matching SAN found")
}
}
if len(tlsSettings.CaCrl) > 0 {
crlData := []byte(strings.TrimSpace(tlsSettings.CaCrl))
block, _ := pem.Decode(crlData)
if block != nil {
crlData = block.Bytes
}
crl, err := x509.ParseRevocationList(crlData)
if err != nil {
return fmt.Errorf("failed to parse CRL: %w", err)
}
for _, revokedCert := range crl.RevokedCertificateEntries {
if cert.SerialNumber.Cmp(revokedCert.SerialNumber) == 0 {
return fmt.Errorf("certificate is revoked")
}
}
}
return nil
}
// getRootCertFromSecret fetches a map of keys and values from a secret with name in namespace
func (s *Server) getRootCertFromSecret(name, namespace string) (*istioCredentials.CertInfo, error) {
secret, err := s.kubeClient.Kube().CoreV1().Secrets(namespace).Get(context.Background(), name, v1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get credential with name %v: %v", name, err)
}
return kube.ExtractRoot(secret.Data)View on GitHub (pinned to 8dc789c5cf)
Solutions
- Validate the file: openssl crl -in crl.pem -noout -text (add -inform DER if raw).
- Re-encode as canonical PEM CRL and update the mesh config or secret.
- If you did not intend revocation checking, remove caCrl entirely.
- Regenerate a fresh CRL if the old one used deprecated structures.
Example fix
# before: certificate pasted into caCrl -> x509.ParseRevocationList fails -> error 837 tlsSettings: caCrl: "-----BEGIN CERTIFICATE-----..." # after tlsSettings: caCrl: "-----BEGIN X509 CRL-----\nMIIB...\n-----END X509 CRL-----\n"
Defensive patterns
Strategy: validation
Validate before calling
// validate CRL material before it enters tlsSettings
func isParseableCRL(s string) bool {
data := []byte(strings.TrimSpace(s))
if b, _ := pem.Decode(data); b != nil { data = b.Bytes }
_, err := x509.ParseRevocationList(data)
return err == nil
} Prevention
- Distribute CRLs via the same secret mechanism as root certs; validate with 'openssl crl -noout' in CI.
- Regenerate CRLs with modern openssl; avoid hand-editing base64.
When it happens
Trigger: caCrl populated with a certificate instead of a CRL; base64 blob with newlines stripped or added by YAML folding; CRL from an old openssl version the parser rejects; empty-ish whitespace content that survives the len>0 check; secret key holding ca.crt copied into the crl field.
Common situations: Hand-assembled tlsSettings referencing a CRL distributed via secret; CI templating that re-wraps long base64 lines; mixing up which secret key (crl vs crt) got pasted.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- certificate is revoked
- failed generating istiod key cert %v
- set keyCertBundle failed: %v
- failed to read transport credentials from config: %v
- failed to add ca certificate from configSource.tlsSettings t
AI-assisted analysis of istio/istio@8dc789c5cf (2026-08-15).
Data as JSON: /api/errors/1eb56f4852104abc.
Report an issue: GitHub.