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

modules: introduce mkcert (development certification authority) #74

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
78 changes: 77 additions & 1 deletion devshell.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
imports = [
"language.go"
"language.go",
"ca.mkcert"
]

[devshell]
Expand Down Expand Up @@ -45,3 +46,78 @@ category = "utilites"
help = "golang linter"
package = "golangci-lint"
category = "linters"

[mkcert]
enable = true
root-ca.key = """
-----BEGIN PRIVATE KEY-----
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
xS044vroff+d0i4NxpOfBXyf
-----END PRIVATE KEY-----
"""
root-ca.cert = """
-----BEGIN CERTIFICATE-----
MIIEzjCCAzagAwIBAgIRAKGyGtqQLfNkWqnQWQ5mhx0wDQYJKoZIhvcNAQELBQAw
fzEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSowKAYDVQQLDCFuaXhi
bGRAbG9jYWxob3N0IChOaXggYnVpbGQgdXNlcikxMTAvBgNVBAMMKG1rY2VydCBu
aXhibGRAbG9jYWxob3N0IChOaXggYnVpbGQgdXNlcikwHhcNMjEwMTI3MTg1NTM1
WhcNMzEwMTI3MTg1NTM1WjB/MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQg
Q0ExKjAoBgNVBAsMIW5peGJsZEBsb2NhbGhvc3QgKE5peCBidWlsZCB1c2VyKTEx
MC8GA1UEAwwobWtjZXJ0IG5peGJsZEBsb2NhbGhvc3QgKE5peCBidWlsZCB1c2Vy
KTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAJpNoK7FKbvIdPHxYEGu
HKoCyMNi+OxTDXRrrUPWgkDr64KIQwevv1ePddIzSE1levtOfL2l6oquzTtOqZFj
jaAzrD/VafQqXs4PBtMpN5IZzNqmrTCZ3tvVm2sjh3diPd2N2BfEuVf4KgE7aN91
BK/k5s4MFZcTvERA1CBZ1Dg6q65v6r7y2v3q/vuDN4LGsVC0Nk3ySSbhQZ1IGCPC
uqalnyghdP8SM7v2UiK9F5nyiVwmAsRE/AE0agGZO/0MDPJmLYbrBwi2L+Q+MU0n
8MBW9fGEDSmazISdKCdlxNLCZZKsA6v5ZMuQvuCGy/kN4gF66WVp+zr9+9AwCocO
F7yW7igWYdDzPoeqZvu0KsqcFnYYxCgkBFIC2LoubsuOBegPN3cqdxOVSgdTkREh
+BlUOoGtlrC8wnxXqvvD4Us/Az2DAmoIuRi6xS9wHjrN1+BkznPeAcsiFcWh917G
KCTHmEwveH74Z3UOiXhi+1CZT4Rs6LsR9WB2jJrKzsh8TwIDAQABo0UwQzAOBgNV
HQ8BAf8EBAMCAgQwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUvFZHpiR1
SsZgx18IXS4sV2goJwwwDQYJKoZIhvcNAQELBQADggGBAEhEXonraBKooVsYVdd6
EuLD5LJ9rLuVN0QCOWzMDgqc1iHX+nTEjH6OctBpdGo+1RRE4UB1SHoaCW7LcJJx
1UCPHvMTby2U0Y1E7NS9dOdt3slUQUF86KfecV8UfTLgqWvN8W3pdyNqk8X7g5FO
vnoWMRXopNyI/AnnAfEMC2rA1+fgJXFIi7Ny5vHiPoaPolvULDU8gwcBPpGB80z0
py4x/DcO4UoNB11fs2+XNV6UGHfLB1R1OJmhdCbEQ7cmIetg11ThuvD8YiomKb1O
wJO5moU86AJ52o19C3AmYKsClhGwnGLGNgOslFIozRi7eSPX7B9UdEJUvj2tGkUE
mpSjE6hTUtEinmuQ0gkf4jaqcWetJnhUVaNGsbixWdRtkNkvICkToCGhHXFKDGfr
qrM5Rs0xtUAp91/DZ+vbPsuWzvRibCrck89vyg1lGemhMf8g34U1ocf5KlyLvO3c
o3E+CRMwgG1IP4ktc63dfXPvbfN+lKjk1LVhMBPXeqhJ2A==
-----END CERTIFICATE-----
"""
113 changes: 113 additions & 0 deletions extra/ca/mkcert.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
{ lib, pkgs, config, ... }:
with lib;
let
cfg = config.mkcert;

maybeReadFile = obj:
if (builtins.typeOf obj == "path") then
builtins.readFile obj
else
obj
;

# These are all the options available for specifying a certificate/key file.
rootCAOption = {
key = mkOption {
description = "Text or file of the root CA key to install";
default = null;
type = types.nullOr (types.either types.str types.path);
};
cert = mkOption {
description = "Text or file of the root CA certificate to install";
default = null;
type = types.nullOr (types.either types.str types.path);
};
};

# A collection of development certificate authority files
rootCADir =
let
adHoc = pkgs.runCommandLocal "rootCA" {} ''
export CAROOT=$out
${pkgs.mkcert}/bin/mkcert 2>/dev/null
'';

isPreconfigured =
assert assertMsg (
cfg.root-ca != {} && cfg.root-ca.cert != null && cfg.root-ca.key != null
) "[mkcert]: either set, both, root CA key and certificate or none.";
(cfg.root-ca.key != null && cfg.root-ca.cert != null);

key = pkgs.writeText "rootCA-key.pem" (maybeReadFile cfg.root-ca.key);
cert = pkgs.writeText "rootCA.pem" (maybeReadFile cfg.root-ca.cert);

preconfigured = pkgs.runCommand "rootCA" {} ''
mkdir $out
cp ${key} $out/${key.name}
cp ${cert} $out/${cert.name}
'';
in
if isPreconfigured then preconfigured else adHoc;

# Execute this script to install the project's development certificate authority
install-mkcert-ca = pkgs.writeShellScriptBin "install-mkcert-ca" ''
set -euo pipefail
shopt -s nullglob

log() {
IFS=$'\n' loglines=($*)
for line in ${"$"}{loglines[@]}; do echo -e "[mkcert] $line" >&2; done
}

# Set the CA root files directory for mkcert via env variable
export CAROOT=${rootCADir}

# Install local CA into system, java and nss (includes Firefox) trust stores
log "Install development CA into the system stores..."
log $(sudo -K; ${pkgs.mkcert}/bin/mkcert -install 2>&1)
log "root CA directory: $(${pkgs.mkcert}/bin/mkcert -CAROOT 2>&1)"

uninstall() {
log $(${pkgs.mkcert}/bin/mkcert -uninstall 2>&1)
}

# TODO: Uninstall when leaving the devshell
# trap uninstall EXIT

'';
in
{
options.mkcert = {
enable = mkEnableOption "provide a development CA within the shell";

root-ca = mkOption {
type = types.submodule { options = rootCAOption; };
default = {};
description = "preconfigure root CA files";
example = literalExample "
{
key = ''
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
'';
cert = ./path/tocert.pem;
}
";
};
};

config = mkIf cfg.enable {
env = [{
name = "CAROOT";
value = "${rootCADir}";
}];
commands = [ { package = pkgs.mkcert; category = "certs"; } ];
devshell = {
packages = [ install-mkcert-ca ];
startup.install-mkcert-ca.text = "
$DEVSHELL_DIR/bin/install-mkcert-ca
";
};
};
}