Commandline tool to easily lock (encrypt) and unlock (decrypt) project tokens, credentials and keys. Optionally includes a daemon that automatically locks a project after a certain time.
It uses Age for encryption, so no hassle with GnuPG setup or anything.
Warning
Please read the Security Considerations chapter to learn about Lockdown's failure modes and other things you should be aware of.
A birds-eye view of how it works:
$ ls
README.md secret.json google_api_secret.json script.py
$ lockdown genconf secret.json google_api_secret.json
Generated '.lockdown.conf' in current dir
$ lockdown lock
Using public key '/home/fboender/.config/lockdown/lockdown.pub' (0FEE8A7A3E6C7EBC)
Locking 'secret.json'
Locking 'google_api_secret.json'
$ lockdown status
Project '/path/to/project' is locked
$ lockdown unlock
Password for /home/fboender/.config/lockdown/lockdown.key:
Unlocking 'secret.json'
Unlocking 'google_api_secret.json'
Warning
Lockdown is a work in progress. See the Notes and Todos section for more information.
Recently there was another high-profile supply chain attack on various npm packages. This time, a credential stealer was embedded in the attack. We are always told to not execute untrusted code, but the reality is that this simply cannot be avoided in all cases.
I have a lot of projects that I occasionally work on. Many of these projects
require tokens, secrets, kubeconfig.yml files, etc.
When I'm not working on these projects, I don't want these tokens to be vulnerable to credential exfiltration. But I also want it to be easy to get back to working on a project I haven't worked on for a while.
Lockdown automatically locks such credentials when I'm not working on a project, and makes it easy to unlock all required credentials when I resume work.
- Uses Age for encryption, so no hassle with GnuPG setup or anything
- Unlock multiple secrets in one go
- Manually lock secrets or automatically with a background daemon
- Use a single key, or optionally specify a different key per project
- Recursive globbing for lock files ala Git is supported (e.g.
**/*.yml)
Lockdown searches the current and parent dirs until it finds a
.lockdown.conf file. This file specifies how and what to lock:
$ cd /path/to/project
$ cat .lockdown.conf
{
"lock_files": [
"secret.json",
"google_api_secret.json",
"google_api_tokens.json",
]
}
We can lock the credentials:
$ lockdown lock
Using public key '/home/fboender/.config/lockdown/lockdown.pub' (0FEE8A7A3E6C7EBC)
Locking 'secret.json'
Locking 'google_api_secret.json'
Locking 'google_api_tokens.json'
This takes the configured files, and encrypts them using an Age public key:
$ ls -l
README.md
secret.json.age
google_api_secret.json.age
google_api_tokens.json.age
To unlock, you will need to provide the password to the private key:
$ lockdown unlock
Password for /home/fboender/.config/lockdown/lockdown.key:
Unlocking 'secret.json'
Unlocking 'google_api_secret.json'
Unlocking 'google_api_tokens.json'
An optional background daemon (lockdown daemon) can run in the
background and scan for unlocked projects in defined directories. These are
specified in the daemon.conf configuration file:
{
# Top level dirs which are recursively scanned for .lockdown.conf files
"base_dirs": [
"~",
],
...
It will automatically lock projects after a certain (configurable) period.
INFO lockdownd | Lock file '/path/to/project/secret.json' older than 3600 seconds old. Locking project.
By default it will not lock a project if any of the current user's processes has a working directory that's under the project's directory (i.e. you're probably working on the project):
INFO lockdownd | Lock file '/path/to/project/secret.json' older than 3600 seconds old. Locking project.
INFO lockdownd | User has process running in '/path/to/project'. Not locking.
As soon as we change directories in the shell, the project gets locked:
/path/to/project $ cd ..
The logging shows the project being locked:
INFO lockdownd | Lock file '/path/to/project/secret.json' older than 3600 seconds old. Locking project.
Optionally, a desktop notification can be shown when a project gets
locked. This can be turned on in the ~/.config/lockdown/daemon.conf file
with the desktop_notify setting. For this to work, notify-send must be
available on the system.
Lockdown is distributed as a standalone linux x86-64 binary. There currently is no support for Windows or MacOS.
Download the latest release and install Lockdown:
$ tar -vxf ~/Downloads/lockdown-*.tar.gz
$ cd lockdown-<VERSION>
$ ./install.sh
If you generated default keys during installation, you can immediately start using Lockdown. If not, see below on how to generate initial or additional keys.
Go to a project's directory and create a lockdown configuration file.
$ ls
README.md secret.json google_api_secret.json script.py
$ lockdown genconf secret.json google_api_secret.json
Generated '.lockdown.conf' in current dir
$ lockdown lock
Using public key '/home/fboender/.config/lockdown/lockdown.pub' (0FEE8A7A3E6C7EBC)
Locking 'secret.json'
Locking 'google_api_secret.json'
$ lockdown status
Project '/path/to/project' is locked
$ lockdown unlock
Password for /home/fboender/.config/lockdown/lockdown.key:
Unlocking 'secret.json'
Unlocking 'google_api_secret.json'
You can generate additional keys and use those for more sensitive tokens.
Generate a new public / private key pair:
$ lockdown genkey
Password for the new key?:
Verify password?:
Wrote encrypted key to 'lockdown.key'
Wrote public key to 'lockdown.pub'
You can configure the keys in a .lockdown.conf file somewhere:
$ cd /path/to/project
$ vi .lockdown.conf
{
# Separate keys
"priv_key_path": "lockdown.key",
"pub_key_path": "lockdown.pub",
# List of files to lock/unlock
"lock_files": [
"secret.json",
],
}
Paths are relative to the location of the .lockdown.conf file, unless you
specify an absolute path. You can refer to your home directory using ~/:
{
# Separate keys
"priv_key_path": "~/.config/lockdown/keys/sensitive.key",
"pub_key_path": "~/.config/lockdown/keys/sensitive.pub",
...
You can use wildcards (globbing) to have lockdown dynamically find out which
files to lock and unlock. You must quote the lock file when using genconf:
$ lockdown genconf '*.yml'
$ tail .lockdown.conf
# List of files to lock/unlock
"lock_files": [
"*.yml",
],
$ lockdown -v status
Loading public key from '/home/fboender/.config/lockdown/lockdown.pub'
Using lock file: /path/to/project/cred_prod.yml
Using lock file: /path/to/project/cred_acc.yml
/path/to/project/cred_prod.yml is not locked
/path/to/project/cred_acc.yml is not locked
Project '/path/to/project' is not (fully) locked
Recursive globbing is also supported. This will find matching files anywhere in the project:
$ lockdown genconf '**/*.yml'
An optional daemon can be ran in the background to automatically lock projects when they are not in use.
If you installed Lockdown globally, the daemon will run in the usual systemd way:
$ sudo journalctl -u lockdown.service
Oct 01 09:50:51 hank systemd[5890]: Started lockdown.service - Lockdown daemon.
Oct 01 09:50:51 hank lockdown[1161448]: 2025-10-01 09:50:51,194 INFO daemon | Finding directories containing .lockdown.conf files under /home/fboender
Oct 01 09:50:53 hank lockdown[1161448]: 2025-10-01 09:50:53,166 INFO project | Lock file '/path/to/project/secret.json' older than 3600 seconds old. Locking project.
Oct 01 09:50:53 hank lockdown[1161448]: 2025-10-01 09:50:53,210 INFO project | User has process running in '/path/to/project'. Not locking.
The daemon configuration is installed in /etc/lockdown/daemon.conf and a
systemd unit service file in /etc/systemd/system/lockdown.service.
If you installed Lockdown for just your user, the daemon runs under your user account using systemd. It will automatically start at system boot and it will persist even when you log out.
You can interact with the daemon in the usual systemd way, except you need to
add the --user flag.
# See systemd unit status
$ systemctl --user status lockdown.service
# View logging
$ journalctl --follow --user -u lockdown.service
The daemon configuration is installed in ~/.config/lockdown/daemon.conf and
a (user) systemd unit service file in
~/.config/systemd/user/lockdown.service.
To enable verbose logging, edit
/.config/systemd/user/lockdown.service and add a -v parameter to
the Exec line:
ExecStart=%h/.local/bin/lockdown -v daemon
Reload systemd and restart the service:
$ systemctl --user daemon-reload
$ systemctl --user restart lockdown.service
To add a locked indicator to your prompt when you change to the directory of a
project, add the following to your ~/.bashrc:
prompt_lockdown_locked() {
if [ -f ".lockdown.conf" ]; then
if [ "$(lockdown status | grep "is locked$")" != "" ]; then
echo "π"
fi
fi
}
PS1="$(prompt_lockdown_locked) $PS1"
Lockdown is a last line of defense. You should not use it as your primary means of protecting secrets. Please take the following things into consideration:
-
Running Lockdown under your own user (compared to a system wide installation) significantly reduces the security of Lockdown. An attacker that knows Lockdown is running can manipulate the binary, the daemon and the daemon configuration file. System wide installation is recommended
-
Lockdown is meant to protect against drive-by credential harvesting and cannot protect against an attacker that has prolonged access to locked projects. The longer an attacker has access to your account, the higher the risk of failure
-
Lockdown makes no attempt to thwart anything running as your user from obtaining the passwords to private keys, other than never storing passwords on disk. There's no fancy memory protection or wiping.
-
Basically if a process dumps the memory of a Lockdown process while you're entering a private key's password, it's probably game over. See also the next item.
You should take into consideration the following advice:
-
Remove credentials from your system when you do not require them for extended periods of time, rather than using Lockdown to protect them. Lockdown should only be used to protect projects you expect to actively work in the short-term future.
-
Run all untrusted code (including development libraries and frameworks) in a sandboxed environment per project.
-
I strongly encourage you to NEVER store the password to Lockdown private keys anywhere on the same system as where the private keys live. Keep it in your mind, not in your password manager or whatever. If a credential stealer nabs both the Lockdown keys and a plain text dump of your password manager, the show is over.
-
Use separate keys for important things. The security model of Lockdown is mostly to protect "idle" tokens from being exfiltrated in plain text, because they were on your system unprotected. However, if you protect all your tokens with a single private key, and you use that once to unlock a specific project, an attacker could use the same private key to unlock all your other secrets.
To reduce the fallout from such a situation, you should use separate private/public keys for important tokens.
-
Verify the fingerprint of the public key when locking projects. When generating a private and public key, Lockdown shows the fingerprint of the public key. When a project is locked, the fingerprint is also shown. You should verify that the fingerprints match, or an attacker could replace your public key with their own. When you unlock and relock a project, the project will be locked with the attacker's public key, meaning they can also unlock the project with the private key they control. There is no way to automatically verify the public key, since any place where we could store this information is also writable by an attacker.
- Pyrage library. Lockdown uses a pure-python implementation of Age called pyrage. There is no information available on how well tested this is, and whether its crypto has been reviewed. But hey, I guess badly encrypted tokens are better than plain text tokens.
- Password-protected private keys. Age private keys are not encrypted by default. I encrypt them using Age's own symmetric encryption, essentially "putting a password on the private key". I assume I've done this correctly, but it has not been reviewed.
- Lockdown daemon should verify public keys somehow
- Only linux support for now, but should (theoretically) be able to run under windows and macos
- Currently no easy way to change the password of a private key, although you
can just decrypt and re-encrypt with the
agecli (symmetric mode)