1{ config, lib, pkgs, ... }:
2
3let
4 cfg = config.services.kasmweb;
5in
6{
7 options.services.kasmweb = {
8 enable = lib.mkEnableOption (lib.mdDoc "kasmweb");
9
10 networkSubnet = lib.mkOption {
11 default = "172.20.0.0/16";
12 type = lib.types.str;
13 description = lib.mdDoc ''
14 The network subnet to use for the containers.
15 '';
16 };
17
18 postgres = {
19 user = lib.mkOption {
20 default = "kasmweb";
21 type = lib.types.str;
22 description = lib.mdDoc ''
23 Username to use for the postgres database.
24 '';
25 };
26 password = lib.mkOption {
27 default = "kasmweb";
28 type = lib.types.str;
29 description = lib.mdDoc ''
30 password to use for the postgres database.
31 '';
32 };
33 };
34
35 redisPassword = lib.mkOption {
36 default = "kasmweb";
37 type = lib.types.str;
38 description = lib.mdDoc ''
39 password to use for the redis cache.
40 '';
41 };
42
43 defaultAdminPassword = lib.mkOption {
44 default = "kasmweb";
45 type = lib.types.str;
46 description = lib.mdDoc ''
47 default admin password to use.
48 '';
49 };
50
51 defaultUserPassword = lib.mkOption {
52 default = "kasmweb";
53 type = lib.types.str;
54 description = lib.mdDoc ''
55 default user password to use.
56 '';
57 };
58
59 defaultManagerToken = lib.mkOption {
60 default = "kasmweb";
61 type = lib.types.str;
62 description = lib.mdDoc ''
63 default manager token to use.
64 '';
65 };
66
67 defaultGuacToken = lib.mkOption {
68 default = "kasmweb";
69 type = lib.types.str;
70 description = lib.mdDoc ''
71 default guac token to use.
72 '';
73 };
74
75 defaultRegistrationToken = lib.mkOption {
76 default = "kasmweb";
77 type = lib.types.str;
78 description = lib.mdDoc ''
79 default registration token to use.
80 '';
81 };
82
83 datastorePath = lib.mkOption {
84 type = lib.types.str;
85 default = "/var/lib/kasmweb";
86 description = lib.mdDoc ''
87 The directory used to store all data for kasmweb.
88 '';
89 };
90
91 listenAddress = lib.mkOption {
92 type = lib.types.str;
93 default = "0.0.0.0";
94 description = lib.mdDoc ''
95 The address on which kasmweb should listen.
96 '';
97 };
98
99 listenPort = lib.mkOption {
100 type = lib.types.int;
101 default = 443;
102 description = lib.mdDoc ''
103 The port on which kasmweb should listen.
104 '';
105 };
106
107 sslCertificate = lib.mkOption {
108 type = lib.types.nullOr lib.types.path;
109 default = null;
110 description = lib.mdDoc ''
111 The SSL certificate to be used for kasmweb.
112 '';
113 };
114
115 sslCertificateKey = lib.mkOption {
116 type = lib.types.nullOr lib.types.path;
117 default = null;
118 description = lib.mdDoc ''
119 The SSL certificate's key to be used for kasmweb. Make sure to specify
120 this as a string and not a literal path, so that it is not accidentally
121 included in your nixstore.
122 '';
123 };
124 };
125
126 config = lib.mkIf cfg.enable {
127
128 systemd.services = {
129 "init-kasmweb" = {
130 wantedBy = [
131 "docker-kasm_db.service"
132 ];
133 before = [
134 "docker-kasm_db.service"
135 "docker-kasm_redis.service"
136 "docker-kasm_db_init.service"
137 "docker-kasm_api.service"
138 "docker-kasm_agent.service"
139 "docker-kasm_manager.service"
140 "docker-kasm_share.service"
141 "docker-kasm_guac.service"
142 "docker-kasm_proxy.service"
143 ];
144 serviceConfig = {
145 Type = "oneshot";
146 ExecStart = pkgs.substituteAll {
147 src = ./initialize_kasmweb.sh;
148 isExecutable = true;
149 binPath = lib.makeBinPath [ pkgs.docker pkgs.openssl pkgs.gnused ];
150 runtimeShell = pkgs.runtimeShell;
151 kasmweb = pkgs.kasmweb;
152 postgresUser = cfg.postgres.user;
153 postgresPassword = cfg.postgres.password;
154 inherit (cfg)
155 datastorePath
156 sslCertificate
157 sslCertificateKey
158 redisPassword
159 defaultUserPassword
160 defaultAdminPassword
161 defaultManagerToken
162 defaultRegistrationToken
163 defaultGuacToken;
164 };
165 };
166 };
167 };
168
169 virtualisation = {
170 oci-containers.containers = {
171 kasm_db = {
172 image = "postgres:12-alpine";
173 environment = {
174 POSTGRES_PASSWORD = cfg.postgres.password;
175 POSTGRES_USER = cfg.postgres.user;
176 POSTGRES_DB = "kasm";
177 };
178 volumes = [
179 "${cfg.datastorePath}/conf/database/data.sql:/docker-entrypoint-initdb.d/data.sql"
180 "${cfg.datastorePath}/conf/database/:/tmp/"
181 "kasmweb_db:/var/lib/postgresql/data"
182 ];
183 extraOptions = [ "--network=kasm_default_network" ];
184 };
185 kasm_db_init = {
186 image = "kasmweb/api:${pkgs.kasmweb.version}";
187 user = "root:root";
188 volumes = [
189 "${cfg.datastorePath}/:/opt/kasm/current/"
190 "kasmweb_api_data:/tmp"
191 ];
192 dependsOn = [ "kasm_db" ];
193 entrypoint = "/bin/bash";
194 cmd = [ "/opt/kasm/current/init_seeds.sh" ];
195 extraOptions = [ "--network=kasm_default_network" "--userns=host" ];
196 };
197 kasm_redis = {
198 image = "redis:5-alpine";
199 entrypoint = "/bin/sh";
200 cmd = [
201 "-c"
202 "redis-server --requirepass ${cfg.redisPassword}"
203 ];
204 extraOptions = [ "--network=kasm_default_network" "--userns=host" ];
205 };
206 kasm_api = {
207 image = "kasmweb/api:${pkgs.kasmweb.version}";
208 user = "root:root";
209 volumes = [
210 "${cfg.datastorePath}/:/opt/kasm/current/"
211 "kasmweb_api_data:/tmp"
212 ];
213 dependsOn = [ "kasm_db_init" ];
214 extraOptions = [ "--network=kasm_default_network" "--userns=host" ];
215 };
216 kasm_manager = {
217 image = "kasmweb/manager:${pkgs.kasmweb.version}";
218 user = "root:root";
219 volumes = [
220 "${cfg.datastorePath}/:/opt/kasm/current/"
221 ];
222 dependsOn = [ "kasm_db" "kasm_api" ];
223 extraOptions = [ "--network=kasm_default_network" "--userns=host" "--read-only"];
224 };
225 kasm_agent = {
226 image = "kasmweb/agent:${pkgs.kasmweb.version}";
227 user = "root:root";
228 volumes = [
229 "${cfg.datastorePath}/:/opt/kasm/current/"
230 "/var/run/docker.sock:/var/run/docker.sock"
231 "${pkgs.docker}/bin/docker:/usr/bin/docker"
232 "${cfg.datastorePath}/conf/nginx:/etc/nginx/conf.d"
233 ];
234 dependsOn = [ "kasm_manager" ];
235 extraOptions = [ "--network=kasm_default_network" "--userns=host" "--read-only" ];
236 };
237 kasm_share = {
238 image = "kasmweb/share:${pkgs.kasmweb.version}";
239 user = "root:root";
240 volumes = [
241 "${cfg.datastorePath}/:/opt/kasm/current/"
242 ];
243 dependsOn = [ "kasm_db" "kasm_redis" ];
244 extraOptions = [ "--network=kasm_default_network" "--userns=host" "--read-only" ];
245 };
246 kasm_guac = {
247 image = "kasmweb/kasm-guac:${pkgs.kasmweb.version}";
248 user = "root:root";
249 volumes = [
250 "${cfg.datastorePath}/:/opt/kasm/current/"
251 ];
252 dependsOn = [ "kasm_db" "kasm_redis" ];
253 extraOptions = [ "--network=kasm_default_network" "--userns=host" "--read-only" ];
254 };
255 kasm_proxy = {
256 image = "kasmweb/nginx:latest";
257 ports = [ "${cfg.listenAddress}:${toString cfg.listenPort}:443" ];
258 user = "root:root";
259 volumes = [
260 "${cfg.datastorePath}/conf/nginx:/etc/nginx/conf.d:ro"
261 "${cfg.datastorePath}/certs/kasm_nginx.key:/etc/ssl/private/kasm_nginx.key"
262 "${cfg.datastorePath}/certs/kasm_nginx.crt:/etc/ssl/certs/kasm_nginx.crt"
263 "${cfg.datastorePath}/www:/srv/www:ro"
264 "${cfg.datastorePath}/log/nginx:/var/log/external/nginx"
265 "${cfg.datastorePath}/log/logrotate:/var/log/external/logrotate"
266 ];
267 dependsOn = [ "kasm_manager" "kasm_api" "kasm_agent" "kasm_share"
268 "kasm_guac" ];
269 extraOptions = [ "--network=kasm_default_network" "--userns=host"
270 "--network-alias=proxy"];
271 };
272 };
273 };
274 };
275}