blob: e9195fbd5160890a673422771cb55f515fc9e9b4 (
plain) (
blame)
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
|
{ 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;
defaultText = lib.literalExpression "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` overrides {option}`services.step-ca.settings.address`.
'';
};
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` overrides {option}`services.step-ca.settings.address`.
'';
};
settings = lib.mkOption {
type = with lib.types; attrsOf anything;
description = ''
Settings that go into {file}`ca.json`. See
[the step-ca manual](https://smallstep.com/docs/step-ca/configuration)
for more information. The easiest way to
configure this module would be to run `step ca init`
to generate {file}`ca.json` and then import it using
`builtins.fromJSON`.
[This article](https://smallstep.com/docs/step-cli/basic-crypto-operations#run-an-offline-x509-certificate-authority)
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 {file}`/var/lib/step-ca/db`.
::: {.warning}
The {option}`services.step-ca.settings.address` option
will be ignored and overwritten by
{option}`services.step-ca.address` and
{option}`services.step-ca.port`.
:::
'';
};
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}
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.
:::
'';
};
};
};
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 = {
User = "step-ca";
Group = "step-ca";
UMask = "0077";
Environment = "HOME=%S/step-ca";
WorkingDirectory = ""; # override upstream
ReadWritePaths = ""; # 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 yet
# PrivateUsers = true; # doesn't work with privileged ports therefore not supported by upstream
DynamicUser = true;
StateDirectory = "step-ca";
};
};
users.users.step-ca = {
home = "/var/lib/step-ca";
group = "step-ca";
isSystemUser = true;
};
users.groups.step-ca = {};
networking.firewall = lib.mkIf cfg.openFirewall {
allowedTCPPorts = [ cfg.port ];
};
}
);
}
|