Handling secrets
We strongly recommend not putting any sensitive information such as passwords or private keys into your repository. This page describes the helpers available in BundleWrap to manage those secrets without checking them into version control.
.secrets.cfg
When you initially ran bw repo create
, a file called .secrets.cfg
was put into the root level of your repo. It's an INI-style file that by default contains two random keys BundleWrap uses to protect your secrets.
.secrets.cfg
. Immediately add it to your .gitignore
or equivalent.Derived passwords
In some cases, you can control (i.e. manage with BundleWrap) both ends of the authentication process. A common example is a config file for a web application that holds credentials for a database also managed by BundleWrap. In this case, you don't really care what the password is, you just want it to be the same on both sides.
To accomplish that, just write this in your template (Mako syntax shown here):
database_user = "foo"
database_password = "${repo.vault.password_for("my database")}"
In your bundle, you can then configure your database user like this:
postgres_roles = {
"foo": {
'password': repo.vault.password_for("my database"),
},
}
It doesn't really matter what string you call password_for()
with, it just has to be the same on both ends. BundleWrap will then use that string, combine it with the default key called generate
in your .secrets.cfg
and derive a random password from that.
This makes it easy to change all your passwords at once (e.g. when an employee leaves or when required for compliance reasons) by rotating keys.
.secrets.cfg
very closely. If it is compromised, so are all your passwords. Use your own judgement.Static passwords
When you need to store a specific password, you can encrypt it symmetrically:
$ bw debug -c "print(repo.vault.encrypt('my password'))"
gAAAA[...]mrVMA==
You can then use this encrypted password in a template like this:
database_user = "foo"
database_password = "${repo.vault.decrypt("gAAAA[...]mrVMA==")}"
Files
You can also encrypt entire files:
$ bw debug -c "repo.vault.encrypt_file('/my/secret.file', 'encrypted.file'))"
data/
subdirectory of your repo.If the source file was encoded using UTF-8, you can then simply pass the decrypted content into a file item:
files = {
"/secret": {
'content': repo.vault.decrypt_file("encrypted.file"),
},
}
If the source file is binary however (or any encoding other than UTF-8), you must use base64:
files = {
"/secret": {
'content': repo.vault.decrypt_file_as_base64("encrypted.file"),
'content_type': 'base64',
},
}
Key management
Multiple keys
You can always add more keys to your .secrets.cfg
, but you should keep the defaults around. Adding more keys makes it possible to give different keys to different teams. By default, BundleWrap will skip items it can't find the required keys for.
When using .password_for()
, .decrypt()
etc., you can provide a key
argument to select the key:
repo.vault.password_for("some database", key="devops")
Rotating keys
.password_for()
. The other methods use symmetric encryption and require manually updating the encrypted text after the keys has changed.You can generate a new key by running bw debug -c "print(repo.vault.random_key())"
. Place the result in your .secrets.cfg
. Then you need to distribute the new key to your team and run bw apply
for all your nodes.