ippo

MFA behind Caddy

MFA behind Caddy

Two factor authantication on selfhosted services behind caddy with caddy-security lug-in

what you’ll get:

  • A portal with links to your selfhosted services protected behind a reverse proxy
  • Automated redirects to https with automatic ssl
  • Two factor authentication

This caddy plugin minimises your requred domains as youll only need one dynamic dns domain name and the plugin will handle the redirects to your internal localhost ip’s that your services reside.

Note that youll need to authenticate your service either from your portal url or the direct service URL you specify in the plug in

what you’ll need:

  • caddyserver
  • caddy-security plugin
  • xcaddy
  • GO language
  • bcrypt-cl (optional)

Bellow commands are for arch, use you package manager.

# Install go

sudo pacman -S go

install xcaddy

go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest

Build caddy with the caddy-security plugins for arm using GOOS and GOARCH env variables:

1
2
3
4
GOOS=linux GOARCH=arm64 go/bin/xcaddy build \
    --with github.com/greenpau/caddy-security \
    --with github.com/greenpau/caddy-trace \
    --with github.com/caddy-dns/cloucloudflare

this will create a caddy executable in your HOME

  • move to to /usr/bin

sudo cp caddy /usr/bin/

  • Test that it worked

caddy version

install bcrypt-cl to create hash for passwords

go install github.com/ryicoh/bcrypt-cli@latest

  • add ~/go/bin to PATH

export PATH=~/go/bin:$PATH

  • select your password e.g. “mypassoword”

  • get the hash

echo "mypassoword" | bcrypt-CLI

  • create caddy config dir

sudo mkdir /etc/caddy/

  • create caddy config

sudo nano /etc/caddy/Caddyfile

paste

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
{ 
        order authenticate first
        order trace before reverse_proxy
        order authorize before reverse_proxy
    security {
                       messaging email provider localhost-smtp-server {
                        address 192.168.1.24:1025 #your raspberry's ip
                        protocol smtp
                        passwordless
                        sender root@localhost "My Auth Portal"
                        bcc ippo@localhost #your random username
        }
        authentication portal myportal {
            crypto default token lifetime 3600 
            crypto key sign-verify {env.JWT_SECRET}
            backend local /var/lib/caddy/users.json local #use caddy's $HOME so that it can write
                    cookie domain ippocratis.duckdns.org #your valid dynamic dns pointing in your raspberry
            ui {
                links { # Icons here -> https://icons8.com/line-awesome
                    "radicale" https://radicale.ippocratis.duckdns.org icon "las la-cloud"
                    "photoprism" https://photoprism.ippocratis.duckdns.org icon "las la-photo-video"
                    "wallabag" https://wallabag.ippocratis.duckdns.org icon "las la-tv"
                }
            }
            transform user {
                match origin local
                action add role authp/user
                ui link "Portal Settings" /settings icon "las la-cog"
            }
        }
        authorization policy mypolicy {
            set auth url https://auth.ippocratis.duckdns.org/
            crypto key verify {env.JWT_SECRET}
            allow roles authp/admin authp/user
        }
    }
}
auth.ippocatis.duckdns.org {
    route {
        authenticate with myportal
    }
}

radicale.ippocratis.duckdns.org {
    authorize with mypolicy
    reverse_proxy localhost:5232
}

photoprism.ippocratis.duckdns.org {
    authorize with mypolicy
    reverse_proxy localhost:2342
}

  • Create a group named caddy

sudo groupadd --system caddy

  • Create a user named caddy, with a writeable home directory
1
2
3
4
5
6
7
sudo useradd --system \
    --gid caddy \
    --create-home \
    --home-dir /var/lib/caddy \
    --shell /usr/sbin/nologin \
    --comment "Caddy web server" \
    caddy
  • choose a systemd unit file

https://github.com/caddyserver/dist/blob/master/init/caddy.service

  • copy it

The usual place to save the service file is: /etc/systemd/system/caddy.service

on manjaro arm its under

/etc/systemd/system/multi-user.target.wants/caddy.service

  • create service

sudo nano /etc/systemd/system/multi-user.target.wants/caddy.service

paste it

  • reload daemon

sudo systemctl daemon-reload

  • enable unit

sudo systemctl enable --now caddy

  • grab the webadmin users password from logs (will change later)

journalctl -u caddy --no-pager | grep webadmin@localdomain.local

  • copy secret

  • navigate to auth.ippocratis.duckdns.org (auth url in our example)

user = webadmin pass = your copied secret

  • change password

on the web interface

go to portal settings

passwords

and change it

password criteria (length,lower/upercase etc) is under /var/lib/caddy/users.json

add multifactor authentication

on the web interface

go to portal settings

mfa

add mfa app

scan qr

open your mfa app eg aegis and scan the qr

relogin to test it

user and password are stored in /var/lib/caddy/users.json

select caddy’s $HOME (/var/lib/caddy) as caddy may not be able to write on other dirs

  • test redirections

on the web interface open a link e.g. radicale in our example

then log out

cookie should not let you log in with the “direct url”

try to to navigate to radicale.ippocratis.duckdns.org in our example the radicale redir

it should ask you your mfa key and not let you in

Enjoy

comments powered by Disqus