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

zimbatm c93d68b6 812346c9

Changed files
+144 -5
nixos
modules
virtualisation
+144 -5
nixos/modules/virtualisation/google-compute-image.nix
···
with lib;
let
diskSize = 1024; # MB
+
gce = pkgs.google-compute-engine;
in
{
imports = [ ../profiles/headless.nix ../profiles/qemu-guest.nix ./grow-partition.nix ];
-
-
# https://cloud.google.com/compute/docs/tutorials/building-images
-
networking.firewall.enable = mkDefault false;
system.build.googleComputeImage = import ../../lib/make-disk-image.nix {
name = "google-compute-image";
···
services.openssh.permitRootLogin = "prohibit-password";
services.openssh.passwordAuthentication = mkDefault false;
+
# Use GCE udev rules for dynamic disk volumes
+
services.udev.packages = [ gce ];
+
# Force getting the hostname from Google Compute.
networking.hostName = mkDefault "";
# Always include cryptsetup so that NixOps can use it.
environment.systemPackages = [ pkgs.cryptsetup ];
+
# Rely on GCP's firewall instead
+
networking.firewall.enable = mkDefault false;
+
# Configure default metadata hostnames
networking.extraHosts = ''
169.254.169.254 metadata.google.internal metadata
···
networking.usePredictableInterfaceNames = false;
+
# allow the google-accounts-daemon to manage users
+
users.mutableUsers = true;
+
# and allow users to sudo without password
+
security.sudo.enable = true;
+
security.sudo.extraConfig = ''
+
%google-sudoers ALL=(ALL:ALL) NOPASSWD:ALL
+
'';
+
+
# NOTE: google-accounts tries to write to /etc/sudoers.d but the folder doesn't exist
+
# FIXME: not such file or directory on dynamic SSH provisioning
+
systemd.services.google-accounts-daemon = {
+
description = "Google Compute Engine Accounts Daemon";
+
# This daemon creates dynamic users
+
enable = config.users.mutableUsers;
+
after = [
+
"network.target"
+
"google-instance-setup.service"
+
"google-network-setup.service"
+
];
+
wantedBy = [ "multi-user.target" ];
+
requires = ["network.target"];
+
path = with pkgs; [ shadow ];
+
serviceConfig = {
+
Type = "simple";
+
ExecStart = "${gce}/bin/google_accounts_daemon --debug";
+
};
+
};
+
+
systemd.services.google-clock-skew-daemon = {
+
description = "Google Compute Engine Clock Skew Daemon";
+
after = [
+
"network.target"
+
"google-instance-setup.service"
+
"google-network-setup.service"
+
];
+
requires = [ "network.target" ];
+
wantedBy = [ "multi-user.target" ];
+
serviceConfig = {
+
Type = "simple";
+
ExecStart = "${gce}/bin/google_clock_skew_daemon --debug";
+
};
+
};
+
+
systemd.services.google-instance-setup = {
+
description = "Google Compute Engine Instance Setup";
+
after = ["fs.target" "network-online.target" "network.target" "rsyslog.service"];
+
before = ["sshd.service"];
+
wants = ["local-fs.target" "network-online.target" "network.target"];
+
wantedBy = [ "sshd.service" "multi-user.target" ];
+
path = with pkgs; [ ethtool ];
+
serviceConfig = {
+
ExecStart = "${gce}/bin/google_instance_setup --debug";
+
Type = "oneshot";
+
};
+
};
+
+
systemd.services.google-ip-forwarding-daemon = {
+
description = "Google Compute Engine IP Forwarding Daemon";
+
after = ["network.target" "google-instance-setup.service" "google-network-setup.service"];
+
requires = ["network.target"];
+
wantedBy = [ "multi-user.target" ];
+
path = with pkgs; [ iproute ];
+
serviceConfig = {
+
Type = "simple";
+
ExecStart = "${gce}/bin/google_ip_forwarding_daemon --debug";
+
};
+
};
+
+
systemd.services.google-shutdown-scripts = {
+
description = "Google Compute Engine Shutdown Scripts";
+
after = [
+
"local-fs.target"
+
"network-online.target"
+
"network.target"
+
"rsyslog.service"
+
"google-instance-setup.service"
+
"google-network-setup.service"
+
];
+
wants = [ "local-fs.target" "network-online.target" "network.target"];
+
wantedBy = [ "multi-user.target" ];
+
serviceConfig = {
+
ExecStart = "${pkgs.coreutils}/bin/true";
+
ExecStop = "${gce}/bin/google_metadata_script_runner --debug --script-type shutdown";
+
Type = "oneshot";
+
RemainAfterExit = true;
+
TimeoutStopSec = 0;
+
};
+
};
+
+
systemd.services.google-network-setup = {
+
description = "Google Compute Engine Network Setup";
+
after = [
+
"local-fs.target"
+
"network-online.target"
+
"network.target"
+
"rsyslog.service"
+
];
+
wants = [ "local-fs.target" "network-online.target" "network.target"];
+
wantedBy = [ "multi-user.target" ];
+
serviceConfig = {
+
ExecStart = "${gce}/bin/google_network_setup --debug";
+
KillMode = "process";
+
Type = "oneshot";
+
};
+
};
+
+
systemd.services.google-startup-scripts = {
+
description = "Google Compute Engine Startup Scripts";
+
after = [
+
"local-fs.target"
+
"network-online.target"
+
"network.target"
+
"rsyslog.service"
+
"google-instance-setup.service"
+
"google-network-setup.service"
+
];
+
wants = [ "local-fs.target" "network-online.target" "network.target"];
+
wantedBy = [ "multi-user.target" ];
+
serviceConfig = {
+
ExecStart = "${gce}/bin/google_metadata_script_runner --debug --script-type startup";
+
KillMode = "process";
+
Type = "oneshot";
+
};
+
};
+
+
# TODO: remove this
systemd.services.fetch-ssh-keys =
{ description = "Fetch host keys and authorized_keys for root user";
···
serviceConfig.StandardOutput = "journal+console";
};
-
# Setings taken from https://cloud.google.com/compute/docs/tutorials/building-images#providedkernel
+
# Settings taken from https://github.com/GoogleCloudPlatform/compute-image-packages/blob/master/google_config/sysctl/11-gce-network-security.conf
boot.kernel.sysctl = {
-
# enables syn flood protection
+
# Turn on SYN-flood protections. Starting with 2.6.26, there is no loss
+
# of TCP functionality/features under normal conditions. When flood
+
# protections kick in under high unanswered-SYN load, the system
+
# should remain more stable, with a trade off of some loss of TCP
+
# functionality/features (e.g. TCP Window scaling).
"net.ipv4.tcp_syncookies" = mkDefault "1";
# ignores source-routed packets
···
# randomizes addresses of mmap base, heap, stack and VDSO page
"kernel.randomize_va_space" = mkDefault "2";
+
+
# Reboot the machine soon after a kernel panic.
+
"kernel.panic" = mkDefault "10";
+
+
## Not part of the original config
# provides protection from ToCToU races
"fs.protected_hardlinks" = mkDefault "1";