kubernetes/kops · error

fetching intermediate certificate from

Error message

fetching intermediate certificate from %s: status %d

What it means

fetchCertificate requires the AIA endpoint to answer with HTTP 200. Any other status (404 for a retired intermediate, 403 for blocked access, 5xx for CA outages) is converted to this error, which embeds the URL and the offending status code for diagnostics.

Solutions

  1. Check the URL with curl -I to see the actual status and confirm the certificate URL is still valid
  2. Re-read the current signer's AIA extension — the URL may have been rotated by the CA
  3. Retry after transient 5xx; the negative cache will throttle repeated attempts
  4. Clear any proxy that injects non-200 responses for the CA host
Defensive patterns

Strategy: retry

Validate before calling

resp, err := http.Head(url)
if err != nil || resp.StatusCode != http.StatusOK {
    return nil, fmt.Errorf("AIA URL %s unhealthy (status %v)", url, resp.StatusCode)
}
resp.Body.Close()

Try / catch

_, err := fetchCertificate(client, url)
var statusErr interface{ } 
if err != nil && strings.Contains(err.Error(), "status ") {
    code := extractStatusCode(err.Error())
    if code >= 500 { /* retry with backoff */ } else { /* fail fast: URL retired or forbidden */ }
}

Prevention

When it happens

Trigger: fetchCertificate receives a response with StatusCode != http.StatusOK while fetching an intermediate certificate from an AIA URL.

Common situations: Intermediate certificate retired/rotated so its URL 404s; corporate proxy returning 403; CA endpoint outage returning 503; CDN misconfiguration.

Understand the failure class

Related errors


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

Appendix: source

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

			// Fetched, but nothing matched current's issuer; stop with what we have.
			break
		}
		current = issuer
	}

	return pool, nil
}

// fetchCertificate fetches and parses a DER-encoded certificate from the given URL.
func fetchCertificate(client *http.Client, url string) (*x509.Certificate, error) {
	resp, err := client.Get(url)
	if err != nil {
		return nil, fmt.Errorf("fetching intermediate certificate from %s: %w", url, err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("fetching intermediate certificate from %s: status %d", url, resp.StatusCode)
	}

	// Cap the body read to reject pathologically large responses. Read one extra byte so we can
	// distinguish "at the limit" from "exceeded limit".
	body, err := io.ReadAll(io.LimitReader(resp.Body, intermediateCertMaxResponseBytes+1))
	if err != nil {
		return nil, fmt.Errorf("reading intermediate certificate from %s: %w", url, err)
	}
	if len(body) > intermediateCertMaxResponseBytes {
		return nil, fmt.Errorf("intermediate certificate from %s exceeds %d bytes", url, intermediateCertMaxResponseBytes)
	}

	cert, err := x509.ParseCertificate(body)
	if err != nil {
		return nil, fmt.Errorf("parsing intermediate certificate from %s: %w", url, err)
	}
	return cert, nil
}

View on GitHub (pinned to 4c8573c808)