A fork of attic a self-hostable Nix Binary Cache server
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #186 from zhaofengli/nixos-hardening

nixos: Apply changes from nixpkgs module

authored by

Zhaofeng Li and committed by
GitHub
48c8b395 b322faab

+150 -97
+2 -2
book/src/admin-guide/deployment/nixos.md
··· 41 41 services.atticd = { 42 42 enable = true; 43 43 44 - # Replace with absolute path to your credentials file 45 - credentialsFile = "/etc/atticd.env"; 44 + # Replace with absolute path to your environment file 45 + environmentFile = "/etc/atticd.env"; 46 46 47 47 settings = { 48 48 listen = "[::]:8080";
+5
crane.nix
··· 108 108 license = licenses.asl20; 109 109 maintainers = with maintainers; [ zhaofengli ]; 110 110 platforms = platforms.linux ++ platforms.darwin; 111 + mainProgram = "attic"; 111 112 }; 112 113 113 114 passthru = { ··· 147 148 148 149 CARGO_PROFILE_RELEASE_LTO = "fat"; 149 150 CARGO_PROFILE_RELEASE_CODEGEN_UNITS = "1"; 151 + 152 + meta = { 153 + mainProgram = "atticd"; 154 + }; 150 155 } // extraArgs); 151 156 152 157 # Attic interacts with Nix directly and its tests require trusted-user access
+1 -1
integration-tests/basic/default.nix
··· 152 152 153 153 services.atticd = { 154 154 enable = true; 155 - credentialsFile = "/etc/atticd.env"; 155 + environmentFile = "/etc/atticd.env"; 156 156 settings = { 157 157 listen = "[::]:8080"; 158 158
+141 -94
nixos/atticd.nix
··· 1 - { lib, pkgs, config, ... }: 1 + { 2 + lib, 3 + pkgs, 4 + config, 5 + ... 6 + }: 2 7 3 8 let 4 9 inherit (lib) types; ··· 11 16 12 17 format = pkgs.formats.toml { }; 13 18 14 - checkedConfigFile = pkgs.runCommand "checked-attic-server.toml" { 15 - configFile = cfg.configFile; 16 - } '' 17 - cat $configFile 19 + checkedConfigFile = 20 + pkgs.runCommand "checked-attic-server.toml" 21 + { 22 + configFile = cfg.configFile; 23 + } 24 + '' 25 + cat $configFile 18 26 19 - export ATTIC_SERVER_TOKEN_HS256_SECRET_BASE64="dGVzdCBzZWNyZXQ=" 20 - export ATTIC_SERVER_DATABASE_URL="sqlite://:memory:" 21 - ${cfg.package}/bin/atticd --mode check-config -f $configFile 22 - cat <$configFile >$out 23 - ''; 27 + export ATTIC_SERVER_TOKEN_HS256_SECRET_BASE64="dGVzdCBzZWNyZXQ=" 28 + export ATTIC_SERVER_DATABASE_URL="sqlite://:memory:" 29 + ${lib.getExe cfg.package} --mode check-config -f $configFile 30 + cat <$configFile >$out 31 + ''; 24 32 25 33 atticadmShim = pkgs.writeShellScript "atticadm" '' 26 34 if [ -n "$ATTICADM_PWD" ]; then ··· 42 50 --wait \ 43 51 --collect \ 44 52 --service-type=exec \ 45 - --property=EnvironmentFile=${cfg.credentialsFile} \ 53 + --property=EnvironmentFile=${cfg.environmentFile} \ 46 54 --property=DynamicUser=yes \ 47 55 --property=User=${cfg.user} \ 48 56 --property=Environment=ATTICADM_PWD=$(pwd) \ ··· 51 59 ${atticadmShim} "$@" 52 60 ''; 53 61 54 - hasLocalPostgresDB = let 55 - url = cfg.settings.database.url or ""; 56 - localStrings = [ "localhost" "127.0.0.1" "/run/postgresql" ]; 57 - hasLocalStrings = lib.any (lib.flip lib.hasInfix url) localStrings; 58 - in config.services.postgresql.enable && lib.hasPrefix "postgresql://" url && hasLocalStrings; 62 + hasLocalPostgresDB = 63 + let 64 + url = cfg.settings.database.url or ""; 65 + localStrings = [ 66 + "localhost" 67 + "127.0.0.1" 68 + "/run/postgresql" 69 + ]; 70 + hasLocalStrings = lib.any (lib.flip lib.hasInfix url) localStrings; 71 + in 72 + config.services.postgresql.enable && lib.hasPrefix "postgresql://" url && hasLocalStrings; 59 73 in 60 74 { 75 + imports = [ 76 + (lib.mkRenamedOptionModule [ "services" "atticd" "credentialsFile" ] [ "services" "atticd" "environmentFile" ]) 77 + ]; 78 + 61 79 options = { 62 80 services.atticd = { 63 - enable = lib.mkOption { 64 - description = '' 65 - Whether to enable the atticd, the Nix Binary Cache server. 66 - ''; 67 - type = types.bool; 68 - default = false; 69 - }; 70 - package = lib.mkOption { 71 - description = '' 72 - The package to use. 73 - ''; 74 - type = types.package; 75 - default = pkgs.attic-server; 76 - }; 77 - credentialsFile = lib.mkOption { 81 + enable = lib.mkEnableOption "the atticd, the Nix Binary Cache server"; 82 + 83 + package = lib.mkPackageOption pkgs "attic-server" { }; 84 + 85 + environmentFile = lib.mkOption { 78 86 description = '' 79 87 Path to an EnvironmentFile containing required environment 80 88 variables: ··· 85 93 type = types.nullOr types.path; 86 94 default = null; 87 95 }; 96 + 88 97 user = lib.mkOption { 89 98 description = '' 90 99 The group under which attic runs. ··· 92 101 type = types.str; 93 102 default = "atticd"; 94 103 }; 104 + 95 105 group = lib.mkOption { 96 106 description = '' 97 107 The user under which attic runs. ··· 99 109 type = types.str; 100 110 default = "atticd"; 101 111 }; 112 + 102 113 settings = lib.mkOption { 103 114 description = '' 104 115 Structured configurations of atticd. 105 116 ''; 106 117 type = format.type; 107 - default = {}; # setting defaults here does not compose well 118 + default = { }; # setting defaults here does not compose well 108 119 }; 120 + 109 121 configFile = lib.mkOption { 110 122 description = '' 111 123 Path to an existing atticd configuration file. ··· 131 143 132 144 There are several other supported modes that perform one-off operations, but these are the only ones that make sense to run via the NixOS module. 133 145 ''; 134 - type = lib.types.enum ["monolithic" "api-server" "garbage-collector"]; 146 + type = lib.types.enum [ 147 + "monolithic" 148 + "api-server" 149 + "garbage-collector" 150 + ]; 135 151 default = "monolithic"; 136 152 }; 137 153 ··· 146 162 }; 147 163 }; 148 164 }; 149 - config = lib.mkIf (cfg.enable) (lib.mkMerge [ 150 - { 151 - assertions = [ 152 - { 153 - assertion = cfg.credentialsFile != null; 154 - message = '' 155 - <option>services.atticd.credentialsFile</option> is not set. 165 + 166 + config = lib.mkIf cfg.enable { 167 + assertions = [ 168 + { 169 + assertion = cfg.environmentFile != null; 170 + message = '' 171 + <option>services.atticd.environmentFile</option> is not set. 156 172 157 - Run `openssl genrsa -traditional -out private_key.pem 4096 | base64 -w0` and create a file with the following contents: 173 + Run `openssl genrsa -traditional -out private_key.pem 4096 | base64 -w0` and create a file with the following contents: 158 174 159 - ATTIC_SERVER_TOKEN_RS256_SECRET="output from command" 175 + ATTIC_SERVER_TOKEN_RS256_SECRET="output from command" 160 176 161 - Then, set `services.atticd.credentialsFile` to the quoted absolute path of the file. 162 - ''; 163 - } 164 - { 165 - assertion = !lib.isStorePath cfg.credentialsFile; 166 - message = '' 167 - <option>services.atticd.credentialsFile</option> points to a path in the Nix store. The Nix store is globally readable. 177 + Then, set `services.atticd.environmentFile` to the quoted absolute path of the file. 178 + ''; 179 + } 180 + { 181 + assertion = !lib.isStorePath cfg.environmentFile; 182 + message = '' 183 + <option>services.atticd.environmentFile</option> points to a path in the Nix store. The Nix store is globally readable. 168 184 169 - You should use a quoted absolute path to prevent this. 170 - ''; 171 - } 172 - ]; 185 + You should use a quoted absolute path to prevent leaking secrets in the Nix store. 186 + ''; 187 + } 188 + ]; 173 189 174 - services.atticd.settings = { 175 - database.url = lib.mkDefault "sqlite:///var/lib/atticd/server.db?mode=rwc"; 190 + services.atticd.settings = { 191 + database.url = lib.mkDefault "sqlite:///var/lib/atticd/server.db?mode=rwc"; 176 192 177 - # "storage" is internally tagged 178 - # if the user sets something the whole thing must be replaced 179 - storage = lib.mkDefault { 180 - type = "local"; 181 - path = "/var/lib/atticd/storage"; 182 - }; 193 + # "storage" is internally tagged 194 + # if the user sets something the whole thing must be replaced 195 + storage = lib.mkDefault { 196 + type = "local"; 197 + path = "/var/lib/atticd/storage"; 183 198 }; 199 + }; 184 200 185 - systemd.services.atticd = { 186 - wantedBy = [ "multi-user.target" ]; 187 - after = [ "network.target" ] 188 - ++ lib.optionals hasLocalPostgresDB [ "postgresql.service" "nss-lookup.target" ]; 189 - serviceConfig = { 190 - ExecStart = "${cfg.package}/bin/atticd -f ${checkedConfigFile} --mode ${cfg.mode}"; 191 - EnvironmentFile = cfg.credentialsFile; 192 - StateDirectory = "atticd"; # for usage with local storage and sqlite 193 - DynamicUser = true; 194 - User = cfg.user; 195 - Group = cfg.group; 196 - ProtectHome = true; 197 - ProtectHostname = true; 198 - ProtectKernelLogs = true; 199 - ProtectKernelModules = true; 200 - ProtectKernelTunables = true; 201 - ProtectProc = "invisible"; 202 - ProtectSystem = "strict"; 203 - Restart = "on-failure"; 204 - RestartSec = 10; 205 - RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ]; 206 - RestrictNamespaces = true; 207 - RestrictRealtime = true; 208 - RestrictSUIDSGID = true; 209 - ReadWritePaths = let 201 + systemd.services.atticd = { 202 + wantedBy = [ "multi-user.target" ]; 203 + after = [ "network-online.target" ] ++ lib.optionals hasLocalPostgresDB [ "postgresql.service" ]; 204 + requires = lib.optionals hasLocalPostgresDB [ "postgresql.service" ]; 205 + wants = [ "network-online.target" ]; 206 + 207 + serviceConfig = { 208 + ExecStart = "${lib.getExe cfg.package} -f ${checkedConfigFile} --mode ${cfg.mode}"; 209 + EnvironmentFile = cfg.environmentFile; 210 + StateDirectory = "atticd"; # for usage with local storage and sqlite 211 + DynamicUser = true; 212 + User = cfg.user; 213 + Group = cfg.group; 214 + Restart = "on-failure"; 215 + RestartSec = 10; 216 + 217 + CapabilityBoundingSet = [ "" ]; 218 + DeviceAllow = ""; 219 + DevicePolicy = "closed"; 220 + LockPersonality = true; 221 + MemoryDenyWriteExecute = true; 222 + NoNewPrivileges = true; 223 + PrivateDevices = true; 224 + PrivateTmp = true; 225 + PrivateUsers = true; 226 + ProcSubset = "pid"; 227 + ProtectClock = true; 228 + ProtectControlGroups = true; 229 + ProtectHome = true; 230 + ProtectHostname = true; 231 + ProtectKernelLogs = true; 232 + ProtectKernelModules = true; 233 + ProtectKernelTunables = true; 234 + ProtectProc = "invisible"; 235 + ProtectSystem = "strict"; 236 + ReadWritePaths = 237 + let 210 238 path = cfg.settings.storage.path; 211 239 isDefaultStateDirectory = path == "/var/lib/atticd" || lib.hasPrefix "/var/lib/atticd/" path; 212 - in lib.optionals (cfg.settings.storage.type or "" == "local" && !isDefaultStateDirectory) [ path ]; 213 - }; 240 + in 241 + lib.optionals (cfg.settings.storage.type or "" == "local" && !isDefaultStateDirectory) [ path ]; 242 + RemoveIPC = true; 243 + RestrictAddressFamilies = [ 244 + "AF_INET" 245 + "AF_INET6" 246 + "AF_UNIX" 247 + ]; 248 + RestrictNamespaces = true; 249 + RestrictRealtime = true; 250 + RestrictSUIDSGID = true; 251 + SystemCallArchitectures = "native"; 252 + SystemCallFilter = [ 253 + "@system-service" 254 + "~@resources" 255 + "~@privileged" 256 + ]; 257 + UMask = "0077"; 214 258 }; 259 + }; 215 260 216 - environment.systemPackages = [ atticadmWrapper ]; 217 - } 218 - (lib.mkIf cfg.useFlakeCompatOverlay { 219 - nixpkgs.overlays = [ overlay ]; 220 - }) 221 - ]); 261 + environment.systemPackages = [ 262 + atticadmWrapper 263 + ]; 264 + 265 + nixpkgs.overlays = lib.mkIf cfg.useFlakeCompatOverlay [ 266 + overlay 267 + ]; 268 + }; 222 269 }
+1
package.nix
··· 70 70 license = licenses.asl20; 71 71 maintainers = with maintainers; [ zhaofengli ]; 72 72 platforms = platforms.linux ++ platforms.darwin; 73 + mainProgram = "attic"; 73 74 }; 74 75 }