Deploying to AWS with Terraform and Nix
Terraform, NixLet's say that you want to deploy this NixOS configuration onto AWS:
configuration.nix
{ ... }:
{
# Put your NixOS configuration here. Eg:
services.nginx.enable = true;
}
The first thing to do is to create another NixOS configuration that includes the amazon-image config and your main config. This is what ultimately is going to end-up on the VM:
aws-deploy.nix
{ modulesPath, ... }:
{
imports = [
"${modulesPath}/virtualisation/amazon-image.nix"
# path to your config
./configuration.nix
];
}
TODO: Setup CI here and Eval NixOS to pre-fill the cache.
With that in hand, we can now write a bit of Terraform code:
``plain text
variable "name" {
description = "Name prefix"
}
Generate a SSH key-pair
resource "tls_private_key" "machine" { algorithm = "RSA" }Record the SSH public key into AWS
resource "aws_key_pair" "machine" { key_name = var.name public_key = tls_private_key.machine.public_key_openssh }Store the private key locally. This is going to be used by the deploy_nixos module below
to deploy NixOS.
resource "local_file" "machine_ssh_key" { sensitive_content = tls_private_key.machine.private_key_pem filename = "${path.module}/id_rsa.pem" file_permission = "0600" }This is the security group that will be attached to the instance
resource "aws_security_group" "machine" { name = var.name }A bunch of rules for the group
resource "aws_security_group_rule" "machine_ingress_ssh" { description = "Allow SSH from everywhere" type = "ingress" from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] security_group_id = aws_security_group.machine.id }resource "aws_security_group_rule" "machine_ingress_http" { description = "Allow HTTP from everywhere" type = "ingress" from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] security_group_id = aws_security_group.machine.id }
resource "aws_security_group_rule" "machine_egress_all" { description = "Allow to connect to the whole Internet" type = "egress" from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] security_group_id = aws_security_group.machine.id }
Permissions for the AWS instance
data "aws_iam_policy_document" "machine" { statement { sid = "1"actions = [ "s3:ListAllMyBuckets", "s3:GetBucketLocation", ]
resources = [ "arn:aws:s3:::*", ] } }
A bunch of IAM resources needed to give permissions to the instance
resource "aws_iam_role" "machine" { name = var.nameassume_role_policy = < resource "aws_iam_role_policy" "machine" {
name = var.name
role = aws_iam_role.machine.name
policy = data.aws_iam_policy_document.machine.json
} resource "aws_iam_instance_profile" "machine" {
name = var.name
role = aws_iam_role.machine.name
depends_on = [aws_iam_role_policy.machine]
} root_block_device {
volume_type = "gp2"
volume_size = "50" # GiB
} lifecycle {
create_before_destroy = true
}
} # FIXME: pin nixpkgs
# NIX_PATH = "nixpkgs=${path.module}/../../nix/nixpkgs.nix"
nixos_config = "${path.module}/configuration.nix" target_host = aws_instance.machine.public_ip
target_user = "root"
ssh_private_key_file = local_file.machine_ssh_key.filename triggers = {
# Force a new deployment if the instance ID has changed. The ID changes if
# the instance is re-created for example.
machine_id = aws_instance.machine.id
}
}
`The actual AWS instance
resource "aws_instance" "machine" {
# Base image to start the instance with
ami = module.nixos_image.ami
iam_instance_profile = aws_iam_instance_profile.machine.id
instance_type = "c5.large"
key_name = aws_key_pair.machine.key_name
security_groups = [aws_security_group.machine.name]
tags = { "Name" = var.name }
This deploys the NixOS configuration onto the VM
module "machine_deploy" {
source = "git@github.com:tweag/terraform-nixos.git//deploy_nixos?ref=dbba649db86d90166d7573bb60ba40ac790e17d1"
Downsides
Upsides
TODO