at 18.03-beta 11 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4let 5 diskSize = 1024; # MB 6 gce = pkgs.google-compute-engine; 7in 8{ 9 imports = [ ../profiles/headless.nix ../profiles/qemu-guest.nix ]; 10 11 system.build.googleComputeImage = import ../../lib/make-disk-image.nix { 12 name = "google-compute-image"; 13 postVM = '' 14 PATH=$PATH:${pkgs.stdenv.lib.makeBinPath [ pkgs.gnutar pkgs.gzip ]} 15 pushd $out 16 mv $diskImage disk.raw 17 tar -Szcf nixos-image-${config.system.nixos.label}-${pkgs.stdenv.system}.raw.tar.gz disk.raw 18 rm $out/disk.raw 19 popd 20 ''; 21 configFile = <nixpkgs/nixos/modules/virtualisation/google-compute-config.nix>; 22 format = "raw"; 23 inherit diskSize; 24 inherit config lib pkgs; 25 }; 26 27 fileSystems."/" = { 28 device = "/dev/disk/by-label/nixos"; 29 autoResize = true; 30 }; 31 32 boot.growPartition = true; 33 boot.kernelParams = [ "console=ttyS0" "panic=1" "boot.panic_on_fail" ]; 34 boot.initrd.kernelModules = [ "virtio_scsi" ]; 35 boot.kernelModules = [ "virtio_pci" "virtio_net" ]; 36 37 # Generate a GRUB menu. Amazon's pv-grub uses this to boot our kernel/initrd. 38 boot.loader.grub.device = "/dev/sda"; 39 boot.loader.timeout = 0; 40 41 # Don't put old configurations in the GRUB menu. The user has no 42 # way to select them anyway. 43 boot.loader.grub.configurationLimit = 0; 44 45 # Allow root logins only using the SSH key that the user specified 46 # at instance creation time. 47 services.openssh.enable = true; 48 services.openssh.permitRootLogin = "prohibit-password"; 49 services.openssh.passwordAuthentication = mkDefault false; 50 51 # Use GCE udev rules for dynamic disk volumes 52 services.udev.packages = [ gce ]; 53 54 # Force getting the hostname from Google Compute. 55 networking.hostName = mkDefault ""; 56 57 # Always include cryptsetup so that NixOps can use it. 58 environment.systemPackages = [ pkgs.cryptsetup ]; 59 60 # Rely on GCP's firewall instead 61 networking.firewall.enable = mkDefault false; 62 63 # Configure default metadata hostnames 64 networking.extraHosts = '' 65 169.254.169.254 metadata.google.internal metadata 66 ''; 67 68 networking.timeServers = [ "metadata.google.internal" ]; 69 70 networking.usePredictableInterfaceNames = false; 71 72 # allow the google-accounts-daemon to manage users 73 users.mutableUsers = true; 74 # and allow users to sudo without password 75 security.sudo.enable = true; 76 security.sudo.extraConfig = '' 77 %google-sudoers ALL=(ALL:ALL) NOPASSWD:ALL 78 ''; 79 80 # NOTE: google-accounts tries to write to /etc/sudoers.d but the folder doesn't exist 81 # FIXME: not such file or directory on dynamic SSH provisioning 82 systemd.services.google-accounts-daemon = { 83 description = "Google Compute Engine Accounts Daemon"; 84 # This daemon creates dynamic users 85 enable = config.users.mutableUsers; 86 after = [ 87 "network.target" 88 "google-instance-setup.service" 89 "google-network-setup.service" 90 ]; 91 wantedBy = [ "multi-user.target" ]; 92 requires = ["network.target"]; 93 path = with pkgs; [ shadow ]; 94 serviceConfig = { 95 Type = "simple"; 96 ExecStart = "${gce}/bin/google_accounts_daemon --debug"; 97 }; 98 }; 99 100 systemd.services.google-clock-skew-daemon = { 101 description = "Google Compute Engine Clock Skew Daemon"; 102 after = [ 103 "network.target" 104 "google-instance-setup.service" 105 "google-network-setup.service" 106 ]; 107 requires = [ "network.target" ]; 108 wantedBy = [ "multi-user.target" ]; 109 serviceConfig = { 110 Type = "simple"; 111 ExecStart = "${gce}/bin/google_clock_skew_daemon --debug"; 112 }; 113 }; 114 115 systemd.services.google-instance-setup = { 116 description = "Google Compute Engine Instance Setup"; 117 after = ["fs.target" "network-online.target" "network.target" "rsyslog.service"]; 118 before = ["sshd.service"]; 119 wants = ["local-fs.target" "network-online.target" "network.target"]; 120 wantedBy = [ "sshd.service" "multi-user.target" ]; 121 path = with pkgs; [ ethtool openssh ]; 122 serviceConfig = { 123 ExecStart = "${gce}/bin/google_instance_setup --debug"; 124 Type = "oneshot"; 125 }; 126 }; 127 128 systemd.services.google-ip-forwarding-daemon = { 129 description = "Google Compute Engine IP Forwarding Daemon"; 130 after = ["network.target" "google-instance-setup.service" "google-network-setup.service"]; 131 requires = ["network.target"]; 132 wantedBy = [ "multi-user.target" ]; 133 path = with pkgs; [ iproute ]; 134 serviceConfig = { 135 Type = "simple"; 136 ExecStart = "${gce}/bin/google_ip_forwarding_daemon --debug"; 137 }; 138 }; 139 140 systemd.services.google-shutdown-scripts = { 141 description = "Google Compute Engine Shutdown Scripts"; 142 after = [ 143 "local-fs.target" 144 "network-online.target" 145 "network.target" 146 "rsyslog.service" 147 "google-instance-setup.service" 148 "google-network-setup.service" 149 ]; 150 wants = [ "local-fs.target" "network-online.target" "network.target"]; 151 wantedBy = [ "multi-user.target" ]; 152 serviceConfig = { 153 ExecStart = "${pkgs.coreutils}/bin/true"; 154 ExecStop = "${gce}/bin/google_metadata_script_runner --debug --script-type shutdown"; 155 Type = "oneshot"; 156 RemainAfterExit = true; 157 TimeoutStopSec = 0; 158 }; 159 }; 160 161 systemd.services.google-network-setup = { 162 description = "Google Compute Engine Network Setup"; 163 after = [ 164 "local-fs.target" 165 "network-online.target" 166 "network.target" 167 "rsyslog.service" 168 ]; 169 wants = [ "local-fs.target" "network-online.target" "network.target"]; 170 wantedBy = [ "multi-user.target" ]; 171 serviceConfig = { 172 ExecStart = "${gce}/bin/google_network_setup --debug"; 173 KillMode = "process"; 174 Type = "oneshot"; 175 }; 176 }; 177 178 systemd.services.google-startup-scripts = { 179 description = "Google Compute Engine Startup Scripts"; 180 after = [ 181 "local-fs.target" 182 "network-online.target" 183 "network.target" 184 "rsyslog.service" 185 "google-instance-setup.service" 186 "google-network-setup.service" 187 ]; 188 wants = [ "local-fs.target" "network-online.target" "network.target"]; 189 wantedBy = [ "multi-user.target" ]; 190 serviceConfig = { 191 ExecStart = "${gce}/bin/google_metadata_script_runner --debug --script-type startup"; 192 KillMode = "process"; 193 Type = "oneshot"; 194 }; 195 }; 196 197 # TODO: remove this 198 systemd.services.fetch-ssh-keys = 199 { description = "Fetch host keys and authorized_keys for root user"; 200 201 wantedBy = [ "sshd.service" ]; 202 before = [ "sshd.service" ]; 203 after = [ "network-online.target" ]; 204 wants = [ "network-online.target" ]; 205 206 script = let wget = "${pkgs.wget}/bin/wget --retry-connrefused -t 15 --waitretry=10 --header='Metadata-Flavor: Google'"; 207 mktemp = "mktemp --tmpdir=/run"; in 208 '' 209 # When dealing with cryptographic keys, we want to keep things private. 210 umask 077 211 # Don't download the SSH key if it has already been downloaded 212 echo "Obtaining SSH keys..." 213 mkdir -m 0700 -p /root/.ssh 214 AUTH_KEYS=$(${mktemp}) 215 ${wget} -O $AUTH_KEYS --header="Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/instance/attributes/sshKeys 216 if [ -s $AUTH_KEYS ]; then 217 218 # Read in key one by one, split in case Google decided 219 # to append metadata (it does sometimes) and add to 220 # authorized_keys if not already present. 221 touch /root/.ssh/authorized_keys 222 NEW_KEYS=$(${mktemp}) 223 # Yes this is a nix escape of two single quotes. 224 while IFS=''' read -r line || [[ -n "$line" ]]; do 225 keyLine=$(echo -n "$line" | cut -d ':' -f2) 226 IFS=' ' read -r -a array <<< "$keyLine" 227 if [ ''${#array[@]} -ge 3 ]; then 228 echo ''${array[@]:0:3} >> $NEW_KEYS 229 echo "Added ''${array[@]:2} to authorized_keys" 230 fi 231 done < $AUTH_KEYS 232 mv $NEW_KEYS /root/.ssh/authorized_keys 233 chmod 600 /root/.ssh/authorized_keys 234 rm -f $KEY_PUB 235 else 236 echo "Downloading http://metadata.google.internal/computeMetadata/v1/project/attributes/sshKeys failed." 237 false 238 fi 239 rm -f $AUTH_KEYS 240 ''; 241 serviceConfig.Type = "oneshot"; 242 serviceConfig.RemainAfterExit = true; 243 serviceConfig.StandardError = "journal+console"; 244 serviceConfig.StandardOutput = "journal+console"; 245 }; 246 247 # Settings taken from https://github.com/GoogleCloudPlatform/compute-image-packages/blob/master/google_config/sysctl/11-gce-network-security.conf 248 boot.kernel.sysctl = { 249 # Turn on SYN-flood protections. Starting with 2.6.26, there is no loss 250 # of TCP functionality/features under normal conditions. When flood 251 # protections kick in under high unanswered-SYN load, the system 252 # should remain more stable, with a trade off of some loss of TCP 253 # functionality/features (e.g. TCP Window scaling). 254 "net.ipv4.tcp_syncookies" = mkDefault "1"; 255 256 # ignores source-routed packets 257 "net.ipv4.conf.all.accept_source_route" = mkDefault "0"; 258 259 # ignores source-routed packets 260 "net.ipv4.conf.default.accept_source_route" = mkDefault "0"; 261 262 # ignores ICMP redirects 263 "net.ipv4.conf.all.accept_redirects" = mkDefault "0"; 264 265 # ignores ICMP redirects 266 "net.ipv4.conf.default.accept_redirects" = mkDefault "0"; 267 268 # ignores ICMP redirects from non-GW hosts 269 "net.ipv4.conf.all.secure_redirects" = mkDefault "1"; 270 271 # ignores ICMP redirects from non-GW hosts 272 "net.ipv4.conf.default.secure_redirects" = mkDefault "1"; 273 274 # don't allow traffic between networks or act as a router 275 "net.ipv4.ip_forward" = mkDefault "0"; 276 277 # don't allow traffic between networks or act as a router 278 "net.ipv4.conf.all.send_redirects" = mkDefault "0"; 279 280 # don't allow traffic between networks or act as a router 281 "net.ipv4.conf.default.send_redirects" = mkDefault "0"; 282 283 # reverse path filtering - IP spoofing protection 284 "net.ipv4.conf.all.rp_filter" = mkDefault "1"; 285 286 # reverse path filtering - IP spoofing protection 287 "net.ipv4.conf.default.rp_filter" = mkDefault "1"; 288 289 # ignores ICMP broadcasts to avoid participating in Smurf attacks 290 "net.ipv4.icmp_echo_ignore_broadcasts" = mkDefault "1"; 291 292 # ignores bad ICMP errors 293 "net.ipv4.icmp_ignore_bogus_error_responses" = mkDefault "1"; 294 295 # logs spoofed, source-routed, and redirect packets 296 "net.ipv4.conf.all.log_martians" = mkDefault "1"; 297 298 # log spoofed, source-routed, and redirect packets 299 "net.ipv4.conf.default.log_martians" = mkDefault "1"; 300 301 # implements RFC 1337 fix 302 "net.ipv4.tcp_rfc1337" = mkDefault "1"; 303 304 # randomizes addresses of mmap base, heap, stack and VDSO page 305 "kernel.randomize_va_space" = mkDefault "2"; 306 307 # Reboot the machine soon after a kernel panic. 308 "kernel.panic" = mkDefault "10"; 309 310 ## Not part of the original config 311 312 # provides protection from ToCToU races 313 "fs.protected_hardlinks" = mkDefault "1"; 314 315 # provides protection from ToCToU races 316 "fs.protected_symlinks" = mkDefault "1"; 317 318 # makes locating kernel addresses more difficult 319 "kernel.kptr_restrict" = mkDefault "1"; 320 321 # set ptrace protections 322 "kernel.yama.ptrace_scope" = mkOverride 500 "1"; 323 324 # set perf only available to root 325 "kernel.perf_event_paranoid" = mkDefault "2"; 326 327 }; 328 329}