Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: NixOS/nixpkgs
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 70e723551093
Choose a base ref
...
head repository: NixOS/nixpkgs
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: d31f89df4466
Choose a head ref
  • 2 commits
  • 5 files changed
  • 2 contributors

Commits on Aug 3, 2018

  1. nixos/cfssl: init

    - based on module originally written by @srhb
    - complies with available options in cfssl v1.3.2
    - uid and gid 299 reserved in ids.nix
    - added simple nixos test case
    Johan Thomsen committed Aug 3, 2018
    Copy the full SHA
    7d7c36f View commit details
  2. Merge pull request #44127 from johanot/nixos-cfssl

    nixos/cfssl: Add new module for cfssl
    infinisil authored Aug 3, 2018

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    d31f89d View commit details
Showing with 280 additions and 0 deletions.
  1. +2 −0 nixos/modules/misc/ids.nix
  2. +1 −0 nixos/modules/module-list.nix
  3. +209 −0 nixos/modules/services/security/cfssl.nix
  4. +1 −0 nixos/release.nix
  5. +67 −0 nixos/tests/cfssl.nix
2 changes: 2 additions & 0 deletions nixos/modules/misc/ids.nix
Original file line number Diff line number Diff line change
@@ -323,6 +323,7 @@
mapred = 296;
hadoop = 297;
hydron = 298;
cfssl = 299;

# When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!

@@ -606,6 +607,7 @@
mapred = 296;
hadoop = 297;
hydron = 298;
cfssl = 299;

# When adding a gid, make sure it doesn't match an existing
# uid. Users and groups with the same name should have equal
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
@@ -622,6 +622,7 @@
./services/search/hound.nix
./services/search/kibana.nix
./services/search/solr.nix
./services/security/cfssl.nix
./services/security/clamav.nix
./services/security/fail2ban.nix
./services/security/fprintd.nix
209 changes: 209 additions & 0 deletions nixos/modules/services/security/cfssl.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
{ config, lib, pkgs, ... }:

with lib;

