Keyboard shortcuts

Press โ† or โ†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

cryl

A small tool for generating, encrypting, and managing secrets.

cryl allows you to create and renew secrets using a specification. The specification contains instructions for cryl for how to import existing secrets, generate or renew secrets and export those secrets in that order.

All imports, generations and exports happen in the order of execution as specified in the specification.

Installation

cryl is available as the default nix package of the cryl flake. cryl is supported on all default systems.

Invoking

You can invoke cryl in two ways:

  1. cryl <path>: This tells cryl to load the specification from the given path. Supported formats are json, yaml and toml. cryl automatically detects the format of the specification via the file extension.
  2. ... | cryl stdin <format>: This tells cryl to load the specification from standard input. In this mode you have to tell cryl the format of the specification.

cryl will always take these arguments into account:

  • --dry-run- don't run exports
  • --allow-script- allow script generator
  • --max-imports: int = 1024- maximum allowed imports
  • --max-generations: int = 1024- maximum allowed generations
  • --max-exports: int = 1024- maximum allowed exports
  • --max-specification-size: int = (1024 * 1024)- maximum allowed specification size in bytes
  • --manifest-format: string = "json" - select manifest format from 'json', 'yaml' and 'toml'
  • --verbose - turn on logging from modules
  • --very-verbose - turn on logging from tools (implies verbose)

Manifest

After each successful run, cryl creates a manifest file (cryl-manifest.json by default) in the working directory. This manifest serves as an audit trail and helps detect supply chain attacks or tampering.

The manifest contains:

  • cryl_version - The version of cryl used
  • timestamp - When the run occurred (ISO 8601 / RFC 3339 format)
  • spec_hash - SHA256 hash of the input specification
  • spec_format - Format of the specification (json, yaml, toml)
  • environment - Map of tool names (openssl, ssh-keygen, etc.) to their versions and paths
  • output_hashes - SHA256 hashes of all generated files

You can control manifest creation with:

  • --no-manifest - Don't create a manifest file
  • --manifest-format - Change the format (json, yaml, toml; default: json)

The manifest is only created when the run succeeds. No manifest is written on error. The manifest file itself is not included in output_hashes.

Sandbox

By default, cryl runs in a bubblewrap sandbox. The --nosandbox argument can be provided to disable the sandbox. When cryl is running in a sandbox the following arguments will be taken into account:

  • --ro-binds: list<string> = []- additional read-only bind mounts to add to bubblewrap
  • --binds: list<string> = []- additional bind mounts to add to bubblewrap
  • --tools: list<string> = []- additional list of tool binaries that cryl is allowed to access via PATH
  • --allow-net- allow network while running

When not in a sandbox, cryl will take these arguments into account:

  • --stay: By default, cryl will create a temporary directory and change its directory to it. You can instruct cryl to stay in the directory in which it was invoked by passing this argument.
  • --keep: By default, cryl will delete the contents of the working directory at the end of its execution. This is a safety precaution so that your filesystem doesn't contain secrets in plaintext for anyone to see after it is done with work. You can disable this behavior by passing this argument.

cryl also allows you to invoke all of the importers, generators and exporters on their own. Please note, however, that while cryl does have safety precautions when using it in the main ways as described here, invoking the importers, generators and exporters by themselves is done with minimal safety precautions which is limited to setting file permissions on generated files.

Additional Commands

In addition to the main commands above, cryl provides several other commands:

  • cryl schema: Print the JSON schema used to validate specifications to stdout. This can be useful for IDE integration or validation tools.

  • cryl import <importer> [args]: Run a specific importer directly. This allows you to test any importer (copy, vault, vault-file) without a full specification. See the Importers chapter for available importers and their arguments.

  • cryl generate <generator> [args]: Run a specific generator directly. This allows you to test any generator (id, key, password, tls-root, etc.) without a full specification. See the Generators chapter for available generators and their arguments.

  • cryl export <exporter> [args]: Run a specific exporter directly. This allows you to test any exporter (copy, vault, vault-file) without a full specification. See the Exporters chapter for available exporters and their arguments.

Specification

Here is an example of the specification in TOML format:

