slackhq/nebula · error

out-key must be encrypted interactively

Error message

out-key must be encrypted interactively

What it means

The nebula-cert ca command, when -encrypt is given, reads a passphrase interactively from the terminal. If the passphrase reader reports ErrNoTerminal (stdin is not a TTY), the command aborts with "out-key must be encrypted interactively" because encrypted key output requires a human at a terminal.

Source

Thrown at cmd/nebula-cert/ca.go:229

	var claims ioClaims
	if err := reserveOutputs(&claims,
		"out-key", *cf.outKeyPath,
		"out-crt", *cf.outCertPath,
		"out-qr", *cf.outQRPath,
	); err != nil {
		return err
	}

	var passphrase []byte
	if !isP11 && *cf.encryption {
		passphrase = []byte(os.Getenv("NEBULA_CA_PASSPHRASE"))
		if len(passphrase) == 0 {
			for i := 0; i < 5; i++ {
				errOut.Write([]byte("Enter passphrase: "))
				passphrase, err = pr.ReadPassword()

				if err == ErrNoTerminal {
					return fmt.Errorf("out-key must be encrypted interactively")
				} else if err != nil {
					return fmt.Errorf("error reading passphrase: %s", err)
				}

				if len(passphrase) > 0 {
					break
				}
			}

			if len(passphrase) == 0 {
				return fmt.Errorf("no passphrase specified, remove -encrypt flag to write out-key in plaintext")
			}
		}
	}

	var curve cert.Curve
	var pub, rawPriv []byte
	var p11Client *pkclient.PKClient

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Run the command in an interactive terminal (allocate a TTY: docker run -it, ssh -t).
  2. Drop the -encrypt flag so the out-key is written in plaintext (then protect the file yourself).
  3. Use a non-interactive alternative such as generating the key programmatically with the cert library and encrypting it yourself.
  4. Check nebula-cert's version for a -quiet-passphrase/non-interactive passphrase flag if automation requires encryption.

Example fix

// before (CI script, no TTY)
nebula-cert ca -name "ca" -encrypt

// after
docker exec -it ca-container nebula-cert ca -name "ca" -encrypt
// or, without a TTY:
nebula-cert ca -name "ca"  # plaintext out-key
Defensive patterns

Strategy: validation

Validate before calling

// before invoking nebula-cert with -encrypt, ensure a TTY exists
if fi, _ := os.Stdin.Stat(); (fi.Mode() & os.ModeCharDevice) == 0 {
    return fmt.Errorf("-encrypt requires an interactive terminal")
}

Try / catch

out, err := exec.Command("nebula-cert", "ca", "-encrypt", ...).CombinedOutput()
if err != nil && strings.Contains(string(out), "out-key must be encrypted interactively") {
    // retry with a TTY (docker -it / ssh -t) or without -encrypt
    return err
}

Prevention

When it happens

Trigger: Running `nebula-cert ca -encrypt` with stdin redirected, piped, or from a non-interactive context (cron, CI, Docker without -t) so the password reader returns ErrNoTerminal on the first prompt attempt.

Common situations: Automating CA generation in CI pipelines, scripting nebula-cert with echo'd passphrases, running inside a container without a TTY, or using SSH without -t.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/26dd62375d19ba11. Report an issue: GitHub.