From 5a24b568c2c1d678934370dd6f3418595a459334 Mon Sep 17 00:00:00 2001 From: David Arnold Date: Wed, 7 Oct 2020 17:11:36 -0500 Subject: [PATCH] Add mkcert and hostctl instrumentation --- .gitignore | 3 ++ devshell.toml | 20 +++++++++++ devshell/config.go | 14 ++++---- docs/devshell.toml | 19 ++++++++++ docs/devshell.toml.md | 24 +++++++++++++ hostctl/default.nix | 40 +++++++++++++++++++++ mkDevShell/instrumentation.nix | 64 ++++++++++++++++++++++++++++++++++ mkDevShell/options.nix | 53 ++++++++++++++++++++++++++-- overlay.nix | 1 + 9 files changed, 229 insertions(+), 9 deletions(-) create mode 100644 .gitignore create mode 100644 hostctl/default.nix create mode 100644 mkDevShell/instrumentation.nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..b32f47a4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# mimick use case where users are expected to boostrap their dev ca +# this is also better for testing devhsell ca bootstrapping +dev-ca diff --git a/devshell.toml b/devshell.toml index 1955f9f7..624e50d0 100644 --- a/devshell.toml +++ b/devshell.toml @@ -16,6 +16,18 @@ packages = [ # # motd = "" +# This setting helps to add a project's shared *development* root CA +# to host's local trust stores by instrumenting the mkcert third party tool. +# Defining this section also adds `mkcert` to the available packages. +# Set to the path where mkcert-generated CAROOT files are expected to exist +# +# NOTES: +# - be careful to only put *development* certificates under version control +# - create those files with the devshell generated *-install-CA command +# - optionally put this path under .gitignore, if you want users to +# generate certificates themselves on first clone (using *-install-CA) +dev-ca-path = "./dev-ca" + # Use this section to set environment variables to have in the environment. # # NOTE: all the values are escaped @@ -54,3 +66,11 @@ help = "github utility" name = "hub" package = "gitAndTools.hub" category = "utilites" + +# These settings help to manage local DNS overrides via +# instrumentation of the hostcl third party tool. +# Defining this section also adds `hostctl` to the available packages. +[static-dns] +"test.domain.local" = "172.0.0.1" +"shared.domain.link-local" = "169.254.0.5" + diff --git a/devshell/config.go b/devshell/config.go index d7136769..3959e0d4 100644 --- a/devshell/config.go +++ b/devshell/config.go @@ -22,12 +22,14 @@ type configCommand struct { } type config struct { - Name string `toml:"name"` - Packages []string `toml:"packages"` - Motd *string `toml:"motd"` - Env map[string]interface{} `toml:"env"` - Bash configBash `toml:"bash,omitempty"` - Commands []configCommand `toml:"commands"` + Name string `toml:"name"` + Packages []string `toml:"packages"` + Motd *string `toml:"motd"` + DevCaPath *string `toml:"dev-ca-path,omitempty"` + Env map[string]interface{} `toml:"env"` + Bash configBash `toml:"bash,omitempty"` + Commands []configCommand `toml:"commands"` + StaticDNS map[string]interface{} `toml:"static-dns,omitempty"` } func configLoad(path string) (*config, error) { diff --git a/docs/devshell.toml b/docs/devshell.toml index 858a3029..779cb470 100644 --- a/docs/devshell.toml +++ b/docs/devshell.toml @@ -16,6 +16,18 @@ packages = [ # # motd = "" +# This setting helps to add a project's shared *development* root CA +# to host's local trust stores by instrumenting the mkcert third party tool. +# Defining this section also adds `mkcert` to the available packages. +# Set to the path where mkcert-generated CAROOT files are expected to exist +# +# NOTES: +# - be careful to only put *development* certificates under version control +# - create those files with the devshell generated *-install-CA command +# - optionally put this path under .gitignore, if you want users to +# generate certificates themselves on first clone (using *-install-CA) +# dev-ca-path = "./dev-ca" + # Use this section to set environment variables to have in the environment. # # NOTE: all the values are escaped @@ -54,3 +66,10 @@ help = "github utility" name = "hub" package = "gitAndTools.hub" category = "utilites" + +# These settings help to manage local DNS overrides via +# instrumentation of the hostcl third party tool. +# Defining this section also adds `hostctl` to the available packages. +[static-dns] +"test.domain.local" = "172.0.0.1" +"shared.domain.link-local" = "169.254.0.5" diff --git a/docs/devshell.toml.md b/docs/devshell.toml.md index a06969b3..c528c55d 100644 --- a/docs/devshell.toml.md +++ b/docs/devshell.toml.md @@ -24,6 +24,18 @@ packages = [ # # motd = "" +# This setting helps to add a project's shared *development* root CA +# to host's local trust stores by instrumenting the mkcert third party tool. +# Defining this section also adds `mkcert` to the available packages. +# Set to the path where mkcert-generated CAROOT files are expected to exist +# +# NOTES: +# - be careful to only put *development* certificates under version control +# - create those files with the devshell generated *-install-CA command +# - optionally put this path under .gitignore, if you want users to +# generate certificates themselves on first clone (using *-install-CA) +# dev-ca-path = "./dev-ca" + # Use this section to set environment variables to have in the environment. # # NOTE: all the values are escaped @@ -61,6 +73,14 @@ category = "formatters" help = "github utility" name = "hub" package = "gitAndTools.hub" +category = "utilities" + +# These settings help to manage local DNS overrides via +# instrumentation of the hostcl third party tool. +# Defining this section also adds `hostctl` to the available packages. +[static-dns] +"test.domain.local" = "172.0.0.1" +"shared.domain.link-local" = "169.254.0.5" ``` ## Schema @@ -84,6 +104,8 @@ The name field is optional and defaults to `devshell`. ### The `motd` field +### The `dev-ca-path` field + ### The `env` section ### The `bash.extra` field @@ -97,3 +119,5 @@ The name field is optional and defaults to `devshell`. * `name`: * `package`: +### The `static-dns` section + diff --git a/hostctl/default.nix b/hostctl/default.nix new file mode 100644 index 00000000..2ace1db2 --- /dev/null +++ b/hostctl/default.nix @@ -0,0 +1,40 @@ +{ buildGoModule, fetchFromGitHub, lib, installShellFiles }: + +buildGoModule rec { + pname = "hostctl"; + version = "1.0.14"; + + src = fetchFromGitHub { + owner = "guumaster"; + repo = pname; + rev = "v${version}"; + sha256 = "02bjii97l4fy43v2rb93m9b0ad8y6mjvbvp4sz6a5n0w9dm1z1q9"; + }; + + vendorSha256 = "1lqk3cda0frqp2vwkqa4b3xkdw814wgkbr7g9r2mwxn85fpdcq5c"; + + doCheck = false; + buildFlagsArray = [ "-ldflags=-s -w -X github.com/guumaster/hostctl/cmd/hostctl/actions.version=${version}" ]; + + nativeBuildInputs = [ installShellFiles ]; + postInstall = '' + $out/bin/hostctl completion bash > hostctl.bash + $out/bin/hostctl completion zsh > hostctl.zsh + installShellCompletion hostctl.{bash,zsh} + # replace above by following once merged https://github.com/NixOS/nixpkgs/pull/83630 + # installShellCompletion --cmd hostctl \ + # --bash <($out/bin/hostctl completion bash) \ + # --zsh <($out/bin/hostctl completion zsh) + ''; + + meta = with lib; { + description = "Your dev tool to manage /etc/hosts like a pro!"; + longDescription = '' + This tool gives you more control over the use of your hosts file. + You can have multiple profiles and switch them on/off as you need. + ''; + homepage = "https://guumaster.github.io/hostctl/"; + license = licenses.mit; + maintainers = with maintainers; [ blaggacao ]; + }; +} diff --git a/mkDevShell/instrumentation.nix b/mkDevShell/instrumentation.nix new file mode 100644 index 00000000..813e11fe --- /dev/null +++ b/mkDevShell/instrumentation.nix @@ -0,0 +1,64 @@ +{ lib, pkgs, config }: +let + inherit (config) + name + dev-ca-path + static-dns + ; + installProjectCA = { + name = "ca-install"; + help = "install dev CA"; + category = "host state"; + package = pkgs.mkcert; + command = '' + echo "$(tput bold)Installing the ${name}'s dev CA into local trust stores via mkcert command ...$(tput sgr0)" + export CAROOT=${dev-ca-path} + ${pkgs.mkcert}/bin/mkcert -install + ''; + }; + uninstallProjectCA = { + name = "ca-uninstall"; + help = "uninstall dev CA"; + category = "host state"; + package = pkgs.mkcert; + command = '' + echo "$(tput bold)Purging the ${name}'s dev CA from local trust stores via mkcert command ...$(tput sgr0)" + export CAROOT=${dev-ca-path} + ${pkgs.mkcert}/bin/mkcert -uninstall + ''; + }; + + etcHosts = pkgs.writeText "${name}-etchosts" + (lib.concatStringsSep "\n" + (lib.mapAttrsToList (name: value: value + " " + name) static-dns) + ); + # since this temporarily modifies /etc/hosts, use of sudo can't be avoided + fqdnsActivate = { + name = "dns-activate"; + category = "host state"; + help = "activate pre-configured static dns"; + package = pkgs.hostctl; + command = '' + echo "$(tput bold)Installing ${name}'s static local DNS resolution via hostctl command ...$(tput sgr0)" + sudo ${pkgs.hostctl}/bin/hostctl add ${name} --from ${etcHosts} + ''; + }; + fqdnsDeactivate = { + name = "dns-deactivate"; + category = "host state"; + help = "deactivate pre-configured static dns"; + package = pkgs.hostctl; + command = '' + echo "$(tput bold)Purging ${name}'s static local DNS resolution via hostctl command ...$(tput sgr0)" + sudo ${pkgs.hostctl}/bin/hostctl remove ${name} + ''; + }; +in +( + if static-dns == null || static-dns == "" then [ ] + else [ fqdnsActivate fqdnsDeactivate ] +) ++ +( + if dev-ca-path == null || dev-ca-path == "" then [ ] + else [ installProjectCA uninstallProjectCA ] +) diff --git a/mkDevShell/options.nix b/mkDevShell/options.nix index 11aff60c..bde0ec0f 100644 --- a/mkDevShell/options.nix +++ b/mkDevShell/options.nix @@ -1,6 +1,8 @@ { lib, pkgs, config, ... }: with lib; let + instrumentedCommands = import ./instrumentation.nix { inherit lib pkgs config; }; + resolveKey = key: let attrs = builtins.filter builtins.isString (builtins.split "\\." key); @@ -137,6 +139,27 @@ in ''; }; + # exclusively consumed by command instrumentation + dev-ca-path = mkOption { + type = types.str; + default = ""; + description = '' + Path to a development CA. + + Users can load/unload this dev CA easily and cleanly into their local + trust stores via a wrapper around mkcert third party tool so that browsers + and other tools would accept issued certificates under this CA as valid. + + Use cases: + - Ship static dev certificates under version control and make them trusted + on user machines: add the rootCA under version control alongside the + your dev certificates. + - Provide users with easy and reliable CA bootstrapping through the mkcert + command: exempt this path from version control via .gitignore and have + users easily and reliably bootstrap a dev CA infrastructure on first use. + ''; + }; + commands = mkOption { type = types.listOf (types.submodule { options = commandOptions; }); default = [ ]; @@ -210,6 +233,23 @@ in ''; }; + # exclusively consumed by command instrumentation + static-dns = mkOption { + type = types.attrs; + default = { }; + description = '' + A list of static DNS entries, for which to enable instrumentation. + + Users can enable/disable listed static DNS easily and cleanly + via a wrapper around the hostctl third party tool. + ''; + example = { + "test.domain.local" = "172.0.0.1"; + "shared.domain.link-local" = "169.254.0.5"; + }; + }; + + }; config = { @@ -223,10 +263,17 @@ in DEVSHELL_MENU ''; } - ]; + ] ++ instrumentedCommands; packages = - builtins.filter (x: x != null) - (map (x: x.package) config.commands); + lib.unique ( + builtins.filter + (x: x != null) + ( + map + (x: x.package) + config.commands + ) + ); }; } diff --git a/overlay.nix b/overlay.nix index d2770bae..41dc3148 100644 --- a/overlay.nix +++ b/overlay.nix @@ -2,4 +2,5 @@ final: prev: { devshell = prev.callPackage ./devshell { }; mkDevShell = prev.callPackage ./mkDevShell { }; + hostctl = prev.callPackage ./hostctl { }; }