[[imports]]
importer = "copy"
arguments.path = "../id"
arguments.to = "id"
arguments.allow_fail = true

[[imports]]
importer = "copy"
arguments.from = "../key"
arguments.to = "key"
arguments.allow_fail = true

[[generations]]
generator = "id"
arguments.name = "id"
arguments.length = 16

[[generations]]
generator = "key"
arguments.name = "key"
arguments.length = 32
arguments.renew = true

[[exports]]
exporter = "copy"
arguments.from = "id"
arguments.to = "../id"

[[exports]]
exporter = "copy"
arguments.from = "key"
arguments.to = "../key"

This specification will instruct cryl to do the following:

  1. Copy the ../id and then ../key files into the working directory while allowing cryl to fail if the files do not exist (useful when generating secrets for the first time) time)

  2. Generate the id file with the contents of a alphanumeric identifier of length 16 if it doesn't exist

  3. Generate the key file with the contents of a alphanumeric key of length 32 overwriting the original if it exists (renewal)

  4. Copy the id file into ../id and then the key file into ../key overwriting the original files if they exist

cryl validates every specification against the schema.json file.

Importers

The following are all available importers in cryl. The type corresponds to the importer field in the specification.

Copy

Uses cp -f to copy a file.

  • Type: copy
  • Arguments:
    • from (path): From where to copy the file.
    • to (path): Where to put the file.
    • allow_fail (boolean, = false): Allow failing to copy the file.
    • renew (boolean, = false): Overwrite the destination file if it exists.

Vault

Uses medusa to import multiple files from Vault.

  • Type: vault
  • Arguments:
    • path (string): Vault path where to load files from. The path will get suffixed with a current key because it lets the corresponding vault exporter to export multiple versions of the same secrets.
    • allow_fail (boolean, = false): Allow failing to load files.

Vault file

Uses Vault CLI to import a single file from Vault.

  • Type: vault-file
  • Arguments:
    • path (string): Vault path where to load files from. The path will get suffixed with a current key because it lets the corresponding vault exporter to export multiple versions of the same secrets.
    • file (string): Key of the file to load.
    • allow_fail (boolean, = false): Allow failing to load file.

Generators

The following are all available generators in cryl. The type corresponds to the generator field in the specification.

Generate Copy

Uses raw read + save to copy a file.

  • Type: copy
  • Arguments:
    • from (path): Source file path.
    • to (path): Destination file path.
    • renew (boolean, = false): Overwrite the destination if it exists.

Generate Text

Writes a text file during generation.

  • Type: text
  • Arguments:
    • name (path): Destination file name.
    • text (string): Text content to write.
    • renew (boolean, = false): Overwrite the destination if it exists.

JSON

Generates a JSON file from input data.

  • Type: json
  • Arguments:
    • name (path): Path to the JSON file.
    • value (object): Contents of the JSON file.
    • renew (boolean, = false): Whether to overwrite on subsequent runs.

YAML

Generates a YAML file from input data.

  • Type: yaml
  • Arguments:
    • name (path): Path to the YAML file.
    • value (object): Contents of the YAML file.
    • renew (boolean, = false): Whether to overwrite on subsequent runs.

TOML

Generates a TOML file from input data.

  • Type: toml
  • Arguments:
    • name (path): Path to the TOML file.
    • value (object): Contents of the TOML file.
    • renew (boolean, = false): Whether to overwrite on subsequent runs.

Id

Generates a random alphanumeric id and writes it to a file.

  • Type: id
  • Arguments:
    • name (path): Destination file name for the id.
    • length (int, = 16): Number of characters in the id.
    • renew (boolean, = false): Overwrite the destination if it exists.

Key

Generates a random alphanumeric key and writes it to a file. ๐Ÿ”‘

  • Type: key
  • Arguments:
    • name (path): Destination file name for the key.
    • length (int, = 32): Number of characters in the key.
    • renew (boolean, = false): Overwrite the destination if it exists.

Pin

Creates a numeric PIN with the given length and writes it to a file.

  • Type: pin
  • Arguments:
    • name (path): Destination file name for the PIN.
    • length (int, = 8): Number of digits in the PIN.
    • renew (boolean, = false): Overwrite the destination if it exists.

