Refactored how SSL certs are configured for nginx
Made a separate ACME module to handle requesting certs from multiple machines. Right now, the module only supports exactly one wildcard cert. It might make sense to have cache.kilonull.com use a cert specific to its subdomain rather than also requesting a wildcard cert (or maybe the nginx on its host shouldn't care about TLS and it should be node's responsibility).
This commit is contained in:
		
							parent
							
								
									60917107b1
								
							
						
					
					
						commit
						d5969ca923
					
				
					 9 changed files with 128 additions and 41 deletions
				
			
		| 
						 | 
				
			
			@ -7,7 +7,7 @@
 | 
			
		|||
}:
 | 
			
		||||
with lib; let
 | 
			
		||||
  cfg = config.aa.nix;
 | 
			
		||||
  selfHostedCacheHost = "http://192.168.113.69/";
 | 
			
		||||
  selfHostedCacheHost = "https://cache.kilonull.com/";
 | 
			
		||||
in {
 | 
			
		||||
  options.aa.nix = with types; {
 | 
			
		||||
    enable = mkEnableOption "manage nix configuration.";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										56
									
								
								modules/security/acme/default.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								modules/security/acme/default.nix
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,56 @@
 | 
			
		|||
{
 | 
			
		||||
  options,
 | 
			
		||||
  config,
 | 
			
		||||
  lib,
 | 
			
		||||
  pkgs,
 | 
			
		||||
  format,
 | 
			
		||||
  ...
 | 
			
		||||
}:
 | 
			
		||||
with lib; let
 | 
			
		||||
  cfg = config.aa.security.acme;
 | 
			
		||||
in {
 | 
			
		||||
  options.aa.security.acme = with types; {
 | 
			
		||||
    enable = mkEnableOption "Automatic Certificate Management Environment (ACME)";
 | 
			
		||||
    useStaging = mkOption {
 | 
			
		||||
      type = bool;
 | 
			
		||||
      description = ''
 | 
			
		||||
        Use the staging environment (use when configuring for the first time to
 | 
			
		||||
        avoid being locked out).
 | 
			
		||||
      '';
 | 
			
		||||
      default = false;
 | 
			
		||||
    };
 | 
			
		||||
    domainName = mkOption {
 | 
			
		||||
      type = str;
 | 
			
		||||
      description = "The domain to request a wildcard cert for.";
 | 
			
		||||
    };
 | 
			
		||||
    dnsCredentialsFile = mkOption {
 | 
			
		||||
      type = path;
 | 
			
		||||
      description = "The path to the credentials file for the DNS provider.";
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  # Only supports exactly one wildcard cert using Cloudflare (only use case I have)
 | 
			
		||||
  config = mkIf cfg.enable {
 | 
			
		||||
    security.acme = {
 | 
			
		||||
      acceptTerms = true;
 | 
			
		||||
      defaults = {
 | 
			
		||||
        email = config.aa.user.email;
 | 
			
		||||
        group = "nginx";
 | 
			
		||||
        server = mkIf cfg.useStaging "https://acme-staging-v02.api.letsencrypt.org/directory";
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      # Wildcard cert
 | 
			
		||||
      certs."${cfg.domainName}" = {
 | 
			
		||||
        group = "nginx";
 | 
			
		||||
        dnsProvider = "cloudflare";
 | 
			
		||||
        # Private network resolves *.kilonull.com to private servers but `lego`
 | 
			
		||||
        # (acme client under the hood) needs to find the cloudflare nameservers
 | 
			
		||||
        # to determine the correct zone to apply changes in. Use cloudflare's
 | 
			
		||||
        # own DNS to make `lego` happy (will resolve names to a public IP).
 | 
			
		||||
        dnsResolver = "1.1.1.1:53";
 | 
			
		||||
        credentialsFile = cfg.dnsCredentialsFile;
 | 
			
		||||
        extraDomainNames = [("*." + cfg.domainName)];
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -11,6 +11,14 @@ with lib; let
 | 
			
		|||
in {
 | 
			
		||||
  options.aa.services.adguardhome = with types; {
 | 
			
		||||
    enable = mkEnableOption "adguardhome";
 | 
			
		||||
    acmeCertName = mkOption {
 | 
			
		||||
      type = str;
 | 
			
		||||
      default = "";
 | 
			
		||||
      description = ''
 | 
			
		||||
        If set to a non-empty string, forces SSL with the supplied acme
 | 
			
		||||
        certificate.
 | 
			
		||||
      '';
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  config = mkIf cfg.enable {
 | 
			
		||||
| 
						 | 
				
			
			@ -26,37 +34,16 @@ in {
 | 
			
		|||
    services.nginx = {
 | 
			
		||||
      enable = true;
 | 
			
		||||
      recommendedProxySettings = true;
 | 
			
		||||
      virtualHosts."adguardhome.kilonull.com" = {
 | 
			
		||||
        forceSSL = true;
 | 
			
		||||
        useACMEHost = "kilonull.com";
 | 
			
		||||
        locations."/" = {
 | 
			
		||||
          proxyPass = "http://127.0.0.1:3000";
 | 
			
		||||
      virtualHosts."adguardhome.kilonull.com" =
 | 
			
		||||
        {
 | 
			
		||||
          locations."/" = {
 | 
			
		||||
            proxyPass = "http://127.0.0.1:3000";
 | 
			
		||||
          };
 | 
			
		||||
        }
 | 
			
		||||
        // lib.optionalAttrs (cfg.acmeCertName != "") {
 | 
			
		||||
          forceSSL = true;
 | 
			
		||||
          useACMEHost = cfg.acmeCertName;
 | 
			
		||||
        };
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    # So that nginx has access to the ACME certs
 | 
			
		||||
    users.users.nginx.extraGroups = ["acme"];
 | 
			
		||||
 | 
			
		||||
    age.secrets.cf_dns_kilonull.file = ../../../secrets/cf_dns_kilonull.age;
 | 
			
		||||
 | 
			
		||||
    security.acme = {
 | 
			
		||||
      # NOTE: Uncomment line below when testing changes
 | 
			
		||||
      # defaults.server = "https://acme-staging-v02.api.letsencrypt.org/directory";
 | 
			
		||||
      acceptTerms = true;
 | 
			
		||||
      defaults.email = "iam@alejandr0angul0.dev";
 | 
			
		||||
 | 
			
		||||
      # Wildcard cert
 | 
			
		||||
      certs."kilonull.com" = {
 | 
			
		||||
        dnsProvider = "cloudflare";
 | 
			
		||||
        # Private network resolves *.kilonull.com to private servers but `lego`
 | 
			
		||||
        # (acme client under the hood) needs to find the cloudflare nameservers
 | 
			
		||||
        # to determine the correct zone to apply changes in. Use cloudflare's
 | 
			
		||||
        # own DNS to make `lego` happy (will resolve names to a public IP).
 | 
			
		||||
        dnsResolver = "1.1.1.1:53";
 | 
			
		||||
        credentialsFile = config.age.secrets.cf_dns_kilonull.path;
 | 
			
		||||
        extraDomainNames = ["*.kilonull.com"];
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    networking.firewall = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,14 @@ with lib; let
 | 
			
		|||
in {
 | 
			
		||||
  options.aa.services.nextcloud = with types; {
 | 
			
		||||
    enable = mkEnableOption "nextcloud";
 | 
			
		||||
    acmeCertName = mkOption {
 | 
			
		||||
      type = str;
 | 
			
		||||
      default = "";
 | 
			
		||||
      description = ''
 | 
			
		||||
        If set to a non-empty string, forces SSL with the supplied acme
 | 
			
		||||
        certificate.
 | 
			
		||||
      '';
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  config = mkIf cfg.enable {
 | 
			
		||||
| 
						 | 
				
			
			@ -47,9 +55,9 @@ in {
 | 
			
		|||
    };
 | 
			
		||||
 | 
			
		||||
    # nextcloud module configures nginx, just need to specify SSL stuffs here
 | 
			
		||||
    services.nginx.virtualHosts.${config.services.nextcloud.hostName} = {
 | 
			
		||||
    services.nginx.virtualHosts.${config.services.nextcloud.hostName} = mkIf (cfg.acmeCertName != "") {
 | 
			
		||||
      forceSSL = true;
 | 
			
		||||
      useACMEHost = "kilonull.com";
 | 
			
		||||
      useACMEHost = cfg.acmeCertName;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    networking.firewall.allowedTCPPorts = [80 443];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,14 @@ in {
 | 
			
		|||
      type = str;
 | 
			
		||||
      description = "The subdomain to use.";
 | 
			
		||||
    };
 | 
			
		||||
    acmeCertName = mkOption {
 | 
			
		||||
      type = str;
 | 
			
		||||
      default = "";
 | 
			
		||||
      description = ''
 | 
			
		||||
        If set to a non-empty string, forces SSL with the supplied acme
 | 
			
		||||
        certificate.
 | 
			
		||||
      '';
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  config = mkIf cfg.enable {
 | 
			
		||||
| 
						 | 
				
			
			@ -38,8 +46,8 @@ in {
 | 
			
		|||
 | 
			
		||||
      nginx = {
 | 
			
		||||
        enable = true;
 | 
			
		||||
        virtualHosts = {
 | 
			
		||||
          "${cfg.subdomain_name}.${cfg.domain_name}" = {
 | 
			
		||||
        virtualHosts."${cfg.subdomain_name}.${cfg.domain_name}" =
 | 
			
		||||
          {
 | 
			
		||||
            serverAliases = ["${cfg.subdomain_name}"];
 | 
			
		||||
            locations."/".extraConfig = ''
 | 
			
		||||
              proxy_pass http://localhost:${toString config.services.nix-serve.port};
 | 
			
		||||
| 
						 | 
				
			
			@ -47,13 +55,16 @@ in {
 | 
			
		|||
              proxy_set_header X-Real-IP $remote_addr;
 | 
			
		||||
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 | 
			
		||||
            '';
 | 
			
		||||
          }
 | 
			
		||||
          // lib.optionalAttrs (cfg.acmeCertName != "") {
 | 
			
		||||
            forceSSL = true;
 | 
			
		||||
            useACMEHost = cfg.acmeCertName;
 | 
			
		||||
          };
 | 
			
		||||
        };
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    networking.firewall = {
 | 
			
		||||
      allowedTCPPorts = [80];
 | 
			
		||||
      allowedTCPPorts = [80 443];
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							| 
						 | 
				
			
			@ -2,8 +2,9 @@ let
 | 
			
		|||
  # Remember to pass '--identity identities/me.txt` when using this key
 | 
			
		||||
  users.me = "age1yubikey1qdwgvfqrcqmyw56ux7azuvqr6f8nanszu27nztvxmn4utmplgxctzt90g25";
 | 
			
		||||
 | 
			
		||||
  machines.gospel = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGDzjXVoQEfO9JIcFbp56EvQ0oBdr9Cmhxp4z0ih+ZEZ";
 | 
			
		||||
  machines.node = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIETLBnc8kJokmFiA28BaSYpeE7flY1W0SM5C1pWv/tOv";
 | 
			
		||||
in {
 | 
			
		||||
  "cf_dns_kilonull.age".publicKeys = [users.me machines.node];
 | 
			
		||||
  "cf_dns_kilonull.age".publicKeys = [users.me machines.node machines.gospel];
 | 
			
		||||
  "nextcloud_admin.age".publicKeys = [users.me machines.node];
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,8 @@
 | 
			
		|||
    ./zfs.nix
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  age.secrets.cf_dns_kilonull.file = ../../../secrets/cf_dns_kilonull.age;
 | 
			
		||||
 | 
			
		||||
  aa = {
 | 
			
		||||
    nix.enable = true;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -19,11 +21,19 @@
 | 
			
		|||
 | 
			
		||||
    apps.yubikey.enable = true;
 | 
			
		||||
 | 
			
		||||
    security.acme = {
 | 
			
		||||
      enable = true;
 | 
			
		||||
      # useStaging = true;
 | 
			
		||||
      domainName = "kilonull.com";
 | 
			
		||||
      dnsCredentialsFile = config.age.secrets.cf_dns_kilonull.path;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    services.openssh.enable = true;
 | 
			
		||||
    services.nix-serve = {
 | 
			
		||||
      enable = true;
 | 
			
		||||
      domain_name = "kilonull.com";
 | 
			
		||||
      subdomain_name = "gospel";
 | 
			
		||||
      subdomain_name = "cache";
 | 
			
		||||
      acmeCertName = "kilonull.com";
 | 
			
		||||
    };
 | 
			
		||||
    services.printing.enable = true;
 | 
			
		||||
    services.tailscale = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,8 @@
 | 
			
		|||
    ./zfs.nix
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  age.secrets.cf_dns_kilonull.file = ../../../secrets/cf_dns_kilonull.age;
 | 
			
		||||
 | 
			
		||||
  aa = {
 | 
			
		||||
    nix.enable = true;
 | 
			
		||||
    nix.useSelfhostedCache = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -18,8 +20,20 @@
 | 
			
		|||
      configureServerRouting = true;
 | 
			
		||||
    };
 | 
			
		||||
    services.openssh.enable = true;
 | 
			
		||||
    services.adguardhome.enable = true;
 | 
			
		||||
    services.nextcloud.enable = true;
 | 
			
		||||
    services.adguardhome = {
 | 
			
		||||
      enable = true;
 | 
			
		||||
      acmeCertName = "kilonull.com";
 | 
			
		||||
    };
 | 
			
		||||
    services.nextcloud = {
 | 
			
		||||
      enable = true;
 | 
			
		||||
      acmeCertName = "kilonull.com";
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    security.acme = {
 | 
			
		||||
      enable = true;
 | 
			
		||||
      domainName = "kilonull.com";
 | 
			
		||||
      dnsCredentialsFile = config.age.secrets.cf_dns_kilonull.path;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    system.zfs.enable = true;
 | 
			
		||||
    system.monitoring.enable = true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue