appdaemon icon indicating copy to clipboard operation
appdaemon copied to clipboard

cert_path config does not effect anything

Open groldo opened this issue 4 years ago • 6 comments

Dear devs,

there seems to be a bug with the cert_path config parameter as it does not effect the way a tls connection is made to hass. Im using docker-compose to setup appdaemon on raspberry pi 4.

version: '3'

networks:
  proxy_network:
    external:
      name: proxy-network

services:
  appdaemon:
    image: acockburn/appdaemon:latest
    container_name: "appdaemon"
    build: 
      context: "https://github.com/AppDaemon/appdaemon.git"
    volumes:
      - "/home/someuser/appdaemon-docker/data:/conf"
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
      - /usr/local/share/ca-certificates/ca.crt:/certs/ca.crt
    networks:
      - default
      - proxy_network
        #command: -D DEBUG

and an appdaemon config like this

appdaemon:
  latitude: some_lat
  longitude: some_long
  elevation: some_elev
  time_zone: some_tz
  logfile: STDOUT
  errorfile: STDOUT
  logsize: 100000
  log_generations: 3
  exclude_dirs:
    - .git
  plugins:
    HASS:
      type: hass
      ha_url: "https://some_domain"
      token: "some_token"
      app_dir: /conf/apps
      cert_path: /certs/ca.crt
      cert_verify: True
http:
  url: some_url
api:
hadashboard:
  dash_url: some_url  
  dashboard_dir: /conf/dashboards

i'm getting this error message in short

appdaemon    | 2021-06-24 10:37:39.799537 INFO HASS: Connected to Home Assistant 2021.2.3
appdaemon    | 2021-06-24 10:37:39.945270 WARNING HASS: Error getting metadata - retrying
appdaemon    | 2021-06-24 10:37:39.945973 WARNING HASS: Disconnected from Home Assistant, retrying in 5 seconds

and this one in debug