Password

Generates a random alphanumeric password, hashes it with Argon2, and saves:

  • plaintext to private

  • hashed (public) to public

  • Type: password

  • Arguments:

    • public (path): Destination for the hashed password.
    • private (path): Destination for the plaintext password.
    • length (int, = 8): Number of characters in the password.
    • renew (boolean, = false): Overwrite existing files.

Password-crypt-3

Generates a random alphanumeric password, hashes it with yescrypt (via mkpasswd), and saves:

  • plaintext to private
  • hashed (public) to public

Note: yescrypt hashes are widely compatible with modern Linux distributions โœ…

  • Type: password-crypt-3
  • Arguments:
    • public (path): Destination for the yescrypt-hashed password.
    • private (path): Destination for the plaintext password.
    • length (int, = 8): Number of characters in the password.
    • renew (boolean, = false): Overwrite existing files.

Age-key

Generates an age key pair (using age-keygen) and saves:

  • private key to private
  • public key to public

Note: This key pair is typically needed when using the sops generator, since sops uses the age public key to encrypt secrets and the private key to decrypt them. ๐Ÿ”

  • Type: age-key
  • Arguments:
    • public (string): Destination for the public key.
    • private (string): Destination for the private key.
    • renew (boolean, = false): Overwrite existing files.

SSH Key

Generates an Ed25519 SSH key pair (ssh-keygen -a 100) and saves:

  • private key to private

  • public key to public

  • Type: ssh-key

  • Arguments:

    • name (string): Key comment stored in the public key.
    • public (path): Destination for the public key.
    • private (path): Destination for the private key.
    • password (string, = ""): Path to a file containing the passphrase. Leave empty for no passphrase.
    • renew (boolean, = false): Overwrite existing files.

Wireguard Key

Generates a Wireguard key pair and saves:

  • private key to private

  • public key to public

  • Type: wireguard-key

  • Arguments:

    • public (path): Destination for the public key.
    • private (path): Destination for the private key.
    • renew (boolean, = false): Overwrite existing files.

Key split

Splits a key using Shamir secret sharing (via ssss-split) and writes each share to files named with the given prefix and index, like prefix-0, prefix-1, etc.

  • Type: key-split
  • Arguments:
    • key (string): Path to the key file to split (read as raw).
    • prefix (string): Prefix for each output share file.
    • threshold (int): Minimum shares needed to reconstruct.
    • shares (int): Total number of shares to create.
    • renew (boolean, = false): Overwrite existing files.

Key combine

Combines Shamir shares (via ssss-combine) to reconstruct the original key and saves it to key.

  • Type: key-combine
  • Arguments:
    • shares (string): Comma-separated paths to share files.
    • key (string): Destination path for the reconstructed key.
    • threshold (int): Number of shares required to reconstruct (must match what was used during split).
    • renew (boolean, = false): Overwrite existing file.

Note: Provide at least threshold valid shares. Fewer than that wonโ€™t reconstruct the secret. ๐Ÿงฉ๐Ÿ”

TLS root

Creates a Root CA:

  • writes a minimal OpenSSL config to config
  • generates a private key to private
  • issues a self-signed root certificate to public

Algorithm: EC with curve prime256v1 (aka Pโ€‘256). ๐Ÿง โšก

  • Type: tls-root
  • Arguments:
    • common_name (string): CN for the Root CA.
    • organization (string): Organization name.
    • config (path): Where the temporary OpenSSL config is saved.
    • private (path): Destination for the private key.
    • public (path): Destination for the root certificate.
    • pathlen (int, = 1): Max chain depth; -1 means no limit.
    • days (int, = 3650): Validity period.
    • renew (boolean, = false): Overwrite existing files.

Notes:

  • basicConstraints is set to CA:true (with pathlen if provided).
  • keyUsage includes keyCertSign and cRLSign.
  • Hash: sha256. โœ…

TLS intermediary

Creates an Intermediate CA signed by your Root:

  • writes minimal req/ext config to config (merging request_config)
  • generates a private key and CSR
  • signs CSR with the Root CA, manages serial file

