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