{"record":{"id":"e2cff91fbe9a2d4e","repo":"slackhq/nebula","slug":"ca-key-is-encrypted-and-must-be-decrypted-interact","errorCode":null,"errorMessage":"ca-key is encrypted and must be decrypted interactively","messagePattern":"ca-key is encrypted and must be decrypted interactively","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/nebula-cert/sign.go","lineNumber":154,"sourceCode":"\t\tvar rawCAKey []byte\n\t\trawCAKey, err = readInput(\"ca-key\", *sf.caKeyPath, &claims)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"error while reading ca-key: %s\", err)\n\t\t}\n\n\t\t// naively attempt to decode the private key as though it is not encrypted\n\t\tcaKey, _, curve, err = cert.UnmarshalSigningPrivateKeyFromPEM(rawCAKey)\n\t\tif errors.Is(err, cert.ErrPrivateKeyEncrypted) {\n\t\t\tvar passphrase []byte\n\t\t\tpassphrase = []byte(os.Getenv(\"NEBULA_CA_PASSPHRASE\"))\n\t\t\tif len(passphrase) == 0 {\n\t\t\t\t// ask for a passphrase until we get one\n\t\t\t\tfor i := 0; i < 5; i++ {\n\t\t\t\t\terrOut.Write([]byte(\"Enter passphrase: \"))\n\t\t\t\t\tpassphrase, err = pr.ReadPassword()\n\n\t\t\t\t\tif errors.Is(err, ErrNoTerminal) {\n\t\t\t\t\t\treturn fmt.Errorf(\"ca-key is encrypted and must be decrypted interactively\")\n\t\t\t\t\t} else if err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"error reading password: %s\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\tif len(passphrase) > 0 {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif len(passphrase) == 0 {\n\t\t\t\t\treturn fmt.Errorf(\"cannot open encrypted ca-key without passphrase\")\n\t\t\t\t}\n\t\t\t}\n\t\t\tcurve, caKey, _, err = cert.DecryptAndUnmarshalSigningPrivateKey(passphrase, rawCAKey)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error while parsing encrypted ca-key: %s\", err)\n\t\t\t}\n\t\t} else if err != nil {\n\t\t\treturn fmt.Errorf(\"error while parsing ca-key: %s\", err)","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/cmd/nebula-cert/sign.go#L136-L172","documentation":"When the CA key PEM is encrypted (UnmarshalSigningPrivateKeyFromPEM returns cert.ErrPrivateKeyEncrypted), signCert prompts up to 5 times for a passphrase. If the password reader reports ErrNoTerminal (stdin/stdout is not an interactive TTY, e.g. piped input or a CI job), it cannot prompt and returns this error immediately instead of looping.","triggerScenarios":"signing with an encrypted CA key while stdin is not a terminal: `cat pass.txt | nebula-cert sign -ca-key encrypted-ca.key ...`, running from a systemd unit/CI runner with no TTY, or invoking via exec without a pty","commonSituations":"automation scripts feeding input via pipes; containerized signing jobs; SSH sessions without -t so no pty is allocated; scheduled jobs attempting interactive decryption","solutions":["Decrypt the CA key once, interactively, and sign with the plaintext key file","Provide a pty: run under `ssh -t` or use a terminal for the command","Use a version/mechanism that accepts the passphrase non-interactively (e.g. environment/flag supported by your build) rather than prompting","Store an unencrypted CA key in a secret manager and mount it for automated signing"],"exampleFix":"// before\nnebula-cert sign -ca-key encrypted-ca.key < input.txt   # no TTY, cannot prompt\n// after\nnebula-cert sign -ca-key encrypted-ca.key               # run in an interactive terminal, enter passphrase when prompted","handlingStrategy":"fallback","validationCode":"data, _ := os.ReadFile(caKeyPath)\nif _, _, _, err := cert.UnmarshalSigningPrivateKeyFromPEM(data); errors.Is(err, cert.ErrPrivateKeyEncrypted) && !isATTY(os.Stdin) {\n    return fmt.Errorf(\"encrypted CA key but no TTY; decrypt the key first\")\n}","typeGuard":"func requiresInteractiveDecrypt(err error) bool {\n    return strings.Contains(err.Error(), \"must be decrypted interactively\")\n}","tryCatchPattern":"if err := signCert(args, out, errOut, StdinPasswordReader{}); err != nil {\n    if strings.Contains(err.Error(), \"must be decrypted interactively\") {\n        log.Fatalf(\"allocate a TTY (e.g. ssh -t) or use an unencrypted CA key for automation\")\n    }\n}","preventionTips":["Decrypt the CA key once before automated signing runs","Allocate a pty (ssh -t, script -c) when prompting is expected","Store an unencrypted CA key in a secrets manager for CI","Detect non-TTY environments up front and fail fast with guidance"],"tags":["encryption","tty","passphrase","ca-key","nebula-cert"],"backgroundTag":"encrypted-key-requires-tty","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"}