Managing secrets

Hopefully you don’t subscribe to anything that doesn’t utilise SSL.

The password is in plain text prior to the SSL encryption.
You can’t send a hashed password in SSL or not SSL, the receiving end needs to understand.
And they won’t do that if it’s encrypted before the “agreed” encryption

Yes of course, but it isn’t “sent” in plaintext.

You are right in that ha needs the unencrypted key to feed to ssl.


Can be interesting to have a Vault ( connector integration to manage secret.

So that, just need to push secrets in Vault. When you start HA by example, it request the token (valid for like 10 minutes) or approle credentials in secret mode. In this example, we will see only in config the path of the secret in Vault (like kv/ha/tplink/trololo) (python library can be found here:

Once done, creds are loaded until the next restart (reload) but to check if external component can load also these variables or if it can be like in a jail.

Best regards,


HA needing to be able decrypt secrets.yaml on load is not ideal - but still a big improvement on a plain text file it seems to me.

I posted about potential threats from 3rd party integrations and custom components on the Facebook group page back in early Dec 20. Would be nice to think that post (It generated a lot of interest) is a partial source of this new effort to lock a few sensible things down.
Sandboxing non-curated code from the core makes a lot of sense and certainly improves the general security of HA; there is always more to be done, but this is a great start.

Thanks dev’s for listening (@balloob , @frenck ).

1 Like

That means they would have to build new hashing technique, in a open source project…
You see the issue?

No? OpenSSL is open source - it’s right there in the name - and it secures half the internet, and is good enough for the government, and the banks. There are numerous DPAPI type projects out there. I even referenced one approach that Microsoft took for years.

Not to mention when your password is decrypted it’s still possible to be sniffed.

Yes, but just because a burglar could break a window, doesn’t stop you putting a lock on your front door. I want the config files to be encrypted by default, so that an accidental misconfiguration, or a sync of configuration up to something like github, or even just sharing a config in a forum, doesn’t put the credentials at immediate risk.

Even RSA-240 has been cracked - with enough compute power. Doesn’t mean it’s useless for every day users to protect themselves against.

Zero Trust Architecture has been a thing for more than a decade now - you can run entire clusters with zero-trust networks. There is a better solution out there than dropping passwords in plaintext yaml files. I don’t care which one we choose, so long as we do choose one.



Given the recent security disclosure about unauthenticated directory traversal, this should be a very high priority. If users get bitten by this, it could do serious damage to Home Assistant’s reputation.

Personally, I’ve held off from integrating a lot of services specifically because of concerns about security. For Home Assistant to reach its full potential, it needs a security audit and obvious things like storing plain text credentials need to be fixed.


So I understand that even if the secrets are encrypted on disk that HA is going to need a way to use them unencrypted. But I feel like it’s still a pro if the only way to get decrypted secrets is through HA APIs at runtime instead of having them hanging out unencrypted on disk, right?

For example, what if you could provide an encryption key on a USB drive connected to the host device? Then HA OS could put that key somewhere it has access to but supervisor specifically cannot access. It would then provide that key as a config value to supervisor giving it what it needs to decrypt secrets. But the secrets themselves always remain encrypted at rest, secrets are only available to integrations via APIs that HA carefully manages and controls and no one can get to the encryption key itself from within supervisor. Since supervisor doesn’t let anyone access it’s config value and the file itself is completely inaccessible to anything other then the host OS (which by default provides no mechanism for accessing it directly).

I mean look, I’m not an expert here at all. So absolutely feel free to tell me I’m a naive idiot and dont know what I’m talking about. It just seems like there must be a way. I mean look at node reds handling of credentials which I think seems to work pretty well. Secret value provided via config used to encrypt the credentials on disk with APIs for carefully managed decrypted access only for component developers (and only for the creds they requested in that component).

It depends on the threat model. In any case, to protect everything we only need to keep one secret.

Threat: non-technical wife/kids/friends
Security level: obfuscation
Implementation: hard coded encryption
Caveats: is it worth it?

Threat: Add-On developers stealing your stuff
Security level: general, per-addon encryption
Implementation: each container asks the main container to decrypt secrets
Caveats: need a place to store that one code and keep it safe, like a special file in a container instance. Likely will need to keep two files, one with user password and one with system.

Threat: hackers/government agencies
Security level: per-instance/process implementation
Implementation: Trusted Execution environment processing, RPMB storage, Trusted Execution handles storage.
Caveats: not supported on RPI. RPI does not have a RPMB. No backup on x86, no way to transport by swapping disks.

I think the first thing is to lay out the user stories.
Then we can figure out what’s technically possible
What do we want to get out of encryption? That’s @frenck’s job because what he wants is what is best for the users.


As a senior embedded systems security engineer, I do have a lot of experience in protecting secrets on embedded systems. I’m at your service @frenck.


This is as good as obfuscation when you’ve got access to the machine.

After reading all concerns, I’d suggest a good compromise between extreme lockdown and usability might be a built-in password manager. It would be owned by the ha instance and never show the password in the UI once entered. It would have access granted per-requester based on stack trace. It would not be available outside python Api without an API key for the password manager. Depending on the system, it could utilize platform resources such as RPMB/Trusted Execution Environment, or other. Since owned by HA, it could also be backed up and the backup could be protect via key.

  1. User enters password and assigns key and which addon/platform is being used
  2. Platform request key password or addon/API request key with token
  3. Authorization is verified by token or stack trace (this could be better).
  4. Password is returned

This would protect against posting, addon devs, friends and hackers/government entities depending on the platform.


I like @adamoutler’s suggestion a lot. If implemented and audited, I’d consider using integrations that rely on sensitive credentials. There are so many integrations that I’ve been holding off on, and, for that matter, I’ve been writing a bunch of integrations (e.g. car, home security, etc.) that are now tabled due to this security issue.

Shut up and take my money

1 Like

Admittedly I mostly use secrets as variables for just about anything that gets used in multiple places in my config, like MAC and IP Addresses so that if they change, I can update them in one place without trying to remember everywhere I use that bit of info, more than I use it for passwords… and I’m sure I’m not the only one, cause it works really well for that!
So hopefully if this was followed on with and implemented, it would either allow usage like that as well, or secrets.yaml could be also kept in place (maybe renamed to identify its for not so sensitive info that is used in a lot of places). :crossed_fingers:

But either way, I would love to see something like that implemented :slight_smile:

Had a thought on this today. I noticed the LinuxServer Home Assistant image doesn’t run HA as root but rather as a user in the container. Doing that seems like it could be a solution here. Something like this:

  1. Map a new volume to the home assistant container, call it /etc/secrets for sake of argument
  2. There’s one file in there for now, secrets.yaml
  3. S6 reads in these secrets and provides them as arguments to HA when launching it in run
  4. When reading in the YAML config, HA first looks in the secret store provided via arguments. On fail to find it then looks in /config/secrets.yaml for backwards compatibility
  5. S6 runs HA as a non-root user. This user has no access to /etc/secrets

This solution should work on all 4 installation types although some additional work required for supervisor:

  1. HA Core - User modifies HA launch to include secrets arguments
  2. HA Container - User maps folder to /etc/secrets when launching container
  3. HA OS/Supervised - 2 ways:
    • (Quick way) Allow addons to map /etc/secrets as a volume. Update the Samba/SSH addons with this mapping. Discourage all other addons from using this since it hopefully is a temporary fix in favor of…
    • Add a “secrets” tab in supervisor panel. This UI lets users add and update secret values. The values become masked after entry and can only be replaced, they cannot be seen again (like Github secrets). Supervisor updates /etc/secrets/secrets.yaml with what is entered here. Supervisor and HA share the /etc/secrets volume, no other addon or HA container can.

Note that I’m imagining the file itself remains unencrypted and we rely on user controls to prevent access to it. Encrypting the file is trickier because to Frenck’s point way above, you have to get the encryption key in without letting others see it (hence it can’t be anywhere the root user can see it or you didn’t change anything). And have a solution that supports all 4 installation methods which becomes tricky. This seems like it could work in the meantime?

Of note there would be one downside here. Any change along these lines would mean that updates to secrets would require a restart of HA. HA wouldn’t be able to reload parts of its config with fresh secret values like it does today because it cannot access the secrets file. I feel like that’s an acceptable cost personally but perhaps others think differently.

1 Like

Did you ever get a chance to review the proposals in this thread @frenck?

You’re right in that anyone that has breached the filesystem of the device can realistically crack anything as the project is open source, but there are many reasons that the /config directory of a HA install may end up exposed to the internet, and there’s no reason that the key material securing any encrypted/sensitive values needs to be in that same location.

Any level of security is nothing more than obfuscation to someone with physical access, but this isn’t about physical access, this is about making it easy for end users to protect their credentials instead of storing them in plain text.


Hoping this gets picked up again…someone has this up and running now, via kubernetes. Using Hashicorp Vault to store secrets

1 Like

I am running Home Assistant onto Kubernetes and using SealedSecret from bitnami to securely store secrets.yaml inside my github repo.

kind: SealedSecret
  name: secrets
  namespace: home-automation
    home_city: AgDUbLU7L334basktEdTU5hynRJUhT7u/850mkvKP/EXIgtzpZTwkQCnaFQRQAhFKVwjvlcCqaHxGCVfjg3F2kGivIamRxlDKt2FF8kVQHm1cYuqn708CjOrPOvlUm/Yd+GBNE30T7c5I2YoEizKhLsZjf8zaSNsv9BEscgE/dqRCSDgK9xcurdOK1TY1foxh+1UuWjpg++H4GHnMsuyJsKE2HnyrZ1vcG54l2usRpd7d37rkcmihtywcHs8PSBLqydIjQxRMrYtnTHwtC+ZoxLoqPWjjpBZ0ndNlGcBKpkt2e6ypR0vgCmHO2RE5H3eeAS1PqbWBfTCRsPeCCKiPDLx2IZlCcIdWomBgJ2tk+UzPWRaYKYwt3Iv+3+AB78kIiycPsAQNTpJgs0JWhVjx3kA42eVI71rNAndbVffofs8CYihhQSuK9ZEnna9gKPoDM80HWqQyRX4rgdwwS4xsuil1sWXWF87tn9EMmxh/ox2sBbJWxo3FnTe4z/gBD7k3zzAhOxbPh1noJCRvOBg1N4tJ5fz/8JAkwzF0tkI1AIsnqoiOyBlvA4wzAFrUf+EJFYnArpvj2P2W9sajoTvizIG2scYaLCl5hYdextwzmLki+G9+PPGVoWmHT8x9jGjeuZj4eHMRS4syc9Hx2tkMdPBqq07G6wzdy7cWAPGMUR8zJpUABgWXC01WX2dBbXZSXcUyso=
    home_latitude: AgAXfKHiBS0dIHRoODyLtSaYGwXSw1RfuDeUepGyrI5VaMiboPOo6pOLCspv0ObQMA1rV2N6UZR0IaP0KdFZiWC1dYv18PKchb3KROjpYtoL2MxAlcQ+Ua2MaUUqLM6rwt5Sism5A3g2WO6HqB2PK7DTp3+6XhhzAajcgl/dM1TZCo7fACZGlEMzSSXP0ZnubGjqT4iBoyWAO/jtQ16oyICOWr9VMMAmBbEMTf2ljkRQJRPW18PXSHSUwmV1LucYZxrZyxUrt9qSXLzNedbVd868+T9DOdYFA/1MxPCIt6BaS87rTtCykNYY0jClwNRT8u3TbOrjt9rLcR75Pez6p25SUwkYDMPAoedSQ=
    home_longitude: AgDHcGDimGbOFt4MiFLfRMVcapPaELs5ltNKz4H/KhmppaezkxbhCoCOsSqpXlZ1GN0mofznsfapMdlJxCojOl3D7AL9NgZmE3UFnEje46Lu8LCUdLbHvzXKUY9X/o8yGS7bzNrNIpae8fRuy8o/ccVXwTukTRLpPVUmTIwVnUXqIT0XhYspFfkefjIkjInfuGNjjdjeBHV+rOPDQpw94LMu0/xky2+y/BI63yPvlWkvw7yOidl332mDk3peg42uWvjA==
    home_number: B3QlPHgsTdwsFxA0BmhDwVSPeng/v1rTy+8QeCKdt2p8J2
    home_zipcode: /kfSQX2w4+iOqOh9+bm/qrei+m6PrVJV/C9Oy52Wv3g2RJ19BSAFDtbfsQkDTK8rWwXAmHucPiFzxVwmHKGwkySMF+jtOAW2SYdga+WqZpbYgBKzUKxWVfNDyrXoxDE+wZn7x+2MLReayS20=
    mysql-password: AgApe2KjSZhVniU1L9W1tiISU5p1vx/gn49iScakiCzguKYeGseWhJjFvSqvvgoVoUzfAOYdBzTxiSvEMWeKvzfcStv8ETBS4MH6g7/hopzn86KDXuw8LfQGTOkVj+tBkZjGfXRBacBsZxnPiOM8Sxc/gSFTI1Ah9zbbPM28JrCH0NBP7+2eiwpzfkkjPYZLpYjWZRuIEbj+cPVKFHX/hdzuU/cUEe2J97BkXX9uC7tTk+I5oiTzBC9rHWQRkKdUq27lFTOLke9w3xlygPBbNIZHQaMBoEKD7CPqvCACu1voxPypix/w6oG7E4bBv7KCfJkR9NM38km6VFYvkdEzsZPGdjwZuP/VmdaXdqR5gWUmyzXre+bN3+HDuXCbY9p3uD8dKYdiRxG8V8qyTh3oExLsvNGXVQsxooYOk2t15iTlIY1T+1LXup30GweShoJvv3YNi3l//BxHDHeDY5P2kBU/HhAAGTCZg+x8AM2nhDjd9LJZCLsWUPuD67EewrTNVQaBWK64l0smVxrlglgIrTUcR2bugwWiyOTA+6Yw5mEU/8whbnh7EBYrwlE3ymTtbaOH2Y+1cMwYK3JU9sGo8eIPgsC0DJHgXCJsyzwW34kSwjapbhVqE59FyQZkr3s4pmhKWMafr2FZYwEy0DtQX6wXpjwiMzX31wisPrtiFD0B/sv3enafac9SZ6MV7Q0QuF6bDlxIrlEQ2k/mVtZuhVHiUZdcW/Fn
    mysql-username: AgAu6EdT0IakH5Ns4TiSUI1WaXVzo1BPa+dvw/N+f3WSnr6oNUV/XIA/xkkFYJ8nsVqcelYIX7KqBzIDwVtJZAe9Ts4KocRjAACX+itbuCf90T844GJInxV/Iap7LJPi4XVP2ZFpOy/Ed465X49sSm1E8L+YhxxCHr0XNG9rtTRRFV8Rh+n3lC7rECziZ7u+xfSCBV0XhHl6ZvOEMTiqLdgpsbtyxEclTe/n0jKRQvo+BpqMNwL8MT+52h4WyoPWGcehxzFLcZ82CHPIOZERVl7AGlyo39s16LuwSLRQaSGzkBPh8V4MHXZkKaMQQqOp4UGkxRQm9aYr/7JT3dxogb1RQkB6biw0l7JElVkLysXj8Vmw9qhBAJdnnmY8TIn1WLKb1xnTwBZ3K6UQ6FdN9RMeuJ+/zeQz1JJKoafvWzlWGrZopCfKdwudAaPSbQ0rxuIsP9wFgMsLalJzMyBfy3pA4VE477mPeJTVaTiKNs2toVRyK1gDyL/LzuOSaijixrnJxp+fuTLpzHqLdmsbyFspesB4E88gSqdEAbxaXmHiij1ac0tGwj2jiSRhRM65hpTTGGT/jUtvkdF3SAulPuk9GgUMBxIOk6B/ZAT1P/wOeD13sSVFDi76JWO1uUd0imHo6zQW31qLWtcCVtQJ8aTnlKPYD8NOEoSFltvKcEUMy/orLIpSJJZBDQyTkEMhXYi/8Bv+QJKkeFB0yWoSjw==
    xiaomi_cloud_password: AgAJcv9vZvcmF3dYX/xaHB7WIAyFjvaGjVsVykyvZSVTk+peiCGMPUmEZ9ydNnBvPAB+YZG9x3eyqP0Yn3wOI88Qph0rC3wH++D485kEPesBPsrhcVSVIGlAUQ+oGOk7JUDoq3T3GS0gfP071064yZAp8kH0Mi/UZNC8pKWEScQhBo061Naq+UI8OQY/2yKx4JHDTIWorv/61mObaflxw8v1rnyR1hPyzXmDC0/VM3SoRhTZY+wHLHCl0n/f5QU+tU2+TZaHIbuKYfBEXoJniGnNlI74236aZ4UdnX/PX7p2yF8pox4fic46bn7OhEPpRIhSZVZgoIJcQFhShqMuUMdyoM7N+Hh8bsRxiZL4QSwHJWZTQeXAsngWjnzgC7Gh4s9JJxMnlbZGL2WXKiNzBrD/plpQeOiShQGf2VsF2gUREtpH5ZPwUd+H3JgDz010Xv451PRi3sTzWAcN86ScqNPmYNC6FF8q5bu4+YmxomN9iVBr1Xm0NMIVzHjer/TlZgQca8aSgye+TUtjkoqcW9qhnhXqlEqAR2/HYMhZ384kCv0lN3CVjFQLGV6BCKWkQAJ5R9xHG1ZX0kH+v71why2CIZcJ0dCRayd0RdTvmLVDOgNguR72VWXXmj0rKRNAs+eLgqOa2T7YCGxoEXiLoaRu3HvLwh18HxnSsHSjGLCCAF+UoF0zCLbGWJIQIcEnbFtLLeD3VDOAiuUPoAzkH8ix
    xiaomi_cloud_username: AgAbhK9jR6q/0/v0NnqwMcm8dhUOwbpI5qDXpnSNfAyHEWO9CjOSOKjhMfMjpUc7xMlm/6cjaZiHVWx6DvjbKJXDj78LGYVF+klYVVCB478Z/kdv0bqTaqtzWp87IrPHB6p0KPwtHW3Gqk1pTALR9BDt7pCp5ZWWAAOp6tDLbo+evT7yMY3hpZeB2YR9L0irDr4LXWdSn0Cueb0IPTNF9tzsH9a1kPSxE5huQlOgjLxLqqb8i0Xk7MJe3r2qsXGigSjA2uPn3QrpPfkrPZGqgu19oPO/+3QOc23b92z/mE88v9JProkbK9vQ71aoTUDB9SQ9cKaXruR5jFIXCzJf2Od4O/ER5j6QpA4Ty/roebVurPsizudUQ5J8y3a/IYVBvm2HLg+m6Oisd6rh/SWKjzrJMMFnmxCLAL3Op1TiED2bb+GJAdmZMQBN+3O13PsHjWQvBLRgo+uAtOOP4c1qCp1udRgdzwsisLYHqAjr4gdbqG9H4eR0mU1CBJnHKnweymD702ONhBUwa5Gsji9vQk2/AoYoYj/QZJ1MGTdcZJgl2ZFGp7icrzWqSRW+mhjDJo3eXURSX2yJmzYw+QMpkBxb3FNbW0Kl/FFB4qwfreY+DDH4jZSV+UpLi8Zr5xXj3CFa8l/rK2r3EChYmPvONACuRZrzN13Je9DmjY9fvZYrVgbrPtpttPXPf6+lhDa5DEUp2ajwLqKCVeCRwZwcPGX5
    xiaomi_vacuum_s6_token: AgAcm9eDmKZBcDhP1X0vRxJnKIoc8a8vxfDFHqRgtWKdPukqOl0lgKuaR7fhc3zwc04bGg6FwKgxNWNtqmisoqIKXSI4BCQfu6qkyWNH26pbxDmfPuC9BEKp5oLQgdtld+1RKI8RN/0TFUi9oto2qNK0L3MuYHbSuSeQxwrTb0BrGssqPSvflVHzizaK3mlnDM1uyZnSSbaL4Cnvgpf4ZruO4Ucq2dJUGh8A/fK3NIk+JxedvzBV5bOvKsz3emlFykmqSeP3++lVQU7q8VYEmFQyz3UWNrinMz3FFAdcMFt1xpY50vgJbbiNlb3LMEBPv5Ym8fZlna9LVviNeRXHd5xC0qL7G+mvOXhPoEV4GNxr8P+ltyrSC0jSB/txOKN52ZM/yoGOKWQsecwibmoY5/BaHDjzzXE0LHMjeaWrBTRvGHsFDN/2rdLw4+Y2MOYQc33xJ7F4RHbBotpfP9vS3p76ElFxN3ZE7eGkB5uB58A7rN66OxSNGIImtgqOxAQ+IOYQnrtFT4yCO1IF2oR9ahV6Dr2097z9FRGEv4/uj35LRFL5JD6teWIYApLQaiNM1LeksccAxTxoH3lIr7wox1ZigUHUU/s8Kb8TpHq+ySdtlX9hEkWUboplyVPklq/g5p9L47qPXqAHKLwA06Pe0sBJyig5qqiDy3G7m3FObeHgko3aULEm2fOL7Ha5A7gPzBrHbDX22ASXaA60Oj2IsQxOLUaTeq+1AATJffWcx8XCXA==
      secrets.yaml: |-
        db_url: mysql://{{ index . "mysql-username" }}:{{ index . "mysql-password" }}@home-assistant-mysql.home-automation.svc.cluster.local/home-assistant?charset=utf8mb4
        home_zipcode: {{ index . "home_zipcode" }}
        home_number: {{ index . "home_number" }}
        home_city: {{ index . "home_city" }}
        home_latitude: {{ index . "home_latitude" }}
        home_longitude: {{ index . "home_longitude" }}
        xiaomi_cloud_password: {{ index . "xiaomi_cloud_password" }}
        xiaomi_cloud_username: {{ index . "xiaomi_cloud_username" }}
        xiaomi_vacuum_s6_token: {{ index . "xiaomi_vacuum_s6_token" }}
        proxmox_host: test
        proxmox_username: test
        proxmox_password: test
      labels: home-assistant
      name: secrets
      namespace: home-automation
1 Like

node-red does it very nicely. It uses a root secret which is then used to encrypt all other secrets. It would be nice to have HA use similar concept. The idea is to limit the blast radius in case of breach. While that single secret could be used to decrypt other secrets, it reduces the risk a bit since attacker would have to compromise both the files and security algorithm used.