Allow passing database password as environment variables. #546
Loading…
x
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What I'm trying to do and why
I'm using borgmatic as a cronjob of a kubernetes cluster to backup files and a MySQL database.
My MySQL passwords are defined as Kubernetes Secrets and injected as env var to MySQL container.
I configure the borgmatic job with a config file defined in a ConfigMap (Kubernetes object).
I don't like having to write down my MySQL password directly in the Yaml file, I would like to inject it as a Secret ie. an environment variable directly in the container.
I would like to have a
password_env
key in addition topassword
for the 3 database hooks configuration nodes where I could give the environment variable name where the password will be injected.I made a quick development and it works for my needs, maybe someone might find it useful too.
See: #545
Thanks
Wow, borgmatic on Kubernetes. Never thought I'd see that! Thank you for taking the time to file this and submit the PR. It seems like a totally viable solution for your use case, although I'm also thinking about a few other tickets with related use cases (#370, #382). Specifically, they involve using environment variables for more configuration options than just database password.
So, at the risk of increasing scope, what do you think of a more generalized solution that could be used for other options as well? Something like:
... where
MY_DB_USERNAME
andMY_DB_PASSWORD
are arbitrary environment variables that would get interpolated into the option's value. The same approach could be used for the repository encryption passphrase:Open to other ideas for syntax as well.
I'd be happy to take a stab at this. I just wanted to see if it'd solve your use case first. Thanks!
Thanks for your answer @witten
I understand the idea of using this env resolution mecanism for other configuration nodes, I was too focus on my initial need.
One thing I don't like in my first implementation is that I bypass the syntax validation because variables values are not checked by the schema validation.
Without saying that my solution duplicates every key you want to have in environment (
password
andpassword_env
).I just thought of a maybe better solution, more convenient.
Maybe I could try using https://pypi.org/project/envsubst/ first to resolve all variables in config file, on start, before the schema validation so that you are sure the config file is valid and you don't need to change anything else in the code to be able to use env variables for any node?
If you like the idea, I could update my PR with that?
Yeah, I think it makes sense not to bypass schema validation. There's already precedent for applying logical changes to the loaded configuration before validating it, specifically here: https://projects.torsion.org/borgmatic-collective/borgmatic/src/branch/master/borgmatic/config/validate.py#L101
Those lines apply any command-line overrides to configuration and normalize/upgrade any "old" configuration from a prior schema—all before validation is applied. I could see interpolating environment variables around there, too.
As for the actual substitution, there's precedent for that as well! Specifically, some very basic variable interpolation within command hooks: https://projects.torsion.org/borgmatic-collective/borgmatic/src/branch/master/borgmatic/hooks/command.py#L13
That's one reason I was suggesting the
${FOO}
syntax. It's kind of like the existing hook variable interpolation—with the addition of$
to indicate it's an environment variable. ($FOO
syntax is possible too, but I'd worry that'd break on things like passphrases that contain a literal$
character.)As for
envsubst
, that looks like it hasn't seen any updates recently. I wonder if a similar (less featureful) approach like the command hook interpolation above would work here?Anyway, if you're still interested, I'd welcome an updated PR. That should probably include updating/adding tests as well. Thanks for your patience here!
Thanks for your quick answers.
I'll have a look to both source files you pointed.
Envsubst is a common and basic linux cli tool, part or GNU gettext
I had a look to the python project and it does not seem active recently but on the other hand it does only basic things, that may explain it.
I would propose to either
re.sub
logicenvsubst
as an external process, this would only work on linux, idk if borgmatic supports windows, but a runtime error if you use variables andenvsubst
is not available in your OS looks good to me.In addition, I would implement a
--envsubst
(name TBD) to enable the variable resolution so that it does not change the current behavior ?My personal bias is for the
re.sub()
approach, because:envsubst
isn't a built-in on macOS. I'd prefer not to have Linux-only features unless absolutely necessary.envsubst
(at least of the Python library). Just a basic one-for-one substitution IMO would be enough. (Feel free to tell me about use cases I haven't considered though.)Anyway, on the topic of a flag to enable this behavior, that sounds totally reasonable. I could also see it being enabled by default (so, without a flag) if the interpolation syntax doesn't seem too likely to collide with literal values. Like, I could foresee
encryption_passphrase: !@a#$b!@c#$
causing problems. But there's probably nobody withencryption_passphrase: !@a#${b}!@c#$
in their configuration file. Probably. 😄@witten please have a look to the new PR I just submitted,
I hesitated between using
os.path.expandvars
and there.sub
implentation.I prefered the second one because
expandvars
also resolves$FOO
and you mentionned it would be better not to.Also, using
re.sub
allow to implement shell-like default values like${FOO:-bar}
, feature thatos.path.expandvars
does not support.I implemented some basic unit tests, but did not update any documentation.
Thanks
New docs are up! https://torsion.org/borgmatic/docs/how-to/provide-your-passwords/
Please let me know if you see anything in them that's inaccurate or could be improved. Thanks again!
The documentation is very clear.
Just a missing detail, that I also missed in the unit tests ... you can escape an env var with
\
But then I realized that my implementation had an issue, as you noticed I use a negative lookbehind to ignore escaped env vars like
\${FOO}
.But when you escape an env var, you expect the
\
to be removed like in shellSo that is your password is
abc${foo}def
you can escape it in your config fileI tried to fix this in #549
I do not use a negative lookbehind anymore, to be able to catch the escaped env var and then unescape it. I added a unit test for that purpose.
I also added a test with multiple env var in the same string :)
Awesome, good catch! Really appreciate it.
Released in borgmatic 1.6.4!