~nromdotcom/gemif

2090de89ec812d8fe51338bcd4e1e01c102245fb — Norm MacLennan 11 months ago ad3a15e 0.2.0
Automate deployment of capsule and infrastructure
M .build.yml => .build.yml +9 -0
@@ 31,3 31,12 @@ tasks:
      . ~/.srht_token
      set -x
      make release

  # Don't let's automate this deployment
  # yet, cause it might take a few tries.
  # - deploy_infra: |
  #     cd gemif
  #     set +x
  #     . ~/.srht_token
  #     set -x
  #     make release
\ No newline at end of file

M .gitignore => .gitignore +2 -0
@@ 5,3 5,5 @@ tmp/
bin/
coverage.out
config.toml
.terraform/
terraform.tfstate*

A infra/.terraform.lock.hcl => infra/.terraform.lock.hcl +72 -0
@@ 0,0 1,72 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.

provider "registry.terraform.io/hashicorp/aws" {
  version = "3.20.0"
  hashes = [
    "h1:3M0q/GqB24RM5E1wIu23bEbChJ2RDVaM5lTLENB92Cc=",
    "zh:1b53d410c21332750be561092d412d83014fa0656e00f940944d2e7b07b1b9ec",
    "zh:307bf780790462fe547fe23f8e38a4c178437f3a9dd725f9aa63c6d8c6cbf25d",
    "zh:5818a978b9766b23a190716b85aad3a4731d33ddb8a81080cf3ef6e4bd68a003",
    "zh:5f68eb4779208e21d9657b9ff492aa5f6496efea7994bdec1d302f88b0b65f34",
    "zh:6028208a7b3738801cd9f3376efa40a1e55f4bb8184584f7387b08c054e43c4c",
    "zh:8130269e2d8c80ea9136dcd26cfeb4e1fac83bda4aab0db70f36651a7b22365d",
    "zh:9dd4a07beb89606e051b64ab05d75e1c1616389871a55065676b370aebaed8e5",
    "zh:b7194500db431ba862ea8008db56a5decececda1f904ed8842d2b0f1a04eea9d",
    "zh:ec214b7341137e6dd47754b843ed16fe3e1d32832537042ee81a64a3ccdbb4bd",
    "zh:ec2973e04f3cb853895e51f6ec56660574610b860ee3de669ccbb1f04d1089c9",
  ]
}

provider "registry.terraform.io/hashicorp/template" {
  version = "2.2.0"
  hashes = [
    "h1:94qn780bi1qjrbC3uQtjJh3Wkfwd5+tTtJHOb7KTg9w=",
    "zh:01702196f0a0492ec07917db7aaa595843d8f171dc195f4c988d2ffca2a06386",
    "zh:09aae3da826ba3d7df69efeb25d146a1de0d03e951d35019a0f80e4f58c89b53",
    "zh:09ba83c0625b6fe0a954da6fbd0c355ac0b7f07f86c91a2a97849140fea49603",
    "zh:0e3a6c8e16f17f19010accd0844187d524580d9fdb0731f675ffcf4afba03d16",
    "zh:45f2c594b6f2f34ea663704cc72048b212fe7d16fb4cfd959365fa997228a776",
    "zh:77ea3e5a0446784d77114b5e851c970a3dde1e08fa6de38210b8385d7605d451",
    "zh:8a154388f3708e3df5a69122a23bdfaf760a523788a5081976b3d5616f7d30ae",
    "zh:992843002f2db5a11e626b3fc23dc0c87ad3729b3b3cff08e32ffb3df97edbde",
    "zh:ad906f4cebd3ec5e43d5cd6dc8f4c5c9cc3b33d2243c89c5fc18f97f7277b51d",
    "zh:c979425ddb256511137ecd093e23283234da0154b7fa8b21c2687182d9aea8b2",
  ]
}

