Authelia

Authelia is an open-source authentication and authorization server and portal fulfilling the identity and access management (IAM) role of information security in providing multi-factor authentication and single sign-on (SSO) for your applications via a web portal. It acts as a companion for common reverse proxies.

This is not simple stuff and it require some understanding of what you are doing: just copy-pasting configurations and finger-crossing will not work and only lead to frustration.

I strongly suggest you read the very good Get Started page and the linked references before you proceed.

Installation

First of all, your NGINX must be compiled with auth_request module, but if you followed my NGINX guide (here), you are all set.

While Authelia support docker images, there is really no reason to use a container since it's a single executable that you can simply download and start. So let's install on bare-metal!

As usual, let's create a dedicated user:

useradd -m authelia

in this case, you should let the home folder be under the /home/authelia since this is an authentication service, you want to have it always working even if the /media folder doesn't mount for any reason.

Now it's time to download the latest release from https://github.com/authelia/authelia/releases and install it under user bin folder:

su - authelia
wget https://github.com/authelia/authelia/releases/download/vX.Y.Z/authelia-vX.Y.Z-linux-amd64.tar.gz
mkdir bin config db logs
cd bin
tar xvf ../authelia-vX.Y.Z-linux-amd64.tar.gz

Configuration

You need to copy the provided example configuration and edit to your needs:

cp bin/config-example.yml configuration.yml

As an example, here is my configuration.yml, split into separate sections because it's very long:

configuration.yml
---
theme: 'auto'
server:
  address: 'tcp://127.0.0.1:9071/' # port 9071, default would collide with another service
  endpoints:
    <<< see below >>>
log:
    <<< see below >>>
telemetry:
  metrics:
    enabled: false
totp:
  disable: false
webauthn:
  disable: false
identity_validation:
  reset_password:
    jwt_secret: '<<< put a good secret here >>>>'
authentication_backend:
    <<< see below >>>
password_policy:
  standard:
    enabled: false
    min_length: 8
    max_length: 0
    require_uppercase: true
    require_lowercase: true
    require_number: true
    require_special: true
  zxcvbn:
    enabled: false
    min_score: 3
privacy_policy:
  enabled: false
  require_user_acceptance: false
  policy_url: ''
access_control:
    <<< see below >>>
session:
  secret: '<<< another, different, secret here >>>>'
  cookies:
    -
      domain: 'mydomain.com'
      authelia_url: 'https://login.mydomain.com'
      default_redirection_url: 'https://mydomain.com'
  name: 'authelia_session'
  same_site: 'lax'
  inactivity: '5m'
  expiration: '14h'
  remember_me: '1M'

storage:
  <<< see below >>>

notifier:
  <<< see below >>>

identity_providers:
  oidc:
    <<< see below >>>
...

This file has a few assumptions, for example you need to create login.mydomain.com in your NGINX configuration, create the subdomain in your domain DNS, and generate the corrispective HTTPS certificate. Authelia will not work otherwise, by design.

Access Control

This section is used to define how to access domains, and with which policy. I use single factor at this time, so:

access_control:
  default_policy: 'deny'
  rules:   
    - domain: '*.mydomain.com'
      policy: 'one_factor'

Authentication Backend

I choose to store passwords and users in a yaml text file, for my few users this is perfect and simple enough:

  password_reset:
    disable: false
  file: 
    path: '/home/authelia/config/users_database.yml'
    watch: true

See below on how to add/create users.

Storage

Due to my very limited use case (less than 10 users) i am using SQLite3 as storage backend:

storage:
  encryption_key: '<<< put a good string here >>>>'
  local:
    path: '/home/authelia/db/db.sqlite3'

Notifier

Authelia support both on-flie notifier, which is pretty simple to setup, or email based notifier. While email requires you to setup a dedicated email address for Authelia, it will allow users to reset their password without your actions, which might be desirable.

File based, simple, notifier:

notifier:
  disable_startup_check: false
  filesystem: # Using email notifier is probably better: TBD
    filename: '/home/authelia/config/notification.txt'

SMTP / email notifier:

notifier: 
  disable_startup_check: false
  smtp:   
    address: 'smtp://mail.mydomain.com:587'
    username: 'authelia@mydomain.com'
    password: '<<< put email password here >>>'
    sender: 'Authelia <authelia@mydomain.com>'

Endpoints

Please note the endpoints configuration below: i have created two different endpoints:

  • standard: which will be used by all supported services
  • basic: which will be needed by some protocols like WebDAV and such
  endpoints:
    authz:
      normal:  # This is used for the non-basic auth
        implementation: 'AuthRequest'
        authn_strategies:
          - name: 'CookieSession'
      basic:     # this enables basic auth for services that don't uspport anything else
        implementation: 'AuthRequest'
        authn_strategies:
          - name: 'HeaderAuthorization'
            schemes:
              - 'Basic'

This is different from the stock authelia configuration files and requires one important change to the NGINX snippets below, which i will point out. Do not forget to edit the snippets where indicated.

Log

Moving logging to a separate file, remember to logrotate it, because it will grow a lot over time:

log:
  level: 'debug'
  format: 'text'
  file_path: '/var/log/authelia/authelia.log'

For the log file, you need to create and set permissions to /var/log/authelia:

mkdir /var/log/authelia
chown authelia:authelia /var/log/authelia
chmod 750 /var/log/authelia

OIDC Provider

Setting up Authelia as OIDC Provider is useful to support services that support this protocol, like Jellyfin. See here for more details.

Add the following section to your configuration.yml:

