at 17.09-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 ./grow-partition.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.nixosLabel}-${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.kernelParams = [ "console=ttyS0" "panic=1" "boot.panic_on_fail" ]; 33 boot.initrd.kernelModules = [ "virtio_scsi" ]; 34 boot.kernelModules = [ "virtio_pci" "virtio_net" ]; 35 36 # Generate a GRUB menu. Amazon's pv-grub uses this to boot our kernel/initrd. 37 boot.loader.grub.device = "/dev/sda"; 38 boot.loader.timeout = 0; 39 40 # Don't put old configurations in the GRUB menu. The user has no 41 # way to select them anyway. 42 boot.loader.grub.configurationLimit = 0; 43 44 # Allow root logins only using the SSH key that the user specified 45 # at instance creation time. 46 services.openssh.enable = true; 47 services.openssh.permitRootLogin = "prohibit-password"; 48 services.openssh.passwordAuthentication = mkDefault false; 49 50 # Use GCE udev rules for dynamic disk volumes 51 services.udev.packages = [ gce ]; 52 53 # Force getting the hostname from Google Compute. 54 networking.hostName = mkDefault ""; 55 56 # Always include cryptsetup so that NixOps can use it. 57 environment.systemPackages = [ pkgs.cryptsetup ]; 58 59 # Rely on GCP's firewall instead 60 networking.firewall.enable = mkDefault false; 61 62 # Configure default metadata hostnames 63 networking.extraHosts = '' 64 169.254.169.254 metadata.google.internal metadata 65 ''; 66 67 networking.timeServers = [ "metadata.google.internal" ]; 68 69 networking.usePredictableInterfaceNames = false; 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 197 systemd.services.fetch-ssh-keys = 198 { description = "Fetch host keys and authorized_keys for root user"; 199 200 wantedBy = [ "sshd.service" ]; 201 before = [ "sshd.service" ]; 202 after = [ "network-online.target" ]; 203 wants = [ "network-online.target" ]; 204 205 script = let wget = "${pkgs.wget}/bin/wget --retry-connrefused -t 15 --waitretry=10 --header='Metadata-Flavor: Google'"; 206 mktemp = "mktemp --tmpdir=/run"; in 207 '' 208 # When dealing with cryptographic keys, we want to keep things private. 209 umask 077 210 # Don't download the SSH key if it has already been downloaded 211 echo "Obtaining SSH keys..." 212 mkdir -m 0700 -p /root/.ssh 213 AUTH_KEYS=$(${mktemp}) 214 ${wget} -O $AUTH_KEYS http://metadata.google.internal/computeMetadata/v1/project/attributes/sshKeys 215 if [ -s $AUTH_KEYS ]; then 216 217 # Read in key one by one, split in case Google decided 218 # to append metadata (it does sometimes) and add to 219 # authorized_keys if not already present. 220 touch /root/.ssh/authorized_keys 221 NEW_KEYS=$(${mktemp}) 222 # Yes this is a nix escape of two single quotes. 223 while IFS=''' read -r line || [[ -n "$line" ]]; do 224 keyLine=$(echo -n "$line" | cut -d ':' -f2) 225 IFS=' ' read -r -a array <<< "$keyLine" 226 if [ ''${#array[@]} -ge 3 ]; then 227 echo ''${array[@]:0:3} >> $NEW_KEYS 228 echo "Added ''${array[@]:2} to authorized_keys" 229 fi 230 done < $AUTH_KEYS 231 mv $NEW_KEYS /root/.ssh/authorized_keys 232 chmod 600 /root/.ssh/authorized_keys 233 rm -f $KEY_PUB 234 else 235 echo "Downloading http://metadata.google.internal/computeMetadata/v1/project/attributes/sshKeys failed." 236 false 237 fi 238 rm -f $AUTH_KEYS 239 ''; 240 serviceConfig.Type = "oneshot"; 241 serviceConfig.RemainAfterExit = true; 242 serviceConfig.StandardError = "journal+console"; 243 serviceConfig.StandardOutput = "journal+console"; 244 }; 245 246 # Settings taken from https://github.com/GoogleCloudPlatform/compute-image-packages/blob/master/google_config/sysctl/11-gce-network-security.conf 247 boot.kernel.sysctl = { 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). 253 "net.ipv4.tcp_syncookies" = mkDefault "1"; 254 255 # ignores source-routed packets 256 "net.ipv4.conf.all.accept_source_route" = mkDefault "0"; 257 258 # ignores source-routed packets 259 "net.ipv4.conf.default.accept_source_route" = mkDefault "0"; 260 261 # ignores ICMP redirects 262 "net.ipv4.conf.all.accept_redirects" = mkDefault "0"; 263 264 # ignores ICMP redirects 265 "net.ipv4.conf.default.accept_redirects" = mkDefault "0"; 266 267 # ignores ICMP redirects from non-GW hosts 268 "net.ipv4.conf.all.secure_redirects" = mkDefault "1"; 269 270 # ignores ICMP redirects from non-GW hosts 271 "net.ipv4.conf.default.secure_redirects" = mkDefault "1"; 272 273 # don't allow traffic between networks or act as a router 274 "net.ipv4.ip_forward" = mkDefault "0"; 275 276 # don't allow traffic between networks or act as a router 277 "net.ipv4.conf.all.send_redirects" = mkDefault "0"; 278 279 # don't allow traffic between networks or act as a router 280 "net.ipv4.conf.default.send_redirects" = mkDefault "0"; 281 282 # reverse path filtering - IP spoofing protection 283 "net.ipv4.conf.all.rp_filter" = mkDefault "1"; 284 285 # reverse path filtering - IP spoofing protection 286 "net.ipv4.conf.default.rp_filter" = mkDefault "1"; 287 288 # ignores ICMP broadcasts to avoid participating in Smurf attacks 289 "net.ipv4.icmp_echo_ignore_broadcasts" = mkDefault "1"; 290 291 # ignores bad ICMP errors 292 "net.ipv4.icmp_ignore_bogus_error_responses" = mkDefault "1"; 293 294 # logs spoofed, source-routed, and redirect packets 295 "net.ipv4.conf.all.log_martians" = mkDefault "1"; 296 297 # log spoofed, source-routed, and redirect packets 298 "net.ipv4.conf.default.log_martians" = mkDefault "1"; 299 300 # implements RFC 1337 fix 301 "net.ipv4.tcp_rfc1337" = mkDefault "1"; 302 303 # randomizes addresses of mmap base, heap, stack and VDSO page 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 310 311 # provides protection from ToCToU races 312 "fs.protected_hardlinks" = mkDefault "1"; 313 314 # provides protection from ToCToU races 315 "fs.protected_symlinks" = mkDefault "1"; 316 317 # makes locating kernel addresses more difficult 318 "kernel.kptr_restrict" = mkDefault "1"; 319 320 # set ptrace protections 321 "kernel.yama.ptrace_scope" = mkOverride 500 "1"; 322 323 # set perf only available to root 324 "kernel.perf_event_paranoid" = mkDefault "2"; 325 326 }; 327 328}