mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-06-09 19:13:26 +03:00
227 lines
7.4 KiB
Nix
227 lines
7.4 KiB
Nix
{
|
|
config,
|
|
pkgs,
|
|
lib,
|
|
modulesPath,
|
|
...
|
|
}:
|
|
with lib;
|
|
{
|
|
imports = [
|
|
(modulesPath + "/profiles/qemu-guest.nix")
|
|
(modulesPath + "/virtualisation/digital-ocean-init.nix")
|
|
];
|
|
options.virtualisation.digitalOcean = with types; {
|
|
setRootPassword = mkOption {
|
|
type = bool;
|
|
default = false;
|
|
example = true;
|
|
description = "Whether to set the root password from the Digital Ocean metadata";
|
|
};
|
|
setSshKeys = mkOption {
|
|
type = bool;
|
|
default = true;
|
|
example = true;
|
|
description = "Whether to fetch ssh keys from Digital Ocean";
|
|
};
|
|
seedEntropy = mkOption {
|
|
type = bool;
|
|
default = true;
|
|
example = true;
|
|
description = "Whether to run the kernel RNG entropy seeding script from the Digital Ocean vendor data";
|
|
};
|
|
};
|
|
config =
|
|
let
|
|
cfg = config.virtualisation.digitalOcean;
|
|
hostName = config.networking.hostName;
|
|
doMetadataFile = "/run/do-metadata/v1.json";
|
|
in
|
|
mkMerge [
|
|
{
|
|
fileSystems."/" = lib.mkDefault {
|
|
device = "/dev/disk/by-label/nixos";
|
|
autoResize = true;
|
|
fsType = "ext4";
|
|
};
|
|
boot = {
|
|
growPartition = true;
|
|
kernelParams = [
|
|
"console=ttyS0"
|
|
"panic=1"
|
|
"boot.panic_on_fail"
|
|
];
|
|
initrd.kernelModules = [ "virtio_scsi" ];
|
|
kernelModules = [
|
|
"virtio_pci"
|
|
"virtio_net"
|
|
];
|
|
loader.grub.devices = [ "/dev/vda" ];
|
|
};
|
|
services.openssh = {
|
|
enable = mkDefault true;
|
|
settings.PasswordAuthentication = mkDefault false;
|
|
};
|
|
services.do-agent.enable = mkDefault true;
|
|
networking = {
|
|
hostName = mkDefault ""; # use Digital Ocean metadata server
|
|
};
|
|
|
|
/*
|
|
Check for and wait for the metadata server to become reachable.
|
|
This serves as a dependency for all the other metadata services.
|
|
*/
|
|
systemd.services.digitalocean-metadata = {
|
|
path = [ pkgs.curl ];
|
|
description = "Get host metadata provided by Digitalocean";
|
|
script = ''
|
|
set -eu
|
|
DO_DELAY_ATTEMPTS=0
|
|
while ! curl -fsSL -o $RUNTIME_DIRECTORY/v1.json http://169.254.169.254/metadata/v1.json; do
|
|
DO_DELAY_ATTEMPTS=$((DO_DELAY_ATTEMPTS + 1))
|
|
if (( $DO_DELAY_ATTEMPTS >= $DO_DELAY_ATTEMPTS_MAX )); then
|
|
echo "giving up"
|
|
exit 1
|
|
fi
|
|
|
|
echo "metadata unavailable, trying again in 1s..."
|
|
sleep 1
|
|
done
|
|
chmod 600 $RUNTIME_DIRECTORY/v1.json
|
|
'';
|
|
environment = {
|
|
DO_DELAY_ATTEMPTS_MAX = "10";
|
|
};
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
RuntimeDirectory = "do-metadata";
|
|
RuntimeDirectoryPreserve = "yes";
|
|
};
|
|
unitConfig = {
|
|
ConditionPathExists = "!${doMetadataFile}";
|
|
After =
|
|
[ "network-pre.target" ]
|
|
++ optional config.networking.dhcpcd.enable "dhcpcd.service"
|
|
++ optional config.systemd.network.enable "systemd-networkd.service";
|
|
};
|
|
};
|
|
|
|
/*
|
|
Fetch the root password from the digital ocean metadata.
|
|
There is no specific route for this, so we use jq to get
|
|
it from the One Big JSON metadata blob
|
|
*/
|
|
systemd.services.digitalocean-set-root-password = mkIf cfg.setRootPassword {
|
|
path = [
|
|
pkgs.shadow
|
|
pkgs.jq
|
|
];
|
|
description = "Set root password provided by Digitalocean";
|
|
wantedBy = [ "multi-user.target" ];
|
|
script = ''
|
|
set -eo pipefail
|
|
ROOT_PASSWORD=$(jq -er '.auth_key' ${doMetadataFile})
|
|
echo "root:$ROOT_PASSWORD" | chpasswd
|
|
mkdir -p /etc/do-metadata/set-root-password
|
|
'';
|
|
unitConfig = {
|
|
ConditionPathExists = "!/etc/do-metadata/set-root-password";
|
|
Before = optional config.services.openssh.enable "sshd.service";
|
|
After = [ "digitalocean-metadata.service" ];
|
|
Requires = [ "digitalocean-metadata.service" ];
|
|
};
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
};
|
|
};
|
|
|
|
/*
|
|
Set the hostname from Digital Ocean, unless the user configured it in
|
|
the NixOS configuration. The cached metadata file isn't used here
|
|
because the hostname is a mutable part of the droplet.
|
|
*/
|
|
systemd.services.digitalocean-set-hostname = mkIf (hostName == "") {
|
|
path = [
|
|
pkgs.curl
|
|
pkgs.nettools
|
|
];
|
|
description = "Set hostname provided by Digitalocean";
|
|
wantedBy = [ "network.target" ];
|
|
script = ''
|
|
set -e
|
|
DIGITALOCEAN_HOSTNAME=$(curl -fsSL http://169.254.169.254/metadata/v1/hostname)
|
|
hostname "$DIGITALOCEAN_HOSTNAME"
|
|
if [[ ! -e /etc/hostname || -w /etc/hostname ]]; then
|
|
printf "%s\n" "$DIGITALOCEAN_HOSTNAME" > /etc/hostname
|
|
fi
|
|
'';
|
|
unitConfig = {
|
|
Before = [ "network.target" ];
|
|
After = [ "digitalocean-metadata.service" ];
|
|
Wants = [ "digitalocean-metadata.service" ];
|
|
};
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
};
|
|
};
|
|
|
|
# Fetch the ssh keys for root from Digital Ocean
|
|
systemd.services.digitalocean-ssh-keys = mkIf cfg.setSshKeys {
|
|
description = "Set root ssh keys provided by Digital Ocean";
|
|
wantedBy = [ "multi-user.target" ];
|
|
path = [ pkgs.jq ];
|
|
script = ''
|
|
set -e
|
|
mkdir -m 0700 -p /root/.ssh
|
|
jq -er '.public_keys[]' ${doMetadataFile} > /root/.ssh/authorized_keys
|
|
chmod 600 /root/.ssh/authorized_keys
|
|
'';
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
};
|
|
unitConfig = {
|
|
ConditionPathExists = "!/root/.ssh/authorized_keys";
|
|
Before = optional config.services.openssh.enable "sshd.service";
|
|
After = [ "digitalocean-metadata.service" ];
|
|
Requires = [ "digitalocean-metadata.service" ];
|
|
};
|
|
};
|
|
|
|
/*
|
|
Initialize the RNG by running the entropy-seed script from the
|
|
Digital Ocean metadata
|
|
*/
|
|
systemd.services.digitalocean-entropy-seed = mkIf cfg.seedEntropy {
|
|
description = "Run the kernel RNG entropy seeding script from the Digital Ocean vendor data";
|
|
wantedBy = [ "network.target" ];
|
|
path = [
|
|
pkgs.jq
|
|
pkgs.mpack
|
|
];
|
|
script = ''
|
|
set -eo pipefail
|
|
TEMPDIR=$(mktemp -d)
|
|
jq -er '.vendor_data' ${doMetadataFile} | munpack -tC $TEMPDIR
|
|
ENTROPY_SEED=$(grep -rl "DigitalOcean Entropy Seed script" $TEMPDIR)
|
|
${pkgs.runtimeShell} $ENTROPY_SEED
|
|
rm -rf $TEMPDIR
|
|
'';
|
|
unitConfig = {
|
|
Before = [ "network.target" ];
|
|
After = [ "digitalocean-metadata.service" ];
|
|
Requires = [ "digitalocean-metadata.service" ];
|
|
};
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
};
|
|
};
|
|
|
|
}
|
|
];
|
|
meta.maintainers = with maintainers; [
|
|
arianvp
|
|
eamsden
|
|
];
|
|
}
|