From abc88f0074114ab61f4dab080f2edd356cf2f9ac Mon Sep 17 00:00:00 2001 From: vincent Date: Sun, 28 Jan 2024 09:31:39 +0100 Subject: [PATCH] add packer for hetzner image --- packer/README.md | 155 ++++++ packer/archlinux.pkr.hcl | 106 +++++ packer/files/archlinux/install.sh | 88 ++++ packer/files/archlinux/key.gpg | 445 ++++++++++++++++++ .../systemd/system/hcloud-dl-metadata.service | 14 + .../systemd/system/hcloud-dl-userdata.service | 14 + .../systemd/system/hcloud-hostname.service | 11 + .../etc/systemd/system/hcloud-network.service | 14 + .../systemd/system/hcloud-ssh-keys.service | 14 + .../root/usr/local/bin/hcloud-metadata | 1 + .../root/usr/local/bin/hcloud-network | 29 ++ packer/files/filesystem.sh | 21 + packer/files/hcloud-metadata | 42 ++ 13 files changed, 954 insertions(+) create mode 100644 packer/README.md create mode 100644 packer/archlinux.pkr.hcl create mode 100644 packer/files/archlinux/install.sh create mode 100644 packer/files/archlinux/key.gpg create mode 100644 packer/files/archlinux/root/etc/systemd/system/hcloud-dl-metadata.service create mode 100644 packer/files/archlinux/root/etc/systemd/system/hcloud-dl-userdata.service create mode 100644 packer/files/archlinux/root/etc/systemd/system/hcloud-hostname.service create mode 100644 packer/files/archlinux/root/etc/systemd/system/hcloud-network.service create mode 100644 packer/files/archlinux/root/etc/systemd/system/hcloud-ssh-keys.service create mode 120000 packer/files/archlinux/root/usr/local/bin/hcloud-metadata create mode 100755 packer/files/archlinux/root/usr/local/bin/hcloud-network create mode 100644 packer/files/filesystem.sh create mode 100755 packer/files/hcloud-metadata diff --git a/packer/README.md b/packer/README.md new file mode 100644 index 0000000..7f3552e --- /dev/null +++ b/packer/README.md @@ -0,0 +1,155 @@ +# hcloud-packer-templates + +This repo is used to build linux images (as snapshots) for use with +[Hetzner Cloud](https://www.hetzner.de/cloud) by means of HashiCorp's +[Packer](https://packer.io/). + +Templates for the following distros are currently provided: + + - archlinux + - nixos + +I recommend the use of Hetzner's +[hcloud](https://github.com/hetznercloud/cli/tree/master/cli) command +line tool to manage the resulting images. Hetzner also provides a dedicated +[Terraform Provider](https://www.terraform.io/docs/providers/hcloud/index.html) +that you can use to build servers from these images. Please note that +your images cannot yet be (easily) exported from Hetzner's Cloud. + +## Building Images using this Repo + +Please ensure that you have done the following: + + - installed `packer` on your development machine + - set the `HCLOUD_TOKEN` environment variable to your API token + - reviewed/overriden the templates' variables (as necessary) + +### Getting Started + +To build VM images: + + - `$ packer build templates/archlinux.pkr.hcl` + - `$ packer build templates/nixos.pkr.hcl` + +To view info about past builds: + + - `$ less packer-manifest.json` + +To debug a build: + + - `$ packer build -debug -on-error=ask packer/nixos.pkr.hcl` + - `$ ssh -F/dev/null -i ssh_key_hcloud.pem root@XXX.XXX.XXX.XXX -o StrictHostKeyChecking=no` + +### Internals + +The resulting images are intended to support a Terraform-based (or +custom) workflow that feels close to the one of native Hetzner VMs. + +Hetzner's server infrastructure (mirrors, repos, DNS, NTP, DHCP) and +configuration endpoints are used where possible. This necessarily +involves some analysis of their (partially undocumented) setups and +translations of these to our images, so this may become outdated, may +break, or may not work completely as expected. Error handling is also +pretty bare-bones. + +In particular, support for the following features available on +standard Hetzner VMs is desired: + + - dynamic hostname + - dynamic root ssh keys + - free-form cloud-init userdata + - full IPv6/IPv4 support + - Hetzner Cloud Networks + - Hetzner Cloud Volumes + +The following features are notably unsupported: + + - dynamic initial root passwords (please prefer ssh keys) + - automatic server resizing (use rescue mode, or a new server) + +A general problem is that much of the data necessary for the features +in the lists above is only allocated after a server is instantiated +from a given image and thus can't be taken into account at image +built-time. Hetzer VMs use an hcloud-specific `cloud-init` provider +for this initialization after their instantiation. + +However, the current state of `cloud-init` on Archlinux is less than +ideal, and NixOS has a workflow that's not really compatible. Thus, +these images instead use `hcloud-dl-metadata.service`, which +aggregates and outputs the data normally available to Hetzner VMs to +`/etc/hcloud-metadata.json`, which can then be used in further +distro-specific mechanisms (or directly by you). + +Finally, your custom `cloud-init` userdata, which the Hetzner VMs +happen to treat as an execute-on-boot script, is instead handled by +`hcloud-dl-userdata.service`, which only transcribes it into +`/etc/hcloud-userdata` and nothing else. + +#### Archlinux + +Archlinux images use the file `/etc/hcloud-metadata.json` to drive a +few systemd services, which in turn implement the dynamic features +mentioned above: + + - hcloud-hostname.service (sets hostname) + - hcloud-network.service (configures primary and attached networks) + - hcloud-ssh-keys.service (sets ssh root keys) + +Any further configuration is up to your provisioning tool. + +#### NixOS + +NixOS images export the metadata from `/etc/hcloud-metadata.json` as +the `config.hcloud.*` hierarchy. Since not all `config.hcloud.*` data +is known at snapshop build-time, the system configuration is initially +partially stubbed out at built-time, and the freshly instantiated +server runs `nix-channel --update` and `nixos-rebuild` after +`hcloud-dl-metadata.service` has finished. + +The dynamic features mentioned above are implemented with a few nix +expressions in `/etc/nixos/` using these `config.hcloud.*` +attributes. These settings use the `mkDefaultOption` mechanism, so +you're free to override them as you see fit. + +In general, you can provide the `nix-config-path` packer variable to +point to a directory of nix expression and other data, like the one +you would place in `/etc/nixos`, which is then baked into the built +image. Note that the whole directory is included in this, including +any `.git/` folder and other data, and that it uses the file +`configuration.nix` as its entrypoint. You do not need to manage +`hardware-configuration.nix` here. + +This `nix-config-path` mechanism allows both small customizations to +the barebones image (producing images primarily intended for +additional provisioning), while also enabling fully baked system +images (for rapid deployment / autoscaling). + +It is planned to transition some or all of the above NixOS workflow +to use flakes instead, but this isn't implemented yet. + +### Known Issues + +- The upstream archlinux bootstrap image's filename is derived from + its release day. I know of no good way to automatically get this + date. Set `-var arch-image=archlinux-bootstrap-20XX.XX.XX-x86_64.tar.gz` + if your builds are failing because of this issue. + +- Verifying the archlinux bootstrap image is relatively complex due to + the trust setup the archlinux team uses. We don't properly derive + developer key trust from the master key(s), but instead pin the key of + the developer that usually signs the releases. + +## GPG Keys + +The upstream for the GPG keys used by the installation scripts can be +found on these pages: + + - Archlinux: https://www.archlinux.org/master-keys/ + - Nixos: https://nixos.org/nix/download.html + +## License + +You can redistribute and/or modify these files unter the terms of the +GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any +later version. See the LICENSE file for details. diff --git a/packer/archlinux.pkr.hcl b/packer/archlinux.pkr.hcl new file mode 100644 index 0000000..65674a8 --- /dev/null +++ b/packer/archlinux.pkr.hcl @@ -0,0 +1,106 @@ +variable "extra-packages" { + type = list(string) + default = [] +} + +variable "hcloud-servertype" { + type = string + default = "cx11" +} + +variable "hcloud-token" { + type = string + default = "${env("HCLOUD_TOKEN")}" + sensitive = true +} + +variable "system-keymap" { + type = string + default = "fr" +} + +variable "system-locale" { + type = string + default = "fr_FR.UTF-8" +} + +variable "system-timezone" { + type = string + default = "UTC" +} + +locals { + arch-release = "${ legacy_isotime("2006-01") }-01" + build-id = "${ uuidv4() }" + build-labels = { + os-flavor = "archlinux" + "archlinux/iso.release" = "${ local.arch-release }" + "packer.io/build.id" = "${ local.build-id }" + "packer.io/build.time" = "{{ timestamp }}" + "packer.io/version" = "{{ packer_version }}" + } +} +packer { + required_plugins { + hcloud = { + version = ">= 1.1.1" + source = "github.com/hetznercloud/hcloud" + } + } +} +source "hcloud" "archlinux" { + server_type = "${ var.hcloud-servertype }" + image = "debian-11" + #image_filter = { + # with_selector = [ "os_flavor=debian" ] + # most_recent = true + #} + rescue = "linux64" + location = "hel1" + snapshot_name = "archlinux-{{ timestamp }}" + snapshot_labels = local.build-labels + ssh_username = "root" + token = "${ var.hcloud-token }" +} + +build { + sources = [ "source.hcloud.archlinux" ] + + provisioner "shell" { + script = "files/filesystem.sh" + environment_vars = [ "LABEL=${local.build-id}" ] + } + + provisioner "file" { + destination = "/mnt/" + source = "files/archlinux/root/" + } + + provisioner "file" { + destination = "/tmp/key-${local.build-id}.gpg" + source = "files/archlinux/key.gpg" + } + + provisioner "shell" { + inline = [ + "gpg --batch --import /tmp/key-${local.build-id}.gpg", + "chmod --recursive u=rwX,g=rX,o=rX /mnt", + "chmod --recursive u=rwx,g=rx,o=rx /mnt/usr/local/bin/*", + ] + } + + provisioner "shell" { + script = "files/archlinux/install.sh" + environment_vars = [ + "ARCH_RELEASE=${local.arch-release}", + "EXTRA_PACKAGES=${join(" ", var.extra-packages)}", + "KEYMAP=${var.system-keymap}", + "LOCALE=${var.system-locale}", + "TIMEZONE=${var.system-timezone}", + ] + } + + post-processor "manifest" { + custom_data = local.build-labels + } +} diff --git a/packer/files/archlinux/install.sh b/packer/files/archlinux/install.sh new file mode 100644 index 0000000..f85104b --- /dev/null +++ b/packer/files/archlinux/install.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +# required env: +# - ARCH_RELEASE +# - KEYMAP +# - LOCALE +# - TIMEZONE +# +# optional env +# - EXTRA_PACKAGES + +set -euo pipefail + +readonly ARCH_MIRROR='https://mirror.hetzner.de/archlinux' +readonly ARCH_ISO="archlinux-bootstrap-${ARCH_RELEASE//-/.}-x86_64.tar.gz" + +# obtain arch tools +curl --fail -o "${ARCH_ISO}" "${ARCH_MIRROR}/iso/${ARCH_RELEASE//-/.}/${ARCH_ISO}" +curl --fail -o "${ARCH_ISO}.sig" "${ARCH_MIRROR}/iso/${ARCH_RELEASE//-/.}/${ARCH_ISO}.sig" +gpg --verify "./${ARCH_ISO}.sig" "./${ARCH_ISO}" +tar xzf "./${ARCH_ISO}" +rm "./${ARCH_ISO}" # save ramfs memory + +# prepare mounts +readonly iso='/root/root.x86_64' +mount --bind "$iso" "$iso" # XXX arch-chroot needs / to be a mountpoint +mount --bind /mnt "$iso/mnt" + +# install base +"${iso}/bin/arch-chroot" "$iso" < /etc/pacman.d/mirrorlist +pacman-key --init +pacman-key --populate archlinux +pacstrap /mnt base linux grub nano btrfs-progs openssh curl jq python-yaml $EXTRA_PACKAGES + +# fstab +genfstab -U /mnt > /mnt/etc/fstab +echo 'proc /proc proc defaults,hidepid=2 0 0' >> /mnt/etc/fstab +EOF + +# configure base +"${iso}/bin/arch-chroot" /mnt < /etc/vconsole.conf +echo '${LOCALE} UTF-8' > /etc/locale.gen +echo 'LANG=${LOCALE}' > /etc/locale.conf +locale-gen + +# network +mkdir -p /root/.ssh/ +systemctl enable systemd-networkd systemd-resolved sshd +cat > /etc/systemd/network/default.network < /etc/hostname + +EOF + +# clean up +rm /mnt/root/.bash_history +rm -r /mnt/var/cache/* diff --git a/packer/files/archlinux/key.gpg b/packer/files/archlinux/key.gpg new file mode 100644 index 0000000..f5881ac --- /dev/null +++ b/packer/files/archlinux/key.gpg @@ -0,0 +1,445 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +WeUKJv3rncMRi7cKEJ/oNJQ+RaaTDyC0yBv///////////////////////////// +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////// +/////////////////////////////////4kCHAQQAQIABgUCU0UnugAKCRCHLmcU +6vXsRHSTD/0fR8mHPnnQo+Psl2Iyr4CX1HyS+9ReheyXKN/MJ4pME1NGL4vYqAbN +ZI0ihpnKwb6MHwU0snq8C8U/Iv2GMa9H5C01z847zoiN4xmnxXCZmUaBgBiKrER4 +M6sdHqQGHX4LfnRGZ4P5vICKOOTJYI9JtaHefHZSrfq0FsOwOB9I/G2ubCMiOFhS +IzzADmUoHD6t7eY62d9La+iXO40D92ZlnFzOCewYXMsXQzM7lz+LyF6lnu5FP6Gy +gVeQzCXryq9x0Ip3AJOa+0DZ1H02P6XiJgaN0RvAEyqMbKDcJb9uSmuA9IUjNpP+ +3Ti4sq+XqiCyTjwHpaqmzDT48CXpMIV0Jeg+jl57k2oXvwu/UIz2NFRluvt727Ao +FRNpSramobtYqEQZF2QHy43S3VC5UoFPvrEUZQjTw+k1QTh9YZBuRypqxHPMJJrM +dpUeJo3J8KsAjc3hja5bgAshCAv+UXtK5ZkyoQ6AuCwVVtXoRLTNUGWmGU4i1NcH +i6c9Qo3aCssT6pFYavRsV6ZeM6FsHq6vO8+lN8LIhulsGsAod5EO5c+Bgb4VMOqT +S2Ki11hA+M/+O/BO2WR/dR/J0H+CAu2X5PzsI5E6xDUsSuOLDlsgFiG3MLvZDF5d +UERDsPa65eqcLXU26KoQJhPq1YFlTLGxenmbo93XnzQACB/1+FW8a4kCHAQQAQgA +BgUCV8GZTgAKCRAPitZ5umHrCTu0D/92BSrWtvYQoGNsCs4rBY8oFEEri6Bnh+6H +bHVkS0QEq+nITLNeH5QN7rTN7EDYIEni1nlMq4dQ05uSbezpaSHawqZO6HOn2VyF +x4UTzPxDjFNGTtNuSFgJpF1GNC629a8SU+BuZwlXWYAMeQJPhw/sVN+XzIEmQ5z5 +2I70qkM9RixpYn8UIMk4T7Oj4cVHii3DOHWU94KxTrzTS3BELM/xIAX833YIuD9o +OljpoI6GXHWPxkudLnmY4bKIXVu+7deeod6np06Qg0gb5AuIKa/O30lyYIczQ/5l +G3clB+Sxxpl2Xr2x0DCtxbi3LRFzds+z4yPJ2qhj2eMfsxb9MAQqQPVBTco9vnPI +Nt/iWWHpBNa5GIX3XHHGFBXDtDjriTKKjK5CIW+mBG9k1djXRoorgC0dRZj0r1Hn +fJx4R1VW+GTuuT8Hwj8AiGJRcirmU7tt2xbHW8leV9mzxB8Eyb24auZt2B/A2sTr +XeN4I9S9rpEa/ihHe79aSjzHSzCWfzrZbZkeuGjS+CAfWUgaSdOPWq7lHtb8q3gS +FsXMyiCzmOwuy5vVCMavYz2qZdglVvmcVSQ88zDu0QjdjjtHyIy62bk24fbyAUbL +x4ecpMHcTRpeVv+/gfaACNBc/zzCEi+foFgILRN/IUFniXv3OKIy3dlmPc25rIp4 +GhGLc6wfEYkCHAQQAQgABgUCWD4vrQAKCRCU1PHssSX7eD6/D/0e6Aot0Qlmymqh +25YpmUltJyMnBgp5nz+wcArm7nM8a0xoS/gWvN4ULKeZhd5hwMVSlziIgH3pfLNi +jZ6pZdigZFkoANgiiR2s9aoVsuVuKHcfwLmY1IFCVmHN3e8L0+wgbWGqHogsQ2bK +QGbBDi4mKb1DfWtCHYajV/qBYIImszqGrOpfuHQDoXegC60Rm5e/Mh4BjaK/eSMd +SC/o3T6Q3TAK8OrBphFuRj2hAXHMWI3G5frzeXHKWhUJhxS9tMtQQ9+jMqHFcmSV +/OISzbOT+UT7xNbek+zIbGG8+tBFgTTjlt1ucKizZc07+OzJotou5tbEGgeTgMCt +XKH5qroI4NA4+B4sLZ1vbZ1+TTpwmIedT4v+jZpGm8xIhln5GUakOeZFUgVtD1nX +arkjnTAo6guiSShQ9xMc+WGJ4T9s+ZBnr44938bZXUh+ru/8gErJnsGpvmqvk761 +LCTmhSQS9ZdpgMbTEECIeWbmLGkKrNwBEmaxApN4uZ67B5QHPIfvI88zve09Pz1r +ll785jaY73ZAtwueuf99B+A/yJp57dIISTxjuxT9hB76VlSD23XoEMD+tJSqdOXB +qYkyDMxLm3rY+w1d92r/y3W8zWx6bBY3Qr2w5UbTeGj0bLLafUt+Ar9FbYEJ6Nto +JLlf0ELhCCSoaQ7M3RANob6u7Kqs8YkCMwQQAQoAHRYhBHc8Q2r87r12hYco5f1x +B5y/oZtxBQJYYyupAAoJEP1xB5y/oZtxdh8P/jZfj05Zqql+y2iMI3Fkf4v5aPla +2t95D5eSBwgX2Vf0LHbuk3mDQAuNkA/5OKl10g6HoaoXP7k8YudOgEB6RdX6+Rqq +qc2gLRoSTrNFz4qksfqTPMkrqndZaHTCX2CzHBX5bqTrynjZ+kZAQFupvKM4C27e +kr5KtyAEP2cnlG5S8X/HPgUocxm4Lh6hgqGPv/VoOMUHSRTHyEjpWU6UlCQhzbGu +0gwTA0XkYNg9cyn2/vnOlzzNn3t0Kd0LDpMesPDAh99Izo4oVzGZMTNXtN0ZxJ8w +qWiCKQVfjFM19N6cCSg0TqhntwLu/2N0NO8G3+lNCuD0+Njicbl5i4c9hWrxaL/F +vSsI4IUfZ/FVnHR0BeG5ZSYH5701fg40ZdLjUz5qcoRPDUcghdUarjiTXVkh6R0D +F8We0666GZ20mtRCVNVkYnSYgLl0szjITPSDWjeYAqgyZ8YxghFSz43X65C0zg2J +pJeStg50bML9lMm/mpgvWNm55xE1naSdZAeKg1Y/ry0pKHlF2pTFAgq27yjcNwUm +GqsP/2GIB/brUj80TEIe45/MSqeOXT66MAaQelSnrDoC18JOmXeD5tlEDOZ3PlO9 +XM9H9NzxD6FD+8ti0VZE+IQRGA51Jgg/U8y2NsfIYfindvEXY7xDUPA080SSaixd +Vv3GGBC9K0vzjOmuiQIzBBABCAAdFiEE3bhnuSqnicFl7vp5m3KbBqaAwoEFAlln +RP4ACgkQm3KbBqaAwoEx7g//TkKo3oHjqIdHNrqH8PAjda8zYvIxYjXthm2KfYE0 +itYoEuepKp1u2xhX6HINX8+Vec/Q7z/QJ3hbC0L9xrq3l/kVDQnW+o6NKLXoAToD +MT3CDEN2XITMLKJpF+OeyVqma/GvggWq0dFaQ8kxiyguBwewQNTuMRrjn5KQQM9B +IIS2w6JkhOERV274Q9opN/KXz23GKMFkYs/yx47dky7o8urHI9zYUnoQ4WOZxlgl +9EF9gp/PTmizLA9/pH0JbpT/PWolzXaq4g0wod517vbVdEEIiH3HmzqVaVju8lVx +UQ0W8u8ZCNdyslPn++s8k/VOi8kJC7a9yrxXJHFHKSCE3eHslMa4We5nk8gGku43 +pKnM2MZCMHqNOesExJR96aEKuGlpJ6dLciYdSu4djF1rkPaB1yaPX5NyjCqvL1et +h9MLsWmtajo1wCi62+8F1z9cUwqea2vJwdKCalH7geEQi2gQygrcJj6Caq09glPf +I5B9UZX36hCqbYay86O1lQqHtSyG26b5M049LcjnieCffVTIpMVdcdzOvQTuJcn5 +vD4HNWOSjgwbOZHgvtXaEQ0k+DjxmIYdUHPWEBldsimawC7cSZdlHPiuGktdtEGe +eSBaL1723DULLnGLVlolojU1SgpQLjfIupuqB696uwxr4a4pKPHQf+PtmSgVE1hz +ZFeJAjMEEAEKAB0WIQTYr92geltu36fYzNrW0FX5J4Q/HAUCXZDo8QAKCRDW0FX5 +J4Q/HDFnD/9zX1Agyyuy59/eii2lGqEMUIzS+2X9dppn5Li5r2yVhHr9yOpF5dxl +oW7H42OmYXUq2gcOPP8Dtt1xeHlfF86VaU6gaoFOQHwV9+MD7pqykWAP8/A1J9MR +glEdviehkErizPeEgXdQWOsuRK5aaMmSfEWZifc2MsTkeFs2dE35LooS/nPRa87J +Cy88NtcXO05nIOP968y+2cxlc/2ORIdlWr0vPVVIha2v5GSq11kvoYp9nzuMt11K +Z6mdp8F0k14ZV7k0jf21ipm65XtNwgtmP97R2jvRMF/1qtAuR9DlCOnRJ5jeV2Kn +9aGhD9HF4OtozPUPpqL9xjk1JQSey25wD4dYnO+lfXO3xdpSGjFy9YThCQKktmvf +fXNnmyz+oG4bXu/F8sHyVCL66Nu22aW/LeQVQp7wanNot4Y8pnpFZsuc9/OXnL+b +3mohdeoBckbPWN8ztcXsYALQ1QJ368np/JXqJKGflHP4POu4rApsrE+RX4Sfi2E8 +FtaxO6cLgGhWCMq26pi+1urWU/arlGaLv4JuXr4SzAXUVYpfUgJOvYU/ENT/LZGz +tYcb+hNk9lWFgNgo1dacRCB8+YoknhGG23ml0fmzRKnH18YQIT8Y5yCkI8HY+rik +OGH2QeFn0+zv2oG3qYkk2MGy2W6GR3aQnt4HGQQIVo+pixna32KeUokBMwQQAQgA +HRYhBFNfjAM5RQ8FSk0oJwYJamrRzt2sBQJdmb5uAAoJEAYJamrRzt2sFoQH/3N1 +Qk3tOILqreZcywTABlf3Ud3zmqF/aC/5cfRk+1tT2MJqxZkK7vOaPlV10Pw+zA2a +okacaki1NYjjvhii+3cmd82FK/8fJI/Cg9BwxudOAEbeqo9Rzl11dse3etHaba1n +W1vsKArbOXjWN8ST9va0sAYibZqZOgLBWKVmOaJLWM2pRk/xAGw7TUMwu1kXgomo +qr7fIsVgXem7y+eBPtAFb4UU/5j+7MLL7lSq+VbExtNxyLnbn//gNWu6P3IDQ27O +dHJZX7UmFQuP6MVj3M2u1Dbu/Wz+6YD5qRvLphbm1MAaOoom6mETXvGMdI+JVMnl +PtxzDtxguy/H74VFUFCIdQQQFggAHRYhBMfnhJRm/iNYNDWIN3JYc0tBwxVJBQJd +mK5wAAoJEHJYc0tBwxVJhGoA/2bjgHtCpF00WbNczXfCIaBgwLMXDRnPqtjfgIIn +ogUxAP9hEDtBqnmqUst+JkRuetrJgr28sl8NjHVyOCl9u+IcAIkCMwQQAQgAHRYh +BD3OUdYJMOukeFi6QUb2M8uw60vyBQJdmZR8AAoJEEb2M8uw60vy5CcP/1yJPrqY +pz/cttdDCgVTljTGbndnamgFf+Z4d6eXQ315dfmIxv/7jEj98q35AzWZRNHzgAA+ +ECn7yOdWD86mW6EPefSONSCWGa1AD8/225VfLwyA5isAb2L3Efvqm8JleSkU9ZvG +osSrkjq/P4PQSEHFWjFLYOXWncKYHJMyRXezla4nW8PZQ4SQxyFZwfheKaImSqIm +Ue1H1o4vaKpzZNxHN8RmdGImS7EyDDKxy9oYkpVtMLjFNs4BHXOJerCaDfoWPudK +CNKaCifzS057jaBprrZue9yA0RYGHvPk2Ycc97QkxVVsIC9lHTJuu0IkNyKS5xaO +/aWh9g+/XCVJZQumJo52SrCHigIXewbVz9brTdqWKroo3t87c4z0Own5ah3GvglO +hq0/iI4poKqeO8JmqBZ2QCSMd0wzPYZkxj5PK6ZnmLrWZDp+Oq/D0iF1tj1X1n5Q +WAQu8XVv7Mx24TLhsltwrHyoZul/oOhA6I0L/sxJcLcv051l948PQlYnJvmWDGKD +AhPd8XSfbUU6wFlK3orj4ovqIloDugSgQeInE0OIEokBQo4zNDUnh02OPAQ5XYEg +e5scCmbJml7HU0s5GEG+Wxngu50TZXKXqW80QgndlInZ2f46epu9GLFVwGOvhQaF +6v2tsVBr3spQ5mBUmk5jY0ps0VMarkK6lqTqiQIzBBABCgAdFiEE60+eWmDTIjK7 +UhUMEsh6KP6sayAFAl2bmPUACgkQEsh6KP6sayDK/RAAkRrJuv1RhtjBxrBTmKXt +7whw3kFEqUpclaREkekK5qHVNsdJSvLL0raJWpR/b9l/LBq+0yuXxhHteQKRXoMz +g0EqYvMAIGSUgKbtTdtqQzO132ttma/tFMQFTGikhd/JIuC04/zIbU9UM6rjqdVm +P5uAR9gX/KuIW+IZxXj+TK+YGi9ejI0p6MY3SJ3qy/egkThgrgKib+Q8rV4klpsK +13N88doeaGK4+Jus3wdV09heZdQZ5Tk3kGARjMTBIn1EXEk4Kw/F6un3LmZJLhX+ +OrCiRHRoZtHamWtgE7Fnw1BT7dAVcZice6r2UV3t0WWdkpWHfZ6Dbf80jsyEwIE8 +UDg3DJ2htxqvF78cX9EXY6PSibRflqeYkji07Hj3MJyhfee1prTfYXrFXwk4PJpC +FsnPnWvzB3Gw60aobtbMSxmpDVFzz3WpnUEVyQG6ezeOqSjfMoLLL/hsRqbTXPnQ +BT43r2cS88jO/wamk4sBlxlaJ2x3UJelnkSSrokGjE3H7wvsZCEUCIc6p/3+UVb1 +otyPTYUL4YP4AfVV7X8B5jk/kNNpOdFshDej5xC0BDPJgTTID4xH1GG99T7Boqqk +TXyOHOYE7XC32/6AG1XUmF1KmR28c0W6hrSGErXmOnKW558gxw6HwbfmJGJ8GZ1R +q52MKvoGGE7JWQSCj7FXNdyJAjMEEAEKAB0WIQT+LmJJIBylSk+5DQZugMoURoed +BAUCXZtmkwAKCRBugMoURoedBJ0BEACc3zAlpb1rR3EWLtUHq/Tf8r1xsmDLQ1Dc +iJ9L5XjZF5qe7QMSyUGF5LOEg1/kmXEg5A3GiUcUGX5mAagoFitrz71hiInmHldB +asOsPsTXS5VVTvIXLhrg502PYESFLVmbRUb4xyy4FJ1wjASPuTc8AVfEaazYPdd5 +PKamJnGKCzcNgTqAW+qDeIRBhS6KVXLcx1wOz9SsKITlpc/KULs/3H/flxWRloT1 +9RuFDHoUmuLJKXJVtlJ2+ffC6Z9rIdlJRf8ZQJlrzlr/xCOtiy/nirXi5GRcXMxQ +hBVJnRDOy85zWIOZyaYDCBIzVpW8s/0H322Cxsk8zwt5C3UvhqtbkOTsLs6kVgrI +qnnStjFr7FYrHus5bAXj+NykvtpBGutAjvKdAqHWUlKGoEQS7K4i6lvEEPzGR5jP +WjbDB1Qa9jFLH56tpX4bR6mn0oUDc6Ao9bdXR30OivpRTeh15a+8cRHrY4rsBJA8 +kqFpQowcXRx74fc+Z5UjbFuf5NpV7KT+2NJGO0LFSsoDhr6gOhOtJhcmo2KikqXh +lLSo+0fqbKEnHagnh3o0hLsiOVjqsKI9KQl7h7rNu9LHDjcBUbhV2Sn9HYzFy9bu +49HZ+S3YoSEV3AWZXmrqY4eEZ67E2pmUXZGuDlIRzeSFdTICcTSdLQZlAatf6sqa +bOz1Z3SnfIkCMwQTAQgAHRYhBLWXHyxcEKmgjGADD3hsY/Mw18uSBQJdmZZpAAoJ +EHhsY/Mw18uS7jcQAJAolNsukFWQsnsQE+rfGTsFtnc8qcF/REWFyU9b/mDDLMc3 +t8lPKvlJ3JoYH+0Hf4nJbNo0dswAbbLHzxrBDyyiQDPkV/zAJ7o1Y3twYvAIgq08 +VfQVojW6bJzi4aQao/WQ9eDIVTW95tFGsoEdAvgWiY/BEAjTIYb7k5xsuYEQ3xQF +wlGaIg7xORkfJ6o/R8RodGbeDKzap+ze8nRDczG3DVFC8g9rEqBKy1ye2gQJaVsR +fuIB/hULGncKyIjIIAkXr/fZWUOguGflGbRu8fqjhmcbIVU2x6JoZOTC/tjCNU1/ +MKykxVIwrN/CG65vtCxH89A+WaAXa/QxT/dZ701moIu7ZJpLlQ4tZOK4/kKMMSZy +w1qj/d5nNSURVTNK0QQGRCC0XQynPOxbd8uXlKSqj717U1v0WF8RF3ccdKZlvRLz +rkz2ZCm9pb4KN0SFARSDSc90NI2+4BEOqm1SBrbo4Poyu9XY9qvN0vQM18a3zuYu +N1++mf+0XlO3FsJupX91Xn8wjtbTjKBnkMx0XZVCx2NAcQpWVg9Pq17/6xx1Fk86 +Zn3VRu/dcU8MD1G7pkV9CM8jVdtUeOzZnKgBcR5IcZg4ouOObN+Kl3R8HYyVUQLN +GBR9T5uZ9mSf7tX1huhxOtzijhgM5vN8Rgj10ZJKlllRgDQl4eCr3AhWnt6+iQIz +BBMBCgAdFiEEuBsFHy1/yGeq/zWljb1juCBy13oFAl2jWHQACgkQjb1juCBy13pC +CxAAwYvcJDOlOEG0PXP4HmWWtWFypWpul1/uy0MRMHPHhHWx21psmcVJcFZoCHPJ +NrBQ7Mp5tm5QGU0J8TgAV5rGKBrQv9lI+OcHPGnkVt31guErsxHzn+bpx5Lw6yur ++S2jhSoFDmtVmID1II7JnuX3pCL+j4SwXllgmZC8Tt77tYpX6rsOMxNOjdLyzN3y +YejGg7NZnCizsfDqBDglDZeCJuqRD1A8AjSoqhLNWJjjNRBv0cLd6yPzPv0ev7sV +xw/9Qvl7pfYn5ZJT9rJQx80y3Wl/4tpIdDx1zWPBZJR57gbuqJZL8yhXX6ZLahvK +FdfAqlwBfJcBv+F/I6IvQDC5/ahn3jjQshDAUMUTpsqDVIXrbNmJxGurRLnhCV7I +m17yjesu/UOhGKnWE2EHQlJPsmZ1M5R50rEOAOBOfhu179Q9ajs+Y8LHOYioAWXh +MRXtQ+nMkcc3RiY0A+oFoTVMGtOqHA8W4zMu4/Lu/iFwQKJ8cmkjoXB26oRpDVTf +YMK1QChFnrhTB/+W8SENDAlFKZYCoTolG+z4F+pQsRDV857UyJcWP6v2vcJe3F24 +ObjuCXNYiJr+KUqdZegyYDCMou4jdzH+Yyv6UsI/aO6BouJrOylMkOmLY39kzHek +DUumW55fZicGmxwjldR8VBaY2xYwctW7rqpPXIdumPJ6r32JAjMEEAEKAB0WIQTB +ADRmdmNOgMlA+56cAv9Bn+y+FgUCXdBkDQAKCRCcAv9Bn+y+FlzQD/9jlljuzfup +f8rTwhCOIH7JQxB2MShLqf0glZlrpkQSt00YUh9ZQpLI6aJwFRkcI2GcF8leKvz8 +gaGeMTR+yIGpTzNOOVyUnCsVDSAqYwqsE3gYFMJnPs0stP+bDUzIulOkWfxpDbTw +5xSWbajew54+4wtnk8YY1jyqaMuH4+A0G6EUPg/E4jf7xBVzigwce6rt4Ycjtj8H +/kdRgLRCPWd0KY09dOJrl8BiX1sTitw7G76nDDihoPGq927hgEQR82ICBKAYrAzR +cYcFeKoL9q9yfN/8aWBxfHEjY8U/3igrHrhpgwP7n7MOUAgxAZTpECnRYH100uk5 +cekk0Q474Tw2KBvTM+liODgh4gx/NxcwsqBHHlt8Vm/HxG3B/NN1xDZhWFcg0olK +pVCok3h8rA347wd6xYXrd79whIlRfHUqrn/bXw8l3GnwAotdoIaNq5/AcApZpc1+ +NqLAQTl9YpzYeRo/Rpw0qdu7CLSvIiwUdsKJNZqjNHZJ+F8lWXO2H8sIQDQk8WqS +LuvOm5FwJEou/aGdm2nOi6Yo9CY3Uhu5ZGGrdAV9hoNSJW1Z9H+fgj/o8hhgBlzo +x0Uy59oWI0fKY5y3iTyE4ajzlZJ5BFql4S28FiDRdaeO7MqNRKZXvbqXvr/6+OPc +eoyk3hW4aCZw5b7rZ0jQF5YdY3LttSsKZ4kBUgQTAQgAPAIbAwYLCQgHAwIGFQgC +CQoLBBYCAwECHgECF4AWIQRKpHZ7vJxLHRiuKLd/LUNLl0HorAUCYX6nZQIZAQAK +CRB/LUNLl0HorNKAB/91+uRNJaohO5mun3qJpicRNdyECoCyZJfxGl+t841fTaOK ++STJafgMnsYkkoE87rBbh45wtOPFMofo7ckaB8ELl8t+nAndCijjadM3Ro9Bjin2 +/hySY4Xb4v2e+x45qE3Lj81uYknHPJggYwap5hTkya4N6cZuh1+zZy0rGdm7/Udg +S84rBnfyamEeuynjiLCP1BXEOu7Zx7k6djjfry08rd+qyWwUJQ7wfUZ0UjmjtVDl +SPHj4+XMx85fvtOISpy4A6bAX7kJTc0sOTGb0dC9rsSKwb6/R23yv5Llt5FDoclV +9zMC30PALSu7A80TQ+pxaxidruovwHjHsAa/q1xntCVQaWVycmUgU2NobWl0eiA8 +cGllcnJlQGFyY2hsaW51eC5vcmc+iQFOBBMBCAA4FiEESqR2e7ycSx0Yrii3fy1D +S5dB6KwFAmF+pvoCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQfy1DS5dB +6KzebQf/SlbQ/oidRHFVS++YLSSDYxj/6X82ubEel6Nl/XBR80cVMKbzpPliUIys +fe2imCCKCevg8VXdHbmYauO7dP3Mis8APbd/CtVGulJlixaFv7z1RpgVMI33/oH4 +RYR2LwOzmReqGu3vYrcUeleFMW7+Q4dr2pMrgML6eMslyF+A+PGEkLQAnia/u/g7 +PK9J9sk/h5TEqmOQLD9yuaTZ3EOQ6SVvVgo0imWEj8JnwPJtvpuNARDsDs9EyFFb +n0W8gHghN2L2xNmmZTiKy3klglEATq+tb855BW6Idw+MECHe+XdlVQ6qDppuKXVv +OKgRF7kcs+aQhEDIItzIvuKEc3pxr4kBswQQAQgAHRYhBA6LZEB59Znfwd3DlzNI +iC9qxqTCBQJhfrFqAAoJEDNIiC9qxqTCZlcL/2axYANMdSQLyrLJn6ZVzFWHli/I +UmE04jeqeQqNjexuJoKsSmVeNn6GhKgneiP0uf9XUtbq8HGWFefVzR0ZIqPNABQi +WxZJUDTvmPGbU7sIw5r/4MzWRI6R79jPzPchEtw26l/LhLB9zCLp20lLtgI8w/Uz +fJxKx3Kw44wBpdssjRuvsg1vbkHcR3Kch93o9yqrAmvsDWBdacxlmHSucLtHHRm5 +34o7bDuR+K4Nu2PJ6L/X9+kVAlKwMM49ziQMmd68UuT6WNo/aBZirtKf207ZVRH4 +tSUuExHj8+L6AqlKgmXn685BKM92qPv+e8QqdQyBrHFqqrQcVfUXVtHxyS42SlXP +dOOlAlSXea8cjd+IdgyobqWzjjLU6GEk4nc25UCWt74m8Bzx5YlltlhAeMQ2dybf +fXuxEFDC9ul2cTJbLRo+9tRyZg6oFnFG4sTlRHmsEAa2FJ7qKFfgC74QVr2UpfsP +BbQNp5GUuqQRrWpc2/uJg2+UQGmUxSePV52fioh1BBAWCgAdFiEEKsCkLvsLXLx6 +BALtTclbbXvpiS4FAmHkPfcACgkQTclbbXvpiS6Y9AD8DK3lhc4mwMSH7W4VHo6e +3VY30QFJXSgAVtOKGiu5WZEA/jgoIj5h1U7YLslS1WLFNseTkt8y2WtC9gBmw7uw +EYsEiQIzBBABCgAdFiEEkf/gcA6AYZzrcyNcqI4j43dRTgAFAmH/wx8ACgkQqI4j +43dRTgAqAA//QbjIM+XSmgalQzMNeWPn3R9PSWU6hnfRRWuwwO+n6buwGz/D0JV0 +bF+Wg5/nQrmYLTbThQYDp4ZPfjKXP56E0oPytwv9D+vTivXAGX8atgODRJYIXNh1 +OompwW7UtvBfPlqPEfqV957C67VXWA1xWQoD3obKWBv5jJCvkIBnsKEpfoGR5JP2 +vFuh06nW+k7Sjm6xna8lh9T4KiK9iU5UVG0RV5UnIUj/D2lcMHz8MBBXt6FuE8TD +76NoTfOYoaAXxxPph0HpOAcDm2/6RNSU26dObzIY1F/fjKBUSYiNJJ3tdq4+MN2O +Eg+bh/LTi6lnVoO3Ja/h9YeGawIGBuKbNPrCUCFxRL4LH+2JH81H9IK1jGxmRiom +HwNR90C8qQzCPjr/x27mjXjZ0bl7j3qxEmV8p/fmWuLkK6wp17a9NkyX0q8vhhFI +T0iihnQp38S4lzoN64QP0dT8cdRw9pa64DxJMo5XciyM431Z91784rsphLhkvco6 +MViKtmsQL4HvIjodcmzzQiYSOGNvtvTd08RH1Z/ck0EZ0UHPTsTToRx5NMNGfsKk +Zo0bWbdKUlP/pW2f3UfSLw/rlCZ79IRmmdWNj+aWduV5lR6sAYVxuT60nz3nY+mH +3qB4VcU76EXmGhjiW0B9hSVEz1jwhnsa0NxLSWyL1AXzPS2X0Hsy+8yIeAQwFgoA +IBYhBCrApC77C1y8egQC7U3JW2176YkuBQJlBX0RAh0AAAoJEE3JW2176Yku6LwA +/jY8bOCa5JfljQc3zBn7AT7qMS6mxymxNi+bCDgTQWyYAQCGjeYCnDILB9O85UFq +IwXoX13ro3cAzW98b8kcu0wMCrkBDQRNoXnlAQgAw8Twos3KzoR9dkWyJPHp0rK2 +wE20J0oKVNwxxe+o9oFSLbAc6X42IEAng+SmrF7hZhRaYdqWO96grqA0MRU6OICT +WbfdP6Fewv7zxMDGOTJB3StmwdwZWc57IZKRzZlkQSrwqxydPY2cZgiAnjcpoTMg +GARljOzEwsxLCpPQrqZcReUAKQm1sLZWVaYMa2vdDMwVZUE/hK14i5V7fERuu90Z +RnhaTncViuFEm69QL6mMTFemOLP5iqXACUAXS+SHkU/AZ2huZlY0tFIDfDHjenPj +Zb35xQWRfVxWV3xSdUKw2p3sk9fNYLigeGqcZr7cl8Q/TmHVvxFxmxqXWxdzsQAR +AQABiQEfBBgBAgAJBQJNoXnlAhsMAAoJEH8tQ0uXQeisvOYH/R7TzLJySKosyXeb +NqEZKWMT4siyqavtJR9kfsj6NUMre86UdUlfIklQ2k4msXxeAcGUM9ELdBZyKa81 +riMNhYxJRP7VRR/hcPUlubd9Zcvr/412vohnDFyG5Q1+SNIKn311SURs2cz0A1dG +L+M8j/9h7L9BdudDdjfP3Gaj2l+SdHSqzoQ5oucnOVqGCc82Vc10bl8Mwp3J9Mpm +bXjhsHGluJJmk0D2994nZkxPPaV57JIEBaX7QHbz8PUH/841YU7RV/ecLaDT3GDr +TCAEafzno2swR2kVvjSFsgr4+/DEaMvbNEzgM8HMjglqY8x7j77JYP1NBxK2wxoT +bGvP3ZyYMwRjX5FXFgkrBgEEAdpHDwEBB0B3dd1nA6aaIAt4/B3boG7eE9uUB8d+ +UY34u52ATZDJvLQkUGllcnJlIFNjaG1pdHogPHBpZXJyZUBhcmNobGludXguZGU+ +iJYEExYIAD4CGwMFCRwyBIAFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQQ+gMoa +i4n2nLpX2Yp2pe+QVESaXAUCY1+TaAAKCRB2pe+QVESaXN2LAP0d/tMN/EGsnVjC +kP2Uu1RUjgqnN7c/l145vlESwYTmhwEA+ftbKY8WhNR+uvF+aWypm1LP7YPkZ1cR +ZBg5OpS+7QyJAbMEEAEIAB0WIQQOi2RAefWZ38Hdw5czSIgvasakwgUCY1+cJAAK +CRAzSIgvasakwhZwC/9NLPHNU85/bChecDx+PeGYCGA0AHVm8CycZ6qVDzcyPIe7 +FBsknd6wSJ5LV1mg6UgOH11JFLF29gd3eJdFmdZbNHCXGTY96VqPCwjwZdUHZPMz +E0FNgjkAQnqTv+f8BUFNw9y5f6OPyHyzlyljdEg7BBP+wpauoYGlcx7+1vWfSX3d +BGc3Nb3eivIaY/RIUyS3FtuQZq33+P4crfTD0hiqLVB8gBAcF8xH49JrFxY0RqHd +Q19CXz5ECtuUUBmHfd8L+2/6jhO9GIUAndJ2kHaRA05eD59mIii+aoYCSoEAA6KA +feeCm1luiq+Lvwh9nxWoHpU+yUKCIE7fWZXdiMlPxbpMN8RcSTwTayV5kWQMJZNS +Pv4dYU06ppUlK6+KvkM9y1hsqvoAdQ6DrzeYu+iai5gLxzyyg/WEFJ0NEL9g5dzq +XkSfgyGjUhhcfcJCQShiQm59M7OC5hrbcdCdJZpuf4hdJ0qHFDlESjYyKZTWzeh/ +ZIdozKwqcgkHEr+9APaJATMEEAEIAB0WIQRKpHZ7vJxLHRiuKLd/LUNLl0HorAUC +Y1+bhQAKCRB/LUNLl0HorFLSCAC0vcuNH6JGkIu23VGjFVZK0RTv12lKKtGtTpbV +vkNmoPjMdaGIAyZK9XeNGpYZpSGNDD+jJtqwcHZaHQ75uOfx3neY1USokX30KWIK +yxJZ+yxoU6p4i8XtMZTWHu72XLvZZTviTRMkMSM4Yjz5qezm+dW05looRKnBSl41 +WqJG7AMZqBiDMLq2lVp82OGCfxHpgpC0u9vqJMD6nBLiiWBHzCv8JW/Ke8KUOlQK +33RN290WhdTMimf3KmY1pmj+BCA/GtUxYhPnbfFUE/bPsJ2I0+t7VndBD4Ysw8HS +jwPFiiiM7UdxhO3WPr8TgI+aJHO5V4WnVUuIOadti39V1gv5tCVQaWVycmUgU2No +bWl0eiA8cGllcnJlQGFyY2hsaW51eC5vcmc+iJkEExYIAEECGwMFCRwyBIAFCwkI +BwIGFQoJCAsCBBYCAwECHgECF4AWIQQ+gMoai4n2nLpX2Yp2pe+QVESaXAUCY1+T +aAIZAQAKCRB2pe+QVESaXLQPAQCFeOXY4m9LPfMDNzrOIElLyh+w9p9PBa80AsAs +jXGC1gEAy9Ymc3jnAj2MJDnby3b5WyNzDbjBMKVhv2CvmDln0AqJAbMEEAEIAB0W +IQQOi2RAefWZ38Hdw5czSIgvasakwgUCY1+cGgAKCRAzSIgvasakwsXiC/9nHc94 +4OmKaNwYrwl/A6J+NbQuB++nEuTwaUyjyV8+O1pRAgTUfSmYys7ePs7WRcw6DayT +hPeSoBVce5BZvqCb+/BcxnZ1UwQ4Be7HoQu+2jkHfXXiTRSEe9UEOMLNCQkqmeSd +H0g4dE2iXBYJadm8s/D0Mltm5x+eEr2NGBB882LGfsUmdObGBBqMQIvAPbQn/hSh +aOdZ5I6qtpebawM/R69k7a0qzvCdvznb2kdGS+r5d2jn5fuCSI8Mv8thsuwOzbJy +sERY2zOJRdck8+5rDVuUoc5RQH2F6JrGSgua64dPtF3vcH2dqiVdv1Duja/kLWPa +3M2/nf3JEuVcmcCwMopRwYbsn18wdtNwEJ3ie2xu9eC8JVSU+OLsoHj6pYxblnG0 +ja/0ou2MY6QMm9/njKqk6wBzZbCSt/6XTXnOtLvNqk9I596n2x087X1Kwp8H2Com +e05PwDDeMwsZA1yo8uErlziD3RItWlI7RxL+Z7WbEmyvpBf2MUfgiWDb8RKJATME +EAEIAB0WIQRKpHZ7vJxLHRiuKLd/LUNLl0HorAUCY1+bbgAKCRB/LUNLl0HorJDv +CACLULxwujuLpIYHdl29dbKAKcCJxPfWUvzIWOM5R4zfVt+IbmZ7OjjKBR/sF0u0 +XsDD57PW//VLTByhhkP/MKCB7VfPT/rNOSEnoMvb2DbQPiqVO1DPb/y0QsRPKeUp +mhLZrH6PAlx6wtZoxci6HWv3V8+sGlhqQTQ0bjBf/5b1tXuVPgPnZmf+aPYR5Vru +yvKySNZdEuLlC8wpIJeNh5nwZCKMZ0W0ad+fQm5lJtXgY9h2bAzaiOcOuubzq65X +GfVhMCZyid1JfrTkiefhb1W0hwoHiXzioKso/JnhH2dXzNDKj1wg/2JR82WXkCtt +jv4BsT112cEP9kHeDrer5yOKiQIzBBABCgAdFiEEkf/gcA6AYZzrcyNcqI4j43dR +TgAFAmOVn8MACgkQqI4j43dRTgAr8hAAxF+Rqia2CWqZHR287oN1k/VP0U8EulSP +rVWJB0nxW7fJdEm+CSaBzM+TH8kJ7TMZSH7MZgIVVFA8yhEZQgY6xsRAuESOr5A1 +pqVCjPNxc/a7t5UXXU78JD3mYZZEuL7U/vpC7GaJHfQ0Pzv0/77aqP3rdFDqGhtw +sHHleI5L4oJQnvXvwCL3Gg6L1C+0HJDmYzXDF0gJE8ebPV8Dr04tPMMHbx5PA3Lh +2HSdV5n7pfJWL9NBfc+Rl89eidvs4IRwjLQbSXbxzYFQd5C32/Nh7RcMLNefvedb +HR3YMBWXbPBi92RAC0r3N6Yd1CLiFeHUSTxXdAsAK4u0MCYXuYfqQBtwToGq5KxS +fklf/fzLcP77mQMBTcqbgyNFrdh0J/R4fWyZwUKPzkwhVjdmFbbcd21/P14c/TMJ +/B8FNU7YiikBKjjM4gxiLuKqxEGleZd7rWE51wbD613zqUONOVjliHamFml8VGWS +8J7QhM5TRxNUsptnScusaUgNKIuryZvWYQpR/w+uBKKViAPtsQabiKILg5CAScmA +g8+YJqT10dHkDnZQ8xB24m6OJxfykQgonkgKO6OJj3W3vrKPLoWQjrGhlGLIwTzz +Fc4TBug7b/uLavooeR3SaqaYB1gOlzpB9xYfUmZ67qOJm10+m7xRCwKX9P8PLXg0 +PXB4VhQODuCIdQQQFgoAHRYhBGnmRx464GUpdSmDLmug9aIDf09BBQJjjdwZAAoJ +EGug9aIDf09B3KYA/jJH/pskgWvVI3QpzEYWiQQxEIZstuUsI77UQDHFUPEpAQCy +UwcxLAqVWC2o1ZQtjm2Y0kXhGSdhwwzOBPsPj/BFCIh1BBAWCgAdFiEEKsCkLvsL +XLx6BALtTclbbXvpiS4FAmN+bJQACgkQTclbbXvpiS7TMAEAuxyrxDb4YaTevJYz +9N0pdHXds98n3xmLgWI2PX6jrH8BAI9fBKOqJaox1mEapwLo60tHmxQb3FcnB6WO +f4B9nhAJiHUEEBYKAB0WIQQ1cvoqGwZ/IsWK8VX4uCG0Km/c1wUCZTbTfgAKCRD4 +uCG0Km/c1zCxAP4uBlNopTnbWsqRvPRiwtTaJuOYFTMBD5wSJVb4gYss0gEAt1gt +OBFSfNizTqv/ZE9z7N/ZB9LlncNmEMmroP1EAQSJAjMEEAEKAB0WIQTYr92geltu +36fYzNrW0FX5J4Q/HAUCZYOAiwAKCRDW0FX5J4Q/HLSbD/9vpRMPo5HH1/I96mIk +SCqRK5REokhKuhdpfHoJouXYkruE9UI+6ZWRubcvIN2fcWAroE8Jl8N4QIgvAL08 +HRBuVQeF/du61Izm8ELfZlZBwLv7pS3LUr9uzNGGwuZUBHxAQjq3bjmyc/JU+9wR +WqvZtcXpVoFdAkIM2sUzjD1y+qmNxXi0AHR/zA7ZhkLuqrNq5AGqActhP+a44pb6 +1nZcUnnDDAGse//c4l6hhAxXxXz0sZt0G/xq/ZEbppPSrTjIZYs9ISbMnLY5BxM/ +C5M9d6wqzBtz+FA401I6P7zpqNJvOkGkPvVXCG6IAwrcMRySFl9/54AtHQwPZbT5 +nHGkJBz2/f6H8oJqD5qwxZTy/h5Yqs4+rS4DDeg1j1ECp7VqvmwM4A134IVHzkvC +5G9mp1VDFFa5st2LfNcdotviFDW+dH1r2h4L+ssnIMrRmoCfK4cr0kxKcpWj9OyO +Hwkf26Zv+dsffMuMeQpZJl4vAKRSrh82V6v3L/j4yQTOK9xykSjCUMJtEzkEYS1o +peJ0o1osQGIjtTuQcLZn3GSfDSNXgPhf1TF0tvg/65O8B8fjSMah9yyjHnapxeCw +YRgaf8FZVksAyZT7l/dhOLxeH4Vp7en9puvxKHiEF6YwawSUVuH1fk92hJLgnuVQ +cK6BL6FOCWiILkO3ct+UlXabvLgzBGNfkdMWCSsGAQQB2kcPAQEHQONJa7FWudVg +QhwmVEk+afnhF4Ea+o/4RgHYFXHlkU+/iH4EGBYIACYWIQQ+gMoai4n2nLpX2Yp2 +pe+QVESaXAUCY1+R0wIbIAUJHDIEgAAKCRB2pe+QVESaXMQbAQDC8O6JSfUyDDTH +v+bSFfO94ACAtV0lYP7T9iJ6nET0agD+MKA1xrYC5bKLjXoVhCQW2q2UiNZRvnqF +jlaUG+k1kg64OARjX5FXEgorBgEEAZdVAQUBAQdAiF7S3xQyk34bhzbgHJb9jW+7 +WbcLrYqy+VE/PD9HQA0DAQgHiH4EGBYIACYWIQQ+gMoai4n2nLpX2Yp2pe+QVESa +XAUCY1+RVwIbDAUJHDIEgAAKCRB2pe+QVESaXKdmAP4+WJsBOVqlXHPoSmsYx+eS +169SV9ZDBKFEn7D/HwjPIAD/Sc6+gTuPix2+DhChb+zac9hoPLwQr9cAxFPXl5Jx +ggc= +=xOvq +-----END PGP PUBLIC KEY BLOCK----- diff --git a/packer/files/archlinux/root/etc/systemd/system/hcloud-dl-metadata.service b/packer/files/archlinux/root/etc/systemd/system/hcloud-dl-metadata.service new file mode 100644 index 0000000..a13313e --- /dev/null +++ b/packer/files/archlinux/root/etc/systemd/system/hcloud-dl-metadata.service @@ -0,0 +1,14 @@ +[Unit] +Description=Download cloud-init & hetzner network metadata +Requires=network-online.target +After=network-online.target +ConditionPathExists=!/etc/hcloud-metadata.json + +[Service] +Type=oneshot +DynamicUser=yes +ExecStart=/usr/local/bin/hcloud-metadata +StandardOutput=truncate:/etc/hcloud-metadata.json + +[Install] +WantedBy=multi-user.target diff --git a/packer/files/archlinux/root/etc/systemd/system/hcloud-dl-userdata.service b/packer/files/archlinux/root/etc/systemd/system/hcloud-dl-userdata.service new file mode 100644 index 0000000..3181aa8 --- /dev/null +++ b/packer/files/archlinux/root/etc/systemd/system/hcloud-dl-userdata.service @@ -0,0 +1,14 @@ +[Unit] +Description=Download cloud-init userdata +Requires=network-online.target +After=network-online.target +ConditionPathExists=!/etc/hcloud-userdata + +[Service] +Type=oneshot +DynamicUser=yes +ExecStart=/usr/bin/curl --fail -s http://169.254.169.254/hetzner/v1/userdata +StandardOutput=truncate:/etc/hcloud-userdata + +[Install] +WantedBy=multi-user.target diff --git a/packer/files/archlinux/root/etc/systemd/system/hcloud-hostname.service b/packer/files/archlinux/root/etc/systemd/system/hcloud-hostname.service new file mode 100644 index 0000000..446176c --- /dev/null +++ b/packer/files/archlinux/root/etc/systemd/system/hcloud-hostname.service @@ -0,0 +1,11 @@ +[Unit] +Description=Import hcloud hostname +Requires=hcloud-dl-metadata.service +After=hcloud-dl-metadata.service + +[Service] +Type=oneshot +ExecStart=/bin/sh -c 'hostnamectl set-hostname $(jq -r .hostname /etc/hcloud-metadata.json)' + +[Install] +WantedBy=multi-user.target diff --git a/packer/files/archlinux/root/etc/systemd/system/hcloud-network.service b/packer/files/archlinux/root/etc/systemd/system/hcloud-network.service new file mode 100644 index 0000000..6955952 --- /dev/null +++ b/packer/files/archlinux/root/etc/systemd/system/hcloud-network.service @@ -0,0 +1,14 @@ +[Unit] +Description=Import hcloud network config +Requires=hcloud-dl-metadata.service +After=hcloud-dl-metadata.service +ConditionPathExists=/etc/systemd/network/default.network + +[Service] +Type=oneshot +DynamicUser=yes +ExecStart=/usr/local/bin/hcloud-network +StandardOutput=truncate:/etc/systemd/network/default.network + +[Install] +WantedBy=multi-user.target diff --git a/packer/files/archlinux/root/etc/systemd/system/hcloud-ssh-keys.service b/packer/files/archlinux/root/etc/systemd/system/hcloud-ssh-keys.service new file mode 100644 index 0000000..bace375 --- /dev/null +++ b/packer/files/archlinux/root/etc/systemd/system/hcloud-ssh-keys.service @@ -0,0 +1,14 @@ +[Unit] +Description=Import hcloud root ssh keys +Requires=hcloud-dl-metadata.service +After=hcloud-dl-metadata.service +ConditionPathExists=!/root/.ssh/authorized_keys + +[Service] +Type=oneshot +DynamicUser=yes +ExecStart=/usr/bin/jq -r '.ssh_keys|join("\n")' /etc/hcloud-metadata.json +StandardOutput=truncate:/root/.ssh/authorized_keys + +[Install] +WantedBy=multi-user.target diff --git a/packer/files/archlinux/root/usr/local/bin/hcloud-metadata b/packer/files/archlinux/root/usr/local/bin/hcloud-metadata new file mode 120000 index 0000000..6c46a85 --- /dev/null +++ b/packer/files/archlinux/root/usr/local/bin/hcloud-metadata @@ -0,0 +1 @@ +../../../../../hcloud-metadata \ No newline at end of file diff --git a/packer/files/archlinux/root/usr/local/bin/hcloud-network b/packer/files/archlinux/root/usr/local/bin/hcloud-network new file mode 100755 index 0000000..8ead56a --- /dev/null +++ b/packer/files/archlinux/root/usr/local/bin/hcloud-network @@ -0,0 +1,29 @@ +#!/bin/bash + +readonly f=/etc/hcloud-metadata.json + +cat <