1 { config, lib, options, pkgs, ... }:
3 cfg = config.services.etcd;
4 opt = options.services.etcd;
8 options.services.etcd = {
9 enable = lib.mkOption {
10 description = "Whether to enable etcd.";
12 type = lib.types.bool;
15 package = lib.mkPackageOption pkgs "etcd" { };
18 description = "Etcd unique node name.";
19 default = config.networking.hostName;
20 defaultText = lib.literalExpression "config.networking.hostName";
24 advertiseClientUrls = lib.mkOption {
25 description = "Etcd list of this member's client URLs to advertise to the rest of the cluster.";
26 default = cfg.listenClientUrls;
27 defaultText = lib.literalExpression "config.${opt.listenClientUrls}";
28 type = lib.types.listOf lib.types.str;
31 listenClientUrls = lib.mkOption {
32 description = "Etcd list of URLs to listen on for client traffic.";
33 default = ["http://127.0.0.1:2379"];
34 type = lib.types.listOf lib.types.str;
37 listenPeerUrls = lib.mkOption {
38 description = "Etcd list of URLs to listen on for peer traffic.";
39 default = ["http://127.0.0.1:2380"];
40 type = lib.types.listOf lib.types.str;
43 initialAdvertisePeerUrls = lib.mkOption {
44 description = "Etcd list of this member's peer URLs to advertise to rest of the cluster.";
45 default = cfg.listenPeerUrls;
46 defaultText = lib.literalExpression "config.${opt.listenPeerUrls}";
47 type = lib.types.listOf lib.types.str;
50 initialCluster = lib.mkOption {
51 description = "Etcd initial cluster configuration for bootstrapping.";
52 default = ["${cfg.name}=http://127.0.0.1:2380"];
53 defaultText = lib.literalExpression ''["''${config.${opt.name}}=http://127.0.0.1:2380"]'';
54 type = lib.types.listOf lib.types.str;
57 initialClusterState = lib.mkOption {
58 description = "Etcd initial cluster configuration for bootstrapping.";
60 type = lib.types.enum ["new" "existing"];
63 initialClusterToken = lib.mkOption {
64 description = "Etcd initial cluster token for etcd cluster during bootstrap.";
65 default = "etcd-cluster";
69 discovery = lib.mkOption {
70 description = "Etcd discovery url";
75 clientCertAuth = lib.mkOption {
76 description = "Whether to use certs for client authentication";
78 type = lib.types.bool;
81 trustedCaFile = lib.mkOption {
82 description = "Certificate authority file to use for clients";
84 type = lib.types.nullOr lib.types.path;
87 certFile = lib.mkOption {
88 description = "Cert file to use for clients";
90 type = lib.types.nullOr lib.types.path;
93 keyFile = lib.mkOption {
94 description = "Key file to use for clients";
96 type = lib.types.nullOr lib.types.path;
99 openFirewall = lib.mkOption {
100 type = lib.types.bool;
103 Open etcd ports in the firewall.
105 - 2379/tcp for client requests
106 - 2380/tcp for peer communication
110 peerCertFile = lib.mkOption {
111 description = "Cert file to use for peer to peer communication";
112 default = cfg.certFile;
113 defaultText = lib.literalExpression "config.${opt.certFile}";
114 type = lib.types.nullOr lib.types.path;
117 peerKeyFile = lib.mkOption {
118 description = "Key file to use for peer to peer communication";
119 default = cfg.keyFile;
120 defaultText = lib.literalExpression "config.${opt.keyFile}";
121 type = lib.types.nullOr lib.types.path;
124 peerTrustedCaFile = lib.mkOption {
125 description = "Certificate authority file to use for peer to peer communication";
126 default = cfg.trustedCaFile;
127 defaultText = lib.literalExpression "config.${opt.trustedCaFile}";
128 type = lib.types.nullOr lib.types.path;
131 peerClientCertAuth = lib.mkOption {
132 description = "Whether to check all incoming peer requests from the cluster for valid client certificates signed by the supplied CA";
134 type = lib.types.bool;
137 extraConf = lib.mkOption {
139 Etcd extra configuration. See
140 <https://github.com/coreos/etcd/blob/master/Documentation/op-guide/configuration.md#configuration-flags>
142 type = lib.types.attrsOf lib.types.str;
144 example = lib.literalExpression ''
147 "NAME" = "default-name";
148 "MAX_RESULT_BUFFER" = "1024";
149 "MAX_CLUSTER_SIZE" = "9";
150 "MAX_RETRY_ATTEMPTS" = "3";
155 dataDir = lib.mkOption {
156 type = lib.types.path;
157 default = "/var/lib/etcd";
158 description = "Etcd data directory.";
162 config = lib.mkIf cfg.enable {
163 systemd.tmpfiles.settings."10-etcd".${cfg.dataDir}.d = {
168 systemd.services.etcd = {
169 description = "etcd key-value store";
170 wantedBy = [ "multi-user.target" ];
171 after = [ "network-online.target" ]
172 ++ lib.optional config.networking.firewall.enable "firewall.service";
173 wants = [ "network-online.target" ]
174 ++ lib.optional config.networking.firewall.enable "firewall.service";
176 environment = (lib.filterAttrs (n: v: v != null) {
177 ETCD_NAME = cfg.name;
178 ETCD_DISCOVERY = cfg.discovery;
179 ETCD_DATA_DIR = cfg.dataDir;
180 ETCD_ADVERTISE_CLIENT_URLS = lib.concatStringsSep "," cfg.advertiseClientUrls;
181 ETCD_LISTEN_CLIENT_URLS = lib.concatStringsSep "," cfg.listenClientUrls;
182 ETCD_LISTEN_PEER_URLS = lib.concatStringsSep "," cfg.listenPeerUrls;
183 ETCD_INITIAL_ADVERTISE_PEER_URLS = lib.concatStringsSep "," cfg.initialAdvertisePeerUrls;
184 ETCD_PEER_CLIENT_CERT_AUTH = toString cfg.peerClientCertAuth;
185 ETCD_PEER_TRUSTED_CA_FILE = cfg.peerTrustedCaFile;
186 ETCD_PEER_CERT_FILE = cfg.peerCertFile;
187 ETCD_PEER_KEY_FILE = cfg.peerKeyFile;
188 ETCD_CLIENT_CERT_AUTH = toString cfg.clientCertAuth;
189 ETCD_TRUSTED_CA_FILE = cfg.trustedCaFile;
190 ETCD_CERT_FILE = cfg.certFile;
191 ETCD_KEY_FILE = cfg.keyFile;
192 }) // (lib.optionalAttrs (cfg.discovery == ""){
193 ETCD_INITIAL_CLUSTER = lib.concatStringsSep "," cfg.initialCluster;
194 ETCD_INITIAL_CLUSTER_STATE = cfg.initialClusterState;
195 ETCD_INITIAL_CLUSTER_TOKEN = cfg.initialClusterToken;
196 }) // (lib.mapAttrs' (n: v: lib.nameValuePair "ETCD_${n}" v) cfg.extraConf);
199 Documentation = "https://github.com/coreos/etcd";
206 ExecStart = "${cfg.package}/bin/etcd";
212 environment.systemPackages = [ cfg.package ];
214 networking.firewall = lib.mkIf cfg.openFirewall {
216 2379 # for client requests
217 2380 # for peer communication
224 description = "Etcd daemon user";
227 users.groups.etcd = {};