netbirdio/netbird · error

generate root key: %w

Error message

generate root key: %w

What it means

reposign.GenerateRootKey failed (root.go:50). The function generates an Ed25519 keypair via ed25519.GenerateKey(rand.Reader), embeds metadata (ID from SHA-256 of the public key, timestamps), and PEM-encodes two JSON blobs. The only realistic failure is the crypto/rand read: the system entropy source (/dev/urandom) is unavailable or exhausted. The json.Marshal steps handle plain structs and cannot realistically fail.

Source

Thrown at client/cmd/signer/rootkey.go:58

	createRootKeyCmd.Flags().StringVar(&privKeyFile, "priv-key-file", "", "Path to output private key file")
	createRootKeyCmd.Flags().StringVar(&pubKeyFile, "pub-key-file", "", "Path to output public key file")
	createRootKeyCmd.Flags().DurationVar(&rootExpiration, "expiration", 0, "Expiration time for the root key (e.g., 720h,)")

	if err := createRootKeyCmd.MarkFlagRequired("priv-key-file"); err != nil {
		panic(err)
	}
	if err := createRootKeyCmd.MarkFlagRequired("pub-key-file"); err != nil {
		panic(err)
	}
	if err := createRootKeyCmd.MarkFlagRequired("expiration"); err != nil {
		panic(err)
	}
}

func handleGenerateRootKey(cmd *cobra.Command, privKeyFile, pubKeyFile string, expiration time.Duration) error {
	rk, privPEM, pubPEM, err := reposign.GenerateRootKey(expiration)
	if err != nil {
		return fmt.Errorf("generate root key: %w", err)
	}

	// Write private key
	if err := os.WriteFile(privKeyFile, privPEM, 0o600); err != nil {
		return fmt.Errorf("write private key file (%s): %w", privKeyFile, err)
	}

	// Write public key
	if err := os.WriteFile(pubKeyFile, pubPEM, 0o600); err != nil {
		return fmt.Errorf("write public key file (%s): %w", pubKeyFile, err)
	}

	cmd.Printf("%s\n\n", rk.String())
	cmd.Printf("✅ Root key pair generated successfully.\n")
	return nil
}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Check the entropy device: ls -l /dev/urandom and cat a few bytes to confirm it is readable
  2. Restart the process or host — transient early-boot starvation resolves once the kernel CRNG is ready
  3. For containers, ensure /dev/urandom is mounted (it is bind-mounted by default in standard runtimes); fix the runtime config if it was removed
  4. If the error is a marshal message instead of a rand error, treat it as a code bug and inspect local modifications to reposign
Defensive patterns

Strategy: retry

Validate before calling

func entropyAvailable() error {
    f, err := os.Open("/dev/urandom")
    if err != nil {
        return fmt.Errorf("entropy source unavailable: %w", err)
    }
    defer f.Close()
    buf := make([]byte, 8)
    if _, err := io.ReadFull(f, buf); err != nil {
        return fmt.Errorf("entropy read failed: %w", err)
    }
    return nil
}

Try / catch

var rk *reposign.RootKey
var privPEM, pubPEM []byte
err := retry(3, 100*time.Millisecond, func() error {
    rk, privPEM, pubPEM, err = reposign.GenerateRootKey(expiration)
    return err
})
if err != nil {
    // entropy or environment problem: surface it, do not fabricate a key
    return fmt.Errorf("generate root key: %w", err)
}

Prevention

When it happens

Trigger: create-root-key running in a restricted container or chroot where /dev/urandom is not mounted; severe entropy starvation during early boot of a VM; otherwise practically unreachable.

Common situations: Minimal Docker images with an empty /dev; sandboxed CI runners restricting device access; embedded hosts early in boot before the CRNG initializes.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/46e225a21567cad0. Report an issue: GitHub.