Let Home Assistant trust a personal certificate authority

Thank you for the suggestion, but krich11 and I are both on HassOS, not Supervised.
For us, the certifi certificate store resets on every reboot and so far I haven’t found out how HassOS handles initialization so that I could run a script on every boot (You can find what I’ve tried in that matter in my last comment before this one).
We also were already appending in pem format to our certifi store, whereby krich11 seems to have got it running, with the problem that a reboot resets the store, and I have properly appended my certificate but wasn’t able to connect to HomeMatic with the verify_ssl option nonetheless.

I verified the success of my appendix with the following script,

import certifi
import requests

try:
        print('Checking connection to RaspberryMatic...')
        requests.get('URL_TO_CCU')
        print('SSL is fine.')
except requests.exceptions.SSLError as err:
        print('SSL Error.')

which printed SSL error before my appendix and SSL is fine afterwards as expected.

1 Like

Was there any further progress being made? I am facing the same issue and created my own Root CA which of course hass.io does not accept. Because of that I can no longer connect to my QNAP NAS, QVR Pro and the Unifi components for presence detection. All use the certificates created with that Root CA which I would need to add to HA.

Does anyone know if a feature request or something exists to maybe create an “official” way to add it permanently to HA?

Thanks!

1 Like

Sadly not, I’m still facing the same issue.
I’m not aware of a feature request and hadn’t thought of one before because I expected some mildly-hacky way to accomplish this, even though certifi states that adding certificates is not supported.

I’m not sure how likely it will be for the request to go through, since it seems to me that the certificate store would need to be changed and that very few people are using their own CAs like us, but I can create a request over the next few days!

I think in this case the official way is the best way to do it. I personally created certificates covering the internal domains within my LAN and the externally reachable ones. So while the external part is no biggie with given plugins like Let’s Encrypt, etc. the challenge is always the internal domains. Since I did not want to use things strictly over the internet when I’m at home, I did not want to go all external.
So perhaps with a feature request we can at least get more information on how it can be done manually if there won’t be any “officially” implemented solution.
Maybe you can post the link to the request here as well for upvoting. :wink:

1 Like

Just posted the feature request!

Let me know if I should edit something in that would be better to have on top than in a separate comment!

Ok, I think I’ve got a workaround for homeassistant OS, but this is more like a workaround than a perm solution given you will lose this every time you install a core upgrade.

  1. Get that USB drive ready with the authorized_keys file described here: https://developers.home-assistant.io/docs/operating-system/debugging/
  2. Login to the :22222 ssh, and type “login” to get the shell
  3. Warg into the home assistant container: docker exec -it homeassistant /bin/bash
  4. Add your certificates to /etc/ssl/certs/ and ultimately to /etc/ssl/certs/ca-certificates.crt

Adding certs follows the same process you get automated by update-ca-certificates many linux distros:

  • Copy the cert into the /etc/ssl/certs directory
  • Get a hash with openssl x509 -hash -noout -in yourcert.pem
  • Symlink the certificate to $hash.0 (for example: fe8a2cd8.0 -> SZAFIR_ROOT_CA2.pem)
  • Add the cert to the end of /etc/ssl/certs/ca-certificates.crt (it is likely that this alone is enough, the rest is future-proofing / past-proofing)
  • Test success with curl https://yoursite.lan

The process of adding this can be automated rather easily, however my homeassisntant based cert-injector automation needs to wait :smiley:

Hope that helps,
mb

3 Likes

Wow, that looks promising, thanks a lot! I’ll definitely give it a try as soon as I find the time!

Presumably it’s even more helpful to kurisutian, since he can’t simply turn off verify_ssl like I can as it seems :sweat_smile:
And luckily, a MITM attack via my RaspberryMatic in my home network is rather unlikely - at least I hope that it is… :smiley:

Cool!

For the automation piece what I have in mind is:

  • sensor to check if https site loads with curl -skIX
  • sensor to check of https site loads with curl -sIX

Should only the last one fail, we need to inject the certs with a shell_command.

And this ideally fixes sensors as well upon the next check. Exceptions would be integrations that kick when initialized and put on an error path when they fail. Worst case: needs a restart.

Yeah, needs some time but nothing significant I imagine.

1 Like

Hi!, i need help on how to copy the CA file into step 4 ? I’m completely loss on where I’m when seeing the homeassistant /bin/bash. I also can not paste/edit via terminal text editor like nano or vim in there. I’m sorry for my silly question. Thanks anyway.