provider "registry.terraform.io/hashicorp/tls" {
  version = "3.0.0"
  hashes = [
    "h1:LtCEW5v1E5Eo49+kQOsKHRYf9Hc8ZR0jTpK+mXszPHs=",
    "zh:05eac573a1fe53227bcc6b01daf6ddf0b73456f97f56f316f1b3114a4771e175",
    "zh:09390dad764c76f0fd59cae4dad296e3e39487e06de3a4bc0df73916c6bb2f17",
    "zh:142d0bc4722ab088b7ca124b0eb44206b9d100f51035c162d50ef552e09813d0",
    "zh:2c391743dd20f43329c0d0d49dec7827970d788115593c0e32a57050c0a85337",
    "zh:525b12fc87369c0e6d347afe6c77668aebf56cfa078bb0f1f01cc2ee01ac7016",
    "zh:5583d81b7a05c6d49a4c445e1ee62e82facb07bb9204998a836b7b522a51db8d",
    "zh:925e3acc70e18ed1cd296d337fc3e0ca43ac6f5bf2e660f24de750c7754f91aa",
    "zh:a291457d25b207fd28fb4fad9209ebb591e25cfc507ca1cb0fb8b2e255be1969",
    "zh:bbf9e2718752aebfbd7c6b8e196eb2e52730b66befed2ea1954f9ff1c199295e",
    "zh:f4b333c467ae02c1a238ac57465fe66405f6e2a6cfeb4eded9bc321c5652a1bf",
  ]
}

provider "registry.terraform.io/vancluever/acme" {
  version     = "1.6.3"
  constraints = "1.6.3"
  hashes = [
    "h1:lawZQigHAXHysEGpf8wRPRt4m5Z4fwEP/kKMO90O1cQ=",
    "zh:02f887ebb2cc5da7572deefe589c2f171e66b3f311c89e2cf029397e331bd6b7",
    "zh:0bc067cf16dc160d356a379ed243d82c349f1e29a396ce9063431cfc096b534a",
    "zh:1e83ce6e3de17e520baba77796fb3b4753b23ab494c2c2cf7b4d6e52a0e2d152",
    "zh:2b33a4828dd4521b82fe3a4d9efc91336d78a8669707b9be98329973253c6c11",
    "zh:3f687f27b271ec49e41a9edcaf781509c71a6d32a5c45bf7d050b89714d243e7",
    "zh:59fb7a8c51cbd5387813e6cb2101d21e7057ae1857e8cb9bf1d1d7dd95afbafb",
    "zh:671234c923f5a081c391ab719f87e4f41a3675309f629d652bd3a42c8aa84313",
    "zh:6d312732d36fc71a6a03e38b2bc0fa5db0d915183f11ad334ce26eb49f845cb4",
    "zh:8480464df4492563fa613a155768aad5b74c21f128e20dd1623ab7e9b0fb966e",
    "zh:a3b0bd1b656ef6d3748c1854358e36c623f877aebcbb8295890ed806b7198e96",
    "zh:a81d1347debd955657e637cc09d5c7b56dd4ab64b680c984ef78f08ba908084d",
  ]
}

A infra/dns.tf => infra/dns.tf +11 -0
@@ 0,0 1,11 @@
data "aws_route53_zone" "fedifarm" {
  name = "fedi.farm."
}

resource "aws_route53_record" "gemif" {
  zone_id = data.aws_route53_zone.fedifarm.zone_id
  name    = "gemif.fedi.farm"
  type    = "A"
  ttl     = "300"
  records = [aws_eip.gemif.public_ip]
}

A infra/ec2.tf => infra/ec2.tf +64 -0
@@ 0,0 1,64 @@
provider "aws" {
  region = "us-east-1"
}

data "aws_ami" "amz2" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-arm64-gp2"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}

resource "aws_instance" "gemif" {
  ami              = data.aws_ami.amz2.id
  instance_type    = "t4g.nano"
  user_data_base64 = data.template_cloudinit_config.config.rendered

  iam_instance_profile   = aws_iam_instance_profile.gemif.name
  vpc_security_group_ids = [aws_security_group.allow_gem.id]

  tags = {
    Name = "GemIF Server"
  }

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_security_group" "allow_gem" {
  name        = "allow_gem"
  description = "Allow Gemini inbound traffic"

  ingress {
    description = "Gemini from Internet"
    from_port   = 1965
    to_port     = 1965
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_eip" "gemif" {
  instance = aws_instance.gemif.id
  vpc      = true

  tags = {
    Name = "GemIF Server"
  }
}
\ No newline at end of file

A infra/iam.tf => infra/iam.tf +30 -0
@@ 0,0 1,30 @@
resource "aws_iam_instance_profile" "gemif" {
  name = "gemif-profile"
  role = aws_iam_role.gemif.name
}

resource "aws_iam_role" "gemif" {
  name = "gemif-role"
  path = "/"

  assume_role_policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "sts:AssumeRole",
            "Principal": {
               "Service": "ec2.amazonaws.com"
            },
            "Effect": "Allow",
            "Sid": ""
        }
    ]
}
EOF
}

