diff --git a/morph/grid/local/README.rst b/morph/grid/local/README.rst index 345547244635734278aa76cb5cd59946f2afd37f..f899c4975bab131e969acc79e8b39dee139b1554 100644 --- a/morph/grid/local/README.rst +++ b/morph/grid/local/README.rst @@ -33,13 +33,6 @@ Use the local development environment install -d ~/.ssh ; vagrant ssh-config >> ~/.ssh/config -5. Edit the generated configuration: Add the ``publicIP`` addresses from ``grid.nix`` to ssh config **Host** match blocks (**not** HostName) so the ``Host`` lines all read like:: - - Host payments 192.168.67.21 - HostName 127.0.0.1 - User vagrant - [...] - Latest Morph honors the ``SSH_CONFIG_FILE`` environment variable (`since 3f90aa88 (March 2020, v 1.5.0) <https://github.com/DBCDK/morph/commit/3f90aa885fac1c29fce9242452fa7c0c505744ef#diff-d155ad793bd62e6ea4c44ba985049ecb13a4f4f32f799791b2bce695a16c0101>`_), so in the future this should get a bit more convenient. 6. Add your SSH key to ``users.nix`` so you'll be able to log in after deploying the new configuration:: @@ -56,4 +49,3 @@ Use the local development environment morph upload-secrets grid.nix You should now be able to log in with the users and keys you set in your ``users.nix`` file. - diff --git a/morph/grid/local/Vagrantfile b/morph/grid/local/Vagrantfile index 7ad95ca872a72e5da6c11b3269e2a824cf8a55f9..fd374a2cc26da63262a16fdf462e235fc5523fd1 100644 --- a/morph/grid/local/Vagrantfile +++ b/morph/grid/local/Vagrantfile @@ -8,7 +8,7 @@ Vagrant.configure("2") do |config| # For a complete reference, please see the online documentation at # https://docs.vagrantup.com. - config.vm.define "payments" do |config| + config.vm.define "payments.localdev" do |config| config.vm.hostname = "payments" config.vm.box = "esselius/nixos" config.vm.box_version = "20.09" @@ -20,7 +20,7 @@ Vagrant.configure("2") do |config| config.vm.provision "shell", inline: "sudo mv /tmp/payments-localdev-ssl/* /var/lib/letsencrypt/live/payments.localdev/" end - config.vm.define "storage1" do |config| + config.vm.define "storage1.localdev" do |config| config.vm.hostname = "storage1" config.vm.box = "esselius/nixos" config.vm.box_version = "20.09" @@ -28,7 +28,7 @@ Vagrant.configure("2") do |config| config.vm.network "private_network", ip: "192.168.67.22" end - config.vm.define "storage2" do |config| + config.vm.define "storage2.localdev" do |config| config.vm.hostname = "storage2" config.vm.box = "esselius/nixos" config.vm.box_version = "20.09" @@ -36,7 +36,7 @@ Vagrant.configure("2") do |config| config.vm.network "private_network", ip: "192.168.67.23" end - config.vm.define "monitoring" do |config| + config.vm.define "monitoring.localdev" do |config| config.vm.hostname = "monitoring" config.vm.box = "esselius/nixos" config.vm.box_version = "20.09" @@ -54,4 +54,3 @@ Vagrant.configure("2") do |config| end end - diff --git a/morph/grid/local/config.json b/morph/grid/local/config.json index 38f00367bf2fa36ad7663c89f7849146783b8515..3d377cc0e1ebbdec0dff421c806c901e2e5ce06d 100644 --- a/morph/grid/local/config.json +++ b/morph/grid/local/config.json @@ -1,4 +1,5 @@ -{ "publicStoragePort": 8898 +{ "domain": "localdev" +, "publicStoragePort": 8898 , "ristrettoSigningKeyPath": "./secrets/ristretto.signing-key" , "stripeSecretKeyPath": "./secrets/stripe.secret" , "monitoringvpnKeyDir": "./secrets/monitoringvpn" diff --git a/morph/grid/local/grid.nix b/morph/grid/local/grid.nix index 1729425d91bc02f56fa895d04731ffcc74971cbe..5345a16198e79dd8c91c8566fb62480ce5cea51a 100644 --- a/morph/grid/local/grid.nix +++ b/morph/grid/local/grid.nix @@ -10,47 +10,45 @@ let monitoringvpnKeyDir = toString ./. + "/${rawConfig.monitoringvpnKeyDir}"; }; - payments = let publicIPv4 = "192.168.67.21"; in { + payments = { imports = [ gridlib.issuer - (gridlib.hardware-virtual ({ inherit publicIPv4; })) + (gridlib.hardware-virtual ({ publicIPv4 = "192.168.67.21"; })) (gridlib.customize-issuer (config // { monitoringvpnIPv4 = "172.23.23.11"; })) ]; }; - storage1 = let publicIPv4 = "192.168.67.22"; in { + storage1 = { imports = [ gridlib.storage - (gridlib.hardware-virtual ({ inherit publicIPv4; })) + (gridlib.hardware-virtual ({ publicIPv4 = "192.168.67.22"; })) (gridlib.customize-storage (config // { - inherit publicIPv4; monitoringvpnIPv4 = "172.23.23.12"; stateVersion = "19.09"; })) ]; }; - storage2 = let publicIPv4 = "192.168.67.23"; in { + storage2 = { imports = [ gridlib.storage - (gridlib.hardware-virtual ({ inherit publicIPv4; })) + (gridlib.hardware-virtual ({ publicIPv4 = "192.168.67.23"; })) (gridlib.customize-storage (config // { - inherit publicIPv4; monitoringvpnIPv4 = "172.23.23.13"; stateVersion = "19.09"; })) ]; }; - monitoring = let publicIPv4 = "192.168.67.24"; in { + monitoring = { imports = [ gridlib.monitoring - (gridlib.hardware-virtual ({ inherit publicIPv4; })) + (gridlib.hardware-virtual ({ publicIPv4 = "192.168.67.24"; })) (gridlib.customize-monitoring { - inherit hostsMap publicIPv4 vpnClientIPs nodeExporterTargets; - inherit (config) monitoringvpnKeyDir; + inherit hostsMap vpnClientIPs nodeExporterTargets; + inherit (config) domain monitoringvpnKeyDir; monitoringvpnIPv4 = "172.23.23.1"; stateVersion = "19.09"; }) diff --git a/morph/grid/production/config.json b/morph/grid/production/config.json index ef7dc53649febcd7beb7901bb3608204df197059..21e080d587ae2713a73f756b2b7e078d843b2a95 100644 --- a/morph/grid/production/config.json +++ b/morph/grid/production/config.json @@ -1,4 +1,5 @@ -{ "publicStoragePort": 8898 +{ "domain": "private.storage" +, "publicStoragePort": 8898 , "ristrettoSigningKeyPath": "./secrets/ristretto.signing-key" , "stripeSecretKeyPath": "./secrets/stripe.secret" , "monitoringvpnKeyDir": "./secrets/monitoringvpn" diff --git a/morph/grid/production/grid.nix b/morph/grid/production/grid.nix index 7a8e29bb58da584d07660663912a1c993146787b..ae51174b4f15a72ca0c1d1798b067ecb1db64bb3 100644 --- a/morph/grid/production/grid.nix +++ b/morph/grid/production/grid.nix @@ -21,25 +21,29 @@ let ]; }; - monitoring = let publicIPv4 = "monitoring.private.storage"; in { + monitoring = { imports = [ gridlib.monitoring gridlib.hardware-aws (gridlib.customize-monitoring { - inherit hostsMap publicIPv4 vpnClientIPs nodeExporterTargets; - inherit (config) monitoringvpnKeyDir; + inherit hostsMap vpnClientIPs nodeExporterTargets; + inherit (config) domain monitoringvpnKeyDir; monitoringvpnIPv4 = "172.23.23.1"; stateVersion = "19.09"; }) ]; }; - defineStorageNode = name: { vpnIP, stateVersion }: let nodecfg = import "${./.}/${name}-config.nix"; in { + defineStorageNode = name: { vpnIP, stateVersion }: + let + nodecfg = import "${./.}/${name}-config.nix"; + hardware ="${./.}/${name}-hardware.nix"; + in { imports = [ # Get some of the very lowest-level system configuration for this # node. This isn't all *completely* hardware related. Maybe some # more factoring is in order, someday. - "${./.}/${name}-hardware.nix" + hardware # Slightly awkwardly, enable some of our hardware / network / bootloader options. ../../../nixos/modules/100tb.nix @@ -102,7 +106,6 @@ in { network = { description = "PrivateStorage.io Production Grid"; }; - - "payments.privatestorage.io" = payments; + inherit payments; inherit monitoring; } // storageNodes diff --git a/morph/grid/testing/config.json b/morph/grid/testing/config.json index a44b465f7f293f9d70c369a076c30b6cf810924f..c069bbed531e63a425e16a1838dedbfd2f17374d 100644 --- a/morph/grid/testing/config.json +++ b/morph/grid/testing/config.json @@ -1,4 +1,5 @@ -{ "publicStoragePort": 8898 +{ "domain": "privatestorage-staging.com" +, "publicStoragePort": 8898 , "ristrettoSigningKeyPath": "./secrets/ristretto.signing-key" , "stripeSecretKeyPath": "./secrets/stripe.secret" , "monitoringvpnKeyDir": "./secrets/monitoringvpn" diff --git a/morph/grid/testing/grid.nix b/morph/grid/testing/grid.nix index 8e68558a13c750eebac48c40dc0822d7f24db1bf..19eefd9d50d49094a0bcf87698f8c8091032e1fa 100644 --- a/morph/grid/testing/grid.nix +++ b/morph/grid/testing/grid.nix @@ -21,25 +21,24 @@ let ]; }; - storage001 = let publicIPv4 = "3.120.26.190"; in { + storage001 = { imports = [ gridlib.storage ./testing001-hardware.nix (gridlib.customize-storage (config // { - inherit publicIPv4; monitoringvpnIPv4 = "172.23.23.12"; stateVersion = "19.03"; })) ]; }; - monitoring = let publicIPv4 = "18.156.171.217"; in { + monitoring = { imports = [ gridlib.monitoring gridlib.hardware-aws (gridlib.customize-monitoring { - inherit hostsMap publicIPv4 vpnClientIPs nodeExporterTargets; - inherit (config) monitoringvpnKeyDir; + inherit hostsMap vpnClientIPs nodeExporterTargets; + inherit (config) domain monitoringvpnKeyDir; monitoringvpnIPv4 = "172.23.23.1"; stateVersion = "19.09"; }) diff --git a/morph/lib/customize-issuer.nix b/morph/lib/customize-issuer.nix index 410bce47db83381f42949a4b8dd3f552f1b0bc5c..28edb72e7e0b74879e9e676113c327f50b040d40 100644 --- a/morph/lib/customize-issuer.nix +++ b/morph/lib/customize-issuer.nix @@ -26,6 +26,15 @@ # A string giving the VPN IPv4 address for this system. , monitoringvpnIPv4 + # A string giving the domain name associated with this grid. This is meant + # to be combined with the hostname for this system to produce a + # fully-qualified domain name. For example, an issuer might have "payments" + # as its hostname and belong to a grid with the domain + # "example-grid.invalid". This ``domain`` parameter should have the value + # ``"example-grid.invalid"`` for the system figure out that + # ``payments.example-grid.invalid`` is the name of this system. +, domain + # A set mapping usernames as strings to SSH public keys as strings. For # each element of the site, the indicated user is configured on the system # with the indicated SSH key as an authorized key. @@ -43,7 +52,16 @@ # to allow. , allowedChargeOrigins , ... -}: { +}: +{ config, ... }: { + # The morph default deployment target the name of the node in the network + # attrset. We don't always want to give the node its proper public address + # there (because it depends on which domain is associated with the grid + # being configured and using variable names complicates a lot of things). + # Instead, just tell morph how to reach the node here - by using its fully + # qualified domain name. + deployment.targetHost = "${config.networking.hostName}.${config.networking.domain}"; + deployment.secrets = { "ristretto-signing-key".source = ristrettoSigningKeyPath; "stripe-secret-key".source = stripeSecretKeyPath; @@ -51,6 +69,8 @@ "monitoringvpn-preshared-key".source = "${monitoringvpnKeyDir}/preshared.key"; }; + networking.domain = domain; + services.private-storage.sshUsers = sshUsers; services.private-storage.monitoring.vpn.client = { enable = true; diff --git a/morph/lib/customize-monitoring.nix b/morph/lib/customize-monitoring.nix index 331a2dbd7c9875acbf72ae22da786f4bc868cfc0..c50eb5062b35480d0b3d296cfaea8abd999f36c5 100644 --- a/morph/lib/customize-monitoring.nix +++ b/morph/lib/customize-monitoring.nix @@ -11,9 +11,7 @@ # See ``customize-issuer.nix``. , monitoringvpnKeyDir , monitoringvpnIPv4 - - # XXX To be removed -, publicIPv4 +, domain # A list of VPN IP addresses as strings indicating which clients will be # allowed onto the VPN. @@ -30,12 +28,17 @@ # A string giving the NixOS state version for the system. , stateVersion , ... -}: { - deployment.targetHost = publicIPv4; +}: +{ config, ... }: { + # See customize-issuer.nix for an explanatoin of targetHost value. + deployment.targetHost = "${config.networking.hostName}.${config.networking.domain}"; + deployment.secrets = { "monitoringvpn-private-key".source = "${monitoringvpnKeyDir}/server.key"; "monitoringvpn-preshared-key".source = "${monitoringvpnKeyDir}/preshared.key"; }; + + networking.domain = domain; networking.hosts = hostsMap; services.private-storage.monitoring.vpn.server = { diff --git a/morph/lib/customize-storage.nix b/morph/lib/customize-storage.nix index b9d25e985977bc77d08c21fd869644ab170c3b64..0a08743633126b5898e61a877e62a7b58314b34e 100644 --- a/morph/lib/customize-storage.nix +++ b/morph/lib/customize-storage.nix @@ -7,6 +7,7 @@ , monitoringvpnEndpoint , monitoringvpnIPv4 , sshUsers +, domain # An integer giving the value of a single pass in byte×months. , passValue @@ -15,21 +16,24 @@ # advertisements and on which to listen for storage connections. , publicStoragePort - # XXX To be removed -, publicIPv4 - # A string giving the NixOS state version for the system. , stateVersion , ... -}: { +}: +{ config, ... }: { + # See customize-issuer.nix for an explanatoin of targetHost value. + deployment.targetHost = "${config.networking.hostName}.${config.networking.domain}"; + deployment.secrets = { "ristretto-signing-key".source = ristrettoSigningKeyPath; "monitoringvpn-secret-key".source = "${monitoringvpnKeyDir}/${monitoringvpnIPv4}.key"; "monitoringvpn-preshared-key".source = "${monitoringvpnKeyDir}/preshared.key"; }; + networking.domain = domain; + services.private-storage = { - inherit sshUsers publicIPv4 passValue publicStoragePort; + inherit sshUsers passValue publicStoragePort; }; services.private-storage.monitoring.vpn.client = { diff --git a/nixos/modules/private-storage.nix b/nixos/modules/private-storage.nix index 52720e618973c57b41aade87585c7ab758abff22..38e224709e783b9590de73d728e4d6ca134e5adb 100644 --- a/nixos/modules/private-storage.nix +++ b/nixos/modules/private-storage.nix @@ -18,6 +18,12 @@ let # NOTE: This is promised by the service privacy policy. It *may not* be # raised without following the process for updating the privacy policy. max-incident-age = "29d"; + + fqdn = "${ + assert config.networking.hostName != null; config.networking.hostName + }.${ + assert config.networking.domain != null; config.networking.domain + }"; in { imports = [ @@ -38,12 +44,13 @@ in The package to use for the Tahoe-LAFS daemon. ''; }; - services.private-storage.publicIPv4 = lib.mkOption - { default = "127.0.0.1"; + services.private-storage.publicAddress = lib.mkOption + { default = "${fqdn}"; type = lib.types.str; - example = lib.literalExample "192.0.2.0"; + example = lib.literalExample "storage.example.invalid"; description = '' - An IPv4 address to advertise for this storage service. + A publicly-visible address to use in Tahoe-LAFS advertisements for + this storage service. ''; }; services.private-storage.introducerFURL = lib.mkOption @@ -63,7 +70,7 @@ in ''; }; services.private-storage.issuerRootURL = lib.mkOption - { default = "https://issuer.privatestorage.io/"; + { default = "https://issuer.${config.networking.domain}/"; type = lib.types.str; example = lib.literalExample "https://example.invalid/"; description = '' @@ -122,7 +129,7 @@ in # First, in the syntax which it uses to listen. "tub.port" = "tcp:${toString cfg.publicStoragePort}"; # Second, in the syntax it advertises to in the fURL. - "tub.location" = "tcp:${cfg.publicIPv4}:${toString cfg.publicStoragePort}"; + "tub.location" = "tcp:${cfg.publicAddress}:${toString cfg.publicStoragePort}"; }; storage = { enabled = true; diff --git a/nixos/modules/tests/private-storage.nix b/nixos/modules/tests/private-storage.nix index cbf4c5937ca6780ce9e931d6ceec91c29643fbc3..353abc891fafd1cc988e47a1befa530a012470dc 100644 --- a/nixos/modules/tests/private-storage.nix +++ b/nixos/modules/tests/private-storage.nix @@ -115,7 +115,7 @@ in { ]; services.private-storage = { enable = true; - publicIPv4 = "storage"; + publicAddress = "storage"; introducerFURL = introducerFURL; issuerRootURL = issuerURL; inherit ristrettoSigningKeyPath;