gravitational/teleport · error

certificate required

Error message

certificate required

What it means

An enabled (not disabled) certificate override must supply a certificate — a public key alone is insufficient for an active override because the CA needs the actual certificate to issue from. validateCertificateOverride returns this error when co.Disabled is false and co.Certificate is empty.

Source

Thrown at lib/subca/parsed.go:261

	// PublicKey.
	if co.GetPublicKey() != "" {
		if !certificateOverridePublicKeyRE.MatchString(co.GetPublicKey()) {
			return nil, "", errors.New("invalid public key")
		}
		if wantPublicKey != "" && NormalizePublicKey(co.GetPublicKey()) != wantPublicKey {
			return nil, "public_key", fmt.Errorf("certificate public key mismatch (want %q)", wantPublicKey)
		}
	}

	// Validate "required" fields now that we know both Certificate and PublicKey
	// are valid.
	switch {
	case co.GetDisabled() && co.GetPublicKey() == "" && co.GetCertificate() == "":
		return nil, "", errors.New("certificate or public key required")
	case co.GetDisabled():
		// OK, determined above to have either PublicKey or Certificate.
	case co.GetCertificate() == "":
		return nil, "", errors.New("certificate required")
	}

	// Chain.
	var chain []*x509.Certificate
	if len(co.GetChain()) > 0 {
		if cert == nil {
			return nil, "", errors.New("chain not allowed with an empty certificate")
		}

		// The exact number is arbitrary, the fact that a cap exists isn't.
		const maxChainLength = 10
		if len(co.GetChain()) > maxChainLength {
			return nil, "chain", fmt.Errorf(
				"certificate chain has too many entries (%d > %d)", len(co.GetChain()), maxChainLength)
		}

		chain = make([]*x509.Certificate, len(co.GetChain()))
		prev := cert

View on GitHub (pinned to 1283425b60)

Solutions

  1. Provide the PEM certificate in the override's certificate field
  2. Set disabled: true if the override is only meant to pin/deny a key without active issuance

Example fix

// before (enabled override, no cert)
override:
  public_key: <pem>
// after
override:
  certificate: |
    -----BEGIN CERTIFICATE-----
    ...
    -----END CERTIFICATE-----
Defensive patterns

Strategy: validation

Validate before calling

if !override.GetDisabled() && override.GetCertificate() == "" {
    return trace.BadParameter("enabled certificate override requires a certificate")
}

Type guard

func isEnabledOverrideComplete(o *subcav1.CertificateOverride) bool {
    return o != nil && (o.GetDisabled() || o.GetCertificate() != "")
}

Try / catch

if _, _, err := ValidateAndParseCAOverride(clusterName, co); err != nil {
    if strings.Contains(err.Error(), "certificate required") {
        return trace.BadParameter("provide a PEM certificate or set disabled: true")
    }
    return trace.Wrap(err)
}

Prevention

When it happens

Trigger: Creating a SubCA certificate override with only public_key set and disabled false (or unset), reaching the final case of the required-fields switch.

Common situations: Intending to disable an override but forgetting disabled:true while omitting the certificate; using a public-key-only spec copied from a disabled override.

Understand the failure class

Related errors


AI-assisted analysis of gravitational/teleport@1283425b60 (2026-09-02). Data as JSON: /api/errors/bb698885badd9b6d. Report an issue: GitHub.