Skip to content
Snippets Groups Projects
Commit 4ad78138 authored by Jean-Paul Calderone's avatar Jean-Paul Calderone
Browse files

Quick and dirty Let's Encrypt client service using certbot

parent 0fe80e4e
Branches
Tags
No related merge requests found
{ "publicStoragePort": 8898
, "ristrettoSigningKeyPath": "../../PrivateStorageSecrets/ristretto.signing-key"
, "issuerDomain": "payments.privatestorage.io"
, "letsEncryptAdminEmail": "jean-paul@privatestorage.io"
}
......@@ -3,6 +3,7 @@
# with the testing grid and have one fewer possible point of divergence.
import ./make-grid.nix {
name = "Production";
config = ./grid.config.json;
nodes = cfg: {
# Here are the hosts that are in this morph network. This is sort of like
# a server manifest. We try to keep as many of the specific details as
......
{ hardware
, ristrettoSigningKeyPath
, issuerDomain
, letsEncryptAdminEmail
, stateVersion
, ...
}: {
......@@ -27,6 +29,8 @@
ristrettoSigningKey = builtins.readFile (./.. + ristrettoSigningKeyPath);
database = "SQLite3";
databasePath = "/var/db/vouchers.sqlite3";
inherit letsEncryptAdminEmail;
domain = issuerDomain;
};
system.stateVersion = stateVersion;
......
......@@ -3,11 +3,11 @@
# and a function that takes the grid configuration as an argument and returns
# a set of nodes specifying the addresses and NixOS configurations for each
# server in the morph network.
{ name, nodes }:
{ name, config, nodes }:
let
pkgs = import <nixpkgs> { };
# Load our JSON configuration for later use.
cfg = pkgs.lib.trivial.importJSON ./grid.config.json;
cfg = pkgs.lib.trivial.importJSON config;
in
{
network = {
......
......@@ -9,7 +9,7 @@
# to avoid breaking some software such as
# database servers. You should change this only
# after NixOS release notes say you should.
, ...
}: rec {
deployment = {
secrets = {
......
{ "publicStoragePort": 8898
, "ristrettoSigningKeyPath": "../../PrivateStorageSecrets/ristretto.signing-key"
, "issuerDomain": "payments.privatestorage-staging.com"
, "letsEncryptAdminEmail": "jean-paul@privatestorage.io"
}
......@@ -3,8 +3,14 @@
# with the production grid and have one fewer possible point of divergence.
import ./make-grid.nix {
name = "Testing";
config = ./testing-grid.config.json;
nodes = cfg: {
"testing000" = import ./testing000.nix (cfg // {
"payments.privatestorage-staging.com" = import ./issuer.nix ({
hardware = ./issuer-aws.nix;
stateVersion = "19.03";
} // cfg);
"35.157.216.200" = import ./testing000.nix (cfg // {
publicIPv4 = "35.157.216.200";
});
};
......
{ publicIPv4, publicStoragePort, ristrettoSigningKeyPath }: rec {
{ publicIPv4, publicStoragePort, ristrettoSigningKeyPath, ... }: rec {
deployment = {
secrets = {
......
......@@ -64,11 +64,18 @@ in {
type is being used.
'';
};
services.private-storage-issuer.letsEncryptAdminEmail = lib.mkOption {
type = lib.types.str;
description = ''
An email address to give to Let's Encrypt as an operational contact
for the service's TLS certificate.
'';
};
};
config =
let
acme = "/var/lib/acme";
certroot = "/var/lib/letsencrypt/live";
in lib.mkIf cfg.enable {
# Add a systemd service to run PaymentServer.
systemd.services.zkapissuer = {
......@@ -80,8 +87,8 @@ in {
# interfaces.
"network.target"
];
# Make sure we at least have a self-signed certificate.
requires = lib.optional cfg.tls "acme-selfsigned-${cfg.domain}.service";
# Make sure we at least have a certificate.
requires = lib.optional cfg.tls "cert-${cfg.domain}";
serviceConfig = {
ExecStart =
......@@ -100,12 +107,9 @@ in {
if cfg.tls
then
"--https-port 443 " +
# acme has plugins to write the files in different ways but the
# self-signed certificate generator doesn't. The files it
# writes are weirdly named and shaped but they work.
"--https-certificate-path ${acme}/${cfg.domain}/full.pem " +
"--https-certificate-chain-path ${acme}/${cfg.domain}/fullchain.pem " +
"--https-key-path ${acme}/${cfg.domain}/key.pem"
"--https-certificate-path ${certroot}/${cfg.domain}/cert.pem " +
"--https-certificate-chain-path ${certroot}/${cfg.domain}/chain.pem " +
"--https-key-path ${certroot}/${cfg.domain}/privkey.pem"
else
# Only for automated testing.
"--http-port 80";
......@@ -121,25 +125,30 @@ in {
# Certificate renewal. Note that preliminarySelfsigned only creates the
# service. We must declare that we *require* it in our service above.
security.acme = if cfg.tls
then {
production = false;
preliminarySelfsigned = true;
certs."${cfg.domain}" = {
email = "jean-paul@privatestorage.io";
postRun = "systemctl restart zkapissuer.service";
webroot = "${acme}/acme-challenges";
plugins = [ "account_key.json" "full.pem" "fullchain.pem" "key.pem" ];
systemd.services."cert-${cfg.domain}" = {
enable = true;
description = "Issue/Renew certificate for ${cfg.domain}";
wantedBy = [ "zkapissuer.service" ];
serviceConfig = {
ExecStart =
let
configArgs = "--config-dir /var/lib/letsencrypt --work-dir /var/run/letsencrypt --logs-dir /var/run/log/letsencrypt";
in
pkgs.writeScript "cert-${cfg.domain}-start.sh" ''
#!${pkgs.runtimeShell} -e
# Register if necessary.
${pkgs.certbot}/bin/certbot register ${configArgs} --agree-tos -m ${cfg.letsEncryptAdminEmail} || true
# Obtain the certificate.
${pkgs.certbot}/bin/certbot certonly ${configArgs} -n --standalone --domains ${cfg.domain}
# Restart the server so the new certificate gets used.
systemctl restart zkapissuer.service
'';
};
}
else {};
services.nginx.virtualHosts = if cfg.tls
then {
"${cfg.domain}" = {
locations."/" = "${acme}/acme-challenges";
};
}
else {};
# Open 80 and 443 for the certbot HTTP server and the PaymentServer HTTPS server.
networking.firewall.allowedTCPPorts = [
80
443
];
};
}
8bf142e001b6876b021c8ee90c2c7cec385fe8e9
\ No newline at end of file
353333ef340952c05332e3c271dff953264cb017
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment