{"record":{"id":"f6f7d06d47d30a4b","repo":"kubernetes/kops","slug":"reading-q-certificate-v","errorCode":null,"errorMessage":"reading %q certificate: %v","messagePattern":"reading %q certificate: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"cmd/kops-controller/pkg/server/keystore.go","lineNumber":86,"sourceCode":"// MirrorTo will copy secrets to a vfs.Path, which is often easier for a machine to read\nfunc (k *keystore) MirrorTo(ctx context.Context, basedir vfs.Path) error {\n\treturn fmt.Errorf(\"server-side client does not support MirrorTo\")\n}\n\n// ListKeysets will return all the KeySets.\nfunc (k *keystore) ListKeysets() (map[string]*fi.Keyset, error) {\n\treturn nil, fmt.Errorf(\"server-side client does not support ListKeysets\")\n}\n\nfunc newKeystore(basePath string, cas []string) (*keystore, map[string]string, error) {\n\tkeystore := &keystore{\n\t\tkeys:    map[string]keystoreEntry{},\n\t\tkeySets: map[string]*fi.Keyset{},\n\t}\n\tfor _, name := range cas {\n\t\tcertBytes, err := os.ReadFile(path.Join(basePath, name+\".crt\"))\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"reading %q certificate: %v\", name, err)\n\t\t}\n\t\t// TODO: Support multiple certificates?\n\t\tcertificate, err := pki.ParsePEMCertificate(certBytes)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"parsing %q certificate: %v\", name, err)\n\t\t}\n\n\t\tkeyBytes, err := os.ReadFile(path.Join(basePath, name+\".key\"))\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"reading %q key: %v\", name, err)\n\t\t}\n\t\tkey, err := pki.ParsePEMPrivateKey(keyBytes)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"parsing %q key: %v\", name, err)\n\t\t}\n\n\t\tkeystore.keys[name] = keystoreEntry{\n\t\t\tcertificate: certificate,","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/cmd/kops-controller/pkg/server/keystore.go#L68-L104","documentation":"During startup, newKeystore reads each configured CA's certificate file (<basePath>/<name>.crt) from disk. If that read fails — file missing, wrong permissions, or wrong path — startup aborts with \"reading %q certificate: %v\" wrapping the underlying OS error.","triggerScenarios":"newKeystore(basePath, cas) is invoked by NewServer and os.ReadFile fails for a configured CA: the .crt file does not exist in basePath, the name does not match the filename, basePath itself is wrong, or the controller process lacks read permission on the file.","commonSituations":"Controller started with a wrong PKI directory (e.g. wrong mount in a container image); CA file named differently than the configured CA name (case/extension mismatch); secrets volume not mounted; permissions too restrictive after secret provisioning.","solutions":["Read the wrapped OS error in the message: if it says \"no such file or directory\", confirm <basePath>/<name>.crt exists with exactly that name","Verify the controller's basePath flag/mount points at the directory containing the CA secrets (e.g. /etc/kubernetes/pki or the mounted secret volume)","Check file permissions/ownership so the controller user can read the .crt files","Re-provision or copy the missing CA certificate file and restart kops-controller"],"exampleFix":"// before: controller config\n--pki-dir=/etc/kubernetes/pki  # but ca.crt placed as /etc/kubernetes/pki/kubernetes-ca.cert\n\n// after\nmv /etc/kubernetes/pki/kubernetes-ca.cert /etc/kubernetes/pki/kubernetes-ca.crt\n# ensure file exists: ls /etc/kubernetes/pki/kubernetes-ca.crt","handlingStrategy":"validation","validationCode":"// Pre-flight before starting the server\nfor _, name := range cas {\n\tcrt := filepath.Join(basePath, name+\".crt\")\n\tkey := filepath.Join(basePath, name+\".key\")\n\tfor _, f := range []string{crt, key} {\n\t\tif fi, err := os.Stat(f); err != nil {\n\t\t\treturn fmt.Errorf(\"PKI preflight failed: %s: %w\", f, err)\n\t\t} else if fi.IsDir() {\n\t\t\treturn fmt.Errorf(\"PKI preflight failed: %s is a directory\", f)\n\t\t}\n\t}\n}\n","typeGuard":"func caFilesReadable(basePath, name string) bool {\n\tfor _, suffix := range []string{\".crt\", \".key\"} {\n\t\tf, err := os.Open(path.Join(basePath, name+suffix))\n\t\tif err != nil {\n\t\t\treturn false\n\t\t}\n\t\tf.Close()\n\t}\n\treturn true\n}","tryCatchPattern":"keystore, keypairIDs, err := newKeystore(basePath, cas)\nif err != nil {\n\tif strings.Contains(err.Error(), \"certificate: \") && errors.Is(unwrap(err), os.ErrNotExist) {\n\t\tklog.Fatalf(\"CA certificate missing in %s: %v\", basePath, err)\n\t}\n\treturn err\n}","preventionTips":["Mount the PKI secrets volume correctly in the controller container and verify at startup","Keep CA filenames exactly <name>.crt / <name>.key matching the configured CA names","Verify basePath (e.g. --pki-dir) points at the directory holding the CA files","Check file permissions/ownership for the controller's runtime user","Add a startup preflight that stats all configured CA files before NewServer"],"tags":["pki","filesystem","certificate","startup","kops-controller"],"backgroundTag":"file-not-found","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}