Pfsense HAproxy + authelia

For quite some time I am looking for a way to make my personal servers open to the internet. But I do want them to be secure and prevent hacks. After a quick google search I found Authelia. Unfortunately the setup for Authelia isn’t as straight forward for pfsense as for other proxy managers. With the help of Github and a few Youtubers I made a manual for you to follow in a way I wanted to have.

The manual:

Prerequisites:

  • Up and running PFsense
  • Installed HAproxy-devel (for lua load

Get started:

  1.  Download the following files and save as:
  2. Open filezilla or equivalent and upload the files above to: /usr/local/share/lua/5.3 
  3. Go to services > haproxy > files
  4. Create three entries with the following content:
  5. in HAproxy got to: settings > Global Advanced pass thru paste the following:
lua-prepend-path /usr/local/share/lua/5.3/haproxy-lua-http.lua

Create Backend:

Authelia backend:

Service backend:

In my case this will be photoprism, you will need the following entries to be made (note that this needs to be done for every protected backend).

Access Control list:

NameExpressionValue
remote_user_existCustom aclvar(req.auth_response_header.remote_user) -m found
remote_groups_existCustom aclvar(req.auth_response_header.remote_groups) -m found
remote_name_existCustom aclvar(req.auth_response_header.remote_name) -m found
remote_email_existCustom aclvar(req.auth_response_header.remote_email) -m found

Actions:

ActionParameterCondition acl name
http-request header set
See Belowremote_user_exist

NameRemote-User

fmt%[var(req.auth_response_header.remote_user)]
http-request header set
remote_groups_exist

nameRemote-Groups

fmt%[var(req.auth_response_header.remote_groups)]
http-request header set
remote_name_exist

nameRemote-Name

fmt%[var(req.auth_response_header.remote_name)]
http-request header set
remote_email_exist

nameRemote-Email

fmt%[var(req.auth_response_header.remote_email)]

Frontend:

Within the frontend scroll down to: Default backend, access control lists and actions.

Access control list:

NameExpressionValue
autheliaHost matches:auth.mydomain.me
protected-frontendsHost matches:myservice.mydomain.me

Note that “protected-frontends” is important

ActionParametersCondition acl names
Use BackendSee belowauthelia
backend: be_authelia
CustomSee below{ ssl_fc }
customaction: http-request set-var(req.scheme) str(https)
CustomSee below!{ ssl_fc }
customaction: http-request set-var(req.scheme) str(http)
CustomSee below{ query -m found }
customaction: http-request set-var(req.questionmark) str(?)
http-request header setSee belowprotected-frontends
name: X-Real-IP , fmt: %[src]
http-request header setSee belowprotected-frontends
name: X-Forwarded-Method , fmt: %[var(req.method)]
http-request header setSee belowprotected-frontends
name: X-Forwarded-Proto , fmt: %[var(req.scheme)]
http-request header setSee belowprotected-frontends
name: X-Forwarded-Host , fmt: %[req.hdr(Host)]
http-request header setSee belowprotected-frontends
name: X-Forwarded-Uri , fmt: %[path]%[var(req.questionmark)]%[query]
CustomSee belowprotected-frontends
customaction: http-request lua.auth-request be_authelia_ipvANY /api/verify
http-request redirectSee belowprotected-frontends !{ var(txn.auth_response_successful) -m bool }
rule: location https://auth.mydomain.me/?rd=%[var(req.scheme)]://%[base]%[var(req.questionmark)]%[query]
Use BackendSee belowprotected-frontends
backend: photoprism

Picture in addition to text.

Please note:

customaction: http-request lua.auth-request be_authelia_ipvANY /api/verify

be_authelia_ipvANY is important! be_authelia is the backend we’ve created earlier; ipvANY needs to be added (pfsense does so in haproxy.cfg)

Another route:

In some cases, like mine it might not work as described above however; there is another way. To achieve this you need to tweak a few things as following:

For the frontend ACL:

Name: protected-frontends
Expression: Custom ACL:
Value: hdr(host) -m reg -i ^(?i)(prism|nvr|storj1|spotweb)\.mydomain\.me

Name: host-prism
Expression: Host matches:
Value: prism.mydomain.me
Frontend – ACL

For the frontend action:

Action: Use Backend
Parameters: See below 
Condition ACL names: host-prism
Actions: <your backend>
frontend – action

Above is just an example on how to approach. You need to change accordingly.

Authelia:

For this guide it’s important that you already have an up and running docker with docker compose in order to start. If you don’t have docker up and running, I’ve got you covered. Just folllow this guide

Docker compose – Authelia

version: '3.3'
    
services:
  authelia:
    image: authelia/authelia
    container_name: authelia
    volumes:
      - /myvolume:/config #change this to a shared folder on your system. DO NOT use a "/myvolume"
    ports:
      - 9091:9091
    environment:
      - TZ=Europe/Amsterdam

Start the created container, it will stop, this is normal.

Make configuration:

  1. Navigate by ssh to /myvolume/ and edit configuration.yml.
# yamllint disable rule:comments-indentation
---
###############################################################################
#                           Authelia Configuration                            #
###############################################################################

theme: auto #matches yoursystem theme
jwt_secret: 1234567890abcdefghifjkl #any text or number you want to add here to create jwt Token

default_redirection_url: https://google.com/ #where to redirect for a non-existent URL

server:
  host: 0.0.0.0
  port: 9091
  path: ""
  read_buffer_size: 4096
  write_buffer_size: 4096
  enable_pprof: false
  enable_expvars: false
  disable_healthcheck: false
  tls:
    key: ""
    certificate: ""

log:
  level: debug

totp:
  issuer: yourdomain.com #your authelia top-level domain
  period: 30
  skew: 1

authentication_backend:
  disable_reset_password: false
  refresh_interval: 5m
  file:
    path: /config/users_database.yml #this is where your authorized users are stored
    password:
      algorithm: argon2id
      iterations: 1
      key_length: 32
      salt_length: 16
      memory: 1024
      parallelism: 8

access_control:
  default_policy: deny
  rules:
    ## bypass rule
    - domain: 
        - "auth.mydomain.me" #This should be your authentication URL
      policy: bypass
    - domain: "mydomain.me" #example domain to protect
      policy: one_factor
    - domain: "sub1.mydomain.me" #example subdomain to protect
      policy: one_factor #could also be two_factor


session:
  name: authelia_session
  secret: unsecure_session_secret #any text or number you want to add here to create jwt Token
  expiration: 3600  # 1 hour
  inactivity: 300  # 5 minutes
  domain: mydomain.me  # Should match whatever your root protected domain is

regulation:
  max_retries: 3
  find_time: 10m
  ban_time: 12h

storage:
  local:
    path: /config/db.sqlite3 
  encryption_key: GENERATE_STRING_MORETHAN20_CHARS
  
notifier:
  filesystem:
    filename: /config/notification.txt

2. Next, create and edit a file called: users_database.yml.

users:
  user1: #username for user 1. change to whatever you'd like
    displayname: "User Name 1" #whatever you want the display name to be
    password: "$argon2i$v=19$m=1024,t=1,p=8$eTQ3MXdqOGFiaDZoMUtMVw$OeHWQSg9zGKslOepe5t4D1T9BZJjHA1Z+doxZrZYDgI" #generated at https://argon2.online/
    email: youremail@gmail.com #whatever your email address is
    groups: #enter the groups you want the user to be part of below
      - admins
      - dev
  user2: #username for user 2. change to whatever you'd like. Or delete this section if you only have 1 user
    displayname: "User Name 2" #whatever you want the display name to be
    password: "$argon2i$v=19$m=1024,t=1,p=8$eTQ3MXdqOGFiaDZoMUtMVw$OeHWQSg9zGKslOepe5t4D1T9BZJjHA1Z+doxZrZYDgI" #generated at https://argon2.online/
    email: youremail2@gmail.com #whatever your email address is
    groups: #enter the groups you want the user to be part of below
      - dev

Thank you for reading, I hope this guide was sufficient. whenever something isn’t clear, please let me know. I will try to explain

Dennis

Related Post

Comments (2)

  1. Hello,
    I manage to get one protected back end to work.
    It’s set to two_factor but I don’t get the option activate it.

    Daniel
    August 3, 2022
    1. I gotten t o the part to enable the device but the URL I get is a HTTP and my browser/HAproxy change it to HTTPS and I get a white page.

      Daniel
      August 3, 2022

Leave A Comment

Name

Website

Comment