tvl-depot/users/grfn/terraform/nixosMachine.nix

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

209 lines
5.6 KiB
Nix
Raw Normal View History

{ depot, pkgs, lib, ... }:
# mostly stolen from espes
{ name
, instanceType
, configuration
, prefix ? "${name}_"
, region ? "us-east-2"
, rootVolumeSizeGb ? 50
, securityGroupId ? null
, extraIngressPorts ? [ ]
}:
let
os = depot.ops.nixos.nixosFor ({ modulesPath, ... }: {
imports = [
(pkgs.path + "/nixos/modules/virtualisation/amazon-image.nix")
configuration
];
ec2.hvm = true;
networking.hostName = name;
# TODO: remove this once the terraform tls provider supports ed25519 keys
# https://github.com/hashicorp/terraform-provider-tls/issues/26
services.openssh.extraConfig = ''
PubkeyAcceptedKeyTypes=+ssh-rsa
PubkeyAcceptedAlgorithms=+ssh-rsa
'';
});
targetUser = "root";
ec2Amis = import "${pkgs.path}/nixos/modules/virtualisation/ec2-amis.nix";
osRoot = os.config.system.build.toplevel;
osRootPath = builtins.unsafeDiscardStringContext (toString osRoot.outPath);
drvPath = builtins.unsafeDiscardStringContext (toString osRoot.drvPath);
machineResource = "aws_instance.${prefix}machine";
recursiveMerge = builtins.foldl' lib.recursiveUpdate { };
securityGroupId' =
if isNull securityGroupId
then "\${aws_security_group.${prefix}group.id}"
else securityGroupId;
in
recursiveMerge [
(lib.optionalAttrs (isNull securityGroupId) {
resource.aws_security_group."${prefix}group" = {
provider = "aws.${region}";
vpc_id = null;
# terraform isn't good about knowing what other resources depend on
# security groups
lifecycle.create_before_destroy = true;
};
resource.aws_security_group_rule.all_egress = {
provider = "aws.${region}";
security_group_id = securityGroupId';
type = "egress";
protocol = "-1";
from_port = 0;
to_port = 0;
cidr_blocks = [ "0.0.0.0/0" ];
ipv6_cidr_blocks = [ "::/0" ];
description = null;
prefix_list_ids = null;
self = null;
};
})
rec {
data.external.my_ip = {
program = [
(pkgs.writeShellScript "my_ip" ''
${pkgs.jq}/bin/jq \
-n \
--arg ip "$(curl ifconfig.me)" \
'{"ip":$ip}'
'')
];
};
resource.aws_security_group_rule.provision_ssh_access = {
provider = "aws.${region}";
security_group_id = securityGroupId';
type = "ingress";
protocol = "TCP";
from_port = 22;
to_port = 22;
cidr_blocks = [ "\${data.external.my_ip.result.ip}/32" ];
ipv6_cidr_blocks = [ ];
description = null;
prefix_list_ids = null;
self = null;
};
resource.tls_private_key."${prefix}key" = {
algorithm = "RSA";
};
resource.aws_key_pair."${prefix}generated_key" = {
provider = "aws.${region}";
key_name = "generated-key-\${sha256(tls_private_key.${prefix}key.public_key_openssh)}";
public_key = "\${tls_private_key.${prefix}key.public_key_openssh}";
};
resource.aws_instance."${prefix}machine" = {
provider = "aws.${region}";
ami = ec2Amis."21.05"."${region}".hvm-ebs;
instance_type = instanceType;
vpc_security_group_ids = [ securityGroupId' ];
key_name = "\${aws_key_pair.${prefix}generated_key.key_name}";
root_block_device = {
volume_size = rootVolumeSizeGb;
tags.Name = name;
};
tags.Name = name;
};
resource.null_resource."${prefix}deploy_nixos" = {
triggers = {
# deploy if the machine is recreated
machine_id = "\${${machineResource}.id}";
# deploy on os changes
os_drv = drvPath;
};
connection = {
type = "ssh";
host = "\${${machineResource}.public_ip}";
user = targetUser;
private_key = "\${tls_private_key.${prefix}key.private_key_pem}";
};
# do the actual deployment
provisioner = [
# wait till ssh is up
{ remote-exec.inline = [ "true" ]; }
# copy the nixos closure
{
local-exec.command = ''
export PATH="${pkgs.openssh}/bin:$PATH"
scratch="$(mktemp -d)"
trap 'rm -rf -- "$scratch"' EXIT
# write out ssh key
echo -n "''${tls_private_key.${prefix}key.private_key_pem}" > $scratch/id_rsa.pem
chmod 0600 $scratch/id_rsa.pem
export NIX_SSHOPTS="\
-o StrictHostKeyChecking=no\
-o UserKnownHostsFile=/dev/null\
-o GlobalKnownHostsFile=/dev/null\
-o IdentityFile=$scratch/id_rsa.pem"
nix-build ${drvPath}
nix-copy-closure \
--to ${targetUser}@''${${machineResource}.public_ip} \
${osRootPath} \
--gzip \
--use-substitutes
'';
}
# activate it
{
remote-exec.inline = [
# semicolons mandatory
''
set -e;
nix-env --profile /nix/var/nix/profiles/system --set ${osRootPath};
${osRootPath}/bin/switch-to-configuration switch;
''
];
}
];
};
}
{
resource.aws_security_group_rule = builtins.listToAttrs (map
(port: {
name = "ingress_${toString port}";
value = {
provider = "aws.${region}";
security_group_id = securityGroupId';
type = "ingress";
protocol = "TCP";
from_port = port;
to_port = port;
cidr_blocks = [ "0.0.0.0/0" ];
ipv6_cidr_blocks = [ ];
description = null;
prefix_list_ids = null;
self = null;
};
})
extraIngressPorts);
}
]