at 18.09-beta 12 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4let 5 diskSize = 1536; # 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.hostPlatform.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 # Make sure GCE image does not replace host key that NixOps sets 61 environment.etc."default/instance_configs.cfg".text = lib.mkDefault '' 62 [InstanceSetup] 63 set_host_keys = false 64 ''; 65 66 # Rely on GCP's firewall instead 67 networking.firewall.enable = mkDefault false; 68 69 # Configure default metadata hostnames 70 networking.extraHosts = '' 71 169.254.169.254 metadata.google.internal metadata 72 ''; 73 74 networking.timeServers = [ "metadata.google.internal" ]; 75 76 networking.usePredictableInterfaceNames = false; 77 78 # GC has 1460 MTU 79 networking.interfaces.eth0.mtu = 1460; 80 81 # allow the google-accounts-daemon to manage users 82 users.mutableUsers = true; 83 # and allow users to sudo without password 84 security.sudo.enable = true; 85 security.sudo.extraConfig = '' 86 %google-sudoers ALL=(ALL:ALL) NOPASSWD:ALL 87 ''; 88 89 # NOTE: google-accounts tries to write to /etc/sudoers.d but the folder doesn't exist 90 # FIXME: not such file or directory on dynamic SSH provisioning 91 systemd.services.google-accounts-daemon = { 92 description = "Google Compute Engine Accounts Daemon"; 93 # This daemon creates dynamic users 94 enable = config.users.mutableUsers; 95 after = [ 96 "network.target" 97 "google-instance-setup.service" 98 "google-network-setup.service" 99 ]; 100 wantedBy = [ "multi-user.target" ]; 101 requires = ["network.target"]; 102 path = with pkgs; [ shadow ]; 103 serviceConfig = { 104 Type = "simple"; 105 ExecStart = "${gce}/bin/google_accounts_daemon --debug"; 106 }; 107 }; 108 109 systemd.services.google-clock-skew-daemon = { 110 description = "Google Compute Engine Clock Skew Daemon"; 111 after = [ 112 "network.target" 113 "google-instance-setup.service" 114 "google-network-setup.service" 115 ]; 116 requires = [ "network.target" ]; 117 wantedBy = [ "multi-user.target" ]; 118 serviceConfig = { 119 Type = "simple"; 120 ExecStart = "${gce}/bin/google_clock_skew_daemon --debug"; 121 }; 122 }; 123 124 systemd.services.google-instance-setup = { 125 description = "Google Compute Engine Instance Setup"; 126 after = ["fs.target" "network-online.target" "network.target" "rsyslog.service"]; 127 before = ["sshd.service"]; 128 wants = ["local-fs.target" "network-online.target" "network.target"]; 129 wantedBy = [ "sshd.service" "multi-user.target" ]; 130 path = with pkgs; [ ethtool openssh ]; 131 serviceConfig = { 132 ExecStart = "${gce}/bin/google_instance_setup --debug"; 133 Type = "oneshot"; 134 }; 135 }; 136 137 systemd.services.google-ip-forwarding-daemon = { 138 description = "Google Compute Engine IP Forwarding Daemon"; 139 after = ["network.target" "google-instance-setup.service" "google-network-setup.service"]; 140 requires = ["network.target"]; 141 wantedBy = [ "multi-user.target" ]; 142 path = with pkgs; [ iproute ]; 143 serviceConfig = { 144 Type = "simple"; 145 ExecStart = "${gce}/bin/google_ip_forwarding_daemon --debug"; 146 }; 147 }; 148 149 systemd.services.google-shutdown-scripts = { 150 description = "Google Compute Engine Shutdown Scripts"; 151 after = [ 152 "local-fs.target" 153 "network-online.target" 154 "network.target" 155 "rsyslog.service" 156 "google-instance-setup.service" 157 "google-network-setup.service" 158 ]; 159 wants = [ "local-fs.target" "network-online.target" "network.target"]; 160 wantedBy = [ "multi-user.target" ]; 161 serviceConfig = { 162 ExecStart = "${pkgs.coreutils}/bin/true"; 163 ExecStop = "${gce}/bin/google_metadata_script_runner --debug --script-type shutdown"; 164 Type = "oneshot"; 165 RemainAfterExit = true; 166 TimeoutStopSec = 0; 167 }; 168 }; 169 170 systemd.services.google-network-setup = { 171 description = "Google Compute Engine Network Setup"; 172 after = [ 173 "local-fs.target" 174 "network-online.target" 175 "network.target" 176 "rsyslog.service" 177 ]; 178 wants = [ "local-fs.target" "network-online.target" "network.target"]; 179 wantedBy = [ "multi-user.target" ]; 180 serviceConfig = { 181 ExecStart = "${gce}/bin/google_network_setup --debug"; 182 KillMode = "process"; 183 Type = "oneshot"; 184 }; 185 }; 186 187 systemd.services.google-startup-scripts = { 188 description = "Google Compute Engine Startup Scripts"; 189 after = [ 190 "local-fs.target" 191 "network-online.target" 192 "network.target" 193 "rsyslog.service" 194 "google-instance-setup.service" 195 "google-network-setup.service" 196 ]; 197 wants = [ "local-fs.target" "network-online.target" "network.target"]; 198 wantedBy = [ "multi-user.target" ]; 199 serviceConfig = { 200 ExecStart = "${gce}/bin/google_metadata_script_runner --debug --script-type startup"; 201 KillMode = "process"; 202 Type = "oneshot"; 203 }; 204 }; 205 206 # TODO: remove this 207 systemd.services.fetch-ssh-keys = 208 { description = "Fetch host keys and authorized_keys for root user"; 209 210 wantedBy = [ "sshd.service" ]; 211 before = [ "sshd.service" ]; 212 after = [ "network-online.target" ]; 213 wants = [ "network-online.target" ]; 214 215 script = let wget = "${pkgs.wget}/bin/wget --retry-connrefused -t 15 --waitretry=10 --header='Metadata-Flavor: Google'"; 216 mktemp = "mktemp --tmpdir=/run"; in 217 '' 218 # When dealing with cryptographic keys, we want to keep things private. 219 umask 077 220 # Don't download the SSH key if it has already been downloaded 221 echo "Obtaining SSH keys..." 222 mkdir -m 0700 -p /root/.ssh 223 AUTH_KEYS=$(${mktemp}) 224 ${wget} -O $AUTH_KEYS http://metadata.google.internal/computeMetadata/v1/instance/attributes/sshKeys 225 if [ -s $AUTH_KEYS ]; then 226 227 # Read in key one by one, split in case Google decided 228 # to append metadata (it does sometimes) and add to 229 # authorized_keys if not already present. 230 touch /root/.ssh/authorized_keys 231 NEW_KEYS=$(${mktemp}) 232 # Yes this is a nix escape of two single quotes. 233 while IFS=''' read -r line || [[ -n "$line" ]]; do 234 keyLine=$(echo -n "$line" | cut -d ':' -f2) 235 IFS=' ' read -r -a array <<< "$keyLine" 236 if [ ''${#array[@]} -ge 3 ]; then 237 echo ''${array[@]:0:3} >> $NEW_KEYS 238 echo "Added ''${array[@]:2} to authorized_keys" 239 fi 240 done < $AUTH_KEYS 241 mv $NEW_KEYS /root/.ssh/authorized_keys 242 chmod 600 /root/.ssh/authorized_keys 243 rm -f $KEY_PUB 244 else 245 echo "Downloading http://metadata.google.internal/computeMetadata/v1/project/attributes/sshKeys failed." 246 false 247 fi 248 rm -f $AUTH_KEYS 249 SSH_HOST_KEYS_DIR=$(${mktemp} -d) 250 ${wget} -O $SSH_HOST_KEYS_DIR/ssh_host_ed25519_key http://metadata.google.internal/computeMetadata/v1/instance/attributes/ssh_host_ed25519_key 251 ${wget} -O $SSH_HOST_KEYS_DIR/ssh_host_ed25519_key.pub http://metadata.google.internal/computeMetadata/v1/instance/attributes/ssh_host_ed25519_key_pub 252 if [ -s $SSH_HOST_KEYS_DIR/ssh_host_ed25519_key -a -s $SSH_HOST_KEYS_DIR/ssh_host_ed25519_key.pub ]; then 253 mv -f $SSH_HOST_KEYS_DIR/ssh_host_ed25519_key* /etc/ssh/ 254 chmod 600 /etc/ssh/ssh_host_ed25519_key 255 chmod 644 /etc/ssh/ssh_host_ed25519_key.pub 256 else 257 echo "Setup of ssh host keys from http://metadata.google.internal/computeMetadata/v1/instance/attributes/ failed." 258 false 259 fi 260 rm -rf $SSH_HOST_KEYS_DIR 261 ''; 262 serviceConfig.Type = "oneshot"; 263 serviceConfig.RemainAfterExit = true; 264 serviceConfig.StandardError = "journal+console"; 265 serviceConfig.StandardOutput = "journal+console"; 266 }; 267 268 # Settings taken from https://github.com/GoogleCloudPlatform/compute-image-packages/blob/master/google_config/sysctl/11-gce-network-security.conf 269 boot.kernel.sysctl = { 270 # Turn on SYN-flood protections. Starting with 2.6.26, there is no loss 271 # of TCP functionality/features under normal conditions. When flood 272 # protections kick in under high unanswered-SYN load, the system 273 # should remain more stable, with a trade off of some loss of TCP 274 # functionality/features (e.g. TCP Window scaling). 275 "net.ipv4.tcp_syncookies" = mkDefault "1"; 276 277 # ignores source-routed packets 278 "net.ipv4.conf.all.accept_source_route" = mkDefault "0"; 279 280 # ignores source-routed packets 281 "net.ipv4.conf.default.accept_source_route" = mkDefault "0"; 282 283 # ignores ICMP redirects 284 "net.ipv4.conf.all.accept_redirects" = mkDefault "0"; 285 286 # ignores ICMP redirects 287 "net.ipv4.conf.default.accept_redirects" = mkDefault "0"; 288 289 # ignores ICMP redirects from non-GW hosts 290 "net.ipv4.conf.all.secure_redirects" = mkDefault "1"; 291 292 # ignores ICMP redirects from non-GW hosts 293 "net.ipv4.conf.default.secure_redirects" = mkDefault "1"; 294 295 # don't allow traffic between networks or act as a router 296 "net.ipv4.ip_forward" = mkDefault "0"; 297 298 # don't allow traffic between networks or act as a router 299 "net.ipv4.conf.all.send_redirects" = mkDefault "0"; 300 301 # don't allow traffic between networks or act as a router 302 "net.ipv4.conf.default.send_redirects" = mkDefault "0"; 303 304 # reverse path filtering - IP spoofing protection 305 "net.ipv4.conf.all.rp_filter" = mkDefault "1"; 306 307 # reverse path filtering - IP spoofing protection 308 "net.ipv4.conf.default.rp_filter" = mkDefault "1"; 309 310 # ignores ICMP broadcasts to avoid participating in Smurf attacks 311 "net.ipv4.icmp_echo_ignore_broadcasts" = mkDefault "1"; 312 313 # ignores bad ICMP errors 314 "net.ipv4.icmp_ignore_bogus_error_responses" = mkDefault "1"; 315 316 # logs spoofed, source-routed, and redirect packets 317 "net.ipv4.conf.all.log_martians" = mkDefault "1"; 318 319 # log spoofed, source-routed, and redirect packets 320 "net.ipv4.conf.default.log_martians" = mkDefault "1"; 321 322 # implements RFC 1337 fix 323 "net.ipv4.tcp_rfc1337" = mkDefault "1"; 324 325 # randomizes addresses of mmap base, heap, stack and VDSO page 326 "kernel.randomize_va_space" = mkDefault "2"; 327 328 # Reboot the machine soon after a kernel panic. 329 "kernel.panic" = mkDefault "10"; 330 331 ## Not part of the original config 332 333 # provides protection from ToCToU races 334 "fs.protected_hardlinks" = mkDefault "1"; 335 336 # provides protection from ToCToU races 337 "fs.protected_symlinks" = mkDefault "1"; 338 339 # makes locating kernel addresses more difficult 340 "kernel.kptr_restrict" = mkDefault "1"; 341 342 # set ptrace protections 343 "kernel.yama.ptrace_scope" = mkOverride 500 "1"; 344 345 # set perf only available to root 346 "kernel.perf_event_paranoid" = mkDefault "2"; 347 348 }; 349 350}