Algorithm: EC with curve prime256v1 (Pโ€‘256). ๐ŸŒฟ๐Ÿ”

  • Type: tls-intermediary
  • Arguments:
    • common_name (string): CN for the Intermediate CA.
    • organization (string): Organization name.
    • config (path): Output merged OpenSSL config.
    • private (path): Intermediate private key path.
    • request (path): CSR path.
    • request_config (path): Base req config to extend.
    • ca_public (path): Root certificate.
    • ca_private (path): Root private key.
    • serial (path): Serial tracking file.
    • public (path): Signed intermediate certificate.
    • pathlen (int, = 0): Max chain depth under this intermediate.
    • days (int, = 3650): Validity period.
    • renew (boolean, = false): Overwrite existing files.

Notes:

  • basicConstraints set to CA:true (with pathlen if provided).
  • keyUsage: keyCertSign, cRLSign. Hash: sha256.
  • Keeps your serial tidy by tempโ€™ing and then writing back. โœ…

TLS leaf

Issues a leaf (end-entity) certificate:

  • builds req config with SANs (DNS + IP)
  • generates private key and CSR
  • signs with the provided issuer, manages serial file

Algorithm: EC with curve prime256v1 (Pโ€‘256). ๐Ÿƒ๐Ÿ”

  • Type: tls-leaf
  • Arguments:
    • common_name (string): CN for the cert.
    • organization (string): Org name.
    • sans (string): Comma-separated SANs.
    • config (path): Output ext config used for signing.
    • request_config (path): Req config for CSR.
    • private (path): Private key path.
    • request (path): CSR path.
    • ca_public (path): Issuer certificate.
    • ca_private (path): Issuer private key.
    • serial (path): Serial tracking file.
    • public (path): Signed certificate output.
    • days (int, = 3650): Validity period.
    • renew (boolean, = false): Overwrite existing files.

Notes:

  • basicConstraints = CA:false.
  • keyUsage adjusts for RSA vs EC; extKeyUsage includes serverAuth, clientAuth.
  • Hash: sha256. โœ…

TLS RSA root

Creates a Root CA (self-signed):

  • writes minimal ext config for a CA
  • generates a private key and self-signed cert
  • sets basicConstraints with pathlen

Algorithm: RSA 4096. ๐Ÿ”’

  • Type: tls-root (RSA)
  • See: TLS root heading

TLS RSA intermediary

Creates an Intermediate CA signed by your Root:

  • builds req/ext config (merging req into ext)
  • generates private key and CSR
  • signs with the Root, manages serial file

Algorithm: RSA 4096. ๐Ÿ—๏ธ

TLS RSA leaf

Issues a leaf (end-entity) certificate:

  • builds req config with SANs (DNS + IP)
  • generates private key and CSR
  • signs with the provided issuer, manages serial file

Algorithm: RSA 4096. ๐Ÿƒ

  • Type: tls-leaf (RSA)
  • See: TLS leaf heading

OpenSSL Diffie-Hellman parameters

Generates an OpenSSL Diffie-Hellman parameters file with 2048 bits.

  • Type: tls-dhparam
  • Arguments:
    • name (path): Path to the file to be generated.
    • renew (boolean, = false): Whether to overwrite the parameters file if it already exists.

Nebula CA

Generates a Nebula Certificate Authority (CA) certificate and private key using nebula-cert ca. Duration is computed as hours: days * 24.

  • Type: nebula-ca
  • Arguments:
    • name (string): Common name for the CA.
    • public (path): Output path for the CA certificate.
    • private (path): Output path for the CA private key.
    • days (int, = 3650): Certificate validity in days.
    • renew (boolean, = false): Whether to overwrite existing outputs.

Nebula certificate

Generates a Nebula node certificate and private key signed by the provided Nebula CA using nebula-cert sign.

  • Type: nebula-cert
  • Arguments:
    • ca_public (path): Path to the Nebula CA certificate.
    • ca_private (path): Path to the Nebula CA private key.
    • name (string): Common name for the node certificate.
    • ip (string): Node IP (CIDR or plain IP).
    • public (path): Output path for the node certificate.
    • private (path): Output path for the node private key.
    • renew (boolean, = false): Whether to overwrite existing outputs.

CockroachDB CA

