From 812346c9c9d32c08e1928897c50876fa8e375a3a Mon Sep 17 00:00:00 2001 From: zimbatm Date: Mon, 29 May 2017 15:32:48 +0100 Subject: [PATCH 1/2] google-compute-engine: init at 20170523 --- .../0001-allow-nologin-other-paths.patch | 27 +++++++++ .../google-compute-engine/default.nix | 55 +++++++++++++++++++ pkgs/top-level/all-packages.nix | 2 + 3 files changed, 84 insertions(+) create mode 100644 pkgs/tools/virtualization/google-compute-engine/0001-allow-nologin-other-paths.patch create mode 100644 pkgs/tools/virtualization/google-compute-engine/default.nix diff --git a/pkgs/tools/virtualization/google-compute-engine/0001-allow-nologin-other-paths.patch b/pkgs/tools/virtualization/google-compute-engine/0001-allow-nologin-other-paths.patch new file mode 100644 index 00000000000..650e80c24fb --- /dev/null +++ b/pkgs/tools/virtualization/google-compute-engine/0001-allow-nologin-other-paths.patch @@ -0,0 +1,27 @@ +From 2e9ac201af238b742c7032962b9b12a8b66bab0c Mon Sep 17 00:00:00 2001 +From: zimbatm +Date: Mon, 29 May 2017 22:36:15 +0100 +Subject: [PATCH] allow nologin on other paths + +--- + google_compute_engine/accounts/accounts_utils.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/google_compute_engine/accounts/accounts_utils.py b/google_compute_engine/accounts/accounts_utils.py +index 57e62be..d7eda06 100644 +--- a/google_compute_engine/accounts/accounts_utils.py ++++ b/google_compute_engine/accounts/accounts_utils.py +@@ -295,8 +295,8 @@ class AccountsUtils(object): + # logins. This helps avoid problems caused by operator and root sharing + # a home directory in CentOS and RHEL. + pw_entry = self._GetUser(user) +- if pw_entry and pw_entry.pw_shell == '/sbin/nologin': +- message = 'Not updating user %s. User set /sbin/nologin as login shell.' ++ if pw_entry and os.path.basename(pw_entry.pw_shell) == 'nologin': ++ message = 'Not updating user %s. User set `nologin` as login shell.' + self.logger.debug(message, user) + return True + +-- +2.13.0 + diff --git a/pkgs/tools/virtualization/google-compute-engine/default.nix b/pkgs/tools/virtualization/google-compute-engine/default.nix new file mode 100644 index 00000000000..7a5350fe2eb --- /dev/null +++ b/pkgs/tools/virtualization/google-compute-engine/default.nix @@ -0,0 +1,55 @@ +{ lib +, fetchFromGitHub +, pythonPackages +, bash +, shadow +, systemd +, utillinux +}: +let + version = "20170523"; +in +pythonPackages.buildPythonApplication { + name = "google-compute-engine-${version}"; + namePrefix = ""; + + src = fetchFromGitHub { + owner = "GoogleCloudPlatform"; + repo = "compute-image-packages"; + rev = version; + sha256 = "1qxyj3lj9in6m8yi6y6wcmc3662h9z4qax07v97rdnay99mxdv68"; + }; + + patches = [ ./0001-allow-nologin-other-paths.patch ]; + + postPatch = '' + for file in $(find google_compute_engine -type f); do + substituteInPlace "$file" \ + --replace /bin/systemctl "${systemd}/bin/systemctl" \ + --replace /bin/bash "${bash}/bin/bash" \ + --replace /sbin/hwclock "${utillinux}/bin/hwclock" + + # SELinux tool ??? /sbin/restorecon + done + + substituteInPlace google_config/udev/64-gce-disk-removal.rules \ + --replace /bin/sh "${bash}/bin/sh" \ + --replace /bin/umount "${utillinux}/bin/umount" \ + --replace /usr/bin/logger "${utillinux}/bin/logger" + ''; + + postInstall = '' + # allows to install the package in `services.udev.packages` in NixOS + mkdir -p $out/lib/udev/rules.d + cp -r google_config/udev/*.rules $out/lib/udev/rules.d + ''; + + propagatedBuildInputs = with pythonPackages; [ boto setuptools ]; + + meta = with lib; { + description = "Google Compute Engine tools and services"; + homepage = https://github.com/GoogleCloudPlatform/compute-image-packages; + license = licenses.asl20; + maintainers = with maintainers; [ zimbatm ]; + }; +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 9c0a73ccb3d..d82677928eb 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -2191,6 +2191,8 @@ with pkgs; google-fonts = callPackage ../data/fonts/google-fonts { }; + google-compute-engine = callPackage ../tools/virtualization/google-compute-engine { }; + gource = callPackage ../applications/version-management/gource { }; gpart = callPackage ../tools/filesystems/gpart { }; From c93d68b6ed7704ecd93b7a734ab025d990a9b5b2 Mon Sep 17 00:00:00 2001 From: zimbatm Date: Mon, 29 May 2017 15:33:24 +0100 Subject: [PATCH 2/2] 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 --- .../virtualisation/google-compute-image.nix | 149 +++++++++++++++++- 1 file changed, 144 insertions(+), 5 deletions(-) diff --git a/nixos/modules/virtualisation/google-compute-image.nix b/nixos/modules/virtualisation/google-compute-image.nix index 3943a62f8a4..4a8dadaa281 100644 --- a/nixos/modules/virtualisation/google-compute-image.nix +++ b/nixos/modules/virtualisation/google-compute-image.nix @@ -3,13 +3,11 @@ 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"; postVM = '' @@ -49,12 +47,18 @@ in 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 @@ -64,6 +68,132 @@ in 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"; @@ -113,9 +243,13 @@ in 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 @@ -169,6 +303,11 @@ in # 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";