kubernetes/kops · error

root certificate pool is required

Error message

root certificate pool is required

What it means

Guard error: verifyAttestedDocumentWithRootAndFetcher was invoked with a nil root certificate pool, so there is no trust anchor to verify the attestation chain against. A programming/configuration error in the caller, not attacker-triggered input.

Source

Thrown at upup/pkg/fi/cloudup/azure/attest.go:186

	return fetchIntermediateCertsFromBaseURL(a.client, microsoftIntermediateCertBaseURL, signer)
}

// verifyAttestedDocumentWithRootAndFetcher verifies a PKCS7 attested document using the supplied
// root pool and intermediate fetcher.
//
// The trust progression is:
//  1. parseAndValidatePKCS7Signer verifies the PKCS7 self-signature against the embedded leaf
//     certificate. At this point the signed content is integrity-bound to the leaf, but the
//     leaf itself is still untrusted — its chain to a root has not been built. The leaf's SAN
//     is sanity-checked against the Azure metadata domains here too.
//  2. parseAndValidateAttestedDocumentContent parses the now-integrity-checked signed content
//     for cheap rejection-only checks (nonce binding, freshness) before paying for chain
//     building or network fetches.
//  3. verifySignerCertChain performs the actual cryptographic chain validation against
//     rootCertPool. This is the call that establishes trust in the signer.
func verifyAttestedDocumentWithRootAndFetcher(signature string, body []byte, rootCertPool *x509.CertPool, fetchIntermediates func(*x509.Certificate) (*x509.CertPool, error)) (*attestedData, error) {
	if rootCertPool == nil {
		return nil, fmt.Errorf("root certificate pool is required")
	}

	p7, signer, err := parseAndValidatePKCS7Signer(signature)
	if err != nil {
		return nil, err
	}

	// The signature binds this content to the (still-untrusted) leaf, so it is safe to run
	// rejection-only checks (nonce, freshness) before paying for chain building or network fetches
	// below.
	data, err := parseAndValidateAttestedDocumentContent(p7.Content, body)
	if err != nil {
		return nil, err
	}

	// Verify using only the certificates embedded in the PKCS7 structure; if that succeeds, the signer
	// is trusted. If it fails but the PKCS7 already embeds a cert matching the signer's issuer, the
	// chain is genuinely broken (not just missing an intermediate), so fail fast instead of fetching.

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Ensure the verifier is built via newAttestationVerifier, which always supplies a root pool
  2. Fix the caller to pass a non-nil *x509.CertPool of trusted Microsoft roots
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at upup/pkg/fi/cloudup/azure/attest.go:186 when the library encounters an invalid state.

Common situations: See trigger scenarios.

Understand the failure class


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/311e3064357f52bb. Report an issue: GitHub.