Even though this is a bit off-topic, I don’t think my brainfart deserves a dedicated thread. So here’s my though / idea on how this could be approached. A quick note before I start: I was just about to implement Vault in a similar fashion to the credstash / AWS keystore stuff, but then saw those options to be deprecated. So I cancelled that.
For simplicity I’ll imagine Vault being the default storage for secrets in HA. Here secrets can be accessed by providing a token for authentication + a path. Of course this could be replaced by something internal.
The main problem is (as you already know), that for automatic startup the token to access the secrets needs to be available to HA. By storing it in a file the HA-process can read, an attacker could be able access it in case HA got compromised.
To circumvent this, the token (stored in a file with only root access) could be passed as an environment variable while starting HA. The HA process itself is started as a different user with less privileges, and thereby preventing access to the token-file. During startup HA would fetch the required secrets from Vault (or decrypt them from a custom secrets-storage), and then clear / overwrite the environment-variable once that is done. This way the compromised HA process wouldn’t know the secret anymore, and because the secrets are stored externally (or encrypted), they can’t be accessed (apart from maybe being somewhere in the memory).
The remaining problem in this case would be an integration that’s set up via UI (or something that doesn’t require a restart of HA). After all HA would have to write the secret into the secrets-storage, but it can’t as it’s lacking the required token now. But: it’s UI. So in such a case the user could be queried to provide the token while setting up the integration. Then once HA wrote the secret, it will be forgotten again.
So in pythonic pseudo-code:
$ SECRET_TOKEN="s3cr3t" python3
import os, secretengine
secrets = secretengine.load(os.environ.get('SECERT_TOKEN'))
os.environ['SECRET_TOKEN'] = ''
os.setuid(123)
# Configure integration via UI
secrets.append(app_secret)
secretengine.write(secrets, token_from_ui)
I haven’t put enough thought into this to see the design-flaw in my solution myself (if there is one). At this state it’s really not more than a brainfart. But it might inspire someone to find a solution that’s actually secure.
I don’t know enough about the core to judge if this will fail for other reasons. In my mind this would rely on systemd (which has root privileges) to read the token from disk, pass it via the environment, and start the HA process with the dedicated user. I’m a core User, so that’s why it could work this way. Things could look different though on other installation flavours (which probably won’t have systemd).
Anyways, I just wanted to share this. Maybe it’ll inspire someone to dig deeper and find a solution that provides at least more security for secrets than just having them on the filesystem.