diff --git a/certs/.gitignore b/certs/.gitignore new file mode 100644 index 00000000..868f0236 --- /dev/null +++ b/certs/.gitignore @@ -0,0 +1,2 @@ +*.key +*.csr diff --git a/certs/README.md b/certs/README.md new file mode 100644 index 00000000..eb3029f0 --- /dev/null +++ b/certs/README.md @@ -0,0 +1,7 @@ +# My Private PKI / CA + +This is my private Private Key Infrastructure (PKI) / Certificate Authority (CA) for my personal +use. It is used to issue certificates for my own servers and services. + +All the private keys are ignored by git, and will be stored in my private secrets repo +[../secrets](../secrets/) diff --git a/certs/ecc-ca.crt b/certs/ecc-ca.crt new file mode 100644 index 00000000..a937d953 --- /dev/null +++ b/certs/ecc-ca.crt @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE----- +MIIBajCB8QIJAIwL98is2nQPMAoGCCqGSM49BAMEMB8xHTAbBgNVBAMMFFJ5YW40 +WWluJ3MgUm9vdCBDQSAxMB4XDTI0MDQwMzA4NDgzM1oXDTM0MDQwMTA4NDgzM1ow +HzEdMBsGA1UEAwwUUnlhbjRZaW4ncyBSb290IENBIDEwdjAQBgcqhkjOPQIBBgUr +gQQAIgNiAAQ6ixMbsGZ/u/ZnwzOZ49naVL7rQxm9C74SboGytKcYBH03JjC7tgZ3 +DylirxSLcTYHHtCz9ajdamP6+sgiGVpUODtfGSO+WmS+gAbLjCS37T41bkUhkx88 +JU4NsGhjPXcwCgYIKoZIzj0EAwQDaAAwZQIwDrGLSdO+p/1uywkzqzdM/OnZs8bp +n60uBhUI7EZzDmrouOFeGx+dXYI5yy5AD/qDAjEA7fTQx+jccyOj4dimq1iU9+71 +e/gWYg0rexfy/+9dQY6kvwMzv8Lnm6URaRMbE1Q/ +-----END CERTIFICATE----- diff --git a/certs/ecc-ca.srl b/certs/ecc-ca.srl new file mode 100644 index 00000000..81c83fc0 --- /dev/null +++ b/certs/ecc-ca.srl @@ -0,0 +1 @@ +C050420A8E5A3C1E diff --git a/certs/ecc-csr.conf b/certs/ecc-csr.conf new file mode 100644 index 00000000..c0e8344c --- /dev/null +++ b/certs/ecc-csr.conf @@ -0,0 +1,22 @@ +[ req ] +prompt = no +req_extensions = v3_ext +distinguished_name = req_distinguished_name + +[ req_distinguished_name ] +countryName = US +stateOrProvinceName = NYK +localityName = NYK +organizationName = Ryan4Yin +organizationalUnitName = Ryan4Yin +commonName = writefor.fun # deprecated, use subjectAltName(SAN) instead +emailAddress = rayn4yin@linux.com + +[ alt_names ] +DNS.1 = writefor.fun +DNS.2 = *.writefor.fun + +[ v3_ext ] +subjectAltName=@alt_names +basicConstraints = CA:false +extendedKeyUsage = serverAuth diff --git a/certs/ecc-server.crt b/certs/ecc-server.crt new file mode 100644 index 00000000..b7eb879a --- /dev/null +++ b/certs/ecc-server.crt @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICKTCCAa6gAwIBAgIJAMBQQgqOWjweMAoGCCqGSM49BAMEMB8xHTAbBgNVBAMM +FFJ5YW40WWluJ3MgUm9vdCBDQSAxMB4XDTI0MDQwMzA4NDgzM1oXDTM0MDQwMTA4 +NDgzM1owgYkxCzAJBgNVBAYTAlVTMQwwCgYDVQQIDANOWUsxDDAKBgNVBAcMA05Z +SzERMA8GA1UECgwIUnlhbjRZaW4xETAPBgNVBAsMCFJ5YW40WWluMRUwEwYDVQQD +DAx3cml0ZWZvci5mdW4xITAfBgkqhkiG9w0BCQEWEnJheW40eWluQGxpbnV4LmNv +bTB2MBAGByqGSM49AgEGBSuBBAAiA2IABCNTYKDq/I99NltQR5eKrrovQXp9BbLV +iuUdYmzFrAh+NC9ikiIqTfDwP+c+7QvDyI3KXu3KI2qPSPdxktZKDUPHK4p2Y2kZ +xKOI2IFTgTqV3uBciyx7ayWPTwBYxsTDmqNLMEkwJwYDVR0RBCAwHoIMd3JpdGVm +b3IuZnVugg4qLndyaXRlZm9yLmZ1bjAJBgNVHRMEAjAAMBMGA1UdJQQMMAoGCCsG +AQUFBwMBMAoGCCqGSM49BAMEA2kAMGYCMQCHw9YkDo15P9mqEObvxSUak8tQmhBB +9wB81Qg4c+JsMCZA1rMUB7GkNJj1Dr9rWLoCMQDSituLzmo/yPLEOrbNV83bj3/I +ikKgobSie3pMXm5ZG7krOXaunyFRR/bIkih2V2Q= +-----END CERTIFICATE----- diff --git a/certs/gen-certs.sh b/certs/gen-certs.sh new file mode 100644 index 00000000..6d3ad1d3 --- /dev/null +++ b/certs/gen-certs.sh @@ -0,0 +1,19 @@ +# 1. generate the private key for the CA root certificate +openssl ecparam -genkey -name secp384r1 -out ecc-ca.key +# 2. generate the CA root certificate with the private key +# with the validity period of 10 years +openssl req -x509 -new -SHA512 -key ecc-ca.key -subj "/CN=Ryan4Yin's Root CA 1" -days 3650 -out ecc-ca.crt + +# 3. generate the private key for the server certificate +openssl ecparam -genkey -name secp384r1 -out ecc-server.key +# 4. generate the certificate signing request (CSR) for the server certificate +# using the private key and the configuration file ecc-csr.conf +openssl req -new -SHA512 -key ecc-server.key -out ecc-server.csr -config ecc-csr.conf +# 5. sign the server certificate with the CA root certificate +openssl x509 -req -SHA512 -in ecc-server.csr -CA ecc-ca.crt -CAkey ecc-ca.key \ + -CAcreateserial -out ecc-server.crt -days 3650 \ + -extensions v3_ext -extfile ecc-csr.conf + +openssl x509 -noout -text -in ecc-ca.crt +openssl x509 -noout -text -in ecc-server.crt + diff --git a/flake.lock b/flake.lock index dcebd789..c9427f7c 100644 --- a/flake.lock +++ b/flake.lock @@ -892,10 +892,10 @@ "mysecrets": { "flake": false, "locked": { - "lastModified": 1711871709, - "narHash": "sha256-Pj667YJdXbJPhQVUutpKoqH6e66eF8my5q8RQyl0BXI=", + "lastModified": 1712114794, + "narHash": "sha256-qWSnhqYo7o9+ThiH5TV5yPOWSKXCKpwSP+7HjnjBZvY=", "ref": "refs/heads/main", - "rev": "c0239ed183c43c18f6bdf2f9045602e1bb9ca310", + "rev": "066524c12e11687110642005d5d51fec88306573", "shallow": true, "type": "git", "url": "ssh://git@github.com/ryan4yin/nix-secrets.git" diff --git a/hosts/12kingdoms-rakushun/caddy.nix b/hosts/12kingdoms-rakushun/caddy.nix index a9b4c0d1..ba2d3d3e 100644 --- a/hosts/12kingdoms-rakushun/caddy.nix +++ b/hosts/12kingdoms-rakushun/caddy.nix @@ -1,4 +1,12 @@ -{myvars, ...}: { +{config, ...}: let + hostCommonConfig = '' + encode zstd gzip + tls ${../../certs/ecc-server.crt} ${config.age.secrets."certs/ecc-server.key".path} { + protocols tls1.3 tls1.3 + curves x25519 secp384r1 secp521r1 + } + ''; +in { services.caddy = { enable = true; # Reload Caddy instead of restarting it when configuration file changes. @@ -12,23 +20,19 @@ globalConfig = '' http_port 80 https_port 443 - auto_https off + auto_https disable_certs ''; - # ACME related settings. - # email = myvars.useremail; - # acmeCA = "https://acme-v02.api.letsencrypt.org/directory"; - # Dashboard - virtualHosts."http://home.writefor.fun".extraConfig = '' - encode zstd gzip + virtualHosts."home.writefor.fun".extraConfig = '' + ${hostCommonConfig} reverse_proxy http://localhost:4401 ''; # https://caddyserver.com/docs/caddyfile/directives/file_server - virtualHosts."http://file.writefor.fun".extraConfig = '' + virtualHosts."file.writefor.fun".extraConfig = '' root * /var/lib/caddy/fileserver/ - encode zstd gzip + ${hostCommonConfig} file_server browse { hide .git precompressed zstd br gzip @@ -36,42 +40,42 @@ ''; # Datastore - virtualHosts."http://attic.writefor.fun".extraConfig = '' + virtualHosts."attic.writefor.fun".extraConfig = '' encode zstd gzip reverse_proxy http://localhost:3300 ''; - virtualHosts."http://git.writefor.fun".extraConfig = '' + virtualHosts."git.writefor.fun".extraConfig = '' encode zstd gzip reverse_proxy http://localhost:3301 ''; - virtualHosts."http://sftpgo.writefor.fun".extraConfig = '' + virtualHosts."sftpgo.writefor.fun".extraConfig = '' encode zstd gzip reverse_proxy http://localhost:3302 ''; - virtualHosts."http://webdav.writefor.fun".extraConfig = '' + virtualHosts."webdav.writefor.fun".extraConfig = '' encode zstd gzip reverse_proxy http://localhost:3303 ''; - virtualHosts."http://transmission.writefor.fun".extraConfig = '' + virtualHosts."transmission.writefor.fun".extraConfig = '' encode zstd gzip reverse_proxy http://localhost:9091 ''; # Monitoring - virtualHosts."http://uptime-kuma.writefor.fun".extraConfig = '' + virtualHosts."uptime-kuma.writefor.fun".extraConfig = '' encode zstd gzip reverse_proxy http://localhost:3350 ''; - virtualHosts."http://grafana.writefor.fun".extraConfig = '' + virtualHosts."grafana.writefor.fun".extraConfig = '' encode zstd gzip reverse_proxy http://localhost:3351 ''; - virtualHosts."http://prometheus.writefor.fun".extraConfig = '' + virtualHosts."prometheus.writefor.fun".extraConfig = '' encode zstd gzip reverse_proxy http://localhost:9090 ''; - virtualHosts."http://alertmanager.writefor.fun".extraConfig = '' + virtualHosts."alertmanager.writefor.fun".extraConfig = '' encode zstd gzip reverse_proxy http://localhost:9093 ''; diff --git a/modules/base.nix b/modules/base.nix index 8976cd1b..2a853ab9 100644 --- a/modules/base.nix +++ b/modules/base.nix @@ -10,6 +10,11 @@ ] ++ (import ../overlays args); + # Add my private PKI's CA certificate to the system-wide trust store. + security.pki.certificateFiles = [ + ../certs/ecc-ca.crt + ]; + environment.systemPackages = with pkgs; [ git # used by nix flakes git-lfs # used by huggingface models diff --git a/outputs/aarch64-linux/src/12kingdoms-rakushun.nix b/outputs/aarch64-linux/src/12kingdoms-rakushun.nix index 90860673..07dc55d3 100644 --- a/outputs/aarch64-linux/src/12kingdoms-rakushun.nix +++ b/outputs/aarch64-linux/src/12kingdoms-rakushun.nix @@ -26,6 +26,7 @@ ++ [ {modules.secrets.server.application.enable = true;} {modules.secrets.server.operation.enable = true;} + {modules.secrets.server.webserver.enable = true;} ]; home-modules = map mylib.relativeToRoot [ "home/linux/tui.nix" diff --git a/secrets/nixos.nix b/secrets/nixos.nix index 74243dc1..b447adb7 100644 --- a/secrets/nixos.nix +++ b/secrets/nixos.nix @@ -34,6 +34,7 @@ in { server.application.enable = mkEnableOption "NixOS Secrets for Application Servers"; server.operation.enable = mkEnableOption "NixOS Secrets for Operation Servers(Backup, Monitoring, etc)"; server.kubernetes.enable = mkEnableOption "NixOS Secrets for Kubernetes"; + server.webserver.enable = mkEnableOption "NixOS Secrets for Web Servers(contains tls cert keys)"; impermanence.enable = mkEnableOption "whether use impermanence and ephemeral root file system"; }; @@ -244,5 +245,15 @@ in { // high_security; }; }) + + (mkIf cfg.server.webserver.enable { + age.secrets = { + "certs/ecc-server.key" = { + file = "${mysecrets}/certs/ecc-server.key.age"; + mode = "0400"; + owner = "caddy"; # used by caddy only + }; + }; + }) ]); }