let
cfg = config.services.cfssl;
in {
options.services.cfssl = {
enable = mkEnableOption "the CFSSL CA api-server";

dataDir = mkOption {
default = "/var/lib/cfssl";
type = types.path;
description = "Cfssl work directory.";
};

address = mkOption {
default = "127.0.0.1";
type = types.str;
description = "Address to bind.";
};

port = mkOption {
default = 8888;
type = types.ints.u16;
description = "Port to bind.";
};

ca = mkOption {
defaultText = "\${cfg.dataDir}/ca.pem";
type = types.str;
description = "CA used to sign the new certificate -- accepts '[file:]fname' or 'env:varname'.";
};

caKey = mkOption {
defaultText = "file:\${cfg.dataDir}/ca-key.pem";
type = types.str;
description = "CA private key -- accepts '[file:]fname' or 'env:varname'.";
};

caBundle = mkOption {
default = null;
type = types.nullOr types.path;
description = "Path to root certificate store.";
};

intBundle = mkOption {
default = null;
type = types.nullOr types.path;
description = "Path to intermediate certificate store.";
};

intDir = mkOption {
default = null;
type = types.nullOr types.path;
description = "Intermediates directory.";
};

metadata = mkOption {
default = null;
type = types.nullOr types.path;
description = ''
Metadata file for root certificate presence.
The content of the file is a json dictionary (k,v): each key k is
a SHA-1 digest of a root certificate while value v is a list of key
store filenames.
'';
};

remote = mkOption {
default = null;
type = types.nullOr types.str;
description = "Remote CFSSL server.";
};

configFile = mkOption {
default = null;
type = types.nullOr types.str;
description = "Path to configuration file. Do not put this in nix-store as it might contain secrets.";
};

responder = mkOption {
default = null;
type = types.nullOr types.path;
description = "Certificate for OCSP responder.";
};

responderKey = mkOption {
default = null;
type = types.nullOr types.str;
description = "Private key for OCSP responder certificate. Do not put this in nix-store.";
};

tlsKey = mkOption {
default = null;
type = types.nullOr types.str;
description = "Other endpoint's CA private key. Do not put this in nix-store.";
};

tlsCert = mkOption {
default = null;
type = types.nullOr types.path;
description = "Other endpoint's CA to set up TLS protocol.";
};

mutualTlsCa = mkOption {
default = null;
type = types.nullOr types.path;
description = "Mutual TLS - require clients be signed by this CA.";
};

mutualTlsCn = mkOption {
default = null;
type = types.nullOr types.str;
description = "Mutual TLS - regex for whitelist of allowed client CNs.";
};

tlsRemoteCa = mkOption {
default = null;
type = types.nullOr types.path;
description = "CAs to trust for remote TLS requests.";
};

mutualTlsClientCert = mkOption {
default = null;
type = types.nullOr types.path;
description = "Mutual TLS - client certificate to call remote instance requiring client certs.";
};

mutualTlsClientKey = mkOption {
default = null;
type = types.nullOr types.path;
description = "Mutual TLS - client key to call remote instance requiring client certs. Do not put this in nix-store.";
};

dbConfig = mkOption {
default = null;
type = types.nullOr types.path;
description = "Certificate db configuration file. Path must be writeable.";
};

logLevel = mkOption {
default = 1;
type = types.enum [ 0 1 2 3 4 5 ];
description = "Log level (0 = DEBUG, 5 = FATAL).";
};
};

config = {
users.extraGroups.cfssl = {
gid = config.ids.gids.cfssl;
};

users.extraUsers.cfssl = {
description = "cfssl user";
createHome = true;
home = cfg.dataDir;
group = "cfssl";
uid = config.ids.uids.cfssl;
};

systemd.services.cfssl = mkIf cfg.enable {
description = "CFSSL CA API server";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];

serviceConfig = {
WorkingDirectory = cfg.dataDir;
StateDirectory = cfg.dataDir;
StateDirectoryMode = 700;
Restart = "always";
User = "cfssl";

ExecStart = with cfg; let
opt = n: v: optionalString (v != null) ''-${n}="${v}"'';
in
lib.concatStringsSep " \\\n" [
"${pkgs.cfssl}/bin/cfssl serve"
(opt "address" address)
(opt "port" (toString port))
(opt "ca" ca)
(opt "ca-key" caKey)
(opt "ca-bundle" caBundle)
(opt "int-bundle" intBundle)
(opt "int-dir" intDir)
(opt "metadata" metadata)
(opt "remote" remote)
(opt "config" configFile)
(opt "responder" responder)
(opt "responder-key" responderKey)
(opt "tls-key" tlsKey)
(opt "tls-cert" tlsCert)
(opt "mutual-tls-ca" mutualTlsCa)
(opt "mutual-tls-cn" mutualTlsCn)
(opt "mutual-tls-client-key" mutualTlsClientKey)
(opt "mutual-tls-client-cert" mutualTlsClientCert)
(opt "tls-remote-ca" tlsRemoteCa)
(opt "db-config" dbConfig)
(opt "loglevel" (toString logLevel))
];
};
};

services.cfssl = {
ca = mkDefault "${cfg.dataDir}/ca.pem";
caKey = mkDefault "${cfg.dataDir}/ca-key.pem";
};
};
}
1 change: 1 addition & 0 deletions nixos/release.nix
Original file line number Diff line number Diff line change
@@ -256,6 +256,7 @@ in rec {
tests.buildbot = callTest tests/buildbot.nix {};
tests.cadvisor = callTestOnMatchingSystems ["x86_64-linux"] tests/cadvisor.nix {};
tests.ceph = callTestOnMatchingSystems ["x86_64-linux"] tests/ceph.nix {};
tests.cfssl = callTestOnMatchingSystems ["x86_64-linux"] tests/cfssl.nix {};
tests.chromium = (callSubTestsOnMatchingSystems ["x86_64-linux"] tests/chromium.nix {}).stable or {};
tests.cjdns = callTest tests/cjdns.nix {};
tests.cloud-init = callTest tests/cloud-init.nix {};
67 changes: 67 additions & 0 deletions nixos/tests/cfssl.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import ./make-test.nix ({ pkgs, ...} : {
name = "cfssl";

machine = { config, lib, pkgs, ... }:
{
networking.firewall.allowedTCPPorts = [ config.services.cfssl.port ];

services.cfssl.enable = true;
systemd.services.cfssl.after = [ "cfssl-init.service" ];

systemd.services.cfssl-init = {
description = "Initialize the cfssl CA";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
User = "cfssl";
Type = "oneshot";
WorkingDirectory = config.services.cfssl.dataDir;
};
script = with pkgs; ''
${cfssl}/bin/cfssl genkey -initca ${pkgs.writeText "ca.json" (builtins.toJSON {
hosts = [ "ca.example.com" ];
key = {
algo = "rsa"; size = 4096; };
names = [
{
C = "US";
L = "San Francisco";
O = "Internet Widgets, LLC";
OU = "Certificate Authority";
ST = "California";
}
];
})} | ${cfssl}/bin/cfssljson -bare ca
'';
};
};

testScript =
let
cfsslrequest = with pkgs; writeScript "cfsslrequest" ''
curl -X POST -H "Content-Type: application/json" -d @${csr} \
http://localhost:8888/api/v1/cfssl/newkey | ${cfssl}/bin/cfssljson /tmp/certificate
'';
csr = pkgs.writeText "csr.json" (builtins.toJSON {
CN = "www.example.com";
hosts = [ "example.com" "www.example.com" ];
key = {
algo = "rsa";
size = 2048;
};
names = [
{
C = "US";
L = "San Francisco";
O = "Example Company, LLC";
OU = "Operations";
ST = "California";
}
];
});
in
''
$machine->waitForUnit('cfssl.service');
$machine->waitUntilSucceeds('${cfsslrequest}');
$machine->succeed('ls /tmp/certificate-key.pem');
'';
})