diff --git a/book/src/admin-guide/deployment/nixos.md b/book/src/admin-guide/deployment/nixos.md
index b30f7de..53ad032 100644
--- a/book/src/admin-guide/deployment/nixos.md
+++ b/book/src/admin-guide/deployment/nixos.md
@@ -41,8 +41,8 @@ You can import the module in one of two ways:
services.atticd = {
enable = true;
- # Replace with absolute path to your credentials file
- credentialsFile = "/etc/atticd.env";
+ # Replace with absolute path to your environment file
+ environmentFile = "/etc/atticd.env";
settings = {
listen = "[::]:8080";
diff --git a/crane.nix b/crane.nix
index f7abf6e..fba29a5 100644
--- a/crane.nix
+++ b/crane.nix
@@ -108,6 +108,7 @@ let
license = licenses.asl20;
maintainers = with maintainers; [ zhaofengli ];
platforms = platforms.linux ++ platforms.darwin;
+ mainProgram = "attic";
};
passthru = {
@@ -147,6 +148,10 @@ let
CARGO_PROFILE_RELEASE_LTO = "fat";
CARGO_PROFILE_RELEASE_CODEGEN_UNITS = "1";
+
+ meta = {
+ mainProgram = "atticd";
+ };
} // extraArgs);
# Attic interacts with Nix directly and its tests require trusted-user access
diff --git a/integration-tests/basic/default.nix b/integration-tests/basic/default.nix
index f54b467..9b63cdc 100644
--- a/integration-tests/basic/default.nix
+++ b/integration-tests/basic/default.nix
@@ -152,7 +152,7 @@ in {
services.atticd = {
enable = true;
- credentialsFile = "/etc/atticd.env";
+ environmentFile = "/etc/atticd.env";
settings = {
listen = "[::]:8080";
diff --git a/nixos/atticd.nix b/nixos/atticd.nix
index cfd3c42..dd57b56 100644
--- a/nixos/atticd.nix
+++ b/nixos/atticd.nix
@@ -1,4 +1,9 @@
-{ lib, pkgs, config, ... }:
+{
+ lib,
+ pkgs,
+ config,
+ ...
+}:
let
inherit (lib) types;
@@ -11,16 +16,19 @@ let
format = pkgs.formats.toml { };
- checkedConfigFile = pkgs.runCommand "checked-attic-server.toml" {
- configFile = cfg.configFile;
- } ''
- cat $configFile
+ checkedConfigFile =
+ pkgs.runCommand "checked-attic-server.toml"
+ {
+ configFile = cfg.configFile;
+ }
+ ''
+ cat $configFile
- export ATTIC_SERVER_TOKEN_HS256_SECRET_BASE64="dGVzdCBzZWNyZXQ="
- export ATTIC_SERVER_DATABASE_URL="sqlite://:memory:"
- ${cfg.package}/bin/atticd --mode check-config -f $configFile
- cat <$configFile >$out
- '';
+ export ATTIC_SERVER_TOKEN_HS256_SECRET_BASE64="dGVzdCBzZWNyZXQ="
+ export ATTIC_SERVER_DATABASE_URL="sqlite://:memory:"
+ ${lib.getExe cfg.package} --mode check-config -f $configFile
+ cat <$configFile >$out
+ '';
atticadmShim = pkgs.writeShellScript "atticadm" ''
if [ -n "$ATTICADM_PWD" ]; then
@@ -42,7 +50,7 @@ let
--wait \
--collect \
--service-type=exec \
- --property=EnvironmentFile=${cfg.credentialsFile} \
+ --property=EnvironmentFile=${cfg.environmentFile} \
--property=DynamicUser=yes \
--property=User=${cfg.user} \
--property=Environment=ATTICADM_PWD=$(pwd) \
@@ -51,30 +59,30 @@ let
${atticadmShim} "$@"
'';
- hasLocalPostgresDB = let
- url = cfg.settings.database.url or "";
- localStrings = [ "localhost" "127.0.0.1" "/run/postgresql" ];
- hasLocalStrings = lib.any (lib.flip lib.hasInfix url) localStrings;
- in config.services.postgresql.enable && lib.hasPrefix "postgresql://" url && hasLocalStrings;
+ hasLocalPostgresDB =
+ let
+ url = cfg.settings.database.url or "";
+ localStrings = [
+ "localhost"
+ "127.0.0.1"
+ "/run/postgresql"
+ ];
+ hasLocalStrings = lib.any (lib.flip lib.hasInfix url) localStrings;
+ in
+ config.services.postgresql.enable && lib.hasPrefix "postgresql://" url && hasLocalStrings;
in
{
+ imports = [
+ (lib.mkRenamedOptionModule [ "services" "atticd" "credentialsFile" ] [ "services" "atticd" "environmentFile" ])
+ ];
+
options = {
services.atticd = {
- enable = lib.mkOption {
- description = ''
- Whether to enable the atticd, the Nix Binary Cache server.
- '';
- type = types.bool;
- default = false;
- };
- package = lib.mkOption {
- description = ''
- The package to use.
- '';
- type = types.package;
- default = pkgs.attic-server;
- };
- credentialsFile = lib.mkOption {
+ enable = lib.mkEnableOption "the atticd, the Nix Binary Cache server";
+
+ package = lib.mkPackageOption pkgs "attic-server" { };
+
+ environmentFile = lib.mkOption {
description = ''
Path to an EnvironmentFile containing required environment
variables:
@@ -85,6 +93,7 @@ in
type = types.nullOr types.path;
default = null;
};
+
user = lib.mkOption {
description = ''
The group under which attic runs.
@@ -92,6 +101,7 @@ in
type = types.str;
default = "atticd";
};
+
group = lib.mkOption {
description = ''
The user under which attic runs.
@@ -99,13 +109,15 @@ in
type = types.str;
default = "atticd";
};
+
settings = lib.mkOption {
description = ''
Structured configurations of atticd.
'';
type = format.type;
- default = {}; # setting defaults here does not compose well
+ default = { }; # setting defaults here does not compose well
};
+
configFile = lib.mkOption {
description = ''
Path to an existing atticd configuration file.
@@ -131,7 +143,11 @@ in
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.
'';
- type = lib.types.enum ["monolithic" "api-server" "garbage-collector"];
+ type = lib.types.enum [
+ "monolithic"
+ "api-server"
+ "garbage-collector"
+ ];
default = "monolithic";
};
@@ -146,77 +162,108 @@ in
};
};
};
- config = lib.mkIf (cfg.enable) (lib.mkMerge [
- {
- assertions = [
- {
- assertion = cfg.credentialsFile != null;
- message = ''
- is not set.
-
- Run `openssl genrsa -traditional -out private_key.pem 4096 | base64 -w0` and create a file with the following contents:
-
- ATTIC_SERVER_TOKEN_RS256_SECRET="output from command"
-
- Then, set `services.atticd.credentialsFile` to the quoted absolute path of the file.
- '';
- }
- {
- assertion = !lib.isStorePath cfg.credentialsFile;
- message = ''
- points to a path in the Nix store. The Nix store is globally readable.
-
- You should use a quoted absolute path to prevent this.
- '';
- }
- ];
- services.atticd.settings = {
- database.url = lib.mkDefault "sqlite:///var/lib/atticd/server.db?mode=rwc";
+ config = lib.mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = cfg.environmentFile != null;
+ message = ''
+ is not set.
+
+ Run `openssl genrsa -traditional -out private_key.pem 4096 | base64 -w0` and create a file with the following contents:
+
+ ATTIC_SERVER_TOKEN_RS256_SECRET="output from command"
+
+ Then, set `services.atticd.environmentFile` to the quoted absolute path of the file.
+ '';
+ }
+ {
+ assertion = !lib.isStorePath cfg.environmentFile;
+ message = ''
+ points to a path in the Nix store. The Nix store is globally readable.
+
+ You should use a quoted absolute path to prevent leaking secrets in the Nix store.
+ '';
+ }
+ ];
- # "storage" is internally tagged
- # if the user sets something the whole thing must be replaced
- storage = lib.mkDefault {
- type = "local";
- path = "/var/lib/atticd/storage";
- };
+ services.atticd.settings = {
+ database.url = lib.mkDefault "sqlite:///var/lib/atticd/server.db?mode=rwc";
+
+ # "storage" is internally tagged
+ # if the user sets something the whole thing must be replaced
+ storage = lib.mkDefault {
+ type = "local";
+ path = "/var/lib/atticd/storage";
};
+ };
+
+ systemd.services.atticd = {
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network-online.target" ] ++ lib.optionals hasLocalPostgresDB [ "postgresql.service" ];
+ requires = lib.optionals hasLocalPostgresDB [ "postgresql.service" ];
+ wants = [ "network-online.target" ];
+
+ serviceConfig = {
+ ExecStart = "${lib.getExe cfg.package} -f ${checkedConfigFile} --mode ${cfg.mode}";
+ EnvironmentFile = cfg.environmentFile;
+ StateDirectory = "atticd"; # for usage with local storage and sqlite
+ DynamicUser = true;
+ User = cfg.user;
+ Group = cfg.group;
+ Restart = "on-failure";
+ RestartSec = 10;
- systemd.services.atticd = {
- wantedBy = [ "multi-user.target" ];
- after = [ "network.target" ]
- ++ lib.optionals hasLocalPostgresDB [ "postgresql.service" "nss-lookup.target" ];
- serviceConfig = {
- ExecStart = "${cfg.package}/bin/atticd -f ${checkedConfigFile} --mode ${cfg.mode}";
- EnvironmentFile = cfg.credentialsFile;
- StateDirectory = "atticd"; # for usage with local storage and sqlite
- DynamicUser = true;
- User = cfg.user;
- Group = cfg.group;
- ProtectHome = true;
- ProtectHostname = true;
- ProtectKernelLogs = true;
- ProtectKernelModules = true;
- ProtectKernelTunables = true;
- ProtectProc = "invisible";
- ProtectSystem = "strict";
- Restart = "on-failure";
- RestartSec = 10;
- RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
- RestrictNamespaces = true;
- RestrictRealtime = true;
- RestrictSUIDSGID = true;
- ReadWritePaths = let
+ CapabilityBoundingSet = [ "" ];
+ DeviceAllow = "";
+ DevicePolicy = "closed";
+ LockPersonality = true;
+ MemoryDenyWriteExecute = true;
+ NoNewPrivileges = true;
+ PrivateDevices = true;
+ PrivateTmp = true;
+ PrivateUsers = true;
+ ProcSubset = "pid";
+ ProtectClock = true;
+ ProtectControlGroups = true;
+ ProtectHome = true;
+ ProtectHostname = true;
+ ProtectKernelLogs = true;
+ ProtectKernelModules = true;
+ ProtectKernelTunables = true;
+ ProtectProc = "invisible";
+ ProtectSystem = "strict";
+ ReadWritePaths =
+ let
path = cfg.settings.storage.path;
isDefaultStateDirectory = path == "/var/lib/atticd" || lib.hasPrefix "/var/lib/atticd/" path;
- in lib.optionals (cfg.settings.storage.type or "" == "local" && !isDefaultStateDirectory) [ path ];
- };
+ in
+ lib.optionals (cfg.settings.storage.type or "" == "local" && !isDefaultStateDirectory) [ path ];
+ RemoveIPC = true;
+ RestrictAddressFamilies = [
+ "AF_INET"
+ "AF_INET6"
+ "AF_UNIX"
+ ];
+ RestrictNamespaces = true;
+ RestrictRealtime = true;
+ RestrictSUIDSGID = true;
+ SystemCallArchitectures = "native";
+ SystemCallFilter = [
+ "@system-service"
+ "~@resources"
+ "~@privileged"
+ ];
+ UMask = "0077";
};
+ };
+
+ environment.systemPackages = [
+ atticadmWrapper
+ ];
- environment.systemPackages = [ atticadmWrapper ];
- }
- (lib.mkIf cfg.useFlakeCompatOverlay {
- nixpkgs.overlays = [ overlay ];
- })
- ]);
+ nixpkgs.overlays = lib.mkIf cfg.useFlakeCompatOverlay [
+ overlay
+ ];
+ };
}
diff --git a/package.nix b/package.nix
index e40c765..1614316 100644
--- a/package.nix
+++ b/package.nix
@@ -70,5 +70,6 @@ in rustPlatform.buildRustPackage rec {
license = licenses.asl20;
maintainers = with maintainers; [ zhaofengli ];
platforms = platforms.linux ++ platforms.darwin;
+ mainProgram = "attic";
};
}