Securely load ntfy access token or password #966
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 managed to get my borgmatic config working with systemd credentials for the borg repository password, but I'm not finding a way to securely load the ntfy access token or password for the ntfy hook. I'd like to avoid storing it in plain text in the config file, and instead load it securely.
Steps to reproduce
No response
Actual behavior
No response
Expected behavior
No response
Other notes / implementation ideas
No response
borgmatic version
No response
borgmatic installation method
No response
Borg version
No response
Python version
No response
Database version (if applicable)
No response
Operating system and version
No response
Yeah, as you've probably seen, the way that systemd credentials get to Borg in the docs is via Borg running a "passcommand" ... which doesn't exist for ntfy.
I haven't tried it, but have you considered something like the following for the ntfy use case?
Interesting idea, unfortunately, I couldn't get it to work. After wrestling with getting multiple
systemd-creds
to actually work, it doesn't seem that it's able to find the file to include it properly:from attempting to include it like:
Well, I find that if I instead try:
It actually works. That path is where the decrypted content seems to get mounted, and so the include is able to resolve if you don't depend on environment variable interpolation.
That being said, that feels real bad, and you lose your ability to validate your config file, because that path is only legitimate when the systemd job is running.
Ah, unfortunately it looks like environment variable interpolation is currently done after configuration includes are applied—which means you can't use environment variables within include paths. So that would somehow have to change in order to support this particular solution to your use case.
Interesting! Yeah, it makes sense given the sequencing mentioned above about environment variable interpolation and includes. I agree that it would be better for that path not to be hard-coded. Although it seems like the config file would only work under systemd, regardless of whether an environment variable is used there, and I'm not sure of a way around that.. Maybe a concept other than
!include
that's like include but doesn't get resolved at the point that the configuration file is loaded, but instead gets resolved later on closer to the time it's consumed (by ntfy in this case), similar to Borg's passcommand? I'm not sure exactly how that would work in practice, but I'm open to ideas.Okay, a little brainstorming on how this might look:
Despite the syntax, the
!load_credential
tag would have to be ignored by the configuration loading machinery, so it didn't trigger when configuration files are loaded. Presumably environment variable interpolation would occur just fine afterwards, filling out that credentials directory path. And then within the ntfy hook (and any other hook accepting a credential), the hook could check the credential value for whether it started with!load_credential
and if so, load the credential from file similar to Borg's passcommand.Oh yeah, this is quite true. It's implicitly relying on the fact that, in my specific case, I'm trying to run borgmatic as a systemd service. Totally not a portable solution.
Yeah, that's kind of what I was imagining. I think relying on
!include
feels like it works accidentally and is brittle and subject to accidentally breaking, rather than an intentional configuration option.In mulling this over, how might this work with other non-systemd credential providers? I had a thought that perhaps the config file might let you select a credential provider, perhaps like:
Or perhaps pass, or env vars, or other solutions for retrieving credentials. Based on that, borgmatic would understand the standard way to pull credentials for that solution. Then, maybe the syntax could get cleaned up to something like:
Since, in this case, it understands the expectations around that pathing. I'm definitely out of my zone of experience on this, I was just thinking of ways to address the need without necessarily over-fitting to my specific situation.
As I was working further on my configuration, I found an alternative, sparked from the insight you brought to my attention about
!include
.In order to store my configuration in Git, I moved everything over (system timer, service and borgmatic config) to it's own project repo. I created a file
ntfy_access_token.yaml
, put the access token inside it, and locked it down withchmod 400 ntfy_access_token.yaml
. From there, I set my.gitignore
file to include that specific file, and myconfig.yaml
gets updated to use:After setting up my systemd service with this from within my project repo:
Borgmatic is able to properly locate and pull in the include, and I can commit my config to Git without worrying about publishing secrets.
I suppose I could even
sudo chown root:root ntfy_access_code.yaml
to lock it down even further. It's not encrypted on disk, but it's about the best I can come up with at the moment.I like the idea of borgmatic understanding how to pull credentials for particular credentials providers, but I'm not sure the provider selection should be global for the whole config file. A user might have multiple credentials providers. So how about a variant like this?
Or even:
Thoughts?
I'm glad you have a working alternative for the time being!
That's a good point. There's no good reason to restrict all credentials to be from the same provider.
Of the two, I think I personally prefer
just a bit better. I think it flows a bit better as you read the config, but that's super subjective.
Makes sense!
I added a note to #961 about some potential implementation detail crossover between these respective tickets.
This is now implemented in main and will be part of the next release! Updated documentation will be online shortly. In terms of the syntax, I ended up going with
!credential systemd credentialname
for brevity. And loading of the credential is delayed as long as possible, so for instance if you use!credential
for an Ntfy password, you should still be able to runborgmatic config validate
or evenborgmatic list
outside of systemd. Really, anything that doesn't try to hit Ntfy and therefore need to load the credential.Feedback welcome!
Reopening this. I'm having second thoughts about the syntax, and I want to investigate an alternative before I commit one way or the other, as it's much harder to change it once it's released.
I'm thinking maybe something like this:
My rationale is that it's more in line with the existing constants syntax, and feels less like a weird one off. Plus, semantically this is like plugging in a "constant" that happens to be a credential. The
!credential
syntax is more similar to YAML includes, but this isn't a YAML tag even if it looks like one; it's evaluated as late as possible, whereas YAML tags are evaluated early—at the time the configuration file is parsed.I dunno, maybe I'm overthinking/overcooking this. But I thought it's worth at least investigating.
Okay, I did end up going with the
{credential ...}
syntax for consistency with constants (and also environment variables). Docs will be updated soon.Released in borgmatic 1.9.10!