{"record":{"id":"b4a2b088f6052448","repo":"kubernetes/kops","slug":"fetching-intermediate-certificate-from-s-w","errorCode":null,"errorMessage":"fetching intermediate certificate from %s: %w","messagePattern":"fetching intermediate certificate from (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/azure/attest.go","lineNumber":432,"sourceCode":"\t\t}\n\t\tif issuer == nil {\n\t\t\tif hop == 0 {\n\t\t\t\treturn nil, fmt.Errorf(\"no fetched intermediate certificates matched signer issuer %q\", signer.Issuer)\n\t\t\t}\n\t\t\t// Fetched, but nothing matched current's issuer; stop with what we have.\n\t\t\tbreak\n\t\t}\n\t\tcurrent = issuer\n\t}\n\n\treturn pool, nil\n}\n\n// fetchCertificate fetches and parses a DER-encoded certificate from the given URL.\nfunc fetchCertificate(client *http.Client, url string) (*x509.Certificate, error) {\n\tresp, err := client.Get(url)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"fetching intermediate certificate from %s: %w\", url, err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"fetching intermediate certificate from %s: status %d\", url, resp.StatusCode)\n\t}\n\n\t// Cap the body read to reject pathologically large responses. Read one extra byte so we can\n\t// distinguish \"at the limit\" from \"exceeded limit\".\n\tbody, err := io.ReadAll(io.LimitReader(resp.Body, intermediateCertMaxResponseBytes+1))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"reading intermediate certificate from %s: %w\", url, err)\n\t}\n\tif len(body) > intermediateCertMaxResponseBytes {\n\t\treturn nil, fmt.Errorf(\"intermediate certificate from %s exceeds %d bytes\", url, intermediateCertMaxResponseBytes)\n\t}\n\n\tcert, err := x509.ParseCertificate(body)","sourceCodeStart":414,"sourceCodeEnd":450,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/azure/attest.go#L414-L450","documentation":"fetchCertificate performs an HTTP GET to download a DER-encoded intermediate certificate from an AIA URL. If the HTTP client's Get call itself fails (connection refused, DNS failure, TLS handshake error, timeout), the error is wrapped with the URL for context via %w so callers can errors.Is/As the underlying net error.","triggerScenarios":"fetchCertificate invoked by fetchIntermediateCertsFromBaseURL (or directly in tests) when the transport-level request to the AIA URL fails — unreachable host, DNS resolution failure, network timeout, or TLS errors.","commonSituations":"Cluster egress blocked to Microsoft CA endpoints; private networks without internet access; DNS misconfiguration; firewall/security-group rules blocking outbound 443.","solutions":["Verify outbound HTTPS connectivity from the node to the AIA URL (curl the URL from the host)","Open firewall/security-group egress rules to the Microsoft CA endpoints","Fix DNS resolution on the node (check /etc/resolv.conf, VPC DNS)","Add retry logic for transient network errors and rely on the negative cache to avoid hot-looping"],"exampleFix":"// before\nresp, err := client.Get(url) // no retry; one network blip fails the chain build\nif err != nil { return nil, err }\n// after\nvar cert *x509.Certificate\nerr := retry.OnError(backoff, isNetworkError, func() error {\n    var e error\n    cert, e = fetchCertificate(client, url)\n    return e\n})","handlingStrategy":"retry","validationCode":"// Pre-flight connectivity check before chain building\nresp, err := http.Head(issuerURL)\nif err != nil {\n    return nil, fmt.Errorf(\"AIA host unreachable: %w\", err)\n}\nresp.Body.Close()","typeGuard":null,"tryCatchPattern":"var netErr net.Error\npool, err := fetchIntermediateCerts(client, signer)\nif err != nil && errors.As(err, &netErr) {\n    // transient network error: retry with backoff\n    pool, err = retryWithBackoff(func() (*x509.CertPool, error) {\n        return fetchIntermediateCerts(client, signer)\n    })\n}","preventionTips":["Allow outbound 443 to Microsoft CA/AIA endpoints in security groups and firewalls","Ensure working DNS on nodes","Set explicit HTTP client timeouts and retry transient failures"],"tags":["network","azure","tls","aia-fetch","http-client"],"backgroundTag":"connection-refused","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}