Getting started¶
This page takes one file, credentials.toml, through the basic steps: marking
its secrets, encrypting it and decrypting it, on the command line and in
Python. The sections after that cover checks in CI, changing the password and
supplying it in automation.
1 Mark the secrets¶
A value is secret only when it is wrapped in an object carrying the reserved
__keyloom__ marker. Keyloom never infers from a field name such as
token or password that a value is sensitive. The value holds either the
secret itself or the placeholder __keyloom__secret__:
[git."gitlab.example.org"]
username = "oauth2"
token = { __keyloom__ = "secret", value = "__keyloom__secret__" }
git:
gitlab.example.org:
username: oauth2
token:
__keyloom__: secret
value: __keyloom__secret__
{
"git": {
"gitlab.example.org": {
"username": "oauth2",
"token": {
"__keyloom__": "secret",
"value": "__keyloom__secret__"
}
}
}
}
The wrapper is the same logical object in all three formats, so the rest of this page uses TOML. There are two ways to provide the secret:
- Write the placeholder, as above, and type the secret when the file is encrypted. The secret then never exists in the file as plaintext.
- Write the secret itself into
value. This suits a file kept on a tmpfs or other storage where plaintext is acceptable, a secret that spans several lines such as a PEM key, and an existing plaintext configuration.
2 Encrypt the file¶
2.1 On the command line¶
keyloom encrypt credentials.toml
The command asks for the vault password and then for the secret of every placeholder, each named by its location in the file and each entered twice. Nothing is echoed:
Vault password:
Confirm vault password:
Secret for git."gitlab.example.org".token:
Confirm secret for git."gitlab.example.org".token:
credentials.toml: encrypted 1 secret
A secret typed at the prompt goes to its envelope in memory; a secret written
into value is encrypted without a prompt. Either way the file ends up the
same, and everything outside the wrappers stays readable:
[git."gitlab.example.org"]
username = "oauth2"
token = { __keyloom__ = "secret", value = "$KEYLOOM;1;argon2-v2;s=..." }
Adding a secret later is the same step: add a wrapper and run encrypt
again. Values that are already encrypted are left encrypted and are first
verified against the supplied password, so a single run never produces a file
whose secrets use different passwords.
Placeholders need a terminal. Where there is none, as in a CI job, a
placeholder is an error and nothing is written; secrets written into value
need no terminal.
2.2 In Python¶
keyloom.encrypt_file does the same for a file. prompt is
called once for every placeholder with its location and returns the secret;
None makes a placeholder an error. Pass the same path twice to encrypt in
place:
import getpass
import keyloom
keyloom.encrypt_file(
input_path="credentials.toml",
output_path="credentials.toml",
password=password,
algorithm=keyloom.Algorithm.ARGON2_V2,
prompt=lambda location: getpass.getpass(f"Secret for {location}: "),
)
An application that produces its configuration itself marks the secrets with
keyloom.secret and writes the data with
keyloom.store, which encrypts them on the way to the file:
keyloom.store(
path="credentials.toml",
data={"git": {"token": keyloom.secret(value=token)}},
password=password,
algorithm=keyloom.Algorithm.ARGON2_V2,
)
store writes the file fresh, so the comments of an existing file are lost;
encrypt_file keeps the file as it is apart from the encrypted values. Unlike
the command line, the API has no default algorithm: every call that encrypts
names one, as a member of keyloom.Algorithm.
3 Decrypt the file¶
3.1 On the command line¶
decrypt writes the decrypted file to standard output with the wrappers still
in place:
keyloom decrypt credentials.toml
--unwrap replaces each wrapper by its value and emits the ordinary
configuration:
keyloom decrypt --unwrap credentials.toml
--output FILE writes the decrypted file to disk instead, with mode 0600.
3.2 In Python¶
An application reads the file with keyloom.load, which decrypts
and unwraps the marked values in memory and returns ordinary Python data:
import keyloom
credentials = keyloom.load(path="credentials.toml", password=password)
token = credentials["git"]["gitlab.example.org"]["token"]
keyloom.decrypt_file writes the decrypted file to disk with its
wrappers and mode 0600, so encrypt_file turns it back into an encrypted
file. It refuses to write onto the input file:
keyloom.decrypt_file(
input_path="credentials.toml",
output_path="credentials.plain.toml",
password=password,
)
In both, a marked value that is still plaintext is an error. A file that was never encrypted, or whose envelope was replaced by plaintext, is therefore never decrypted silently.
4 Advanced use¶
4.1 Keep plaintext out of the repository¶
keyloom check credentials.toml
check fails if any marked value is not a well-formed envelope: plaintext, a
placeholder, or a malformed envelope. It needs no password, so it fits a
pre-commit hook or a CI job.
4.2 Change the password or the algorithm¶
reencrypt encrypts every secret again in memory, so the plaintext never
reaches the disk:
keyloom reencrypt --change-password credentials.toml
The same command moves a file to another algorithm with --algorithm.
In Python, keyloom.reencrypt_file takes the current and the new
password. Passing the same password twice changes only the algorithm:
keyloom.reencrypt_file(
input_path="credentials.toml",
output_path="credentials.toml",
password=password,
new_password=new_password,
algorithm=keyloom.Algorithm.ARGON2_V2,
)
4.3 Supply the password in automation¶
Interactive commands prompt for the password. CI jobs, containers and other non-interactive environments pass it on standard input or in a file:
printf '%s\n' "$KEYLOOM_PASSWORD" |
keyloom decrypt --password-stdin credentials.toml
keyloom decrypt \
--password-file /run/secrets/keyloom-password \
credentials.toml
Note
Keyloom has no --password PASSWORD option. A password given as a
command-line argument can leak through shell history, logs or process
inspection.
Next steps¶
How it works explains the wrapper, the envelopes and what Keyloom protects. The command-line reference and the Python API list every command, option and function.