diff --git a/README.md b/README.md index 33582e5..b77ae48 100644 --- a/README.md +++ b/README.md @@ -9,15 +9,16 @@ It supports the following environment variables: - `AMCREST_PORT` (optional, default = 80) - `AMCREST_USERNAME` (optional, default = admin) - `AMCREST_PASSWORD` (required) -- `MQTT_USERNAME` (required) +- `MQTT_USERNAME` (required, unless using TLS client authentication) - `MQTT_PASSWORD` (optional, default = empty password) - `MQTT_HOST` (optional, default = 'localhost') - `MQTT_QOS` (optional, default = 0) - `MQTT_PORT` (optional, default = 1883) -- `MQTT_TLS_ENABLED` (required if using TLS) - set to `true` to enable -- `MQTT_TLS_CA_CERT` (required if using TLS) - path to the ca certs -- `MQTT_TLS_CERT` (required if using TLS) - path to the private cert -- `MQTT_TLS_KEY` (required if using TLS) - path to the private key +- `MQTT_TLS_ENABLED` (optional, default = false) - set to `true` to enable TLS server authentication +- `MQTT_TLS_INSECURE` (optional, default = false) - disables TLS certificate verification - use with caution! Consider using `MQTT_TLS_CA_CERT` instead. +- `MQTT_TLS_CA_CERT` (required if using TLS, unless `MQTT_TLS_INSECURE` is set) - path to the trusted CA certificate file +- `MQTT_TLS_CERT` (required if using TLS client authentication) - path to the client's certificate file +- `MQTT_TLS_KEY` (required if using TLS client authentication) - path to the client's private key file - `HOME_ASSISTANT` (optional, default = false) - `HOME_ASSISTANT_PREFIX` (optional, default = 'homeassistant') - `STORAGE_POLL_INTERVAL` (optional, default = 3600) - how often to fetch storage data (in seconds) (set to 0 to disable functionality) diff --git a/VERSION b/VERSION index d941c12..e92964f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.16 \ No newline at end of file +1.0.17 \ No newline at end of file diff --git a/src/amcrest2mqtt.py b/src/amcrest2mqtt.py index 31054dd..18e7c9c 100644 --- a/src/amcrest2mqtt.py +++ b/src/amcrest2mqtt.py @@ -28,6 +28,7 @@ mqtt_port = int(os.getenv("MQTT_PORT") or 1883) mqtt_username = os.getenv("MQTT_USERNAME") mqtt_password = os.getenv("MQTT_PASSWORD") # can be None mqtt_tls_enabled = os.getenv("MQTT_TLS_ENABLED") == "true" +mqtt_tls_insecure = os.getenv("MQTT_TLS_INSECURE") == "true" mqtt_tls_ca_cert = os.getenv("MQTT_TLS_CA_CERT") mqtt_tls_cert = os.getenv("MQTT_TLS_CERT") mqtt_tls_key = os.getenv("MQTT_TLS_KEY") @@ -123,9 +124,46 @@ if amcrest_password is None: log("Please set the AMCREST_PASSWORD environment variable", level="ERROR") sys.exit(1) -if mqtt_username is None: - log("Please set the MQTT_USERNAME environment variable", level="ERROR") - sys.exit(1) +if mqtt_tls_enabled: + # TLS will be enabled + if not mqtt_tls_insecure: + # TLS verification will be enforced + if mqtt_tls_ca_cert is None: + # No TLS CA certificate was given + log("Missing var: MQTT_TLS_CA_CERT", level="ERROR") + sys.exit(1) + elif not os.path.exists(mqtt_tls_ca_cert) or not os.path.isfile(mqtt_tls_ca_cert): + # Provided TLS CA certificate not found + log("Missing file: MQTT_TLS_CA_CERT file {} not found".format(mqtt_tls_ca_cert), level="ERROR") + sys.exit(1) + + # For TLS, MQTT accepts either TLS client auth or username auth. + if bool(mqtt_tls_cert) != bool(mqtt_tls_key): + # One TLS client auth variable was given, but not the other + if mqtt_tls_cert is None: + log("Missing var: MQTT_TLS_CERT", level="ERROR") + sys.exit(1) + if mqtt_tls_key is None: + log("Missing var: MQTT_TLS_KEY", level="ERROR") + sys.exit(1) + elif mqtt_tls_cert is not None and mqtt_tls_key is not None: + # Both TLS client auth variables were given + if not os.path.exists(mqtt_tls_cert) or not os.path.isfile(mqtt_tls_cert): + log("Missing file: MQTT_TLS_CERT file {} not found".format(mqtt_tls_cert), level="ERROR") + sys.exit(1) + if not os.path.exists(mqtt_tls_key) or not os.path.isfile(mqtt_tls_key): + log("Missing file: MQTT_TLS_KEY file {} not found".format(mqtt_tls_key), level="ERROR") + sys.exit(1) + else: + # No TLS client auth variables were given, so username auth is required + if mqtt_username is None: + log("Missing var: MQTT_USERNAME", level="ERROR") + sys.exit(1) +else: + # TLS not enabled, so only option is username auth. + if mqtt_username is None: + log("Missing var: MQTT_USERNAME", level="ERROR") + sys.exit(1) version = read_version() @@ -212,25 +250,22 @@ mqtt_client = mqtt.Client( ) mqtt_client.on_disconnect = on_mqtt_disconnect mqtt_client.will_set(topics["status"], payload="offline", qos=mqtt_qos, retain=True) + if mqtt_tls_enabled: log(f"Setting up MQTT for TLS") - if mqtt_tls_ca_cert is None: - log("Missing var: MQTT_TLS_CA_CERT", level="ERROR") - sys.exit(1) - if mqtt_tls_cert is None: - log("Missing var: MQTT_TLS_CERT", level="ERROR") - sys.exit(1) - if mqtt_tls_cert is None: - log("Missing var: MQTT_TLS_KEY", level="ERROR") - sys.exit(1) mqtt_client.tls_set( ca_certs=mqtt_tls_ca_cert, certfile=mqtt_tls_cert, keyfile=mqtt_tls_key, - cert_reqs=ssl.CERT_REQUIRED, + cert_reqs=ssl.CERT_NONE if mqtt_tls_insecure else ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLS, ) -else: + if mqtt_tls_insecure: + log("MQTT TLS verification disabled - this is very insecure! Consider setting MQTT_TLS_CA_CERT instead.", level="WARN") + mqtt_client.tls_insecure_set(mqtt_tls_insecure) + +# Need to pass username and password if not using TLS client authentication +if not mqtt_tls_enabled or (mqtt_tls_cert is None and mqtt_tls_key is None): mqtt_client.username_pw_set(mqtt_username, password=mqtt_password) try: