google-compute-image module: use google services

This adds a few google-specific services to setup the machine.

Accounts are now dynamically created using the google-accounts-daemon,
which allows to click on the "SSH" button in the console and have it
working.

The NixOS image now supports the userdata startup and shutdown scripts.

Misc:
* add all the google services from https://github.com/GoogleCloudPlatform/compute-image-packages/tree/master/google_compute_engine_init/systemd
* add udev rules for disk labels
* synched sysctl rules with https://github.com/GoogleCloudPlatform/compute-image-packages/blob/master/google_config/sysctl/11-gce-network-security.conf

+144 -5
+144 -5
nixos/modules/virtualisation/google-compute-image.nix
··· 3 3 with lib; 4 4 let 5 5 diskSize = 1024; # MB 6 + gce = pkgs.google-compute-engine; 6 7 in 7 8 { 8 9 imports = [ ../profiles/headless.nix ../profiles/qemu-guest.nix ./grow-partition.nix ]; 9 - 10 - # https://cloud.google.com/compute/docs/tutorials/building-images 11 - networking.firewall.enable = mkDefault false; 12 10 13 11 system.build.googleComputeImage = import ../../lib/make-disk-image.nix { 14 12 name = "google-compute-image"; ··· 49 47 services.openssh.permitRootLogin = "prohibit-password"; 50 48 services.openssh.passwordAuthentication = mkDefault false; 51 49 50 + # Use GCE udev rules for dynamic disk volumes 51 + services.udev.packages = [ gce ]; 52 + 52 53 # Force getting the hostname from Google Compute. 53 54 networking.hostName = mkDefault ""; 54 55 55 56 # Always include cryptsetup so that NixOps can use it. 56 57 environment.systemPackages = [ pkgs.cryptsetup ]; 57 58 59 + # Rely on GCP's firewall instead 60 + networking.firewall.enable = mkDefault false; 61 + 58 62 # Configure default metadata hostnames 59 63 networking.extraHosts = '' 60 64 169.254.169.254 metadata.google.internal metadata ··· 64 68 65 69 networking.usePredictableInterfaceNames = false; 66 70 71 + # allow the google-accounts-daemon to manage users 72 + users.mutableUsers = true; 73 + # and allow users to sudo without password 74 + security.sudo.enable = true; 75 + security.sudo.extraConfig = '' 76 + %google-sudoers ALL=(ALL:ALL) NOPASSWD:ALL 77 + ''; 78 + 79 + # NOTE: google-accounts tries to write to /etc/sudoers.d but the folder doesn't exist 80 + # FIXME: not such file or directory on dynamic SSH provisioning 81 + systemd.services.google-accounts-daemon = { 82 + description = "Google Compute Engine Accounts Daemon"; 83 + # This daemon creates dynamic users 84 + enable = config.users.mutableUsers; 85 + after = [ 86 + "network.target" 87 + "google-instance-setup.service" 88 + "google-network-setup.service" 89 + ]; 90 + wantedBy = [ "multi-user.target" ]; 91 + requires = ["network.target"]; 92 + path = with pkgs; [ shadow ]; 93 + serviceConfig = { 94 + Type = "simple"; 95 + ExecStart = "${gce}/bin/google_accounts_daemon --debug"; 96 + }; 97 + }; 98 + 99 + systemd.services.google-clock-skew-daemon = { 100 + description = "Google Compute Engine Clock Skew Daemon"; 101 + after = [ 102 + "network.target" 103 + "google-instance-setup.service" 104 + "google-network-setup.service" 105 + ]; 106 + requires = [ "network.target" ]; 107 + wantedBy = [ "multi-user.target" ]; 108 + serviceConfig = { 109 + Type = "simple"; 110 + ExecStart = "${gce}/bin/google_clock_skew_daemon --debug"; 111 + }; 112 + }; 113 + 114 + systemd.services.google-instance-setup = { 115 + description = "Google Compute Engine Instance Setup"; 116 + after = ["fs.target" "network-online.target" "network.target" "rsyslog.service"]; 117 + before = ["sshd.service"]; 118 + wants = ["local-fs.target" "network-online.target" "network.target"]; 119 + wantedBy = [ "sshd.service" "multi-user.target" ]; 120 + path = with pkgs; [ ethtool ]; 121 + serviceConfig = { 122 + ExecStart = "${gce}/bin/google_instance_setup --debug"; 123 + Type = "oneshot"; 124 + }; 125 + }; 126 + 127 + systemd.services.google-ip-forwarding-daemon = { 128 + description = "Google Compute Engine IP Forwarding Daemon"; 129 + after = ["network.target" "google-instance-setup.service" "google-network-setup.service"]; 130 + requires = ["network.target"]; 131 + wantedBy = [ "multi-user.target" ]; 132 + path = with pkgs; [ iproute ]; 133 + serviceConfig = { 134 + Type = "simple"; 135 + ExecStart = "${gce}/bin/google_ip_forwarding_daemon --debug"; 136 + }; 137 + }; 138 + 139 + systemd.services.google-shutdown-scripts = { 140 + description = "Google Compute Engine Shutdown Scripts"; 141 + after = [ 142 + "local-fs.target" 143 + "network-online.target" 144 + "network.target" 145 + "rsyslog.service" 146 + "google-instance-setup.service" 147 + "google-network-setup.service" 148 + ]; 149 + wants = [ "local-fs.target" "network-online.target" "network.target"]; 150 + wantedBy = [ "multi-user.target" ]; 151 + serviceConfig = { 152 + ExecStart = "${pkgs.coreutils}/bin/true"; 153 + ExecStop = "${gce}/bin/google_metadata_script_runner --debug --script-type shutdown"; 154 + Type = "oneshot"; 155 + RemainAfterExit = true; 156 + TimeoutStopSec = 0; 157 + }; 158 + }; 159 + 160 + systemd.services.google-network-setup = { 161 + description = "Google Compute Engine Network Setup"; 162 + after = [ 163 + "local-fs.target" 164 + "network-online.target" 165 + "network.target" 166 + "rsyslog.service" 167 + ]; 168 + wants = [ "local-fs.target" "network-online.target" "network.target"]; 169 + wantedBy = [ "multi-user.target" ]; 170 + serviceConfig = { 171 + ExecStart = "${gce}/bin/google_network_setup --debug"; 172 + KillMode = "process"; 173 + Type = "oneshot"; 174 + }; 175 + }; 176 + 177 + systemd.services.google-startup-scripts = { 178 + description = "Google Compute Engine Startup Scripts"; 179 + after = [ 180 + "local-fs.target" 181 + "network-online.target" 182 + "network.target" 183 + "rsyslog.service" 184 + "google-instance-setup.service" 185 + "google-network-setup.service" 186 + ]; 187 + wants = [ "local-fs.target" "network-online.target" "network.target"]; 188 + wantedBy = [ "multi-user.target" ]; 189 + serviceConfig = { 190 + ExecStart = "${gce}/bin/google_metadata_script_runner --debug --script-type startup"; 191 + KillMode = "process"; 192 + Type = "oneshot"; 193 + }; 194 + }; 195 + 196 + # TODO: remove this 67 197 systemd.services.fetch-ssh-keys = 68 198 { description = "Fetch host keys and authorized_keys for root user"; 69 199 ··· 113 243 serviceConfig.StandardOutput = "journal+console"; 114 244 }; 115 245 116 - # Setings taken from https://cloud.google.com/compute/docs/tutorials/building-images#providedkernel 246 + # Settings taken from https://github.com/GoogleCloudPlatform/compute-image-packages/blob/master/google_config/sysctl/11-gce-network-security.conf 117 247 boot.kernel.sysctl = { 118 - # enables syn flood protection 248 + # Turn on SYN-flood protections. Starting with 2.6.26, there is no loss 249 + # of TCP functionality/features under normal conditions. When flood 250 + # protections kick in under high unanswered-SYN load, the system 251 + # should remain more stable, with a trade off of some loss of TCP 252 + # functionality/features (e.g. TCP Window scaling). 119 253 "net.ipv4.tcp_syncookies" = mkDefault "1"; 120 254 121 255 # ignores source-routed packets ··· 168 302 169 303 # randomizes addresses of mmap base, heap, stack and VDSO page 170 304 "kernel.randomize_va_space" = mkDefault "2"; 305 + 306 + # Reboot the machine soon after a kernel panic. 307 + "kernel.panic" = mkDefault "10"; 308 + 309 + ## Not part of the original config 171 310 172 311 # provides protection from ToCToU races 173 312 "fs.protected_hardlinks" = mkDefault "1";