hashipi

Raspberry Pi Test Cluster for HashiCorp Vault, Nomad and Consul
git clone https://git.in0rdr.ch/hashipi.git
Log | Files | Refs | Pull requests |Archive | README

commit cc2525a002adc4ee82626b09969aef4d354ab2ed
parent 80067c1f048292528a018bcee230fc8b5ac4a69b
Author: Andreas Gruhler <agruhl@gmx.ch>
Date:   Sun, 12 Jan 2025 11:49:05 +0100

feat: qemu emulator on NixOS and Intel node

Diffstat:
MREADME.md | 83++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mbootstrap.sh | 23++++++++++++++++-------
Aconfig/preseed.cfg | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mhashi-pi.pkr.hcl | 60+++++++++++++++++++++++++++++++++++++++++++++++-------------
Ahosts/intel0.pkrvars.hcl | 4++++
Dimg/HashiPi-small.jpg | 0
6 files changed, 209 insertions(+), 55 deletions(-)

diff --git a/README.md b/README.md @@ -1,8 +1,5 @@ # HashiPi - -A RaspberryPi test cluster for HashiCorp Nomad and OpenBao. - -![HashiPi](./img/HashiPi-small.jpg) +A test cluster for HashiCorp Nomad and OpenBao. ## Client-Server Architecture The cluster can be built with 3 or 5 nodes. @@ -12,13 +9,13 @@ the Raft traffic minimal. Example architecture with 5 RaspberyPi nodes: -| Node | RAM | Nomad function | Bao function | -|------|-----|----------------|--------------| -| 00 | 4GB | client/server | server | -| 01 | 4GB | client | n/a | -| 02 | 4GB | client/server | server | -| 03 | 4GB | client | n/a | -| 04 | 4GB | client/server | server | +| Node | Arch | RAM | Nomad function | Bao function | +| ---- | ----- |-----|----------------|--------------| +| 00 | arm64 | 4GB | client/server | server | +| 01 | arm64 | 4GB | client | n/a | +| 02 | arm64 | 4GB | client/server | server | +| 03 | arm64 | 4GB | client | n/a | +| 04 | arm64 | 4GB | client/server | server | For best [performance on low power devices](https://developer.hashicorp.com/consul/docs/install/performance), the @@ -38,20 +35,21 @@ heartbeat_grace = "30s" min_heartbeat_ttl = "30s" ``` -## ARM Builder -These Packer files use the [Packer builder for -ARM](https://github.com/mkaczanowski/packer-builder-arm). Follow the -instructions in the repo to setup the builder and use the provided -[examples](https://github.com/mkaczanowski/packer-builder-arm/tree/master/boards) -to modify to your liking. +## Packer Builders +These Packer files use the following builders: +* [Packer builder for ARM (plugin + "cross")](https://github.com/michalfita/packer-plugin-cross) +* [QEMU](https://developer.hashicorp.com/packer/integrations/hashicorp/qemu) + builder -## Supported Architectures +The packer builder "cross" requires `qemu-img`. -ARM >= ARMv7 +## Supported Architectures +* ARM >= ARMv7 +* AMD64 ## Self-signed TLS Certificates ### OpenBao - To create a new self-signed CA certificate for Bao: ```bash # create bao self-signed CA certificate in ./tls/vault/ @@ -109,7 +107,6 @@ tbd * ACLs for Nomad ## Nomad workload identity configuration - Follow along the tutorial to configure Nomad workload identities with Bao: * https://developer.hashicorp.com/nomad/tutorials/integrate-vault/vault-acl @@ -151,21 +148,10 @@ path "kv/+/{{identity.entity.aliases.AUTH_METHOD_ACCESSOR.metadata.nomad_job_id} $ bao policy write nomad-workloads vault-policy-nomad-workloads.hcl ``` - ## Authorized Keys Copy the contents of an openssh pubkey to `authorized_keys` Packer variable. -## Run Packer -Build [`packer-builder-arm` -plugin](https://github.com/mkaczanowski/packer-builder-arm) according to -projects instructions and move it to the working directory: -```bash -git clone git@github.com:mkaczanowski/packer-builder-arm.git arm-builder -cd arm-builder -go build -cp packer-builder-arm .. && cd - -``` - +## Statically linked QEMU emulator Install the statically linked qemu (emulator) binary. On Debian/Ubuntu: ```bash sudo apt-get install qemu-user-static @@ -208,15 +194,42 @@ interpreter /usr/bin/qemu-aarch64-static ... ``` +## QEMU emulator on NixOS +On NixOS, it is sufficient to [enable the binfmt wrapper in the +configuration](https://wiki.nixos.org/wiki/NixOS_on_ARM/Building_Images): +``` +boot.binfmt.emulatedSystems = [ "aarch64-linux" ]; +``` + +The wrapper on NixOS can be checked on this path: +```bash +cat /proc/sys/fs/binfmt_misc/aarch64-linux +``` + +On NixOS, the interpreter is on this path (`hashi-pi.pkr.hcl`): +```bash + "qemu_binary_source_path": "/run/binfmt/aarch64-linux", + "qemu_binary_destination_path": "/run/binfmt/aarch64-linux" +``` + +## Run Packer +Initialize required packer plugins: +```bash +sudo packer init . +``` + Run packer with a value file to build an image for one host: ```bash -sudo /usr/bin/packer build -var-file=variables.auto.pkrvars.hcl -var-file=hosts/pi0.pkrvars.hcl hashi-pi.pkr.hcl +sudo packer build \ + -only cross.hashipi \ # change to qemu.hashiintel to build amd images + -var-file=variables.auto.pkrvars.hcl \ + -var-file=hosts/pi0.pkrvars.hcl \ + hashi-pi.pkr.hcl ``` The `variable.auto.pkrvars.hcl` contains all sensitive packer variables. ## Write Image to SD Card - To [write the resulting image file to the sd card](https://www.raspberrypi.org/documentation/installation/installing-images/linux.md) with `dd`: diff --git a/bootstrap.sh b/bootstrap.sh @@ -19,12 +19,6 @@ ff02::2 ip6-allrouters 127.0.1.1 $HOSTNAME EOF -# Install script to resize fs -mv /tmp/resizerootfs.service /etc/systemd/system/ -chmod +x /tmp/resizerootfs -mv /tmp/resizerootfs /usr/sbin/ -systemctl enable resizerootfs.service - # Add HashiCorp repository wget -O- https://apt.releases.hashicorp.com/gpg \ | gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg @@ -33,7 +27,7 @@ echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https:// # Install packages apt-get update -DEBIAN_FRONTEND=noninteractive apt-get install -y jq podman cloud-init \ +DEBIAN_FRONTEND=noninteractive apt-get install -y jq podman cloud-init curl \ "nomad=${NOMAD_VERSION}-1" curl -L -o openbao.deb "https://github.com/openbao/openbao/releases/download/v${BAO_VERSION}/bao_${BAO_VERSION}_linux_arm64.deb" @@ -76,3 +70,18 @@ EOF chown -R $USERNAME "/home/${USERNAME}/.ssh" chmod 700 "/home/${USERNAME}/.ssh" chmod 600 "/home/${USERNAME}/.ssh/authorized_keys" + +# Add cloud-init configuration for first boot +# https://cloudinit.readthedocs.io/en/latest/reference/yaml_examples/disk_setup.html +cat << EOF > /etc/cloud/cloud.cfg.d/99_hashipi_cloudinit.cfg +#cloud-config + +# Growpart is enabled by default on the root partition +#growpart: +# mode: auto +# devices: [\"/\"] +# ignore_growroot_disabled: false + +# Resize filesystem to use all available space on partition +resize_rootfs: noblock +EOF diff --git a/config/preseed.cfg b/config/preseed.cfg @@ -0,0 +1,94 @@ +# Preseeding only locale sets language, country and locale. +d-i debian-installer/locale string en_US + +# Keyboard selection. +d-i console-setup/ask_detect boolean false +d-i keyboard-configuration/xkb-keymap select us + +# Set the network interface +d-i netcfg/choose_interface select enp0s2 + +### Clock and time zone setup +d-i clock-setup/utc boolean true +d-i time/zone string UTC + +# Avoid that last message about the install being complete. +d-i finish-install/reboot_in_progress note + +# This is fairly safe to set, it makes grub install automatically to the MBR +# if no other operating system is detected on the machine. +d-i grub-installer/only_debian boolean true +# To install to the first device (assuming it is not a USB stick): +d-i grub-installer/bootdev string default + +### Mirror settings +# If you select ftp, the mirror/country string does not need to be set. +#d-i mirror/protocol string ftp +d-i mirror/country string manual +d-i mirror/http/hostname string debian.ethz.ch +d-i mirror/http/directory string /debian +d-i mirror/http/proxy string + +### Apt setup +# Select which update services to use; define the mirrors to be used. +# Values shown below are the normal defaults. +d-i apt-setup/services-select multiselect security, updates +d-i apt-setup/security_host string security.debian.org + +# Do not prompt for scanning of additional CDs +apt-cdrom-setup apt-setup/cdrom/set-first boolean false +apt-cdrom-setup apt-setup/cdrom/set-next boolean false +apt-cdrom-setup apt-setup/cdrom/set-failed boolean false +apt-cdrom-setup apt-setup/cdrom/set-double boolean false + +# Don't report statistics +popularity-contest popularity-contest/participate boolean false + +### Partitioning +d-i partman-auto/method string lvm + +# This makes partman automatically partition without confirmation. +d-i partman-partitioning/confirm_write_new_label boolean true +d-i partman/choose_partition select finish +d-i partman/confirm boolean true +d-i partman/confirm_nooverwrite boolean true + +# Choose atomic partitioning recipes (all files in one partition) +d-i partman-auto/choose_recipe select atomic +# Use max space available for the new LVM volume +d-i partman-auto-lvm/guided_size string max + +# Confirmation to write the lvm partitions +d-i partman-lvm/confirm boolean true +d-i partman-lvm/confirm_nooverwrite boolean true + +# Disable root account +d-i passwd/root-login boolean true +d-i passwd/root-password-crypted password !disabled +d-i passwd/make-user boolean true + +### Account setup +d-i passwd/username string in0rdr +d-i passwd/user-fullname string in0rdr +d-i passwd/user-uid string 1000 +d-i passwd/user-default-groups string sudo +d-i passwd/user-password-crypted password !disabled +#d-i passwd/user-password password pi +#d-i passwd/user-password-again password pi + +# The installer will warn about weak passwords. If you are sure you know +# what you're doing and want to override it, uncomment this. +d-i user-setup/allow-password-weak boolean true +d-i user-setup/encrypt-home boolean false + +### Package selection +tasksel tasksel/first multiselect standard, ssh-server +d-i pkgsel/include string openssh-server build-essential sudo +d-i pkgsel/upgrade select full-upgrade + +# allow ssh root login +#d-i preseed/late_command string \ +# in-target sed -i 's/^.*PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config +d-i preseed/late_command string \ + in-target sh -c 'mkdir -p /home/in0rdr/.ssh'; \ + in-target sh -c 'echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC2SnNAxEnre9hcPD74wNAouuXMgfIzwsB7qr88xSb8WS8CKqZGXzaQgebc0YExfV7PGyV6KUfu4KUvS1xDboRbU6ZLU4HdGlAi+hdv8dVVzdzCgFmdv5BEGam0SMhlzReWRiDvae0pObAPvAFg5ab6B/t1LjOosBOpPo2JfEkR6zfjDrMCYdEjWB5To1p5AX0BJneTiIeiEqR/05mZUk5L8hMFmwvm8QThd+SzpLY3zgWlWG7TlUQwx78xvell9KC0GChhwlkeEAwE3q1tq/LbgzvtY140Fg0bbBGcYQI4UvG85xfTfpbHeQ1RkSB8Rb8pMkaN7mT+3qhe08cHT9v3" > /home/in0rdr/.ssh/authorized_keys'; diff --git a/hashi-pi.pkr.hcl b/hashi-pi.pkr.hcl @@ -1,3 +1,8 @@ +variable "manifest" { + type = string + default = "manifest.json" +} + variable "authorized_keys" { type = string default = "" @@ -134,7 +139,20 @@ variable "bao_version" { default = "2.0.0-beta20240618" } -source "arm" "hashipi" { +packer { + required_plugins { + qemu = { + version = ">= 1.1.0" + source = "github.com/hashicorp/qemu" + } + cross = { + version = ">= 1.1.3" + source = "github.com/michalfita/cross" + } + } +} + +source "cross" "hashipi" { file_checksum_type = "sha256" file_checksum_url = "${var.img_url}.sha256" file_target_extension = "xz" @@ -165,18 +183,29 @@ source "arm" "hashipi" { qemu_binary_source_path = "/usr/bin/qemu-aarch64-static" } -build { - sources = ["source.arm.hashipi"] - - provisioner "file" { - destination = "/tmp/resizerootfs" - source = "arm-builder/scripts/resizerootfs/resizerootfs" - } +source "qemu" "hashiintel" { + accelerator = "kvm" + boot_command = ["<esc><wait>", "install <wait>", " preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg <wait>", "debian-installer=en_US.UTF-8 <wait>", "auto <wait>", "locale=en_US.UTF-8 <wait>", "kbd-chooser/method=us <wait>", "keyboard-configuration/xkb-keymap=us <wait>", "netcfg/get_hostname={{ .Name }} <wait>", "netcfg/get_domain=libvirt <wait>", "fb=false <wait>", "debconf/frontend=noninteractive <wait>", "console-setup/ask_detect=false <wait>", "console-keymaps-at/keymap=us <wait>", "grub-installer/bootdev=/dev/sda <wait>", "<enter><wait>"] + boot_wait = "5s" + disk_interface = "virtio" + disk_size = "14000" + format = "qcow2" + # headless = true + http_directory = "config" + iso_checksum = "file:http://pkg.adfinis-on-exoscale.ch/debian/dists/Debian12.8/main/installer-amd64/20230607%2Bdeb12u8/images/MD5SUMS" + iso_url = "http://pkg.adfinis-on-exoscale.ch/debian/dists/Debian12.8/main/installer-amd64/20230607%2Bdeb12u8/images/netboot/mini.iso" + memory = "1024" + net_device = "virtio-net" + output_directory = "${var.hostname}" + shutdown_command = "echo 'debian' | sudo -S shutdown -P now" + ssh_timeout = "15m" + ssh_username = "in0rdr" + ssh_private_key_file = "/home/andi/.ssh/id_rsa" + vm_name = "${var.hostname}.qcow2" +} - provisioner "file" { - destination = "/tmp/resizerootfs.service" - source = "arm-builder/scripts/resizerootfs/resizerootfs.service" - } +build { + sources = ["source.cross.hashipi", "source.qemu.hashiintel"] provisioner "shell" { script = "bootstrap.sh" @@ -236,7 +265,7 @@ build { } provisioner "shell" { - script = "openbao.sh" + script = "openbao.sh" remote_folder = "/home/${var.username}" environment_vars = [ "USERNAME=${var.username}", @@ -249,4 +278,9 @@ build { "VAULT_TRANSIT_TOKEN=${var.vault_transit_token}" ] } + + post-processor "manifest" { + output = "${var.manifest}" + strip_path = true + } } diff --git a/hosts/intel0.pkrvars.hcl b/hosts/intel0.pkrvars.hcl @@ -0,0 +1,4 @@ +hostname = "intel0" +img_name = "HashiIntel0.img" +nomad_server = true +nomad_client = true diff --git a/img/HashiPi-small.jpg b/img/HashiPi-small.jpg Binary files differ.