Generates a CockroachDB Certificate Authority (CA) certificate and private key using cockroach cert create-ca.

  • Type: cockroach-ca
  • Arguments:
    • public (path): Output path for the CA certificate.
    • private (path): Output path for the CA private key.
    • renew (boolean, = false): Whether to overwrite existing outputs.

CockroachDB node certificate

Generates a CockroachDB node certificate and key using cockroach cert create-node, signed by the provided CA. Hosts are taken from a comma-separated list.

  • Type: cockroach-node-cert
  • Arguments:
    • ca_public (path): Path to the CA certificate.
    • ca_private (path): Path to the CA private key.
    • public (path): Output path for the node certificate.
    • private (path): Output path for the node private key.
    • hosts (string): Comma-separated host names/IPs for SANs.
    • renew (boolean, = false): Whether to overwrite existing outputs.

CockroachDB client certificate

Generates a CockroachDB client certificate and key for a specific user using cockroach cert create-client, signed by the provided CA.

  • Type: cockroach-client-cert
  • Arguments:
    • ca_public (path): Path to the CA certificate.
    • ca_private (path): Path to the CA private key.
    • public (path): Output path for the client certificate.
    • private (path): Output path for the client private key.
    • user (string): CockroachDB username to embed in the cert filename and CN.
    • renew (boolean, = false): Whether to overwrite existing outputs.

Environment file

Generates and environment (.env) file.

  • Type: env
  • Arguments:
    • name (string): Where to save the environment file.
    • variables (object): Variables pointing to files which to open and include.
    • renew (boolean, = false): Whether to overwrite on subsequent generations.

Moustache template

Generates a populated Mustache template.

  • Type: moustache
  • Arguments:
    • name (string): Where to save the populated template.
    • template (string): The Mustache template.
    • variables (object): Variables to insert into the template.
    • renew (boolean, = false): Whether to overwrite on subsequent generations.

Script

Generates a Nushell script and executes it.

  • Type: script
  • Arguments:
    • name (string): Where to save the script.
    • text (string): The Nushell script contents.
    • renew (boolean, = false): Whether to overwrite on subsequent generations.

Notes:

  • Running this requires the --allow-script flag enabled for execution.

SOPS

Generates SOPS-encrypted secrets from a key-value map.

  • Type: sops
  • Arguments:
    • age (string): Age recipient(s) used for encryption.
    • public (string): Where to save the encrypted secrets (SOPS YAML).
    • private (string): Where to save the plaintext secrets (YAML).
    • secrets (object): Secrets map to insert. Values may be inline strings or file paths to inline.
    • renew (boolean, default: false): Whether to overwrite on subsequent generations.

Notes:

  • Flow:
    1. Secrets -> YAML saved to private (plaintext).
    2. Encrypt with sops encrypt --input-type yaml --age <age> --output-type yaml.
    3. Save encrypted output to public.
  • public is saved as a public artifact; private contains plaintextโ€”handle with care.

Exporters

The following are all available exporters in cryl. The type corresponds to the exporter field in the specification.

Copy

Copies a file overwriting destination if exists.

  • Type: copy
  • Arguments:
    • from (path): Source file to copy.
    • to (path): Destination path.

Vault

Exports all files in the current directory into a Vault KV store twice:

  • once to <path>/current

  • once to <path>/<timestamp>

  • Type: vault

  • Arguments:

    • path (string): Base KV path. Leading/trailing slashes are trimmed.

Behavior:

  • Reads all entries from the working directory (ls).
  • For each file: key = basename, value = file contents (raw, trimmed).
  • Emits a YAML map, then pipes it to:
    • medusa import <path>/current -
    • medusa import <path>/<timestamp> -
  • Overwrites keys on the "current" path; timestamped path is append-only by nature.

Notes:

  • Only top-level files are considered (no recursion).
  • Binary files will be read raw and trimmed; stick to text files.

Vault file

Sends one fileโ€™s contents into Vault KV:

  • writes to <path>/current

  • also snapshots to <path>/<timestamp>

  • Type: vault-file

  • Arguments:

    • path (string): Base KV path. Slashes trimmed.
    • file (string): Local file whose content becomes the value.