-
Notifications
You must be signed in to change notification settings - Fork 0
/
gitea.nix
143 lines (116 loc) · 4.4 KB
/
gitea.nix
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# This module deploys Gitea.
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.my.services.gitea;
internalListenPort = 17610;
ldapOptions = let
inherit (config.my) ldap;
in {
name = "auto-ldap";
security-protocol = "LDAPS";
host = ldap.domainName;
port = "636"; # LDAPS
user-search-base = "ou=users,${ldap.suffix}";
user-filter = "(&(uid=%s)(isMemberOf=cn=gitea-users,ou=groups,${ldap.suffix}))";
admin-filter = "(isMemberOf=cn=gitea-admins,ou=groups,${ldap.suffix})";
username-attribute = "uid";
firstname-attribute = "givenName";
surname-attribute = "sn";
email-attribute = "mail";
bind-dn = "uid=${ldap.searchUserName},ou=users,${ldap.suffix}";
bind-password = ldap.searchUserPassword;
};
ldapFlags = "--attributes-in-bind --synchronize-users";
in {
options.my.services.gitea = {
domainName = mkOption {
default = null;
description = "domain name for Gitea (must be given to enable the service)";
type = types.nullOr types.str;
};
appName = mkOption {
default = config.services.gitea.domainName;
description = "site name";
type = types.str;
};
};
config = mkIf (cfg.domainName != null) {
services.gitea = {
enable = true;
appName = cfg.appName;
settings = {
server = {
DOMAIN = cfg.domainName;
ROOT_URL = "https://${cfg.domainName}/";
HTTP_ADDR = "127.0.0.1";
HTTP_PORT = internalListenPort;
};
# NOTE: default log mode is "console" since Gitea 1.9
log.LEVEL = "Info";
"repository.upload" = {
ENABLED = false;
};
# reject insecure keys
"ssh.minimum_key_sizes" = {
DSA = -1;
ECDSA = -1;
ED25519 = 256;
RSA = 4095;
};
"service" = {
DISABLE_REGISTRATION = true;
REQUIRE_SIGNIN_VIEW = true;
};
"picture" = {
DISABLE_GRAVATAR = true;
};
"api" = {
ENABLE_SWAGGER = false;
};
"oauth2" = {
ENABLE = false;
};
# enable user sync job for LDAP
"cron.sync_external_users" = {
RUN_AT_START = true;
SCHEDULE = "@every 1h";
UPDATE_EXISTING = true;
};
};
};
# LDAP authentication cannot be set up declaratively, so we have to do it
# at the end of the preStart script
#
# WARNING: This assumes that the LDAP auth source has the internal ID 1.
systemd.services.gitea.preStart = let
giteaBin = "${pkgs.gitea}/bin/gitea";
formatOption = key: value: "--${key} ${escapeShellArg value}";
ldapOptionsStrs = mapAttrsToList formatOption ldapOptions;
ldapOptionsStr = concatStringsSep " " ldapOptionsStrs;
in mkAfter ''
if ${giteaBin} admin auth list | grep -q ${ldapOptions.name}; then
${giteaBin} admin auth update-ldap --id 1 ${ldapOptionsStr} ${ldapFlags}
else
${giteaBin} admin auth add-ldap ${ldapOptionsStr} ${ldapFlags}
fi
'';
services.nginx.virtualHosts.${cfg.domainName} = {
forceSSL = true;
enableACME = true;
locations."/".proxyPass = "http://127.0.0.1:${toString internalListenPort}/";
extraConfig = ''
# recommended HTTP headers according to https://securityheaders.io
# NOTE: Gitea already does X-Frame-Options, so we don't need to
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains" always; # six months
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer" always;
add_header Feature-Policy "accelerometer 'none', ambient-light-sensor 'none', autoplay 'none', camera 'none', document-domain 'none', encrypted-media 'none', fullscreen 'none', geolocation 'none', gyroscope 'none', magnetometer 'none', microphone 'none', midi 'none', payment 'none', picture-in-picture 'none', sync-xhr 'none', usb 'none', vibrate 'none', vr 'none'" always;
add_header Content-Security-Policy "default-src 'self' data:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'" always; # Gitea uses inline CSS (ok), inline fonts via data: (well...) and inline JS (shame on you)
# hamper Google surveillance
add_header Permissions-Policy "interest-cohort=()" always;
'';
};
};
}