appdaemon    | 2021-06-24 10:20:52.731829 WARNING HASS: Error getting metadata - retrying
appdaemon    | 2021-06-24 10:20:52.732655 DEBUG AppDaemon: Clearing callbacks for HASS
appdaemon    | 2021-06-24 10:20:52.734074 WARNING HASS: Disconnected from Home Assistant, retrying in 5 seconds
appdaemon    | 2021-06-24 10:20:52.736256 DEBUG HASS: ------------------------------------------------------------
appdaemon    | 2021-06-24 10:20:52.736568 DEBUG HASS: Unexpected error:
appdaemon    | 2021-06-24 10:20:52.736851 DEBUG HASS: ------------------------------------------------------------
appdaemon    | 2021-06-24 10:20:52.739331 DEBUG HASS: Traceback (most recent call last):
appdaemon    |   File "/usr/local/lib/python3.8/site-packages/aiohttp/connector.py", line 969, in _wrap_create_connection
appdaemon    |     return await self._loop.create_connection(*args, **kwargs)  # type: ignore  # noqa
appdaemon    |   File "/usr/local/lib/python3.8/asyncio/base_events.py", line 1050, in create_connection
appdaemon    |     transport, protocol = await self._create_connection_transport(
appdaemon    |   File "/usr/local/lib/python3.8/asyncio/base_events.py", line 1080, in _create_connection_transport
appdaemon    |     await waiter
appdaemon    |   File "/usr/local/lib/python3.8/asyncio/sslproto.py", line 529, in data_received
appdaemon    |     ssldata, appdata = self._sslpipe.feed_ssldata(data)
appdaemon    |   File "/usr/local/lib/python3.8/asyncio/sslproto.py", line 189, in feed_ssldata
appdaemon    |     self._sslobj.do_handshake()
appdaemon    |   File "/usr/local/lib/python3.8/ssl.py", line 944, in do_handshake
appdaemon    |     self._sslobj.do_handshake()
appdaemon    | ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1125)
appdaemon    | 
appdaemon    | The above exception was the direct cause of the following exception:
appdaemon    | 
appdaemon    | Traceback (most recent call last):
appdaemon    |   File "/usr/local/lib/python3.8/site-packages/appdaemon/plugins/hass/hassplugin.py", line 336, in get_updates
appdaemon    |     self.metadata = await self.get_hass_config()
appdaemon    |   File "/usr/local/lib/python3.8/site-packages/appdaemon/plugins/hass/hassplugin.py", line 710, in get_hass_config
appdaemon    |     r = await self.session.get(api_url, headers=headers, verify_ssl=self.cert_verify)
appdaemon    |   File "/usr/local/lib/python3.8/site-packages/aiohttp/client.py", line 520, in _request
appdaemon    |     conn = await self._connector.connect(
appdaemon    |   File "/usr/local/lib/python3.8/site-packages/aiohttp/connector.py", line 535, in connect
appdaemon    |     proto = await self._create_connection(req, traces, timeout)
appdaemon    |   File "/usr/local/lib/python3.8/site-packages/aiohttp/connector.py", line 892, in _create_connection
appdaemon    |     _, proto = await self._create_direct_connection(req, traces, timeout)
appdaemon    |   File "/usr/local/lib/python3.8/site-packages/aiohttp/connector.py", line 1051, in _create_direct_connection
appdaemon    |     raise last_exc
appdaemon    |   File "/usr/local/lib/python3.8/site-packages/aiohttp/connector.py", line 1020, in _create_direct_connection
appdaemon    |     transp, proto = await self._wrap_create_connection(
appdaemon    |   File "/usr/local/lib/python3.8/site-packages/aiohttp/connector.py", line 971, in _wrap_create_connection
appdaemon    |     raise ClientConnectorCertificateError(req.connection_key, exc) from exc
appdaemon    | aiohttp.client_exceptions.ClientConnectorCertificateError: Cannot connect to host some_host:443 ssl:True [SSLCertVerificationError: (1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1125)')]
appdaemon    | 
appdaemon    | 2021-06-24 10:20:52.741320 DEBUG HASS: ------------------------------------------------------------

which does come from here: https://github.com/AppDaemon/appdaemon/blob/aaabc65ca62b9f7c09a6fa42029ec20648a825aa/appdaemon/plugins/hass/hassplugin.py#L691 it seems that there is a connection for a short period and is then closed.

with cert_verify: False everything runs smooth. but that wasn't my goal. so i came up with a workaround which does fix this: when manually installed inside the container the certificate runs perfectly well.

/usr/src/app # cp /certs/ca.crt /etc/ssl/certs/
/usr/src/app # cat /etc/ssl/certs/ca.crt >> /etc/ssl/certs/ca-certificates.crt
docker-compose restart

obviously i can now remove cert_path: /certs/ca.crt and it does run also.

so I don't get what cert_path: /certs/ca.crt is actually doing.

ftr: there is also a bug in the python:3.8-alpine image which the dev branch is using. https://github.com/gliderlabs/docker-alpine/issues/30 which made that i couldn't use update-ca-certificate

ftr2:

/usr/src/app # appdaemon --version
appdaemon 4.0.8

groldo avatar Jun 24 '21 09:06 groldo

as far as i see it it has to do with paths. with /certs/ca.crt you give a path that doesnt exist because certs isnt a root path. and it isnt a relative path. so my guess is that you need to make /usr/local/share/ca-certificates/ca.crt: known and use certs/ca.crt or use /usr/local/share/ca-certificates/ca.crt:/certs/ca.crt

ReneTode avatar Jun 26 '21 01:06 ReneTode

/certs/ca.crtdoes exist. it gets host mounted by docker-compose. And the '/certs' path actually comes from here. Before this I a had set it up to /usr/local/share/ca-certificates/ca.crt.

Additionally appdaemon does load the certificate correctly:

appdaemon    | 2021-06-26 09:13:01.509729 INFO HASS: Connected to Home Assistant 2021.2.3
appdaemon    | 2021-06-26 09:13:01.582142 WARNING AppDaemon: App 'ok' missing 'class' or 'module' entry - ignoring
appdaemon    | 2021-06-26 09:13:01.583114 WARNING AppDaemon: App 'not_found' missing 'class' or 'module' entry - ignoring
some apps are getting added 
appdaemon    | 2021-06-26 09:13:01.619651 INFO AppDaemon: Found 11 total apps
appdaemon    | 2021-06-26 09:13:01.621145 INFO AppDaemon: Starting Apps with 11 workers and 11 pins
appdaemon    | 2021-06-26 09:13:01.628163 INFO AppDaemon: Running on port 5050
appdaemon    | 2021-06-26 09:13:01.728356 WARNING HASS: Error getting metadata - retrying
appdaemon    | 2021-06-26 09:13:01.729442 WARNING HASS: Disconnected from Home Assistant, retrying in 5 seconds
appdaemon    | 2021-06-26 09:13:06.884661 INFO HASS: Connected to Home Assistant 2021.2.3
appdaemon    | 2021-06-26 09:13:07.032627 WARNING HASS: Error getting metadata - retrying
appdaemon    | 2021-06-26 09:13:07.033572 WARNING HASS: Disconnected from Home Assistant, retrying in 5 seconds
appdaemon    | 2021-06-26 09:13:12.175503 INFO HASS: Connected to Home Assistant 2021.2.3

Obviously appdaemon can connect to home assistant via websockets which comes from here otherwise there wouldn't be that Connected to Home... line.

So there might be a problem with the aiohttp module (see log from first post) which isn't make use of cert_path and therefore doesn't load self-signed certificates, if they are not properly set up. As in setted up with update-ca-certificate.

So my guess is when cert_path is set. There must be some magic which puts the certificate from cert_path into the /etc/ssl/certs certificate storage. Because when afterwards loaded with the quickfix from my first post everything is fine.

groldo avatar Jun 26 '21 07:06 groldo

This said the issue topic might be a bit catchy, as it does effect the websockets connection. But I will leave it as it is.

groldo avatar Jun 26 '21 07:06 groldo

in the link you give it says:

If your Home Assistant is running with self-signed certificates, you will want to point to the location of the certificate files as part of the container creation process. Add -v <your_cert_path>:/certs to the docker run command line

but in what you provide i dont see that anywhere.

i see:

    volumes:
      - "/home/someuser/appdaemon-docker/data:/conf"
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
      - /usr/local/share/ca-certificates/ca.crt:/certs/ca.crt

but that doesnt create the /certs

there are a lot of people using certs, and if that setting wasnt working, noone would be able to connect to HA with certs.

ReneTode avatar Jun 26 '21 13:06 ReneTode

docker-compose creates the path on startup and mounts the file to that exact path. So I can assure you the certificate is present and valid.

# docker-compose exec appdaemon /bin/sh
/usr/src/app # ls -lah /certs/
total 12K    
drwxr-xr-x    2 root     root        4.0K Jun 26 09:11 .
drwxr-xr-x    1 root     root        4.0K Jun 26 09:11 ..
-rw-r--r--    1 root     root        1.8K Jun 11 22:38 ca.crt

If it wouldn't be present, the log from above wouldn't state:

appdaemon    | aiohttp.client_exceptions.ClientConnectorCertificateError: Cannot connect to host some_host:443 ssl:True [SSLCertVerificationError: (1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1125)')]

It would say something like "file not found".

groldo avatar Jun 28 '21 17:06 groldo

i dont know if it matters, but i believe the file you showed:

version: '3'

networks:
  proxy_network:
    external:
      name: proxy-network

services:
  appdaemon:
    image: acockburn/appdaemon:latest
    container_name: "appdaemon"
    build: 
      context: "https://github.com/AppDaemon/appdaemon.git"
    volumes:
      - "/home/someuser/appdaemon-docker/data:/conf"
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
      - /usr/local/share/ca-certificates/ca.crt:/certs/ca.crt
    networks:
      - default
      - proxy_network
        #command: -D DEBUG

is yaml and in the volumes you got : which yaml really doesnt like. so i would at least put the volumes in quotes.

my experience with this isnt enough to see other reasons why it isnt working for you, while it works for others. maybe that @Odianosen25 sees it.

ReneTode avatar Jun 28 '21 18:06 ReneTode