1# Test Authelia as an auth server for Traefik as a reverse proxy of a local web service
2{ lib, ... }:
3{
4 name = "authelia";
5 meta.maintainers = with lib.maintainers; [ jk ];
6
7 nodes = {
8 authelia =
9 {
10 pkgs,
11 ...
12 }:
13 {
14 services.authelia.instances.testing = {
15 enable = true;
16 secrets.storageEncryptionKeyFile = "/etc/authelia/storageEncryptionKeyFile";
17 secrets.jwtSecretFile = "/etc/authelia/jwtSecretFile";
18 settings = {
19 authentication_backend.file.path = "/etc/authelia/users_database.yml";
20 access_control.default_policy = "one_factor";
21 session.domain = "example.com";
22 storage.local.path = "/tmp/db.sqlite3";
23 notifier.filesystem.filename = "/tmp/notifications.txt";
24 };
25 };
26
27 # These should not be set from nix but through other means to not leak the secret!
28 # This is purely for testing purposes!
29 environment.etc."authelia/storageEncryptionKeyFile" = {
30 mode = "0400";
31 user = "authelia-testing";
32 text = "you_must_generate_a_random_string_of_more_than_twenty_chars_and_configure_this";
33 };
34 environment.etc."authelia/jwtSecretFile" = {
35 mode = "0400";
36 user = "authelia-testing";
37 text = "a_very_important_secret";
38 };
39 environment.etc."authelia/users_database.yml" = {
40 mode = "0400";
41 user = "authelia-testing";
42 text = ''
43 users:
44 bob:
45 disabled: false
46 displayname: bob
47 # password of password
48 password: $argon2id$v=19$m=65536,t=3,p=4$2ohUAfh9yetl+utr4tLcCQ$AsXx0VlwjvNnCsa70u4HKZvFkC8Gwajr2pHGKcND/xs
49 email: bob@jim.com
50 groups:
51 - admin
52 - dev
53 '';
54 };
55
56 services.traefik = {
57 enable = true;
58
59 dynamicConfigOptions = {
60 tls.certificates =
61 let
62 certDir = pkgs.runCommand "selfSignedCerts" { buildInputs = [ pkgs.openssl ]; } ''
63 openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes -subj '/CN=example.com/CN=auth.example.com/CN=static.example.com' -days 36500
64 mkdir -p $out
65 cp key.pem cert.pem $out
66 '';
67 in
68 [
69 {
70 certFile = "${certDir}/cert.pem";
71 keyFile = "${certDir}/key.pem";
72 }
73 ];
74 http.middlewares.authelia.forwardAuth = {
75 address = "http://localhost:9091/api/verify?rd=https%3A%2F%2Fauth.example.com%2F";
76 trustForwardHeader = true;
77 authResponseHeaders = [
78 "Remote-User"
79 "Remote-Groups"
80 "Remote-Email"
81 "Remote-Name"
82 ];
83 };
84 http.middlewares.authelia-basic.forwardAuth = {
85 address = "http://localhost:9091/api/verify?auth=basic";
86 trustForwardHeader = true;
87 authResponseHeaders = [
88 "Remote-User"
89 "Remote-Groups"
90 "Remote-Email"
91 "Remote-Name"
92 ];
93 };
94
95 http.routers.simplehttp = {
96 rule = "Host(`static.example.com`)";
97 tls = true;
98 entryPoints = "web";
99 service = "simplehttp";
100 };
101 http.routers.simplehttp-basic-auth = {
102 rule = "Host(`static-basic-auth.example.com`)";
103 tls = true;
104 entryPoints = "web";
105 service = "simplehttp";
106 middlewares = [ "authelia-basic@file" ];
107 };
108
109 http.services.simplehttp = {
110 loadBalancer.servers = [
111 {
112 url = "http://localhost:8000";
113 }
114 ];
115 };
116
117 http.routers.authelia = {
118 rule = "Host(`auth.example.com`)";
119 tls = true;
120 entryPoints = "web";
121 service = "authelia@file";
122 };
123
124 http.services.authelia = {
125 loadBalancer.servers = [
126 {
127 url = "http://localhost:9091";
128 }
129 ];
130 };
131 };
132
133 staticConfigOptions = {
134 global = {
135 checkNewVersion = false;
136 sendAnonymousUsage = false;
137 };
138
139 entryPoints.web.address = ":443";
140 };
141 };
142
143 systemd.services.simplehttp =
144 let
145 fakeWebPageDir = pkgs.writeTextDir "index.html" "hello";
146 in
147 {
148 script = "${pkgs.python3}/bin/python -m http.server --directory ${fakeWebPageDir} 8000";
149 serviceConfig.Type = "simple";
150 wantedBy = [ "multi-user.target" ];
151 };
152 };
153 };
154
155 testScript = ''
156 start_all()
157
158 authelia.wait_for_unit("simplehttp.service")
159 authelia.wait_for_unit("traefik.service")
160 authelia.wait_for_unit("authelia-testing.service")
161 authelia.wait_for_open_port(443)
162 authelia.wait_for_unit("multi-user.target")
163
164 with subtest("Check for authelia"):
165 # expect the login page
166 assert "Login - Authelia", "could not reach authelia" in \
167 authelia.succeed("curl --insecure -sSf -H Host:auth.example.com https://authelia:443/")
168
169 with subtest("Check contacting basic http server via traefik with https works"):
170 assert "hello", "could not reach raw static site" in \
171 authelia.succeed("curl --insecure -sSf -H Host:static.example.com https://authelia:443/")
172
173 with subtest("Test traefik and authelia"):
174 with subtest("No details fail"):
175 authelia.fail("curl --insecure -sSf -H Host:static-basic-auth.example.com https://authelia:443/")
176 with subtest("Incorrect details fail"):
177 authelia.fail("curl --insecure -sSf -u 'bob:wordpass' -H Host:static-basic-auth.example.com https://authelia:443/")
178 authelia.fail("curl --insecure -sSf -u 'alice:password' -H Host:static-basic-auth.example.com https://authelia:443/")
179 with subtest("Correct details pass"):
180 assert "hello", "could not reach authed static site with valid credentials" in \
181 authelia.succeed("curl --insecure -sSf -u 'bob:password' -H Host:static-basic-auth.example.com https://authelia:443/")
182 '';
183}