identity_providers:
  oidc:
    hmac_secret: '<<see below>>'
    jwks:
      - key_id: 'main'
        use: 'sig'
        key: |
          -----BEGIN PRIVATE KEY-----
          ... <<< see below >>> ...
          -----END PRIVATE KEY-----
    enable_client_debug_messages: false
    minimum_parameter_entropy: 8
    enforce_pkce: 'public_clients_only'
    enable_pkce_plain_challenge: false
    enable_jwt_access_token_stateless_introspection: false
    discovery_signed_response_alg: 'none'
    discovery_signed_response_key_id: ''
    require_pushed_authorization_requests: false
    authorization_policies:
      policy_name:
        default_policy: 'one_factor'
        rules:
          - policy: 'deny'
            subject: 'group:services'
    lifespans:
      access_token: '1h'
      authorize_code: '1m'
      id_token: '1h'
      refresh_token: '90m'
    cors:
      endpoints:
        - 'authorization'
        - 'token'
        - 'revocation'
        - 'introspection'
      allowed_origins:
        - 'https://mydomain.com'
      allowed_origins_from_client_redirect_uris: false

To generate hmac_secret use the following command:

/home/authelia/bin/authelia-linux-amd64  crypto rand --length 64 --charset alphanumeric

To generate the PRIVATE KEY use the following command:

openssl genrsa -out private.pem 4096 && cat private.pem

You can delete the generated files afterward.

OIDC Client

Each OIDC client must have it's own section in the Authelia configuration file. See here for an example.

identity_providers:
  oidc:
    << omissis, see OIDC Providers above >>
    clients:
      - client_id: ' <<< see below >>>'
        client_name: 'Jellyfin'
        client_secret: '<<< see below >>>'
        public: false
        authorization_policy: 'two_factor'
        require_pkce: true
        pkce_challenge_method: 'S256'
        redirect_uris:
          - 'https://client.example.com/sso/OID/redirect/authelia'
        scopes:
          - 'openid'
          - 'profile'
          - 'groups'
        userinfo_signed_response_alg: 'none'
        token_endpoint_auth_method: 'client_secret_post'

To generate the client_id:

./home/authelia/bin/authelia-linux-amd64 crypto rand --length 72 --charset rfc3986

To generate client_secret:

  /home/authelia/bin/authelia-linux-amd64 crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986

NGINX support files

From this point onward, always refer to Authelia documentation to understand what i am doing.

This is the associated NGINX config file /etc/nginx/mydomain/login/login.conf:

login.conf
server {
        server_name login.mydomain.com;
        listen 443 ssl; 
        listen 8443 ssl; 
        http2 on;

        access_log /var/log/nginx/login.mydomain.com_access_log main;
        error_log /var/log/nginx/login.mydomain.com_error_log info;

        location / {
                include com.mydomain/authelia_proxy.conf;
                proxy_pass http://127.0.0.1:9071;
        }

        location = /api/verify {
                proxy_pass http://127.0.0.1:9071;
        }

        location /api/authz/ {
                proxy_pass http://127.0.0.1:9071;
        }
}

In addition to this one, you need also che following specific NGINX config files:

  • The /etc/nginx/com.mydomain/authelia_proxy.conf: see here
  • The /etc/nginx/com.mydomain/authelia_location.conf: see here
  • The /etc/nginx/com.mydomain/authelia_location-basic.conf: see here
  • The /etc/nginx/com.mydomain/authelia_authrequest.conf: see here
  • The /etc/nginx/com.mydomain/authelia_authrequest-basic.conf: see here

Now, you need to edit the authelia_location.conf and replace the first line to match the standard endpoint defined above:

set $upstream_authelia http://127.0.0.1:9071/api/authz/normal;

And, similarly, you need to edit the authelia_location-basic.conf and replace the first line to match the basic endpoint defined above:

set $upstream_authelia http://127.0.0.1:9071/api/authz/basic;

I have added the specific endpoints (normal / basic) to the URL..

Enable Authelia in NGINX

Well, you can enable Authelia support in any subdomain you want by simply adding the following three lines to your NGINX configurations:

# The following goes in the server section:
        include "org.gardiol/authelia_location.conf";
# The following two can go either in specific location section, or directly in the server section to protect ALL locations:
        include "org.gardiol/authelia_proxy.conf";
        include "org.gardiol/authelia_authrequest.conf";

Adding and editing users

Since i choose file based storage, adding and editing users is a simple matter of editing the following text file /home/authelia/config/users_database.yml. If missing, create it from the following example:

users_database.yml
>
# yamllint disable rule:line-length
---
###############################################################
#                         Users Database                      #
###############################################################

# This file can be used if you do not have an LDAP set up.

users:
  myuser:
    disabled: false
    displayname: "Name Surname"
    password: " << see below >>"
    email: myuser@mydomain.com
    groups:
      - admins
      - dev
...
# yamllint enable rule:line-length

To create passwords, you can use the Authelia binary itself:

/home/authelia/bin/authelia-linux-amd64 crypto hash generate --help

then copy & paste the password hash inside the above yaml file. Authelia should pickup autmatically the change without the need to reload.

I will be working on an automatic synchronization between /etc/passwd users and Authelia users to keep all the authentications in sync in the future.

Autostart

Create the following file as /etc/init.d/authelia:

authelia
#!/sbin/openrc-run
# Copyright 1999-2021 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

description="Authelia - authenticator"
pidfile="/run/authelia.pid"
command_background=true
command="/home/authelia/bin/authelia-linux-amd64"
command_args="--config /home/authelia/configuration.yml"
command_user="authelia:authelia"

depend() {
        need net
}

Make it executable, and enable on boot:

chmod +x /etc/init.d/authelia
rc-update add authelia default
/etc/init.d/authelia start

Update

Download a new binary, replace old, restart service!