{"record":{"id":"1c80bb3a84203d3a","repo":"slackhq/nebula","slug":"sshd-host-key-must-be-provided","errorCode":null,"errorMessage":"sshd.host_key must be provided","messagePattern":"sshd\\.host_key must be provided","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ssh.go","lineNumber":97,"sourceCode":"// that callers may invoke to run the configured ssh server. On\n// failure, it returns nil, error.\nfunc configSSH(l *slog.Logger, ssh *sshd.SSHServer, c *config.C) (func(), error) {\n\tlisten := c.GetString(\"sshd.listen\", \"\")\n\tif listen == \"\" {\n\t\treturn nil, fmt.Errorf(\"sshd.listen must be provided\")\n\t}\n\n\t_, port, err := net.SplitHostPort(listen)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid sshd.listen address: %s\", err)\n\t}\n\tif port == \"22\" {\n\t\treturn nil, fmt.Errorf(\"sshd.listen can not use port 22\")\n\t}\n\n\thostKeyPathOrKey := c.GetString(\"sshd.host_key\", \"\")\n\tif hostKeyPathOrKey == \"\" {\n\t\treturn nil, fmt.Errorf(\"sshd.host_key must be provided\")\n\t}\n\n\tvar hostKeyBytes []byte\n\tif strings.Contains(hostKeyPathOrKey, \"-----BEGIN\") {\n\t\thostKeyBytes = []byte(hostKeyPathOrKey)\n\t} else {\n\t\thostKeyBytes, err = os.ReadFile(hostKeyPathOrKey)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"error while loading sshd.host_key file: %s\", err)\n\t\t}\n\t}\n\n\terr = ssh.SetHostKey(hostKeyBytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error while adding sshd.host_key: %s\", err)\n\t}\n\n\t// Clear existing trusted CAs and authorized keys","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/ssh.go#L79-L115","documentation":"configSSH requires an SSH host key, given either as a PEM literal (detected by \"-----BEGIN\") or a filesystem path via the sshd.host_key config key. If the key is missing/empty, configuration aborts before the server can start, since an SSH server cannot operate without a host identity.","triggerScenarios":"Running with no sshd.host_key value: c.GetString(\"sshd.host_key\", \"\") returns \"\" in ssh.go's configSSH, or the key is set to whitespace/empty quotes.","commonSituations":"First-time setup where no host key was generated yet; the key file path key renamed or the value left blank; secrets not mounted in a container so the config renders empty; a config loader that drops empty-valued keys.","solutions":["Generate a host key (ssh-keygen -t ed25519 -f host_key) and set sshd.host_key to its path.","Paste the PEM key content directly as sshd.host_key (it must contain \"-----BEGIN\").","Verify the secret/file is mounted and the config key is populated at runtime."],"exampleFix":"// before (config)\n[sshd]\n# host_key missing\n// after (config)\n[sshd]\nhost_key = \"/etc/ssh/host_key\"","handlingStrategy":"validation","validationCode":"hk := cfg.GetString(\"sshd.host_key\", \"\")\nif hk == \"\" {\n    return errors.New(\"sshd.host_key required: set a PEM literal or a key file path\")\n}","typeGuard":null,"tryCatchPattern":"run, err := configSSH(logger, srv, c)\nif err != nil {\n    if strings.Contains(err.Error(), \"sshd.host_key must be provided\") {\n        logger.Error(\"missing sshd.host_key; run ssh-keygen and set the config key\")\n        os.Exit(78)\n    }\n    return err\n}","preventionTips":["Generate and mount the host key as part of deployment provisioning.","Include sshd.host_key in your required-config checklist alongside sshd.listen.","In containers, verify secret mounts exist before exec'ing the server."],"tags":["ssh","configuration","host-key","missing-config"],"backgroundTag":"missing-ssh-host-key","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}