Exposing Home Assistant in a secure-way

Series

This post is part of a series, other related posts are:

Abstract

Before putting Home Assistant accessible from Internet, the entire OS must be hardened and secured to avoid unpleasant problems.

DynDNS

First we need to bind a static domain name (DNS) to the Home Assistant server. The domain name must be the same for both external (Internet) and internal (LAN) connections. Otherwise Android/iOS apps must be reconfigured every time.

I suggest FreeDNS, it’s free and supported by Linux. Register and create a subdomain, for example example.mooo.com:

  • Type: A
  • Subdomain: example
  • Domain: mooo.com

Update DynDNS

Once the domain name it’s created, it must be regularly checked and updated. Suppose your Internet connection renegotiate a different public IP address: the DNS must be updated.

# apt-get install ddclient

Edit the configuration file /etc/ddclient.conf:

daemon=5m
pid=/var/run/ddclient.pid
syslog=yes
timeout=10
vervose=no

protocol=freedns
use=web, web=myip.dnsomatic.com
ssl=yes
server=freedns.afraid.org
login=myusername
password='my long password'
example.mooo.com

You can check also my updated ddclient.conf file.

Pay attention and set your login, password and domain name used during FreeDNS configuration. Restart the service:

# systemctl ddclient restart

DDclient will check the public IP address every 5 minutes, and it will update FreeDNS on every change. DDclient logs via Syslog using daemon facility (/var/log/daemon.log on Debian), but remember to set verbose=yes for additional logs.

Installing and configuring an additional webserver

An additional webserver will be used to expose Home Assistant and manage external connections:

# apt-get -y install apache2

Now create a couple of certificates (only non default values are provided):

# openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/ssl/private/apache-default.key -out /etc/ssl/certs/apache-default.crt
Country Name (2 letter code) [AU]:IT
State or Province Name (full name) [Some-State]:Italy
Organization Name (eg, company) [Internet Widgits Pty Ltd]:RR Labs
# openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/ssl/private/apache-homeassistant.key -out /etc/ssl/certs/apache-homeassistant.crt
Country Name (2 letter code) [AU]:IT
State or Province Name (full name) [Some-State]:Italy
Organization Name (eg, company) [Internet Widgits Pty Ltd]:RR Labs
Common Name (e.g. server FQDN or YOUR name) []:example.mooo.com

To avoid certificate error on app or browser, I suggest to install the apache-homeassistant.crt on your mobile Phones:

  • Android: Settings -> Security -> Certificates -> install the certificate
  • iOS: send the certificate via eMail and install it

Now create the default site host /etc/apache2/sites-available/000-default.conf:

<Directory /var/www/html>
    Options none
    AllowOverride None
    Order allow,deny
    Deny from all
</Directory>
 
<VirtualHost _default_:80>
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html
	 
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
 LogLevel error
</VirtualHost>
 
<VirtualHost _default_:443>
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html
	 
    ErrorLog ${APACHE_LOG_DIR}/ssl_error.log
    CustomLog ${APACHE_LOG_DIR}/ssl_access.log combined
    LogLevel error
 
    SSLEngine On
    SSLCertificateKeyFile /etc/ssl/private/apache-default.key
    SSLCertificateFile /etc/ssl/certs/apache-default.crt
</VirtualHost>

The above site will deny every requests done using the IP address (tipically intrusions). The following site will serve requests done using the real domain name (configured in the DDclient section) redirecting them to the Home Assistant server. Create the following configuration file (/etc/apache2/sites-available/001-homeassistant.conf):

<VirtualHost *:443>
    ServerAdmin andrea.dainese@gmail.com
    ServerName example.mooo.com
    ProxyPass / http://127.0.0.1:8123/
    ProxyPassReverse / http://127.0.0.1:8123/
 
    ErrorLog ${APACHE_LOG_DIR}/homeassistant-ssl_error.log
    CustomLog ${APACHE_LOG_DIR}/homeassistant-ssl_access.log combined
    LogLevel error
 
    SSLEngine On
    SSLCertificateKeyFile /etc/ssl/private/apache-homeassistant.key
    SSLCertificateFile /etc/ssl/certs/apache-homeassistant.crt
	 
	<Location />
        AuthName "Private Realm"
        AuthType Basic
        AuthBasicProvider file
        AuthUserFile /etc/apache2/htaccess-hass
        Require valid-user
	</Location>
</VirtualHost>

Check also my updated Apache configuration files:

Now let’s configure the password access:

# htpasswd -cb /etc/apache2/htaccess-hass homeassistantuser homeassistantpassword

Additional users can be created with the following command:

# htpasswd -b /etc/apache2/htaccess-hass additionaluser additionalpassword

Users can be deleted with the following command:

# htpasswd -D /etc/apache2/htaccess-hass additionaluser

Finally enable modules and configured sites only:

# a2enmod ssl
# a2enmod proxy_http
# rm -f /etc/apache2/sites-enabled/*
# a2ensite 000-default.conf
# a2ensite 001-homeassistant.conf
# a2disconf other-vhosts-access-log
# a2disconf serve-cgi-bin
# systemctl restart apache2

OpenSSH

Secure OpenSSH is beyond the scope of this document, but because it’s useful, the following is my suggested configuration:

PermitRootLogin no
PasswordAuthentication no
UseDNS no

Check also my updated sshd_config file.

With the above configuration, users are allowed to authenticate only via key. Root user is not allowed to authenticate.

Enforcing firewall rules

The Linux (iptables) firewall needs to be configured to allow only some services to Internet users. This is a basic firewall configuration:

# iptables -A INPUT -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT
# iptables -A INPUT -s 192.168.0.0/24 -j ACCEPT
# iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# iptables -A INPUT -m state --state INVALID -j DROP
# iptables -P INPUT DROP
# iptables -P FORWARD DROP
# iptables -P OUTPUT ACCEPT

The 192.168.0.0/24 is my home network, and it’s allowed to access the server without restrictions. The last lines enforce some security check. The following block enable a Services chain and open SSH and WebServers port:

# iptables -N Services
# iptables -A INPUT -m state --state NEW -j Services
# iptables -A Services -p tcp -m tcp --dport 22 -j ACCEPT
# iptables -A Services -p tcp -m multiport --dports 80,443 -j ACCEPT
# iptables -A Services -p tcp -m tcp --dport 1883 -j ACCEPT

Enable SSH service only if it’s been secured. Port 1883 is used for MQTT (see later posts about Owntracks and presence detection). Finally save iptables configuration:

# apt-get -y install iptables-persistent
# service iptables-persistent save

Check also my updated iptables rules:

Posted on 04 Oct 2016 by Andrea.
  • Gmail icon
  • Twitter icon
  • Facebook icon
  • LinkedIN icon
  • Google+ icon