Authentication
Having a strong layer of authentication is mandatory for self-hosted services that are exposed to the internet. When talking about authentication it's important to remember that is has a double meaning: to recognize a user, and to restrict access to your service based on who the user is.
I also assume that the focus is home services access, which means a very limiter number of users (spouse, kids, maybe grandparents, maybe a few very close friends) which do not change over time very often, if ever. I don't care about ease of adding new users, and there will be no concept of self registration for users as well.
There are a few key points that i want to stress on authentication:
- From outside, all services must require authentication
- From inside, authentication is required only where a specific user makes a difference
- Not all services will need to differentiate between users
- Avoid double authentication: if a service do not accept SSO, it will be disabled for that service.
- 2FA (Two Factor Authentication) will not be considered (left as an exercise to the reader)
- SSO should be enabled everywhere, but in reality most of services do not support any kind of SSO, so… YMMV.
For example, a media server will need to know who is connecting to show your preferred shows and your “resume from here…” movies. The printer control page instead should be accessible by anyone inside home.
The concept behind SSO
The idea is that you have a dedicated service that provides access control and credential checking for your services. Once the user has authenticated (via password or even via 2FA - Two Factor Auth), the user will be recognized by as many services as possible and automatically logged in without requiring a second login.
The key point is that the SSO happens before the user even reach the service, thus providing an additional layer of security to the service itself, whose authentication layer can be bypassed. It's safer to use one safe and well-proven security layer for every service rather than rely to lots of independent security layers written by different devs, with more or less consciousness about security.
The second key point should be that you add users to a single database, instead of creating the same user for different services each time.
Unfortunately, SSO support by services is rather spotty and more miss than hit. This is very unfortunate, and adding to the fact that a few services even take the further step to require an email-login or such, make SSO not very useful all along. But my hope is that slowly it will be more supported overall.
Different SSO solutions
The most simple SSO possible is to use NGINX PAM Authentication, which will simply map your users to your home server users (the ones in /etc/passwd… managed by the Linux classical adduser/deluser CLI commands).
A more advanced SSO approach is to use a dedicated gateway like Authelia. There are many similar services, but i focused on Authelia because it's fully Open Source in the best concept and it's very well documented.
As a side note, a few words on server login capability. Should the user be allowed also access to the server via SSH / console? An answer to this question is not so simple because of the use of services like NFS or Samba, and wether some users might need to login phisically on the server. I leave these considerations to your use case.
So, the NGINX PAM Auth approach:
- Requires the users to be able to also login via SSH / local console on the server (this can be avoided using NGINX basic auth instead)
- Shows a somewhat ugly (and non-customizable) login popup on the browser
- Much less overall customizable
- Must login separately for each subdomain
- Less flexible, more difficult to integrate with services (no OIDC or OAuth support)
- Easier to integrate with some services, impossible with others.
Instead, the Authelia approach:
- Much more customizable
- Does not let the user to login on the server (unless you link PAM to Authelia)
- Shows a nicer and customizable login page in the browser
- Once logged on one, it will work for all configured subdomains
- More flexible, can support OAuth and such
- Easier to integrate with some services (there will still be services that cannot use it)
- Can simoultaneously use also basic authentication, which is required by some protocols like WebDAV.
Overall, it's a mess. At least you can fully replace NGINX auth with Authelia, leveraging the support for basic auth where needed, but still lots of services have an hard time integrating with an SSO or any kind. While i am slowing trying to migrate everything to Authelia, it's a long game that often requires tickets on GitHub for each service and lots of patience.
This also means that it is impossible to really have only one login for everything. You will have to create the user on the server, then add it to Authelia, then add it to any specific services that cannot use either. Sorry, that's life at this point.
SSO approach matrix
You have the following combinations:
- Services that do not require to differentiate the user
- Services that needs to know who is connecting, and can get this info from the SSO
- Services that needs to know who is connecting, and cannot get this info from the SSO
The general rule is as follow:
Service | From inside | From outside |
---|---|---|
do not require authentication | auth not required | use SSO auth |
Require auth, can use reverse-proxy auth | use SSO auth | use SSO auth |
Require auth, cannot use reverse-proxy auth | use service auth | use service auth |
Using SSO on services that cannot understand SSO auth is, in theory, a great way to increase security as others will not even be able to reach your service, but will require the users to perform the authentication twice and will cause some mobile apps to fail, so i do not recommend it.
Authelia SSO
First of all, follow this page to install the service itself.
In order to use WebDAV, CardDAV or CalDAV, you will need to enable also basic auth on Authelia, at least for specific subdomains and locations.
Authelia works by using the auth_request module of NGINX. The reverse proxy will first send any request to Authelia which will validate the user login. If login is successful, NGINX will then redirect the user to the correct destination page. This process is transparent once the user is logged and very fast.
The entire process is described here and it's a worthwhile read.
In order to use Authelia you need to include a few different snippets of NGINX configuration in your NGINC config files. The snippets are:
- the authelia_location and authelia_location-basic
- the authelia_authrequest and authelia_authrequest-basic
- the authelia_proxy
The authelia_location will create, in your domain, a specific entry point (/internal/authelia/authz/*) that will later on be used for the authentication. This snippet must be added at the server level, so that it is available only once for all the locations on the domain. You can add both the normal and the basic one at the same time.
The authelia_authrequest injects in your location the redirection to the above defined entry point, and this enables the Authelia authentication for the specific location. This can be added aither to a specific location, or can be addedd at server level to have it enabled for all locations within the domain.
The last snippet, authelia_proxy, simply provides some mandatory settings to pass back the authentication information , like username, to the service so that it can be used, by a service well written, to bypass it's own authentication and avoid a second layer of username/password request.
Example configuration
This is my home.mydomain.com NGINX configuration file with Authelia configured:
- home.conf
server { server_name home.mydomain.com; # This listen only when accessed from outside the home network listen 8443 ssl; http2 on; # Authelia auth entry point include "com.mydomain/authelia_location.conf"; # Enable Authelia login for the entire subdomain include "com.mydomain/authelia_proxy.conf"; include "com.mydomain/authelia_authrequest.conf"; # Include all the services under the subdomain include "com.mydomain/home/main.conf"; }
NGINX PAM SSO
This is achieved by using the pam_auth module on Linux. You have already built nginx with pam_auth support, but you need to configure it.
First of all configure PAM, create the file /etc/pam.d/nginx with these lines:
- nginx
auth required pam_unix.so account required pam_unix.so
Now add the following lines to any service you want behind PAM authentication in NGINX:
auth_pam "Home"; auth_pam_service_name "nginx";
You can add them to the location section, but also directly in the server section. In this case, you can disable PAM auth for specific location with:
auth_pam off;
So for example:
server { server_name 10.0.0.1 mydomain.com; listen 8443 ssl; access_log /var/log/nginx/mydomain.com_access_log main; error_log /var/log/nginx/mydomain.com_error_log info; root /data/web/htdocs; auth_pam "Home"; auth_pam_service_name "nginx"; include "com.mydomain/serviceX.conf"; include com.mydomain/certbot.conf; }
Restart your NGINX and you are done!
Specific services configuration
See each service page, i wll write there any service specific details.