diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..512dda8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.envrc +id_ed25519_rocky* +downloaded_iso_path/ diff --git a/configs/ks.cfg b/configs/ks.cfg new file mode 100644 index 0000000..1c3e825 --- /dev/null +++ b/configs/ks.cfg @@ -0,0 +1,23 @@ +#version=RHEL9 +text +skipx +zerombr +clearpart --all --initlabel +autopart --type=lvm +bootloader --location=mbr +timezone Europe/Berlin --utc +keyboard de +lang en_US.UTF-8 +rootpw --lock +user --name=rocky --groups=wheel --lock +sshkey --username=rocky "${ssh_public_key}" +%packages +@^minimal-environment +%end +%post +echo '%wheel ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/wheel-nopasswd +dnf install -y qemu-guest-agent curl +systemctl enable --now qemu-guest-agent +touch /var/log/kickstart_post.log +%end +reboot \ No newline at end of file diff --git a/pve-image.pkr.hcl b/pve-image.pkr.hcl new file mode 100644 index 0000000..5fee7d3 --- /dev/null +++ b/pve-image.pkr.hcl @@ -0,0 +1,115 @@ +packer { + required_plugins { + proxmox = { + version = ">=1.1.2" + source = "github.com/hashicorp/proxmox" + } + } +} + +source "proxmox-iso" "image" { + // PVE login + proxmox_url = var.pve_api_url + username = var.pve_username + token = var.pve_token + node = var.pve_node + insecure_skip_tls_verify = true + + // SSH + ssh_username = var.ssh_username + ssh_private_key_file = var.ssh_private_key_file + ssh_clear_authorized_keys = true + ssh_timeout = "20m" + + // ISO + boot_iso { + type = "scsi" + iso_url = "https://download.rockylinux.org/pub/rocky/9/isos/x86_64/Rocky-9-latest-x86_64-minimal.iso" + iso_checksum = "file:https://download.rockylinux.org/pub/rocky/9/isos/x86_64/Rocky-9-latest-x86_64-minimal.iso.CHECKSUM" + iso_download_pve = false + iso_storage_pool = "local" + unmount = true + } + + os = "l26" + template_description = "Packer generated template image on ${timestamp()}" + + // System + machine = "q35" + bios = "seabios" + qemu_agent = true + + // Disks + scsi_controller = "virtio-scsi-pci" + disks { + type = "scsi" + storage_pool = "local-lvm" + disk_size = "10G" + cache_mode = "writeback" + format = "raw" + io_thread = false + } + + // Cloud-init + cloud_init = true + cloud_init_storage_pool = "local-lvm" + + // CPU & Memory + sockets = 1 + cores = 2 + cpu_type = "host" + memory = 2048 + + // Network + network_adapters { + bridge = "vmbr0" + model = "virtio" + firewall = false + } +} + +build { + source "proxmox-iso.image" { + name = "rocky9" + template_name = "rocky9" + http_port_min = 8100 + http_port_max = 8100 + vm_id = 7000 + boot_wait = "10s" + boot_command = [ + "", + " inst.ks=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ks.cfg", + "" + ] + http_content = { + "/ks.cfg" = templatefile("configs/ks.cfg", { + ssh_public_key = chomp(file(var.ssh_public_key_file)) + }) + } + } + + provisioner "shell" { + execute_command = "sudo sh -c '{{ .Vars }} {{ .Path }}'" + inline = [ + "echo '==> Waiting for kickstart to finish...'", + "while [ ! -f /var/log/kickstart_post.log ]; do sleep 1; done", + "echo '==> Installing packages...'", + "dnf install -y curl", + "echo '==> Cleaning network and machine identifiers...'", + "truncate -s 0 /etc/machine-id", + "rm -f /etc/udev/rules.d/70-persistent-net.rules", + "echo '==> Cleaning SSH keys...'", + "rm -f /etc/ssh/ssh_host_*", + "truncate -s 0 /home/rocky/.ssh/authorized_keys", + "echo '==> Hardening SSH...'", + "sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config", + "sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config", + "sed -i 's/^#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config", + "sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config", + "echo '==> Purging caches and logs...'", + "dnf clean all", + "rm -rf /var/cache/dnf", + "find /var/log -type f -exec truncate -s 0 {} \\;" + ] + } +} \ No newline at end of file diff --git a/pve-vars.pkr.hcl b/pve-vars.pkr.hcl new file mode 100644 index 0000000..d7938fc --- /dev/null +++ b/pve-vars.pkr.hcl @@ -0,0 +1,42 @@ +variable "pve_api_url" { + description = "Proxmox API Endpoint" + type = string + sensitive = true + default = "https://prox-console.tail1ad20b.ts.net/api2/json" +} + +variable "pve_token" { + description = "Proxmox API Token" + type = string + sensitive = true +} + +variable "pve_username" { + description = "Proxmox API username, e.g. 'opentofu@pve!token'" + type = string + sensitive = true +} + +variable "pve_node" { + type = string + default = "pve" +} + +variable "ssh_username" { + description = "Image SSH username" + type = string + default = "rocky" +} + +variable "ssh_private_key_file" { + description = "Path to private SSH key" + type = string + sensitive = true + default = "./id_ed25519_rocky" +} + +variable "ssh_public_key_file" { + description = "Path to public SSH key" + type = string + default = "./id_ed25519_rocky.pub" +} \ No newline at end of file