Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos/step-ca: Declarative step-ca service #112322

Merged
merged 6 commits into from
Apr 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions maintainers/maintainer-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6477,6 +6477,16 @@
githubId = 754512;
name = "Mogria";
};
mohe2015 = {
SuperSandro2000 marked this conversation as resolved.
Show resolved Hide resolved
name = "Moritz Hedtke";
email = "[email protected]";
github = "mohe2015";
githubId = 13287984;
keys = [{
longkeyid = "rsa4096/0x6794D45A488C2EDE";
fingerprint = "1248 D3E1 1D11 4A85 75C9 8934 6794 D45A 488C 2EDE";
}];
};
monsieurp = {
email = "[email protected]";
github = "monsieurp";
Expand Down
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,7 @@
./services/security/shibboleth-sp.nix
./services/security/sks.nix
./services/security/sshguard.nix
./services/security/step-ca.nix
./services/security/tor.nix
./services/security/torify.nix
./services/security/torsocks.nix
Expand Down
134 changes: 134 additions & 0 deletions nixos/modules/services/security/step-ca.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.step-ca;
settingsFormat = (pkgs.formats.json { });
in
{
meta.maintainers = with lib.maintainers; [ mohe2015 ];

options = {
services.step-ca = {
enable = lib.mkEnableOption "the smallstep certificate authority server";
openFirewall = lib.mkEnableOption "opening the certificate authority server port";
package = lib.mkOption {
type = lib.types.package;
default = pkgs.step-ca;
description = "Which step-ca package to use.";
};
address = lib.mkOption {
type = lib.types.str;
example = "127.0.0.1";
description = ''
The address (without port) the certificate authority should listen at.
This combined with <option>services.step-ca.port</option> overrides <option>services.step-ca.settings.address</option>.
'';
};
port = lib.mkOption {
type = lib.types.port;
example = 8443;
description = ''
The port the certificate authority should listen on.
This combined with <option>services.step-ca.address</option> overrides <option>services.step-ca.settings.address</option>.
'';
};
settings = lib.mkOption {
type = with lib.types; attrsOf anything;
description = ''
Settings that go into <filename>ca.json</filename>. See
<link xlink:href="https://smallstep.com/docs/step-ca/configuration">
the step-ca manual</link> for more information. The easiest way to
configure this module would be to run <literal>step ca init</literal>
to generate <filename>ca.json</filename> and then import it using
<literal>builtins.fromJSON</literal>.
<link xlink:href="https://smallstep.com/docs/step-cli/basic-crypto-operations#run-an-offline-x509-certificate-authority">This article</link>
may also be useful if you want to customize certain aspects of
certificate generation for your CA.
You need to change the database storage path to <filename>/var/lib/step-ca/db</filename>.

<warning>
<para>
The <option>services.step-ca.settings.address</option> option
will be ignored and overwritten by
<option>services.step-ca.address</option> and
<option>services.step-ca.port</option>.
</para>
</warning>
'';
};
intermediatePasswordFile = lib.mkOption {
type = lib.types.path;
example = "/run/keys/smallstep-password";
description = ''
Path to the file containing the password for the intermediate
certificate private key.

<warning>
<para>
Make sure to use a quoted absolute path instead of a path literal
to prevent it from being copied to the globally readable Nix
store.
</para>
</warning>
'';
};
};
};

config = lib.mkIf config.services.step-ca.enable (
let
configFile = settingsFormat.generate "ca.json" (cfg.settings // {
address = cfg.address + ":" + toString cfg.port;
});
in
{
assertions =
[
{
assertion = !lib.isStorePath cfg.intermediatePasswordFile;
message = ''
<option>services.step-ca.intermediatePasswordFile</option> points to
a file in the Nix store. You should use a quoted absolute path to
prevent this.
'';
}
];

systemd.packages = [ cfg.package ];

# configuration file indirection is needed to support reloading
environment.etc."smallstep/ca.json".source = configFile;

systemd.services."step-ca" = {
wantedBy = [ "multi-user.target" ];
restartTriggers = [ configFile ];
unitConfig = {
ConditionFileNotEmpty = ""; # override upstream
};
serviceConfig = {
Environment = "HOME=%S/step-ca";
WorkingDirectory = ""; # override upstream
ReadWriteDirectories = ""; # override upstream

# LocalCredential handles file permission problems arising from the use of DynamicUser.
LoadCredential = "intermediate_password:${cfg.intermediatePasswordFile}";

ExecStart = [
"" # override upstream
"${cfg.package}/bin/step-ca /etc/smallstep/ca.json --password-file \${CREDENTIALS_DIRECTORY}/intermediate_password"
];

# ProtectProc = "invisible"; # not supported by upstream yet
# ProcSubset = "pid"; # not supported by upstream upstream yet
# PrivateUsers = true; # doesn't work with privileged ports therefore not supported by upstream

DynamicUser = true;
StateDirectory = "step-ca";
};
};

networking.firewall = lib.mkIf cfg.openFirewall {
allowedTCPPorts = [ cfg.port ];
};
}
);
}
28 changes: 21 additions & 7 deletions pkgs/tools/security/step-ca/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,43 @@
, lib
, fetchFromGitHub
, buildGoModule
, coreutils
, pcsclite
, PCSC
, pkg-config
, hsmSupport ? true
}:

buildGoModule rec {
pname = "step-ca";
version = "0.15.6";
version = "0.15.11";

src = fetchFromGitHub {
owner = "smallstep";
repo = "certificates";
rev = "v${version}";
sha256 = "0n26692ph4q4cmrqammfazmx1k9p2bydwqc57q4hz5ni6jd31zbz";
sha256 = "wFRs3n6V0z2keNVtqFw1q5jpA6BvNK5EftsNhichfsY=";
};

vendorSha256 = "0w0phyqymcg2h2jjasxmkf4ryn4y1bqahcy94rs738cqr5ifyfbg";
vendorSha256 = "f1NdszqYYx6X1HqwqG26jjfjXq1gDXLOrh64ccKRQ90=";

nativeBuildInputs = [ pkg-config ];
nativeBuildInputs = lib.optionals hsmSupport [ pkg-config ];

buildInputs =
lib.optional stdenv.isLinux (lib.getDev pcsclite)
++ lib.optional stdenv.isDarwin PCSC;
lib.optionals (hsmSupport && stdenv.isLinux) [ pcsclite ]
++ lib.optionals (hsmSupport && stdenv.isDarwin) [ PCSC ];

postPatch = ''
substituteInPlace systemd/step-ca.service --replace "/bin/kill" "${coreutils}/bin/kill"
'';

preBuild = ''
${lib.optionalString (!hsmSupport) "export CGO_ENABLED=0"}
'';

postInstall = ''
install -Dm444 -t $out/lib/systemd/system systemd/step-ca.service
'';

# Tests fail on darwin with
# panic: httptest: failed to listen on a port: listen tcp6 [::1]:0: bind: operation not permitted [recovered]
Expand All @@ -35,7 +49,7 @@ buildGoModule rec {
description = "A private certificate authority (X.509 & SSH) & ACME server for secure automated certificate management, so you can use TLS everywhere & SSO for SSH";
homepage = "https://smallstep.com/certificates/";
license = licenses.asl20;
maintainers = with maintainers; [ cmcdragonkai ];
maintainers = with maintainers; [ cmcdragonkai mohe2015 ];
platforms = platforms.linux ++ platforms.darwin;
};
}