From dd6ebb78719fe1c56a4fc487de6882c4e4fc7b92 Mon Sep 17 00:00:00 2001 From: talyz Date: Wed, 13 Jan 2021 11:01:01 +0100 Subject: [PATCH 1/2] google-compute-config: Reintroduce fetch-ssh-keys Reintroduce the `fetch-ssh-keys` service so that GCE images that work with NixOps can once again be built. Also, reformat the code a bit. The service was removed in 88570538b3b19d60b00bc3905bbaaef17e5a5c94, likely due to a comment saying it should be removed. It was still needed for images to work with NixOps, however, and probably needed to be replaced or rewritten rather than removed. --- .../virtualisation/google-compute-config.nix | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/nixos/modules/virtualisation/google-compute-config.nix b/nixos/modules/virtualisation/google-compute-config.nix index 327324f2921..2068924c44b 100644 --- a/nixos/modules/virtualisation/google-compute-config.nix +++ b/nixos/modules/virtualisation/google-compute-config.nix @@ -69,6 +69,69 @@ in # GC has 1460 MTU networking.interfaces.eth0.mtu = 1460; + systemd.services.fetch-ssh-keys = { + description = "Fetch host keys and authorized_keys for root user"; + + wantedBy = [ "sshd.service" ]; + before = [ "sshd.service" ]; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + + script = + let + wget = "${pkgs.wget}/bin/wget --retry-connrefused -t 15 --waitretry=10 --header='Metadata-Flavor: Google'"; + mktemp = "mktemp --tmpdir=/run"; + in '' + # When dealing with cryptographic keys, we want to keep things private. + umask 077 + mkdir -m 0700 -p /root/.ssh + + echo "Obtaining SSH keys..." + AUTH_KEYS=$(${mktemp}) + ${wget} -O $AUTH_KEYS http://metadata.google.internal/computeMetadata/v1/instance/attributes/sshKeys + if [ -s $AUTH_KEYS ]; then + # Read in key one by one, split in case Google decided + # to append metadata (it does sometimes) and add to + # authorized_keys if not already present. + touch /root/.ssh/authorized_keys + NEW_KEYS=$(${mktemp}) + # Yes this is a nix escape of two single quotes. + while IFS=''' read -r line || [[ -n "$line" ]]; do + keyLine=$(echo -n "$line" | cut -d ':' -f2) + IFS=' ' read -r -a array <<< "$keyLine" + if [ ''${#array[@]} -ge 3 ]; then + echo ''${array[@]:0:3} >> $NEW_KEYS + echo "Added ''${array[@]:2} to authorized_keys" + fi + done < $AUTH_KEYS + mv $NEW_KEYS /root/.ssh/authorized_keys + chmod 600 /root/.ssh/authorized_keys + rm -f $KEY_PUB + else + echo "Downloading http://metadata.google.internal/computeMetadata/v1/project/attributes/sshKeys failed." + false + fi + rm -f $AUTH_KEYS + + SSH_HOST_KEYS_DIR=$(${mktemp} -d) + ${wget} -O $SSH_HOST_KEYS_DIR/ssh_host_ed25519_key http://metadata.google.internal/computeMetadata/v1/instance/attributes/ssh_host_ed25519_key + ${wget} -O $SSH_HOST_KEYS_DIR/ssh_host_ed25519_key.pub http://metadata.google.internal/computeMetadata/v1/instance/attributes/ssh_host_ed25519_key_pub + if [ -s $SSH_HOST_KEYS_DIR/ssh_host_ed25519_key -a -s $SSH_HOST_KEYS_DIR/ssh_host_ed25519_key.pub ]; then + mv -f $SSH_HOST_KEYS_DIR/ssh_host_ed25519_key* /etc/ssh/ + chmod 600 /etc/ssh/ssh_host_ed25519_key + chmod 644 /etc/ssh/ssh_host_ed25519_key.pub + else + echo "Setup of ssh host keys from http://metadata.google.internal/computeMetadata/v1/instance/attributes/ failed." + false + fi + rm -rf $SSH_HOST_KEYS_DIR + ''; + serviceConfig.Type = "oneshot"; + serviceConfig.RemainAfterExit = true; + serviceConfig.StandardError = "journal+console"; + serviceConfig.StandardOutput = "journal+console"; + }; + systemd.services.google-instance-setup = { description = "Google Compute Engine Instance Setup"; after = [ "network-online.target" "network.target" "rsyslog.service" ]; From 95f96de78ed47fc77eaffe9399fb672f549fccb3 Mon Sep 17 00:00:00 2001 From: talyz Date: Thu, 11 Feb 2021 21:16:51 +0100 Subject: [PATCH 2/2] gce/fetch-ssh-keys: Put script in separate file, use PrivateTmp... ...check the script with shfmt and shellcheck + some other minor refactoring. --- .../fetch-instance-ssh-keys.bash | 36 ++++++++++ .../virtualisation/google-compute-config.nix | 68 ++++--------------- 2 files changed, 51 insertions(+), 53 deletions(-) create mode 100644 nixos/modules/virtualisation/fetch-instance-ssh-keys.bash diff --git a/nixos/modules/virtualisation/fetch-instance-ssh-keys.bash b/nixos/modules/virtualisation/fetch-instance-ssh-keys.bash new file mode 100644 index 00000000000..4a860196111 --- /dev/null +++ b/nixos/modules/virtualisation/fetch-instance-ssh-keys.bash @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +set -euo pipefail + +WGET() { + wget --retry-connrefused -t 15 --waitretry=10 --header='Metadata-Flavor: Google' "$@" +} + +# When dealing with cryptographic keys, we want to keep things private. +umask 077 +mkdir -p /root/.ssh + +echo "Fetching authorized keys..." +WGET -O /tmp/auth_keys http://metadata.google.internal/computeMetadata/v1/instance/attributes/sshKeys + +# Read keys one by one, split in case Google decided +# to append metadata (it does sometimes) and add to +# authorized_keys if not already present. +touch /root/.ssh/authorized_keys +while IFS='' read -r line || [[ -n "$line" ]]; do + keyLine=$(echo -n "$line" | cut -d ':' -f2) + IFS=' ' read -r -a array <<<"$keyLine" + if [[ ${#array[@]} -ge 3 ]]; then + echo "${array[@]:0:3}" >>/tmp/new_keys + echo "Added ${array[*]:2} to authorized_keys" + fi +done > $NEW_KEYS - echo "Added ''${array[@]:2} to authorized_keys" - fi - done < $AUTH_KEYS - mv $NEW_KEYS /root/.ssh/authorized_keys - chmod 600 /root/.ssh/authorized_keys - rm -f $KEY_PUB - else - echo "Downloading http://metadata.google.internal/computeMetadata/v1/project/attributes/sshKeys failed." - false - fi - rm -f $AUTH_KEYS - - SSH_HOST_KEYS_DIR=$(${mktemp} -d) - ${wget} -O $SSH_HOST_KEYS_DIR/ssh_host_ed25519_key http://metadata.google.internal/computeMetadata/v1/instance/attributes/ssh_host_ed25519_key - ${wget} -O $SSH_HOST_KEYS_DIR/ssh_host_ed25519_key.pub http://metadata.google.internal/computeMetadata/v1/instance/attributes/ssh_host_ed25519_key_pub - if [ -s $SSH_HOST_KEYS_DIR/ssh_host_ed25519_key -a -s $SSH_HOST_KEYS_DIR/ssh_host_ed25519_key.pub ]; then - mv -f $SSH_HOST_KEYS_DIR/ssh_host_ed25519_key* /etc/ssh/ - chmod 600 /etc/ssh/ssh_host_ed25519_key - chmod 644 /etc/ssh/ssh_host_ed25519_key.pub - else - echo "Setup of ssh host keys from http://metadata.google.internal/computeMetadata/v1/instance/attributes/ failed." - false - fi - rm -rf $SSH_HOST_KEYS_DIR + serviceConfig = { + Type = "oneshot"; + ExecStart = pkgs.runCommand "fetch-instance-ssh-keys" { } '' + cp ${./fetch-instance-ssh-keys.bash} $out + chmod +x $out + ${pkgs.shfmt}/bin/shfmt -i 4 -d $out + ${pkgs.shellcheck}/bin/shellcheck $out + patchShebangs $out ''; - serviceConfig.Type = "oneshot"; - serviceConfig.RemainAfterExit = true; - serviceConfig.StandardError = "journal+console"; - serviceConfig.StandardOutput = "journal+console"; + PrivateTmp = true; + StandardError = "journal+console"; + StandardOutput = "journal+console"; + }; }; systemd.services.google-instance-setup = {