resource "aws_iam_role_policy_attachment" "gemif_ssm" {
  role       = aws_iam_role.gemif.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"
}
\ No newline at end of file

A infra/terraform.tf => infra/terraform.tf +9 -0
@@ 0,0 1,9 @@
terraform {
  required_providers {
    acme = {
      source  = "vancluever/acme"
      version = "1.6.3"
    }
  }
  backend "s3" {}
}

A infra/tls.tf => infra/tls.tf +28 -0
@@ 0,0 1,28 @@
provider "tls" {}
provider "acme" {
  # Since actual CA signing doesn't matter, let's just stick with LE staging
  # for now.
  server_url = "https://acme-staging-v02.api.letsencrypt.org/directory"
}

resource "tls_private_key" "gemif" {
  algorithm   = "ECDSA"
  ecdsa_curve = "P384"
}

resource "acme_registration" "le_reg" {
  account_key_pem = tls_private_key.gemif.private_key_pem
  email_address   = "norm@fedi.farm"
}

resource "acme_certificate" "cert" {
  account_key_pem = acme_registration.le_reg.account_key_pem
  key_type        = "P384"

  common_name        = "gemif.fedi.farm"
  min_days_remaining = "14"

  dns_challenge {
    provider = "route53"
  }
}

A infra/user-data.tf => infra/user-data.tf +18 -0
@@ 0,0 1,18 @@
data "template_file" "install_gemif" {
  template = file("${path.module}/user_data/install_gemif.sh")

  vars = {
    cert    = acme_certificate.cert.certificate_pem
    key     = acme_certificate.cert.private_key_pem
    version = var.gemif_version
  }
}

data "template_cloudinit_config" "config" {
  gzip          = true
  base64_encode = true
  part {
    content_type = "text/x-shellscript"
    content      = data.template_file.install_gemif.rendered
  }
}
\ No newline at end of file

A infra/user_data/install_gemif.sh => infra/user_data/install_gemif.sh +56 -0
@@ 0,0 1,56 @@
#! /usr/bin/env sh
mkdir -p /home/ec2-user/gemif && cd $_

cat >/etc/systemd/system/gemif.service <<EOF
[Unit]
Description=GemIF Server
ConditionPathExists=/home/ec2-user/gemif
After=network.target

[Service]
Type=simple
User=ec2-user
Group=ec2-user
LimitNOFILE=1024

Restart=on-failure
RestartSec=10

WorkingDirectory=/home/ec2-user/gemif
ExecStart=/home/ec2-user/gemif/gemif

PermissionsStartOnly=true

[Install]
WantedBy=multi-user.target
EOF

cat >/home/ec2-user/gemif/acme.crt <<EOF
${cert}
EOF

cat >/home/ec2-user/gemif/acme.key <<EOF
${key}
EOF

cat >/home/ec2-user/gemif/config.toml <<EOF
[gemserver]
domain    = "gemif.fedi.farm"
port      = 1965
cert_file = "./acme.crt"
key_file  = "./acme.key"

[engine]
stories_dir         = "./stories/compiled"
render_descriptions = true
statetoken_format   = "proto"
EOF

wget https://git.sr.ht/~nromdotcom/gemif/refs/${version}/gemif-linux-arm64-${version}.tar.gz
wget https://git.sr.ht/~nromdotcom/gemif/refs/${version}/bundled-stories.tar.gz
tar xvf ./gemif-linux-arm64-${version}.tar.gz --strip=3
tar xvf ./bundled-stories.tar.gz
chown -R ec2-user .

systemctl daemon-reload
systemctl start gemif.service

A infra/variables.tf => infra/variables.tf +3 -0
@@ 0,0 1,3 @@
variable "gemif_version" {
  description = "The version of GemIF to deploy"
}
\ No newline at end of file

A scripts/deploy_terraform.sh => scripts/deploy_terraform.sh +17 -0
@@ 0,0 1,17 @@
#!/usr/bin/env sh
set -e

git_tag=`git describe --exact-match 2> /dev/null || echo ""`
if [ "$git_tag" != "" ]; then
  cd ./infra
  terraform init -backend=true \
    -backend-config bucket=$TFSTATE_BUCKET \
    -backend-config region=us-east-1 \
    -backend-config key=gemif \
    -backend-config encrypt=true \
    -input=false

  terraform apply -auto-approve -input=false -var gemif_version=$git_tag
else
  echo "not a tagged commit, nothing to deploy"
fi
\ No newline at end of file