initial commit
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Robert Kaussow 2022-09-08 15:01:32 +02:00
commit 78e049f6e0
Signed by: xoxys
GPG Key ID: 4E692A2EAECC03C0
19 changed files with 659 additions and 0 deletions

6
.dictionary Normal file
View File

@ -0,0 +1,6 @@
packer-hcloud
(P|p)roxmox
HashiCorp
ISOs
jktr
hcloud-packer-templates

42
.drone.yml Normal file
View File

@ -0,0 +1,42 @@
---
kind: pipeline
name: check
platform:
os: linux
arch: amd64
steps:
- name: whitespace
image: thegeeklab/alpine-tools
commands:
- git diff-tree --check $(git hash-object -t tree /dev/null) HEAD
- name: packer
image: hashicorp/packer
commands:
- packer fmt -recursive -check -diff .
- name: markdownlint
image: thegeeklab/markdownlint-cli
commands:
- markdownlint 'README.md'
- name: spellcheck
image: thegeeklab/alpine-tools
commands:
- spellchecker --files 'README.md' -d .dictionary -p spell indefinite-article syntax-urls --no-suggestions
environment:
FORCE_COLOR: true
trigger:
ref:
- refs/heads/main
- refs/tags/**
- refs/pull/**
---
kind: signature
hmac: c0676bb49df70f3e5aaa41597110a6124f0093a21e70c8bcb5e6a537a8295982
...

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.envrc

6
.markdownlint.yml Normal file
View File

@ -0,0 +1,6 @@
---
default: True
MD013: False
MD041: False
MD004:
style: dash

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Robert Kaussow <mail@thegeeklab.de>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

44
README.md Normal file
View File

@ -0,0 +1,44 @@
# packer-hcloud
[![Build Status](https://img.shields.io/drone/build/infra/packer-hcloud?logo=drone&server=https%3A%2F%2Fdrone.rknet.org)](https://drone.rknet.org/infra/packer-hcloud)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?label=license)](LICENSE)
This repository provides infrastructure-as-code examples to automate the creation of virtual machine images on Hetzner Cloud using [HashiCorp Packer](https://www.packer.io) and the [Packer Plugin for Hetzner Cloud](https://www.packer.io/plugins/builders/hetzner-cloud). All examples are written in the HashiCorp Configuration Language `HCL2`.
This project is inspired by [jktr/hcloud-packer-templates](https://github.com/jktr/hcloud-packer-templates).
## Requirements
**Packer**:
- HashiCorp [Packer](https://www.packer.io/intro/getting-started/install.html) v1.7.7 or higher.
- HashiCorp [Packer Plugin for Hetzner Cloud](https://www.packer.io/plugins/builders/hetzner-cloud) (`hcloud`) v1.0.5 or higher.
Required plugins are automatically downloaded during the `packer init` phase. These plugins are placed in the same directory as your Packer executable `/usr/local/bin` or `$HOME/.packer.d/plugins`.
## Configuration
### Download the release
Download the **latest** release.
### Configure the Variables
All available [variables](https://www.packer.io/docs/templates/hcl_templates/variables) are defined in the `variables.pkr.hcl` files. They can be overwritten using environment variables or in the `server.auto.pkrvars.hcl` file.
### Modify the Configurations and Scripts (Optional)
If required, modify the configuration and scripts files.
## Build
Initialize packer and start a build.
```Shell
packer init rocky-9/
packer build rocky-9/
```
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

4
renovate.json Normal file
View File

@ -0,0 +1,4 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["github>thegeeklab/renovate-presets:default"]
}

View File

@ -0,0 +1,69 @@
users:
- default
disable_root: 0
ssh_pwauth: 0
mount_default_fields: [~, ~, 'auto', 'defaults,nofail,x-systemd.requires=cloud-init.service', '0', '2']
resize_rootfs_tmp: /dev
ssh_deletekeys: 1
ssh_genkeytypes: ['rsa', 'ecdsa', 'ed25519']
syslog_fix_perms: ~
disable_vmware_customization: false
cloud_init_modules:
- disk_setup
- migrator
- bootcmd
- write-files
- [ growpart, always ]
- [ resizefs, always ]
- set_hostname
- update_hostname
- [ update_etc_hosts, once-per-instance ]
- rsyslog
- users-groups
- ssh
cloud_config_modules:
- mounts
- locale
- set-passwords
- rh_subscription
- yum-add-repo
- package-update-upgrade-install
- timezone
- puppet
- chef
- salt-minion
- mcollective
- disable-ec2-metadata
- runcmd
cloud_final_modules:
- rightscale_userdata
- scripts-per-once
- scripts-per-boot
- scripts-per-instance
- scripts-user
- ssh-authkey-fingerprints
- keys-to-console
- phone-home
- final-message
- power-state-change
system_info:
default_user:
name: cloud-user
lock_passwd: true
gecos: Cloud User
groups: [adm, systemd-journal]
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
shell: /bin/bash
distro: rhel
paths:
cloud_dir: /var/lib/cloud
templates_dir: /etc/cloud/templates
ssh_svcname: sshd
# vim:syntax=yaml

View File

@ -0,0 +1 @@
datasource_list: [ Hetzner, None ]

View File

@ -0,0 +1,9 @@
disable_root: 0
ssh_pwauth: 1
# Set the distro defaults
system_info:
default_user:
name: root
shell: /bin/bash
lock_passwd: false

View File

@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -eo pipefail
case "$1" in
keys)
if [ ! -f /root/.ssh/authorized_keys ]; then
curl -SsfL http://169.254.169.254/hetzner/v1/metadata/public-keys | /usr/bin/jq -r '.[]' >/root/.ssh/authorized_keys
fi
;;
*)
echo "Invalid command"
exit 3
;;
esac

View File

@ -0,0 +1,12 @@
[Unit]
Description=Import hcloud root ssh keys
Requires=network-online.target
After=network-online.target
ConditionPathExists=!/root/.ssh/authorized_keys
[Service]
Type=oneshot
ExecStart=/usr/local/bin/hcloud-metadata keys
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,167 @@
### Install from network
### Configure network information for target system and activate network devices in the installer environment (optional)
### --onboot enable device at a boot time
### --device device to be activated and / or configured with the network command
### --bootproto method to obtain networking configuration for device (default dhcp)
### --noipv6 disable IPv6 on this device
###
### network --bootproto=static --ip=172.16.11.200 --netmask=255.255.255.0 --gateway=172.16.11.200 --nameserver=172.16.11.4 --hostname centos-linux-8
network --bootproto=dhcp --device=link --activate --onboot=on
### Use the Hetzner mirror for fast installations
url --url="${hcloud_mirror}/BaseOS/x86_64/os/"
repo --name="AppStream" --baseurl="${hcloud_mirror}/AppStream/x86_64/os/"
### Performs the kickstart installation in text mode.
### By default, kickstart installations are performed in graphical mode.
text
### Accepts the End User License Agreement.
eula --agreed
### Sets the language to use during installation and the default language to use on the installed system.
lang ${vm_guest_os_language}
### Sets the default keyboard type for the system.
keyboard ${vm_guest_os_keyboard}
### Set initial root password
rootpw --iscrypted ${build_password_encrypted}
### Configure firewall settings for the system.
### --enabled reject incoming connections that are not in response to outbound requests
### --ssh allow sshd service through the firewall
firewall --enabled --ssh
### Sets up the authentication options for the system.
### The SSDD profile sets sha512 to hash passwords. Passwords are shadowed by default
### See the manual page for authselect-profile for a complete list of possible options.
authselect select sssd
### Sets the state of SELinux on the installed system.
### Defaults to enforcing.
selinux --enforcing
### Sets the system time zone.
timezone ${vm_guest_os_timezone} --utc
### Sets how the boot loader should be installed.
bootloader --location=mbr
### Initialize any invalid partition tables found on disks.
zerombr
### Removes partitions from the system, prior to creation of new partitions.
### By default, no partitions are removed.
### --linux erases all Linux partitions.
### --initlabel Initializes a disk (or disks) by creating a default disk label for all disks in their respective architecture.
clearpart --all --initlabel
### Modify partition sizes for the virtual machine hardware.
### Create primary system partitions.
part /boot --fstype xfs --size=512 --label=BOOTFS
part /boot/efi --fstype vfat --size=512 --label=EFIFS
part pv.01 --size=19 --grow
### Create a logical volume management (LVM) group.
volgroup vg00 --pesize=4096 pv.01
### Modify logical volume sizes for the virtual machine hardware.
### Create logical volumes.
logvol swap --fstype swap --name=lv_swap --vgname=vg00 --size=2048 --label=SWAPFS
logvol / --fstype xfs --name=lv_root --vgname=vg00 --size=6000 --label=ROOTFS
logvol /home --fstype xfs --name=lv_home --vgname=vg00 --size=3000 --label=HOMEFS
logvol /opt --fstype xfs --name=lv_opt --vgname=vg00 --size=1000 --label=OPTFS
logvol /tmp --fstype xfs --name=lv_tmp --vgname=vg00 --size=512 --label=TMPFS --fsoptions="nosuid,noexec,nodev"
logvol /var --fstype xfs --name=lv_var --vgname=vg00 --size=2000 --label=VARFS --fsoptions="nosuid"
logvol /var/tmp --fstype xfs --name=lv_vartmp --vgname=vg00 --size=512 --label=LOGFS --fsoptions="nosuid,noexec,nodev"
logvol /var/www --fstype xfs --name=lv_www --vgname=vg00 --size=1000 --label=LOGFS --fsoptions="nosuid,noexec,nodev"
logvol /var/log --fstype xfs --name=lv_log --vgname=vg00 --size=1000 --label=LOGFS --fsoptions="nosuid,noexec,nodev"
logvol /var/log/audit --fstype xfs --name=lv_audit --vgname=vg00 --size=512 --label=AUDITFS --fsoptions="nosuid,noexec,nodev"
### Modifies the default set of services that will run under the default runlevel.
services --enabled=NetworkManager,sshd
### Do not configure X on the installed system.
skipx
### Disable firstboot.
firstboot --disable
### Packages selection.
%packages
@^minimal-environment
kexec-tools
openssh-server
openssh-clients
sudo
curl
python3
python3-libselinux
jq
-aic94xx-firmware
-atmel-firmware
-b43-openfwwf
-bfa-firmware
-ipw2100-firmware
-ipw2200-firmware
-ivtv-firmware
-iwl100-firmware
-iwl1000-firmware
-iwl3945-firmware
-iwl4965-firmware
-iwl5000-firmware
-iwl5150-firmware
-iwl6000-firmware
-iwl6000g2a-firmware
-iwl6050-firmware
-libertas-usb8388-firmware
-ql2100-firmware
-ql2200-firmware
-ql23xx-firmware
-ql2400-firmware
-ql2500-firmware
-rt61pci-firmware
-rt73usb-firmware
-xorg-x11-drv-ati-firmware
-zd1211-firmware
%end
### Post-installation commands.
%post
dnf makecache
dnf install -y epel-release
dnf makecache
dnf install -y cloud-init
dnf clean all
touch /etc/cloud/cloud-init.disabled
cat >/etc/cloud/cloud.cfg.d/90-hetznercloud.cfg <<EOF
${files_hetznercloud_default_init}
EOF
cat >/etc/cloud/cloud.cfg.d/92-hetznercloud-ds.cfg <<EOF
${files_hetznercloud_ds_init}
EOF
cat >/etc/cloud/cloud.cfg.d/93-hetznercloud.cfg <<EOF
${files_hetznercloud_init}
EOF
echo "Completed cloud-init step!"
cat >/usr/local/bin/hcloud-metadata <<\EOF
${files_hcloud_metadata}
EOF
chmod 700 /usr/local/bin/hcloud-metadata
mkdir /root/.ssh/
chmod 700 /root/.ssh/
cat >/etc/systemd/system/hcloud-ssh-keys.service <<EOF
${files_hcloud_ssh_keys_service}
EOF
systemctl enable hcloud-ssh-keys.service
%end
### Reboot after the installation is complete.
### --eject attempt to eject the media before rebooting.
reboot --eject

View File

@ -0,0 +1,11 @@
// Hetzner Cloud Settings
hcloud_snapshot_description = "Rocky Linux 9"
hcloud_snapshot_name = "rocky-9-cloud"
hcloud_location = "fsn1"
// Virtual Machine Settings
vm_guest_os_keyboard = "de(nodeadkeys)"
vm_guest_os_timezone = "Europe/Berlin"
// Provisioner Settings
build_scripts = ["scripts/10-prepare-kickstart.sh", "scripts/20-rocky-9.sh"]

74
rocky-9/server.pkr.hcl Normal file
View File

@ -0,0 +1,74 @@
packer {
required_version = ">= 1.8.3"
required_plugins {
hcloud = {
version = ">= 1.0.0"
source = "github.com/hashicorp/hcloud"
}
}
}
locals {
data_source_content = templatefile("${abspath(path.root)}/data/init.ks.pkrtpl.hcl", {
build_password_encrypted = var.build_password_encrypted
vm_guest_os_language = var.vm_guest_os_language
vm_guest_os_keyboard = var.vm_guest_os_keyboard
vm_guest_os_timezone = var.vm_guest_os_timezone
hcloud_mirror = var.hcloud_mirror
files_hcloud_metadata = file("${abspath(path.root)}/data/files/hcloud-metadata")
files_hcloud_ssh_keys_service = file("${abspath(path.root)}/data/files/hcloud-ssh-keys.service")
files_hetznercloud_default_init = file("${abspath(path.root)}/data/files/90-hetznercloud.cfg")
files_hetznercloud_ds_init = file("${abspath(path.root)}/data/files/92-hetznercloud-ds.cfg")
files_hetznercloud_init = file("${abspath(path.root)}/data/files/93-hetznercloud.cfg")
})
build_id = "${uuidv4()}"
build_labels = {
"os" = "rockylinux"
"os/release" = "9"
"packer.io/build.time" = "{{ timestamp }}"
"packer.io/build.id" = "${local.build_id}"
"packer.io/version" = "{{ packer_version }}"
}
}
source "hcloud" "rocky-linux-9" {
// Hetzner Cloud Settings
image = "rocky-9"
rescue = "linux64"
token = "${var.hcloud_token}"
// Virtual Machine Settings
location = "${var.hcloud_location}"
server_type = "${var.hcloud_server_type}"
server_name = "${var.hcloud_server_name}"
// Communicator Settings and Credentials
ssh_username = "root"
temporary_key_pair_type = "ed25519"
snapshot_name = "${var.hcloud_snapshot_name}-{{ timestamp }}"
snapshot_labels = local.build_labels
}
build {
sources = ["source.hcloud.rocky-linux-9"]
provisioner "file" {
destination = "/root/ks.cfg"
content = "${local.data_source_content}"
}
provisioner "file" {
destination = "/root/prepare-kickstart.sh"
content = "${local.data_source_content}"
}
provisioner "shell" {
scripts = formatlist("${path.cwd}/%s", var.build_scripts)
remote_folder = "/root"
start_retry_timeout = "15m"
expect_disconnect = true
environment_vars = [
"BUILD_MIRROR=${var.hcloud_mirror}",
]
}
}

68
rocky-9/variables.pkr.hcl Normal file
View File

@ -0,0 +1,68 @@
// Hetzner Cloud Settings
variable "hcloud_mirror" {
type = string
default = "https://mirror.hetzner.com/rockylinux/9"
}
variable "hcloud_token" {
type = string
sensitive = true
}
variable "hcloud_snapshot_description" {
type = string
default = "Rocky Linux 9"
}
variable "hcloud_snapshot_name" {
type = string
default = "rocky-9-cloud"
}
variable "hcloud_location" {
type = string
default = "hel1"
}
variable "hcloud_server_type" {
type = string
default = "cx11"
}
variable "hcloud_server_name" {
type = string
default = "rocky-9-packer"
}
// Virtual Machine Settings
variable "vm_guest_os_language" {
type = string
description = "The guest operating system lanugage."
default = "en_US"
}
variable "vm_guest_os_keyboard" {
type = string
description = "The guest operating system keyboard input."
default = "us"
}
variable "vm_guest_os_timezone" {
type = string
description = "The guest operating system timezone."
default = "America/New_York"
}
// Communicator Settings and Credentials
variable "build_password_encrypted" {
type = string
description = "The encrypted password to login the guest operating system."
sensitive = true
}
// Provisioner Settings
variable "build_scripts" {
type = list(string)
description = "A list of scripts and their relative paths to transfer and execute."
default = []
}

View File

@ -0,0 +1,35 @@
#!/usr/bin/env bash
set -e
### Install requirements
export DEBIAN_FRONTEND=noninteractive
apt-get -qq update && apt-get -qq -y install grub-pc
### Wipe all partitions on the existing disk
wipefs -q --all --force /dev/sda
### Create and partition to allow kickstarts
parted -s /dev/sda mklabel msdos
parted -s /dev/sda mkpart primary 4M 200M
mkfs.ext4 -q -L OEMDRV /dev/sda1
mount /dev/sda1 /boot
### Download kernel and installer initrd to kickstart partition
curl -SsfL -o /boot/vmlinuz "$BUILD_MIRROR/BaseOS/x86_64/os/isolinux/vmlinuz"
curl -SsfL -o /boot/initrd.img "$BUILD_MIRROR/BaseOS/x86_64/os/isolinux/initrd.img"
### Install and configure Grub to load the installer initrd
grub-install --no-floppy /dev/sda
cat >/boot/grub/grub.cfg <<EOF
set default=0
set timeout=5
menuentry "Kickstart Rocky Linux" {
set root=(hd0,1)
linux /vmlinuz ip=dhcp
initrd /initrd.img
}
EOF
mv /root/ks.cfg /boot/ks.cfg
shutdown -r now

61
scripts/20-rocky-9.sh Normal file
View File

@ -0,0 +1,61 @@
#!/bin/bash
set -eo pipefail
#### Update system
echo '> Update packages ...'
dnf -yq update
dnf -q clean all
### Cleans all audit logs
echo '> Cleaning all audit logs ...'
if [ -f /var/log/audit/audit.log ]; then
cat /dev/null >/var/log/audit/audit.log
fi
if [ -f /var/log/wtmp ]; then
cat /dev/null >/var/log/wtmp
fi
if [ -f /var/log/lastlog ]; then
cat /dev/null >/var/log/lastlog
fi
### Cleans persistent udev rules
echo '> Cleaning persistent udev rules ...'
if [ -f /etc/udev/rules.d/70-persistent-net.rules ]; then
rm /etc/udev/rules.d/70-persistent-net.rules
fi
### Clean the /tmp directories
echo '> Cleaning /tmp directories ...'
rm -rf /tmp/*
rm -rf /var/tmp/*
rm -rf /var/cache/dnf/*
### Clean the SSH keys
echo '> Cleaning the SSH keys ...'
shred -u /etc/ssh/*_key /etc/ssh/*_key.pub
rm -f /etc/ssh/ssh_config.d/allow-root-ssh.conf
rm -rf /root/.ssh/authorized_keys
### Clean the machine-id
echo '> Cleaning the machine-id ...'
truncate -s 0 /etc/machine-id
rm -f /var/lib/dbus/machine-id
mkdir -p /var/lib/dbus
ln -s /etc/machine-id /var/lib/dbus/machine-id
### Prepare cloud-init
echo '> Preparing cloud-init ...'
rm -f /etc/cloud/cloud-init.disabled
### Clean the shell history
echo '> Cleaning the shell history ...'
unset HISTFILE
history -cw
echo >~/.bash_history
rm -f /root/.bash_history
### Done
echo '> Done.'

14
test.sh Normal file
View File

@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -eo pipefail
case "$1" in
keys)
if [ ! -f /root/.ssh/authorized_keys ]; then
curl -SsfL http://169.254.169.254/hetzner/v1/metadata/public-keys | /usr/bin/jq -r '.[]' >/root/.ssh/authorized_keys
fi
;;
*)
echo "Invalid command"
exit 3
;;
esac