Edit:
Problem solved, how to resolve:

  1. In the /etc/ssl/certs directory: Get .pem certificate file from web using wget. ($ wget https://ca.example.com/ca.cert.pem)
  2. Get hash, and create symbolic link ($ ln -sf pathtoca.cert.pem pathtosymlinkwithhash)
  3. Create backup of ca-certificates.crt: $ cp ca-certificates.crt ca-certificates.crt.backup
  4. Join the certificate: $ cat ca-certificates.crt.backup ca.cert.pem > ca-certificates.crt

Done

2 Likes

Manual updates for this are tedious if you try to stay up-to-date with HA Core. I have a thread with a feature request here.

Discuss and more importantly, vote!

I’ve got some nastyhack proto code here that automates this process.
With the included binary sensor used, it constantly checks for losing trust, and re-injects as appropriate; this basically “smooths” you through core updates.

The important bit is that you’ll need to run this inside Core (homeassistant docker container).

While I’m sure there must be easier ways around this, I’ve chosen to live with this until a proper solution emerges.
Let me know if this works for you.

mb

1 Like

Here my workaround:

Copy your ca files in your favorite directory. For me it is ~/config/my_ssl. Here I can upload my files through the file editor addon.

Connect to the HA core via SSH Addon, copy the files via “docker cp” and update the system ca files via “docker exec”

for f in $(ls ~/config/my_ssl); do docker cp ~/config/my_ssl/$f homeassistant:/usr/local/share/ca-certificates/; done
docker exec -it homeassistant sh -c "update-ca-certificates"

Yes, you have to do this after every core container update :frowning: .

my_ssl contains the ca certificates:

➜  ~ ll ~/config/my_ssl
total 24K
-rw-r--r--    1 root     root        3.5K Feb  5 14:04 Client.CA.crt
-rw-r--r--    1 root     root        3.5K Feb  5 14:04 DMZ.CA.crt
-rw-r--r--    1 root     root        3.5K Feb  5 14:04 Hausautomation.CA.crt
-rw-r--r--    1 root     root        3.5K Feb  5 14:04 Intra.CA.crt
-rw-r--r--    1 root     root        3.5K Feb  5 14:04 Mgmt.CA.crt
-rw-r--r--    1 root     root        3.5K Feb  5 14:03 Root.CA.crt

This this I can use the checkbox “Check TLS connection” in the homematic integration.

1 Like

Here is a “solution” that allow you to survive home assistant upgrade, and to avoid any ssh as long as you already have hacs installed.

I made this today to test if this would solve issue with the fullykiosk integration using https.
It didn’t …

Create a python script available as a service

Install pyscript

https://hacs-pyscript.readthedocs.io/en/latest/installation.html

Enable allow_all_imports

In config/integrations, click on the configure button on the pyscript integration and check Allow All Imports

Import the script

Using what ever method you use to add or change file on your home assistant instance, add the following script in your config folder under pyscript/add_custom_ca.py

# ==================================================================================================
#  python_scripts/add_custom_ca.py
# ==================================================================================================

# --------------------------------------------------------------------------------------------------
# Add the .pem from the provided path to certifi catalogue
# --------------------------------------------------------------------------------------------------
# from https://community.home-assistant.io/t/let-home-assistant-trust-a-personal-certificate-authority/184917/22?u=vaarlion

import certifi
from os import path as os_path


@service
def add_custom_ca(pem_path):
    """yaml
    name: Add Custom ca
    description: Add the .pem from the provided path to certifi catalogue.
    fields:
      pem_path:
        name: Pem file(s) path
        description: a path or a list of path to .pem file
        exemple: ["/ssl/custome_ca.pem", "/config/www/ssl/extra_ca.pem"]
        selector:
          text:
    """

    inputPath = pem_path
    listPath = []
    if inputPath is None:
        log.warning("===== pem_path is required if you want to add something.")
    else:
        if (
            isinstance(inputPath, str)
            and inputPath
            and task.executor(os_path.isfile, inputPath)
        ):
            listPath.append(inputPath)

        elif isinstance(inputPath, list) and inputPath:
            for path in inputPath:
                if isinstance(path, str) and task.executor(os_path.isfile, path):
                    listPath.append(path)
                else:
                    log.info(
                        "===== ignoring '{}' as it's not a path to an existing file".format(
                            path
                        )
                    )
        else:
            log.warning(
                "===== pem_path is required to be a path or a list of path to existing files"
            )

        cafile = certifi.where()

        for pem in listPath:
            __append_fileA_to_fileB(pem, cafile)


@pyscript_executor
def __append_fileA_to_fileB(fileA, fileB):
    with open(fileA, "rb") as infile:
        customca = infile.read()
    with open(fileB, "r") as outfile:
        cachain = outfile.read()
    if customca.decode("utf-8") not in cachain:
        with open(fileB, "ab") as outfile:
            outfile.write(customca)

Then call the service pyscript.reload

Upload your .pem file

Using the same way you’ve uploaded the script, upload your CA certificate in a .pem format where ever you want. I recommend /ssl/. You can add as many as you want.

Automate it

Testing the service

Try to run the service and make sure there is no error in the log.
in developer-tools/service, run something like

service: pyscript.add_custom_ca
data:
  pem_path: /ssl/mycert.pem

or

service: pyscript.add_custom_ca
data:
  pem_path:
    - /ssl/mycert.pem
    - /config/some_other_cert.pem

With your own file obviously.
Now check to see if this solve your issue. It may not as not every automation use that certificate catalogue, and other have some hard-coded port or protocol.

If it does, then we need to have it survive an upgrade.

Create an automation

Now juste make an automation who run that services as soon as home assistant start :slight_smile:

alias: "Add custom cert on boot"
description: ""
trigger:
  - platform: homeassistant
    event: start
condition: []
action:
  - service: pyscript.add_custom_ca
    data:
      pem_path: /ssl/MainCA.pem
mode: single

No worry, the python script make sure the cert isn’t already present before adding it, so you won’t append it 500 time before the next release.

2 Likes

I don’t know if there is another way to do it, but this one works flawlessly. Thank you!!

My only concern is whether the automation will run before or after it tries to load the integration that needs to verify the certificate.
I will have to wait for the next update to check. In any case, the failure would only occur on the first boot after updating.

1 Like

Hello,
I’ve coded a custom integration to add custom private CA (Certificate Authority) to Home Assistant.
The main purpose is to avoid adding again manually CAs even if Docker container si recreated.
Give it a try : GitHub - Athozs/hass-additional-ca: Add custom CA (Certificate Authority) to Home Assistant.

2 Likes

Howdy @frenck, hope you are well.
This is the 6th solution for something HASS was believed to not need. Any chance we can revisit support for self-signed CA support for HA?

:beers:

4 Likes

I have an fairly easy way of doing this and will survive upgrades/restarts, using Docker. The Home Assistant Docker image already has the ca-certificates package installed so it’s just-a-matter of getting your CA cert into /usr/local/share/ca-certificates/ and running update-ca-certificates. To automate this, I simply mount the following script into /etc/cont-init.d:

#!/bin/sh -e
cp /config/ssl/ca.crt /usr/local/share/ca-certificates/
update-ca-certificates

NOTE: this assumes your CA cert is mounted at /config/ssl/ca.crt. Adjust according to your environment.

My setup looks something like this:
docker-compose.yaml:

services:
  homeassistant:
    # this section redacted
    volumes:
      - /opt/hassio/data/config:/config
      - /opt/hassio/data/ssl:/config/ssl
      - /opt/hassio/data/init:/etc/cont-init.d

My ca.crt (private root CA) is located in /opt/hassio/data/ssl/ca.crt.

My S6 init script:
/opt/hassio/data/init/01_install_ca:

#!/bin/sh -e
cp /config/ssl/ca.crt /usr/local/share/ca-certificates/
update-ca-certificates

Now when you startup the container, you should see the following in you log output:

[cont-init.d] executing container initialization scripts...
[cont-init.d] 01_install_ca: executing... 
WARNING: ca-certificates.crt does not contain exactly one certificate or CRL: skipping
[cont-init.d] 01_install_ca: exited 0.
[cont-init.d] done.
1 Like

It’s unfortunate this add-on is necessary, but thanks so much for writing it! I’m attempting to use it with smtp notify, but it doesn’t seem to use my CA certs, even though they are being installed in ca-certificates.crt by the add-on. openssl s_client successfully verifies my signed cert from within the homeassistant docker container. I think it’s not working because homeassistant.util.ssl client_context() depends on REQUESTS_CA_BUNDLE. Where does this environment variable need to be set when running haos?

Hey,
I could not find on the internet a reliable way to set permanently an environment variable in Home Assistant OS (some kind of hack may be possible I guess though).

Yes, I’ve asked on here and in a few different channels on the ha discord and no one seems to know how to set environment variables when using haos. I’m starting to think it might not be possible, and that my only option would be to redeploy and run on docker containers w/o supervisor or haos. This would be more overhead to manage, and kind of a pain to be honest, but I would then be able to pass environment variables via docker compose. Sure wish there was a better way. Thanks again.