diff options
author | Jakob Odersky <jakob@odersky.com> | 2018-12-04 21:31:01 -0800 |
---|---|---|
committer | Jakob Odersky <jakob@odersky.com> | 2018-12-04 21:39:07 -0800 |
commit | 9588e9366d3455f203e5482a41f712777595bb13 (patch) | |
tree | 272aeababb1b68f477301d67198a82c80d044c01 /terraform | |
parent | db27247dd7d7209ab93419eb33d2ecb21e74c1ec (diff) | |
download | infra-9588e9366d3455f203e5482a41f712777595bb13.tar.gz infra-9588e9366d3455f203e5482a41f712777595bb13.tar.bz2 infra-9588e9366d3455f203e5482a41f712777595bb13.zip |
Simplify terraform and provisioning scripts. Move away from config packages.
Diffstat (limited to 'terraform')
26 files changed, 702 insertions, 265 deletions
diff --git a/terraform/deploy b/terraform/deploy new file mode 100755 index 0000000..a7fdf57 --- /dev/null +++ b/terraform/deploy @@ -0,0 +1,3 @@ +#!/bin/bash + +terraform apply -var-file=<(pass infra/terraform) diff --git a/terraform/main.tf b/terraform/main.tf index b25598e..e29cf6a 100755..100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -16,36 +16,128 @@ provider "cloudflare" { } provider "acme" { - #server_url = "https://acme-staging-v02.api.letsencrypt.org/directory" server_url = "https://acme-v02.api.letsencrypt.org/directory" } -################################################################################ +############################################################ resource "hcloud_ssh_key" "root" { name = "root" - public_key = "${file("~/.ssh/id_rsa.pub")}" + public_key = "${file("root-ssh-key")}" } -module "vps" { - source = "./stdvps" - location = "nbg1" - ssh_key_name = "${hcloud_ssh_key.root.name}" +resource "tls_private_key" "private_key" { + algorithm = "RSA" +} + +resource "acme_registration" "registration" { + account_key_pem = "${tls_private_key.private_key.private_key_pem}" + email_address = "jakob@odersky.com" +} + +resource "acme_certificate" "certificate" { + account_key_pem = "${acme_registration.registration.account_key_pem}" + common_name = "crashbox.io" + + subject_alternative_names = [ + "ip.crashbox.io", + "git.crashbox.io", + ] + + dns_challenge { + provider = "cloudflare" + + config { + CLOUDFLARE_EMAIL = "jakob@odersky.com" + CLOUDFLARE_API_KEY = "${var.secret_cloudflare_token}" + } + } +} + +resource "cloudflare_record" "record_caa" { + domain = "crashbox.io" + name = "crashbox.io" + + data = { + flags = "0" + tag = "issue" + value = "letsencrypt.org" + } + + type = "CAA" +} + +resource "random_id" "peter" { + prefix = "peter-" + byte_length = 2 +} + +resource "hcloud_server" "peter" { + name = "${random_id.peter.hex}" + image = "debian-9" + server_type = "cx11" + location = "nbg1" + ssh_keys = ["${hcloud_ssh_key.root.name}"] + + provisioner "file" { + content = "${acme_certificate.certificate.private_key_pem}" + destination = "/etc/ssl/private/server.key.pem" + } + + provisioner "file" { + content = "${acme_certificate.certificate.certificate_pem}" + destination = "/etc/ssl/server.cert.pem" + } + + provisioner "file" { + content = "${acme_certificate.certificate.issuer_pem}" + destination = "/etc/ssl/issuer.cert.pem" + } + + provisioner "file" { + source = "./provision" + destination = "/usr/local/share/" + } + + provisioner "remote-exec" { + inline = [ + "chmod +x /usr/local/share/provision/provision", + "/usr/local/share/provision/provision --force", + ] + } +} + +module "peter_mount_volume" { + source = "./mount_volume" volume_name = "master" + host = "${hcloud_server.peter.ipv4_address}" + server_id = "${hcloud_server.peter.id}" +} + +resource "cloudflare_record" "peter_a" { + domain = "crashbox.io" + name = "${hcloud_server.peter.name}" + value = "${hcloud_server.peter.ipv4_address}" + type = "A" } -module "roles" { - source = "./role" - secret_cloudflare_token = "${var.secret_cloudflare_token}" - host = "${module.vps.fqdn}" - id = "${module.vps.id}" - roles = ["ip", "git"] +resource "cloudflare_record" "peter_aaaa" { + domain = "crashbox.io" + name = "${hcloud_server.peter.name}" + value = "${hcloud_server.peter.ipv6_address}1" + type = "AAAA" } -output "vps_address" { - value = "${module.vps.fqdn}" +resource "cloudflare_record" "record_ip" { + domain = "crashbox.io" + name = "ip" + value = "${cloudflare_record.peter_a.hostname}" + type = "CNAME" } -output "vps_roles" { - value = "${join(" ", module.roles.roles)}" +resource "cloudflare_record" "record_git" { + domain = "crashbox.io" + name = "git" + value = "${cloudflare_record.peter_a.hostname}" + type = "CNAME" } diff --git a/terraform/mount_volume/main.tf b/terraform/mount_volume/main.tf new file mode 100644 index 0000000..aed5324 --- /dev/null +++ b/terraform/mount_volume/main.tf @@ -0,0 +1,104 @@ +variable "volume_name" { + type = "string" +} + +variable "host" { + type = "string" +} + +variable "server_id" { + type = "string" +} + +# volumes contain persistent storage and thus need to be initialized +# manually +data "hcloud_volume" "master" { + name = "${var.volume_name}" +} + +resource "hcloud_volume_attachment" "master_attachment" { + volume_id = "${data.hcloud_volume.master.id}" + server_id = "${var.server_id}" +} + +resource "null_resource" "volume_mount" { + triggers = { + attachement_id = "${hcloud_volume_attachment.master_attachment.id}" + } + + connection { + host = "${var.host}" + } + + provisioner "remote-exec" { + inline = ["mkdir -p /mnt/storage"] + } + + provisioner "file" { + content = <<EOF +[Unit] +Description=Mount /mnt/storage directory + +[Mount] +What=${data.hcloud_volume.master.linux_device} +Where=/mnt/storage +Type=ext4 +Options=defaults + +[Install] +WantedBy=multi-user.target +EOF + + destination = "/etc/systemd/system/mnt-storage.mount" + } + + provisioner "file" { + content = <<EOF +[Unit] +Description=Mount /srv to persistent volume storage +After=mnt-storage.mount +BindsTo=mnt-storage.mount + +[Mount] +What=/mnt/storage/srv +Where=/srv +Type=ext4 +Options=bind + +[Install] +WantedBy=multi-user.target +EOF + + destination = "/etc/systemd/system/srv.mount" + } + + provisioner "file" { + content = <<EOF +[Unit] +Description=Mount /home to persistent volume storage +After=mnt-storage.mount +BindsTo=mnt-storage.mount + +[Mount] +What=/mnt/storage/home +Where=/home +Type=ext4 +Options=bind + +[Install] +WantedBy=multi-user.target +EOF + + destination = "/etc/systemd/system/home.mount" + } + + provisioner "remote-exec" { + inline = [ + "systemctl daemon-reload", + "systemctl enable mnt-storage.mount", + "systemctl enable srv.mount", + "systemctl enable home.mount", + "systemctl reboot", + ] + } +} diff --git a/terraform/provision/provision b/terraform/provision/provision new file mode 100755 index 0000000..3a32a63 --- /dev/null +++ b/terraform/provision/provision @@ -0,0 +1,81 @@ +#!/bin/bash + +panic() { + echo "$1" >&2 + echo "Aborting." + exit 1 +} + +[[ $1 == "--force" ]] || panic "Must be run with --force" +[[ $(id --user) -eq 0 ]] || panic "This script must be run as root." + +log() { + echo "provision: $1" >&2 +} + +log "install and configure most essential packages" +apt-get update --quiet=2 +apt-get install --yes --quiet=2 ufw +ufw allow 22/tcp +ufw default deny +ufw --force enable + +log "install service packages" +apt-get install --yes --quiet=2 \ + adduser \ + apt-listchanges \ + ca-certificates \ + cgit \ + curl \ + fcgiwrap \ + git-core \ + jq \ + nginx \ + openssl \ + python3-markdown \ + python3-pygments \ + rsync \ + ssl-cert \ + sudo \ + ufw \ + unattended-upgrades \ + wget + +log "copy package configurations" +rsync -r /usr/local/share/provision/rootfs/ / + +log "ensure certificate bundle exists" +# the ceritifcate bundle should be provisioned by terraform, however +# for testing purposes (such as in a vm) this copies the default +# "snakeoil" test certificates to the appropriate locations if they do +# not already exist +if [[ ! -r /etc/ssl/private/server.key.pem ]] \ + || [[ ! -r /etc/ssl/server.cert.pem ]] \ + || [[ ! -r /etc/ssl/issuer.cert.pem ]]; then + ln -f -s /etc/ssl/private/ssl-cert-snakeoil.key /etc/ssl/private/server.key.pem + ln -f -s /etc/ssl/certs/ssl-cert-snakeoil.pem /etc/ssl/server.cert.pem + ln -f -s /etc/ssl/certs/ssl-cert-snakeoil.pem /etc/ssl/issuer.cert.pem + log "WARNING: no certificates found, falling back to snakeoil certificates!" +fi + +log "configure nginx" +rm -r /etc/nginx/sites-enabled/default +usermod --append --groups ssl-cert www-data +ufw allow 80/tcp +ufw allow 443/tcp + +log "configure git" +adduser --group --system --home /var/lib/git git +mkdir -p /srv/git +chown -R git:git /srv/git +mkdir -p /var/lib/git/www/ +ln -s /usr/share/cgit/cgit.css /var/lib/git/www/cgit.css +ln -s /usr/share/cgit/robots.txt /var/lib/git/www/robots.txt + +log "configure shell accounts" +adduser --uid 1000 --disabled-password --gecos "" jodersky + +log "restart services" +systemctl restart nginx + +log "configuration complete!" diff --git a/terraform/provision/rootfs/etc/apt/apt.conf.d/20auto-upgrades b/terraform/provision/rootfs/etc/apt/apt.conf.d/20auto-upgrades new file mode 100644 index 0000000..8d6d7c8 --- /dev/null +++ b/terraform/provision/rootfs/etc/apt/apt.conf.d/20auto-upgrades @@ -0,0 +1,2 @@ +APT::Periodic::Update-Package-Lists "1"; +APT::Periodic::Unattended-Upgrade "1"; diff --git a/terraform/provision/rootfs/etc/cgitrc.d/crashbox b/terraform/provision/rootfs/etc/cgitrc.d/crashbox new file mode 100644 index 0000000..fdafab6 --- /dev/null +++ b/terraform/provision/rootfs/etc/cgitrc.d/crashbox @@ -0,0 +1,63 @@ +# +# cgit config +# see cgitrc(5) for details +# +# https://git.zx2c4.com/cgit/tree/cgitrc.5.txt + +favicon=/crashbox.svg +logo=/crashbox.svg +root-title=git.crashbox.io +root-desc=Git repositories hosted at crashbox.io +root-readme=/var/lib/git/www/about.md +clone-url=https://git.crashbox.io/$CGIT_REPO_URL + +## List of common mimetypes +mimetype.gif=image/gif +mimetype.html=text/html +mimetype.jpg=image/jpeg +mimetype.jpeg=image/jpeg +mimetype.pdf=application/pdf +mimetype.png=image/png +mimetype.svg=image/svg+xml +mimetype-file=/etc/mime.types + +# Don't show owner on index page +enable-index-owner=0 + +# Enable blame page and create links to it from tree page +enable-blame=1 + +# Enable ASCII art commit history graph on the log pages +enable-commit-graph=1 + +# Show extra links for each repository on the index page +enable-index-links=1 + +# Show number of affected files per commit on the log pages +enable-log-filecount=1 + +# Show number of added/removed lines per commit on the log pages +enable-log-linecount=1 + +# Allow download of tar.gz, tar.bz2 and zip-files +snapshots=tar.gz tar.bz2 zip + +# Highlight code +source-filter=/usr/lib/cgit/filters/syntax-highlighting.py + +# Format "about" files such as markdown readmes +about-filter=/usr/lib/cgit/filters/about-formatting.sh +readme=master:README.md + +# nginx handles negotiating git clones +enable-http-clone=0 + +section-from-path=-1 + +# Remove ".git" suffix in listings +remove-suffix=1 + +# Base URL +virtual-root=/ + +scan-path=/srv/git diff --git a/terraform/provision/rootfs/etc/gh-mirror b/terraform/provision/rootfs/etc/gh-mirror new file mode 100644 index 0000000..4fc987b --- /dev/null +++ b/terraform/provision/rootfs/etc/gh-mirror @@ -0,0 +1,4 @@ +users jodersky /srv/git/mirrors/github/jodersky +orgs project-condor /srv/git/mirrors/github/project-condor +orgs driver-oss /srv/git/mirrors/github/driver-oss +orgs johnandjohn /srv/git/mirrors/github/johnandjohn diff --git a/terraform/provision/rootfs/etc/nginx/conf.d/ssl.conf b/terraform/provision/rootfs/etc/nginx/conf.d/ssl.conf new file mode 100644 index 0000000..bb96ec7 --- /dev/null +++ b/terraform/provision/rootfs/etc/nginx/conf.d/ssl.conf @@ -0,0 +1,15 @@ +# The configuration below can be obtained with the Mozilla SSL +# Configuration Generator at +# https://mozilla.github.io/server-side-tls/ssl-config-generator/ + +ssl_certificate /etc/ssl/server.cert.pem; +ssl_certificate_key /etc/ssl/private/server.key.pem; +ssl_session_timeout 1d; +ssl_session_cache shared:SSL:50m; +ssl_session_tickets off; + +ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; + +ssl_stapling on; +ssl_stapling_verify on; +ssl_trusted_certificate /etc/ssl/issuer.cert.pem; diff --git a/terraform/provision/rootfs/etc/nginx/sites-enabled/default.conf b/terraform/provision/rootfs/etc/nginx/sites-enabled/default.conf new file mode 100644 index 0000000..e10725d --- /dev/null +++ b/terraform/provision/rootfs/etc/nginx/sites-enabled/default.conf @@ -0,0 +1,9 @@ +# Default catch-all configuration, applied when no other configuration matches +server { + server_name _; + listen 80 default_server; + listen [::]:80 default_server; + + # close the connection without sending a response + return 444; +}
\ No newline at end of file diff --git a/terraform/provision/rootfs/etc/nginx/sites-enabled/git.conf b/terraform/provision/rootfs/etc/nginx/sites-enabled/git.conf new file mode 100644 index 0000000..7210dbc --- /dev/null +++ b/terraform/provision/rootfs/etc/nginx/sites-enabled/git.conf @@ -0,0 +1,33 @@ +server { + server_name git.*; + listen 80; + listen [::]:80; + listen 443 ssl; + listen [::]:443 ssl; + + root /var/lib/git/www; + + # requests that should to go to git-http-backend + location ~ ^.*/(HEAD|info/refs|objects/info/.*|git-(upload|receive)-pack)$ { + root /srv/git; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend; + fastcgi_param GIT_PROJECT_ROOT /srv/git; + fastcgi_param GIT_HTTP_EXPORT_ALL ""; + fastcgi_param PATH_INFO $uri; + fastcgi_pass unix:/run/fcgiwrap.socket; + } + + location @cgit { + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME /usr/lib/cgit/cgit.cgi; + fastcgi_param CGIT_CONFIG /etc/cgitrc.d/crashbox; + fastcgi_param PATH_INFO $uri; + fastcgi_pass unix:/run/fcgiwrap.socket; + } + + location / { + try_files $uri @cgit; + } + +} diff --git a/terraform/provision/rootfs/etc/nginx/sites-enabled/ip.conf b/terraform/provision/rootfs/etc/nginx/sites-enabled/ip.conf new file mode 100644 index 0000000..2f3ab1e --- /dev/null +++ b/terraform/provision/rootfs/etc/nginx/sites-enabled/ip.conf @@ -0,0 +1,13 @@ +# Echo remote IP address +# https://michael.lustfield.net/nginx/simple-ip-echo +server { + server_name ip.*; + listen 80; + listen [::]:80; + listen 443 ssl; + listen [::]:443 ssl; + location = / { + default_type text/plain; + echo $remote_addr; + } +}
\ No newline at end of file diff --git a/terraform/provision/rootfs/usr/bin/gh-mirror b/terraform/provision/rootfs/usr/bin/gh-mirror new file mode 100755 index 0000000..54985cb --- /dev/null +++ b/terraform/provision/rootfs/usr/bin/gh-mirror @@ -0,0 +1,59 @@ +#!/bin/bash +# Mirror repositories from GitHub +# +# Arguments: (users|orgs) <name> <output_directory> +# +# Clones (or updates) all repositories of a GitHub user or +# organization. Repositories are created as children of the given +# output directory. +# +# Example: +# gh-mirror users jodersky mirrors/github/jodersky +# +# This script uses GitHub's API, version 3 +# https://developer.github.com/v3/repos/#list-user-repositories +set -o errexit + +account_type="$1" +account_name="$2" +out_dir="${3:-.}" +mkdir -p "$out_dir" + +if [[ -z $account_type ]] || [[ -z $account_name ]]; then + echo "Usage: (users|orgs) <name> <output_directory>" >&2 + exit 1 +fi + +tmp="$(mktemp /tmp/mirror-XXXXXXXXXXXX)" +url="https://api.github.com/$account_type/$account_name/repos?per_page=100" + +function finish { + echo "An error was encountered." >&2 + echo "curl headers are saved in $tmp" >&2 +} +trap finish ERR + +while [[ ! -z "$url" ]]; do + echo "Fetching $url..." >&2 + + mapfile -t repo_data < <(curl --dump-header "$tmp" "$url" | jq --compact-output '.[]') + url="$(< "$tmp" grep Link | grep -oE "[a-zA-Z0-9:/?=.&_]*>; rel=.next" | cut -d'>' -f1)" + + for repo in "${repo_data[@]}"; do + clone_url="$(echo "$repo" | jq -r .clone_url)" + project="$(basename "$clone_url")" + description=$(echo "$repo" | jq -r .description) + + git_dir="$out_dir/$project" + + if [ -d "$git_dir" ]; then + echo "updating $project" >&2 + git -C "$git_dir" fetch --prune + else + echo "mirroring new $project" >&2 + git clone --mirror "$clone_url" "$git_dir" + fi + echo "$description" > "$git_dir/description" + done +done +rm "$tmp" diff --git a/terraform/provision/rootfs/usr/bin/gh-mirror-all b/terraform/provision/rootfs/usr/bin/gh-mirror-all new file mode 100755 index 0000000..fa9054f --- /dev/null +++ b/terraform/provision/rootfs/usr/bin/gh-mirror-all @@ -0,0 +1,7 @@ +#!/bin/bash +mapfile -t lines < /etc/gh-mirror + +for line in "${lines[@]}"; do + read -r type name dir <<< "$line" + gh-mirror "$type" "$name" "$dir" +done diff --git a/terraform/provision/rootfs/var/lib/git/www/about.md b/terraform/provision/rootfs/var/lib/git/www/about.md new file mode 100644 index 0000000..55e68fa --- /dev/null +++ b/terraform/provision/rootfs/var/lib/git/www/about.md @@ -0,0 +1,5 @@ +Tracking of various git repositories. + +![instagram](instagram.png) + +<https://xkcd.com/1150/> diff --git a/terraform/provision/rootfs/var/lib/git/www/crashbox.svg b/terraform/provision/rootfs/var/lib/git/www/crashbox.svg new file mode 100644 index 0000000..87ff69c --- /dev/null +++ b/terraform/provision/rootfs/var/lib/git/www/crashbox.svg @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="64" + height="64" + viewBox="0 0 16.933333 16.933334" + version="1.1" + id="svg8" + inkscape:version="0.92.3 (2405546, 2018-03-11)" + sodipodi:docname="crashbox.svg" + inkscape:export-filename="/home/jodersky/.background.png" + inkscape:export-xdpi="96" + inkscape:export-ydpi="96"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="8.1454544" + inkscape:cx="49.880572" + inkscape:cy="41.270535" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:snap-global="true" + inkscape:snap-bbox="true" + inkscape:bbox-nodes="true" + inkscape:object-paths="true" + inkscape:window-width="1920" + inkscape:window-height="1080" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="0" + inkscape:snap-bbox-edge-midpoints="true" + inkscape:snap-object-midpoints="true" + inkscape:snap-smooth-nodes="true" + units="px" + inkscape:snap-page="true" /> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-280.06665)"> + <g + id="g885" + transform="matrix(0,0.57000354,-0.57000354,0,156.29365,249.65986)" + style="fill:#cccccc"> + <path + id="path871" + d="m 53.344914,259.34398 c 0,-0.44557 7.040667,-12.63991 7.426581,-12.86269 0.385913,-0.22278 14.467808,-0.22279 14.853711,0 0.385913,0.22279 7.427142,12.41711 7.427142,12.86269 1e-5,0.44557 -7.041229,12.6399 -7.427142,12.86269 -0.385903,0.22279 -14.467798,0.22278 -14.853711,-10e-6 -0.385914,-0.22278 -7.426581,-12.41711 -7.426581,-12.86268 z m 0.938299,1e-5 c 0,0.41739 6.596177,11.84071 6.957712,12.0494 0.361535,0.20871 13.553877,0.20872 13.915412,0 0.361535,-0.20869 6.957712,-11.63201 6.957712,-12.04941 0,-0.4174 -6.596177,-11.84072 -6.957712,-12.04943 -0.361535,-0.20869 -13.553877,-0.2087 -13.915412,0 -0.361535,0.2087 -6.957712,11.63202 -6.957712,12.04944 z" + style="fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:0.17204435;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + inkscape:connector-curvature="0" /> + <path + id="path873" + d="m 68.986516,259.38836 c 0,-0.34087 5.34873,-9.60935 5.70206,-9.88448 0.53173,0.60355 5.66767,9.50847 5.66765,9.84278 10e-6,0.3409 -5.35009,9.61103 -5.70248,9.88449 -0.53273,-0.60539 -5.66719,-9.50851 -5.66723,-9.84275 z" + style="fill:#cccccc;fill-opacity:1;stroke:none;stroke-width:0.15927917;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + inkscape:connector-curvature="0" /> + </g> + </g> +</svg> diff --git a/terraform/provision/rootfs/var/lib/git/www/instagram.png b/terraform/provision/rootfs/var/lib/git/www/instagram.png Binary files differnew file mode 100644 index 0000000..dcaff14 --- /dev/null +++ b/terraform/provision/rootfs/var/lib/git/www/instagram.png diff --git a/terraform/role/README.md b/terraform/role/README.md deleted file mode 100644 index 11e2e21..0000000 --- a/terraform/role/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Role-based configuration for standalone hosts. - -Applying a role to a host will install corresponding config packages -and create a role CNAME record to the host. diff --git a/terraform/role/main.tf b/terraform/role/main.tf deleted file mode 100644 index e85fd3b..0000000 --- a/terraform/role/main.tf +++ /dev/null @@ -1,91 +0,0 @@ -variable "host" { - type = "string" -} - -variable "id" { - type = "string" -} - -variable "roles" { - type = "list" -} - -variable "secret_cloudflare_token" { - type = "string" -} - -resource "tls_private_key" "private_key" { - algorithm = "RSA" -} - -resource "acme_registration" "reg" { - account_key_pem = "${tls_private_key.private_key.private_key_pem}" - email_address = "jakob@odersky.com" -} - -resource "acme_certificate" "certificate" { - account_key_pem = "${acme_registration.reg.account_key_pem}" - common_name = "${var.host}" - subject_alternative_names = "${formatlist("%s.crashbox.io", var.roles)}" - - dns_challenge { - provider = "cloudflare" - - config { - CLOUDFLARE_EMAIL = "jakob@odersky.com" - CLOUDFLARE_API_KEY = "${var.secret_cloudflare_token}" - } - } -} - -resource "cloudflare_record" "role_cname" { - count = "${length(var.roles)}" - - domain = "crashbox.io" - name = "${element(var.roles, count.index)}" - value = "${var.host}" - type = "CNAME" -} - -resource "null_resource" "role_config" { - triggers = { - host_id = "${var.id}" - config_packages = "${join(" ", sort(formatlist("crashbox-%s-config", var.roles)))}" - } - - connection { - host = "${var.host}" - } - - provisioner "file" { - content = "${acme_certificate.certificate.certificate_pem}" - destination = "/etc/ssl/server.cert.pem" - } - - provisioner "file" { - content = "${acme_certificate.certificate.issuer_pem}" - destination = "/etc/ssl/issuer.cert.pem" - } - - provisioner "file" { - content = "${acme_certificate.certificate.private_key_pem}" - destination = "/etc/ssl/private/server.key.pem" - } - - provisioner "file" { - source = "${path.root}/../packages/target/archive" - destination = "/usr/local/share/" - } - - provisioner "remote-exec" { - inline = [ - "echo deb [trusted=yes] file:/usr/local/share/archive ./ > /etc/apt/sources.list.d/local-archive.list", - "apt update --quiet=2", - "apt install --quiet=2 --yes ${null_resource.role_config.triggers.config_packages}", - ] - } -} - -output "roles" { - value = "${var.roles}" -} diff --git a/terraform/root-ssh-key b/terraform/root-ssh-key new file mode 100644 index 0000000..11a7a78 --- /dev/null +++ b/terraform/root-ssh-key @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDG5x/YyeCRcIV9TsdyahDpSKQkn/78967VVFvMNjBxDj1/NekINjTgNep7QUxiT16wKH2HFc9ahRGHZ/vK71JDHGZUic+DgvC8lHTTv/Y6aBtstZ9uEv9lz1OOgUDz2sfxLfajCr+40LbgBv8CAJSLBkB0PD5CypUcOtjaD07E6xQD4lMTL1/wsgbLcx4tIQRdQjUziT5d0Zlx9geV/cR4Z3YMNILKMk6vsh4vf3P7qebXv9XOjXE091EIgkfbawYmaB6zcBXoWYDdjPQ+YybqgLFTIjM2OiBmOI+eQFSFlALhP6HUjgbjOub+DnZDGWhH8SlCft6gVMK1lD+Sgud+57R4pXMHIPrIyOJcBF4cWX8biTPg4iLk01sF8hE/5J8fEArs48IhAFj91WW9O/l5torwB5P2g1lM9JxIyqZWSAS63oV4G+8CkgP4TdLYT/LA08F+a40CRateP5WvRGlk1WosMaN+IVHRYd8iFtJBT78hnPyFx3d9UoTCCFskigAueedNzw545nZOJJ4oXbw4WvlTkS/bPDBrj62XRPyrlFPimXLrfGKuY/N7f2wiWbV1Al2EkNurXVUg9sekXEd5cSYyghI14Qp5CyN+D2xkqwNKxC+WL0svIF1wZu39KZaQ2tOFy4ZYae0vut0LjFhJejo+TILLCSeyWf1vVPFrPw== cardno:000605258808 diff --git a/terraform/stdvps/README.md b/terraform/stdvps/README.md deleted file mode 100644 index 316641c..0000000 --- a/terraform/stdvps/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# stdvps -A basic cloud virtual machine. diff --git a/terraform/stdvps/main.tf b/terraform/stdvps/main.tf deleted file mode 100644 index 2e94f1d..0000000 --- a/terraform/stdvps/main.tf +++ /dev/null @@ -1,148 +0,0 @@ -variable "ssh_key_name" { - type = "string" -} - -variable "location" { - type = "string" -} - -variable "volume_name" { - type = "string" - default = "" -} - -resource "random_id" "server" { - prefix = "peter-" - byte_length = 2 -} - -resource "hcloud_server" "server" { - name = "${random_id.server.hex}.crashbox.io" - image = "debian-9" - server_type = "cx11" - location = "${var.location}" - ssh_keys = ["${var.ssh_key_name}"] -} - -resource "cloudflare_record" "record_a" { - domain = "crashbox.io" - name = "${hcloud_server.server.name}" - value = "${hcloud_server.server.ipv4_address}" - type = "A" -} - -resource "cloudflare_record" "record_aaaa" { - domain = "crashbox.io" - name = "${hcloud_server.server.name}" - value = "${hcloud_server.server.ipv6_address}1" - type = "AAAA" -} - -resource "hcloud_volume" "master" { - count = "${var.volume_name == "" ? 0 : 1}" - name = "${var.volume_name}" - size = 50 - server_id = "${hcloud_server.server.id}" -} - -# volumes contain persistent storage and thus need to be initialized manually -resource "null_resource" "volume_mount" { - count = "${var.volume_name == "" ? 0 : 1}" - - triggers = { - server_id = "${hcloud_server.server.id}" - volume_id = "${hcloud_volume.master.id}" - } - - connection { - host = "${hcloud_server.server.ipv4_address}" - } - - provisioner "remote-exec" { - inline = ["mkdir -p /mnt/storage"] - } - - provisioner "file" { - content = <<EOF -[Unit] -Description=Mount /mnt/storage directory - -[Mount] -What=${hcloud_volume.master.linux_device} -Where=/mnt/storage -Type=ext4 -Options=defaults - -[Install] -WantedBy=multi-user.target -EOF - destination = "/etc/systemd/system/mnt-storage.mount" - } - - provisioner "file" { - content = <<EOF -[Unit] -Description=Mount /srv to persistent volume storage -After=mnt-storage.mount -BindsTo=mnt-storage.mount - -[Mount] -What=/mnt/storage/srv -Where=/srv -Type=ext4 -Options=bind - -[Install] -WantedBy=multi-user.target -EOF - destination = "/etc/systemd/system/srv.mount" - } - - provisioner "file" { - content = <<EOF -[Unit] -Description=Mount /home to persistent volume storage -After=mnt-storage.mount -BindsTo=mnt-storage.mount - -[Mount] -What=/mnt/storage/home -Where=/home -Type=ext4 -Options=bind - -[Install] -WantedBy=multi-user.target -EOF - destination = "/etc/systemd/system/home.mount" - } - - provisioner "remote-exec" { - inline = [ - "systemctl daemon-reload", - "systemctl enable --now mnt-storage.mount", - "systemctl enable --now srv.mount", - "systemctl enable --now home.mount" - ] - } -} - -output "ipv4" { - value = "${hcloud_server.server.ipv4_address}" -} - -output "ipv6" { - value = "${hcloud_server.server.ipv6_address}" -} - -output "fqdn" { - value = "${cloudflare_record.record_aaaa.hostname}" -} - -output "id" { - value = "${hcloud_server.server.id}" -} - -output "name" { - value = "${hcloud_server.server.name}" -} diff --git a/terraform/test/.gitignore b/terraform/test/.gitignore new file mode 100644 index 0000000..2f7896d --- /dev/null +++ b/terraform/test/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/terraform/test/Makefile b/terraform/test/Makefile new file mode 100644 index 0000000..7f484e0 --- /dev/null +++ b/terraform/test/Makefile @@ -0,0 +1,62 @@ +all: run + +# Create a base Debian image. +# +# The base image will configure apt to use apt-cacher-ng, which is +# required to be installed on the host. +target/base.img: + mkdir -p target + sudo vmdebootstrap \ + --verbose \ + --owner=$(shell whoami) \ + --size=3G \ + --mirror=http://127.0.0.1:3142/debian \ + --apt-mirror=http://10.0.2.2:3142/debian \ + --configure-apt \ + --distribution=buster \ + --sudo \ + --grub \ + --serial-console \ + --customize=./vm/customize.sh \ + --image $@ + +# Create a copy-on-write snapshot of the base image. +# VMs will use this image to enable quick testing and fast roll-back. +target/snapshot.qcow2: target/base.img + mkdir -p target + rm -f $@ + qemu-img create \ + -f qcow2 \ + -b $(notdir $<) $@ + +# Start a VM for testing config packages +run: target/snapshot.qcow2 + qemu-system-x86_64 \ + -enable-kvm \ + -machine q35,accel=kvm,kernel-irqchip=split \ + -m 1024 \ + -smp 2 \ + -device intel-iommu,intremap=on \ + -netdev user,\ + hostfwd=tcp::10022-:22,\ + hostfwd=tcp::10080-:80,\ + hostfwd=tcp::10443-:443,\ + id=net0 \ + -device e1000,netdev=net0 \ + -virtfs local,\ + path=../provision,\ + mount_tag=host0,\ + security_model=mapped,\ + id=host0 \ + -drive format=qcow2,file=$< \ + -nographic \ + -monitor none \ + -serial stdio + +clean: + rm -rf target/snapshot.qcow2 + +dist-clean: + rm -rf target + +.PHONY: all run clean dist-clean diff --git a/terraform/test/README.md b/terraform/test/README.md new file mode 100644 index 0000000..f418b36 --- /dev/null +++ b/terraform/test/README.md @@ -0,0 +1,26 @@ +# Test Utilities for Provisioning Scripts + +## Dependencies + +```bash +apt install \ + apt-cacher-ng \ + build-essential \ + qemu-kvm \ + vmdebootstrap +``` +## Example + +1. `make run`: starts a virtual machine and mounts provisioning + scripts. Note that running this the first time will build a base + virtual machine image, requiring significatnt time and + bandwidth. Any changes applied to the filesystem from within a + running VM will be contained in a copy-on-write snapshot image. + +2. login with `root` (no password) + +3. `/usr/local/share/provision/provision --force` to run provisioning + scripts + +4. back on the host, visit `https://ip.localhost:10443` to confirm the + service is running diff --git a/terraform/test/vm/customize.sh b/terraform/test/vm/customize.sh new file mode 100755 index 0000000..8d18de0 --- /dev/null +++ b/terraform/test/vm/customize.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +abort() { + echo "$1" >&2 + exit 1 +} + +rootdir="$1" + +# avoid messing with host system, in case this script is run by accident +[[ -n $rootdir ]] || abort "root directory is not set" + +mkdir -p $rootdir/usr/local/share/provision +# mount local provision script directory from host on startup +echo 9p >> $rootdir/etc/initramfs-tools/modules +echo 9pnet >> $rootdir/etc/initramfs-tools/modules +echo 9pnet_virtio >> $rootdir/etc/initramfs-tools/modules +echo "host0 /usr/local/share/provision 9p trans=virtio,version=9p2000.L 0 0" >> $rootdir/etc/fstab + +# boot immediately +sed --in-place 's/GRUB_TIMEOUT=[0-9]\+/GRUB_TIMEOUT=0/g' $rootdir/etc/default/grub diff --git a/terraform/tf b/terraform/tf deleted file mode 100755 index 888e681..0000000 --- a/terraform/tf +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -exec terraform "$@" -var-file=<(pass infra/terraform)
\ No newline at end of file |