Basic Linux server hardening (Packer Templates)

Basic Linux server hardening (Packer Templates)
Photo by Lukas / Unsplash
# Ubuntu Server Noble (24.04.x)
# ---
# Packer Template to create an Ubuntu Server (Noble 24.04.x) on Proxmox

# Variable Definitions
variable "proxmox_api_url" {
    type = string
}

variable "proxmox_api_token_id" {
    type = string
}

variable "proxmox_api_token_secret" {
    type = string
    sensitive = true
}

variable "vm_id" {
    type = number
}

variable "vm_template_name" {
    type    = string
}

variable "username" {
    type    = string
}

variable "ssh_key_path" {
    type    = string
}

# Resource Definition for the VM Template
source "proxmox-iso" "ubuntu-noble-secure" {
    # Proxmox Connection Settings
    proxmox_url = var.proxmox_api_url
    username = var.proxmox_api_token_id
    token = var.proxmox_api_token_secret
    # (Optional) Skip TLS Verification
    insecure_skip_tls_verify = true
    
    # VM General Settings
    # Need to replace the hardcoded node name with a variable
    node = "js-8"
    vm_id = var.vm_id
    vm_name = var.vm_template_name
    template_description = "Ubuntu Server Noble Image"

    # VM OS Settings
    # Need to replace the hardcoded template name with a variable
    boot_iso {
        iso_file = "local:iso/ubuntu-24.04.2-live-server-amd64.iso"
        unmount = true
    }
    
    # VM System Settings
    qemu_agent = true

    # VM Hard Disk Settings
    scsi_controller = "virtio-scsi-pci"

    disks {
        disk_size = "20G"
        format = "raw"
        storage_pool = "local-lvm"
        type = "virtio"
    }

    # VM CPU Settings
    cores = "1"
    
    # VM Memory Settings
    memory = "2048" 

    # VM Network Settings
    network_adapters {
        model = "virtio"
        bridge = "vmbr0"
        firewall = "false"
    } 

    # VM Cloud-Init Settings
    cloud_init = true
    cloud_init_storage_pool = "local-lvm"

    # PACKER Boot Commands
    boot_command = [
        "<esc><wait>",
        "e<wait>",
        "<down><down><down><end>",
        "<bs><bs><bs><bs><wait>",
        "autoinstall ds=nocloud-net\\;s=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ ---<wait>",
        "<f10><wait>"
    ]

    boot                    = "c"
    boot_wait               = "10s"
    communicator            = "ssh"

    # PACKER Autoinstall Settings
    http_directory          = "http" 
    # (Optional) Bind IP Address and Port
    # http_bind_address       = "0.0.0.0"
    # http_port_min           = 8802
    # http_port_max           = 8802

    ssh_username            = "jordan"
    #ssh_private_key_file = var.ssh_key_path
    ssh_agent_auth = true

    # Raise the timeout, when installation takes longer
    ssh_timeout             = "30m"
    ssh_pty                 = true
}

# Build Definition to create the VM Template
build {
    name = var.vm_template_name
    sources = ["source.proxmox-iso.ubuntu-noble-secure"]

    # Provisioning the VM Template for Cloud-Init Integration in Proxmox #1
    provisioner "shell" {
        inline = [
            "while [ ! -f /var/lib/cloud/instance/boot-finished ]; do echo 'Waiting for cloud-init...'; sleep 1; done",
            "sudo rm /etc/ssh/ssh_host_*",
            "sudo truncate -s 0 /etc/machine-id",
            "sudo apt -y autoremove --purge",
            "sudo apt -y clean",
            "sudo apt -y autoclean",
            "sudo cloud-init clean",
            "sudo rm -f /etc/cloud/cloud.cfg.d/subiquity-disable-cloudinit-networking.cfg",
            "sudo rm -f /etc/netplan/00-installer-config.yaml",
            "sudo sync"
        ]
    }

    # Provisioning the VM Template for Cloud-Init Integration in Proxmox #2
    provisioner "file" {
        source = "files/99-pve.cfg"
        destination = "/tmp/99-pve.cfg"
    }

    # Provisioning the VM Template for Cloud-Init Integration in Proxmox #3
    provisioner "shell" {
        inline = [ "sudo cp /tmp/99-pve.cfg /etc/cloud/cloud.cfg.d/99-pve.cfg" ]
    }

    # Ensure SSH is installed and enabled
    provisioner "shell" {
        inline = [
        "sudo apt-get update",
        "sudo apt-get install -y openssh-server",
        "sudo ssh-keygen -A",  # Regenerate SSH host keys
        "sudo systemctl enable ssh",
        "sudo sshd -t || (echo 'SSHD configuration error:' && sudo sshd -T && exit 1)",
        "sudo systemctl start ssh || (sudo systemctl status ssh && sudo journalctl -xeu ssh)"
        ]
    }

    # Provisioning the VM Template with manual user creation
    provisioner "shell" {
        inline = [
            "if ! id -u ${var.username} > /dev/null 2>&1; then sudo useradd -m -s /bin/bash ${var.username}; fi",
            "sudo mkdir -p /home/${var.username}/.ssh",
            "sudo chown -R ${var.username}:${var.username} /home/${var.username}/.ssh",
            "sudo chmod 700 /home/${var.username}/.ssh",
            "sudo chmod 600 /home/${var.username}/.ssh/authorized_keys",
            "sudo passwd -d ${var.username}"
        ]
    }

    # Security Hardening
    provisioner "shell" {
        inline = [
            # SSH Hardening
            "sudo sed -i 's/^#\\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config",
            "sudo sed -i 's/^#\\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config",
            "sudo sed -i 's/^#\\?X11Forwarding.*/X11Forwarding no/' /etc/ssh/sshd_config",
            "echo 'Protocol 2' | sudo tee -a /etc/ssh/sshd_config",
            
            # System Updates
            "sudo apt-get update && sudo apt-get -y dist-upgrade",
            "sudo apt-get -y install unattended-upgrades apt-listchanges",
            "echo 'Unattended-Upgrade::Allowed-Origins:: \"Ubuntu:noble-security\";' | sudo tee -a /etc/apt/apt.conf.d/50unattended-upgrades",
            "echo 'APT::Periodic::Update-Package-Lists \"1\";' | sudo tee -a /etc/apt/apt.conf.d/20auto-upgrades",
            "echo 'APT::Periodic::Unattended-Upgrade \"1\";' | sudo tee -a /etc/apt/apt.conf.d/20auto-upgrades",
            
            # Firewall Setup
            "sudo apt-get -y install ufw",
            "sudo ufw default deny incoming",
            "sudo ufw default allow outgoing",
            "sudo ufw allow ssh",

            # Talos API - critical for management and cluster formation
            "sudo ufw allow 50000/tcp", # Talos API external
            "sudo ufw allow 50001/tcp", # Talos API internal communication

            # Kubernetes control plane
            "sudo ufw allow 6443/tcp", # Kubernetes API server
            "sudo ufw allow 2379:2380/tcp", # etcd client and peer communication
            "sudo ufw allow 10250/tcp", # Kubelet API
            "sudo ufw allow 10251/tcp", # kube-scheduler
            "sudo ufw allow 10252/tcp", # kube-controller-manager

            # Node port range (for NodePort services)
            "sudo ufw allow 30000:32767/tcp",

            # CNI (Container Network Interface) - Many CNIs use these
            "sudo ufw allow 8472/udp", # VXLAN traffic
            "sudo ufw allow 4789/udp", # VXLAN alternate port
            "sudo ufw allow 179/tcp", # Calico BGP

            # Intra-cluster communication (adjust CIDR to match your network)
            "sudo ufw allow from 192.168.4.0/24 to any", # Allow traffic from your cluster network

            "echo 'y' | sudo ufw enable",
            
            # System Hardening
            "sudo apt-get -y install fail2ban",
            "sudo systemctl enable fail2ban",
            "sudo systemctl start fail2ban",
            
            # Secure shared memory
            "echo 'tmpfs /run/shm tmpfs defaults,noexec,nosuid 0 0' | sudo tee -a /etc/fstab",
            
            # Kernel hardening
            "echo 'kernel.randomize_va_space = 2' | sudo tee -a /etc/sysctl.d/90-security.conf",
            "echo 'net.ipv4.conf.all.rp_filter = 1' | sudo tee -a /etc/sysctl.d/90-security.conf",
            "echo 'net.ipv4.conf.default.rp_filter = 1' | sudo tee -a /etc/sysctl.d/90-security.conf",
            "echo 'net.ipv4.tcp_syncookies = 1' | sudo tee -a /etc/sysctl.d/90-security.conf",
            
            # Disable uncommon filesystems
            "echo 'install cramfs /bin/true' | sudo tee -a /etc/modprobe.d/disable-filesystems.conf",
            "echo 'install freevxfs /bin/true' | sudo tee -a /etc/modprobe.d/disable-filesystems.conf",
            "echo 'install jffs2 /bin/true' | sudo tee -a /etc/modprobe.d/disable-filesystems.conf",
            "echo 'install hfs /bin/true' | sudo tee -a /etc/modprobe.d/disable-filesystems.conf",
            "echo 'install hfsplus /bin/true' | sudo tee -a /etc/modprobe.d/disable-filesystems.conf",
            "echo 'install squashfs /bin/true' | sudo tee -a /etc/modprobe.d/disable-filesystems.conf",
            "echo 'install udf /bin/true' | sudo tee -a /etc/modprobe.d/disable-filesystems.conf",
            
            # Remove unnecessary packages
            "sudo apt-get -y remove telnet rsh-client rsh-redone-client",
            
            # Set strong password policy
            "sudo apt-get -y install libpam-pwquality",
            "sudo sed -i 's/^# minlen.*/minlen = 12/' /etc/security/pwquality.conf",
            "sudo sed -i 's/^# dcredit.*/dcredit = -1/' /etc/security/pwquality.conf",
            "sudo sed -i 's/^# ucredit.*/ucredit = -1/' /etc/security/pwquality.conf",
            "sudo sed -i 's/^# ocredit.*/ocredit = -1/' /etc/security/pwquality.conf",
            "sudo sed -i 's/^# lcredit.*/lcredit = -1/' /etc/security/pwquality.conf",
            
            # Secure /tmp
            "echo 'tmpfs /tmp tmpfs defaults,rw,nosuid,nodev,noexec,relatime 0 0' | sudo tee -a /etc/fstab",
            
            # Audit and log settings
            "sudo apt-get -y install auditd audispd-plugins",
            "sudo systemctl enable auditd",
            "sudo sed -i 's/^#max_log_file.*/max_log_file = 50/' /etc/audit/auditd.conf",
            "sudo sed -i 's/^#space_left_action.*/space_left_action = email/' /etc/audit/auditd.conf",
            "sudo sed -i 's/^#action_mail_acct.*/action_mail_acct = root/' /etc/audit/auditd.conf",
            
            # Restrict compiler access
            "sudo apt-get -y install gcc",  # Install for build purposes, but then restrict
            "sudo chmod o-rx /usr/bin/gcc*",
            
            # Set secure umask
            "echo 'umask 027' | sudo tee -a /etc/bash.bashrc",
            "echo 'umask 027' | sudo tee -a /etc/profile",
            
            # Clean up
            "sudo apt-get -y autoremove",
            "sudo apt-get -y clean",

            # Additional kernel hardening parameters
            "echo 'net.ipv4.conf.all.accept_redirects = 0' | sudo tee -a /etc/sysctl.d/90-security.conf",
            "echo 'net.ipv4.conf.default.accept_redirects = 0' | sudo tee -a /etc/sysctl.d/90-security.conf",
            "echo 'net.ipv4.conf.all.secure_redirects = 0' | sudo tee -a /etc/sysctl.d/90-security.conf",
            "echo 'net.ipv4.conf.default.secure_redirects = 0' | sudo tee -a /etc/sysctl.d/90-security.conf",
            "echo 'net.ipv4.conf.all.send_redirects = 0' | sudo tee -a /etc/sysctl.d/90-security.conf",
            "echo 'net.ipv4.conf.default.send_redirects = 0' | sudo tee -a /etc/sysctl.d/90-security.conf",
            "sudo sysctl --system",  # Apply changes immediately
        ]
    }

    # Kubernetes
    provisioner "shell" {
        inline = [
            # Kubernetes prerequisites
            "sudo swapoff -a",
            "sudo sed -i '/swap/d' /etc/fstab",
            
            # Kernel modules for Kubernetes
            "echo 'overlay' | sudo tee -a /etc/modules-load.d/k8s.conf",
            "echo 'br_netfilter' | sudo tee -a /etc/modules-load.d/k8s.conf",
            
            # Kernel parameters for Kubernetes
            "echo 'net.bridge.bridge-nf-call-iptables = 1' | sudo tee -a /etc/sysctl.d/k8s.conf",
            "echo 'net.bridge.bridge-nf-call-ip6tables = 1' | sudo tee -a /etc/sysctl.d/k8s.conf",
            "echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/k8s.conf",
            
            # Apply sysctl changes
            "sudo sysctl --system",
            
            # Configure containerd
            "sudo apt-get install -y containerd",
            "sudo mkdir -p /etc/containerd",
            "containerd config default | sudo tee /etc/containerd/config.toml >/dev/null",
            "sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml",
            "sudo systemctl restart containerd",
            "sudo systemctl enable containerd"
        ]
    }

    # Add additional provisioning scripts here
    provisioner "shell" {
        inline = [
            # Cleaning up
            "sudo systemctl restart sshd",

            # Set up AIDE
            "sudo apt-get install -y aide",
            "sudo aideinit",
            "sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db",
            "echo '0 5 * * * root /usr/bin/aide.wrapper --config /etc/aide/aide.conf --check' | sudo tee /etc/cron.d/aide",

            # Add persistent SSH client hardening
            "sudo mkdir -p /etc/ssh/ssh_config.d",
            "echo 'Host *' | sudo tee /etc/ssh/ssh_config.d/hardened.conf",
            "echo '    KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256' | sudo tee -a /etc/ssh/ssh_config.d/hardened.conf",
            "echo '    HostKeyAlgorithms ssh-ed25519,ssh-rsa' | sudo tee -a /etc/ssh/ssh_config.d/hardened.conf", 
            "echo '    Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com' | sudo tee -a /etc/ssh/ssh_config.d/hardened.conf"
        ]
    }
}

Need to update the comments about replacing the hardcoded template name with a variable once I replace the hardcoded template name with a variable.

And if you happen to be using Talos OS for your Kubernetes backend, here's that version.

# Ubuntu Server Noble (24.04.x)
# ---
# Packer Template to create an Ubuntu Server (Noble 24.04.x) on Proxmox

# Variable Definitions
variable "proxmox_api_url" {
    type = string
}

variable "proxmox_api_token_id" {
    type = string
}

variable "proxmox_api_token_secret" {
    type = string
    sensitive = true
}

variable "vm_id" {
    type = number
}

variable "vm_template_name" {
    type    = string
}

variable "username" {
    type    = string
}

variable "ssh_key_path" {
    type    = string
}

# Resource Definition for the VM Template
source "proxmox-iso" "ubuntu-noble-secure-talos" {
    # Proxmox Connection Settings
    proxmox_url = var.proxmox_api_url
    username = var.proxmox_api_token_id
    token = var.proxmox_api_token_secret
    # (Optional) Skip TLS Verification
    insecure_skip_tls_verify = true
    
    # VM General Settings
    # Need to replace the hardcoded node name with a variable
    node = "js-8"
    vm_id = var.vm_id
    vm_name = var.vm_template_name
    template_description = "Ubuntu Server Noble Image"

    # VM OS Settings
    # Need to replace the hardcoded template name with a variable
    boot_iso {
        iso_file = "local:iso/ubuntu-24.04.2-live-server-amd64.iso"
        unmount = true
    }
    
    # VM System Settings
    qemu_agent = true

    # VM Hard Disk Settings
    scsi_controller = "virtio-scsi-pci"

    disks {
        disk_size = "20G"
        format = "raw"
        storage_pool = "local-lvm"
        type = "virtio"
    }

    # VM CPU Settings
    cores = "1"
    
    # VM Memory Settings
    memory = "2048" 

    # VM Network Settings
    network_adapters {
        model = "virtio"
        bridge = "vmbr0"
        firewall = "false"
    } 

    # VM Cloud-Init Settings
    cloud_init = true
    cloud_init_storage_pool = "local-lvm"

    # PACKER Boot Commands
    boot_command = [
        "<esc><wait>",
        "e<wait>",
        "<down><down><down><end>",
        "<bs><bs><bs><bs><wait>",
        "autoinstall ds=nocloud-net\\;s=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ ---<wait>",
        "<f10><wait>"
    ]

    boot                    = "c"
    boot_wait               = "10s"
    communicator            = "ssh"

    # PACKER Autoinstall Settings
    http_directory          = "http" 
    # (Optional) Bind IP Address and Port
    # http_bind_address       = "0.0.0.0"
    # http_port_min           = 8802
    # http_port_max           = 8802

    ssh_username            = "jordan"
    #ssh_private_key_file = var.ssh_key_path
    ssh_agent_auth = true

    # Raise the timeout, when installation takes longer
    ssh_timeout             = "30m"
    ssh_pty                 = true
}

# Build Definition to create the VM Template
build {
    name = var.vm_template_name
    sources = ["source.proxmox-iso.ubuntu-noble-secure-talos"]

    # Provisioning the VM Template for Cloud-Init Integration in Proxmox #1
    provisioner "shell" {
        inline = [
            "while [ ! -f /var/lib/cloud/instance/boot-finished ]; do echo 'Waiting for cloud-init...'; sleep 1; done",
            "sudo rm /etc/ssh/ssh_host_*",
            "sudo truncate -s 0 /etc/machine-id",
            "sudo apt -y autoremove --purge",
            "sudo apt -y clean",
            "sudo apt -y autoclean",
            "sudo cloud-init clean",
            "sudo rm -f /etc/cloud/cloud.cfg.d/subiquity-disable-cloudinit-networking.cfg",
            "sudo rm -f /etc/netplan/00-installer-config.yaml",
            "sudo sync"
        ]
    }

    # Provisioning the VM Template for Cloud-Init Integration in Proxmox #2
    provisioner "file" {
        source = "files/99-pve.cfg"
        destination = "/tmp/99-pve.cfg"
    }

    # Provisioning the VM Template for Cloud-Init Integration in Proxmox #3
    provisioner "shell" {
        inline = [ "sudo cp /tmp/99-pve.cfg /etc/cloud/cloud.cfg.d/99-pve.cfg" ]
    }

    # Ensure SSH is installed and enabled
    provisioner "shell" {
        inline = [
        "sudo apt-get update",
        "sudo apt-get install -y openssh-server",
        "sudo ssh-keygen -A",  # Regenerate SSH host keys
        "sudo systemctl enable ssh",
        "sudo sshd -t || (echo 'SSHD configuration error:' && sudo sshd -T && exit 1)",
        "sudo systemctl start ssh || (sudo systemctl status ssh && sudo journalctl -xeu ssh)"
        ]
    }

    # Provisioning the VM Template with manual user creation
    provisioner "shell" {
        inline = [
            "if ! id -u ${var.username} > /dev/null 2>&1; then sudo useradd -m -s /bin/bash ${var.username}; fi",
            "sudo mkdir -p /home/${var.username}/.ssh",
            "sudo chown -R ${var.username}:${var.username} /home/${var.username}/.ssh",
            "sudo chmod 700 /home/${var.username}/.ssh",
            "sudo chmod 600 /home/${var.username}/.ssh/authorized_keys",
            "sudo passwd -d ${var.username}"
        ]
    }

    # Security Hardening
    provisioner "shell" {
        inline = [
            # SSH Hardening
            "sudo sed -i 's/^#\\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config",
            "sudo sed -i 's/^#\\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config",
            "sudo sed -i 's/^#\\?X11Forwarding.*/X11Forwarding no/' /etc/ssh/sshd_config",
            "echo 'Protocol 2' | sudo tee -a /etc/ssh/sshd_config",
            
            # System Updates
            "sudo apt-get update && sudo apt-get -y dist-upgrade",
            "sudo apt-get -y install unattended-upgrades apt-listchanges",
            "echo 'Unattended-Upgrade::Allowed-Origins:: \"Ubuntu:noble-security\";' | sudo tee -a /etc/apt/apt.conf.d/50unattended-upgrades",
            "echo 'APT::Periodic::Update-Package-Lists \"1\";' | sudo tee -a /etc/apt/apt.conf.d/20auto-upgrades",
            "echo 'APT::Periodic::Unattended-Upgrade \"1\";' | sudo tee -a /etc/apt/apt.conf.d/20auto-upgrades",
            
            # Firewall Setup
            "sudo apt-get -y install ufw",
            "sudo ufw default deny incoming",
            "sudo ufw default allow outgoing",
            "sudo ufw allow ssh",

            # Talos API - critical for management and cluster formation
            "sudo ufw allow 50000/tcp", # Talos API external
            "sudo ufw allow 50001/tcp", # Talos API internal communication

            # Kubernetes control plane
            "sudo ufw allow 6443/tcp", # Kubernetes API server
            "sudo ufw allow 2379:2380/tcp", # etcd client and peer communication
            "sudo ufw allow 10250/tcp", # Kubelet API
            "sudo ufw allow 10251/tcp", # kube-scheduler
            "sudo ufw allow 10252/tcp", # kube-controller-manager

            # Node port range (for NodePort services)
            "sudo ufw allow 30000:32767/tcp",

            # CNI (Container Network Interface) - Many CNIs use these
            "sudo ufw allow 8472/udp", # VXLAN traffic
            "sudo ufw allow 4789/udp", # VXLAN alternate port
            "sudo ufw allow 179/tcp", # Calico BGP

            # Intra-cluster communication (adjust CIDR to match your network)
            "sudo ufw allow from 192.168.4.0/24 to any", # Allow traffic from your cluster network

            "echo 'y' | sudo ufw enable",
            
            # System Hardening
            "sudo apt-get -y install fail2ban",
            "sudo systemctl enable fail2ban",
            "sudo systemctl start fail2ban",
            
            # Secure shared memory
            "echo 'tmpfs /run/shm tmpfs defaults,noexec,nosuid 0 0' | sudo tee -a /etc/fstab",
            
            # Kernel hardening
            "echo 'kernel.randomize_va_space = 2' | sudo tee -a /etc/sysctl.d/90-security.conf",
            "echo 'net.ipv4.conf.all.rp_filter = 1' | sudo tee -a /etc/sysctl.d/90-security.conf",
            "echo 'net.ipv4.conf.default.rp_filter = 1' | sudo tee -a /etc/sysctl.d/90-security.conf",
            "echo 'net.ipv4.tcp_syncookies = 1' | sudo tee -a /etc/sysctl.d/90-security.conf",
            
            # Disable uncommon filesystems
            "echo 'install cramfs /bin/true' | sudo tee -a /etc/modprobe.d/disable-filesystems.conf",
            "echo 'install freevxfs /bin/true' | sudo tee -a /etc/modprobe.d/disable-filesystems.conf",
            "echo 'install jffs2 /bin/true' | sudo tee -a /etc/modprobe.d/disable-filesystems.conf",
            "echo 'install hfs /bin/true' | sudo tee -a /etc/modprobe.d/disable-filesystems.conf",
            "echo 'install hfsplus /bin/true' | sudo tee -a /etc/modprobe.d/disable-filesystems.conf",
            "echo 'install squashfs /bin/true' | sudo tee -a /etc/modprobe.d/disable-filesystems.conf",
            "echo 'install udf /bin/true' | sudo tee -a /etc/modprobe.d/disable-filesystems.conf",
            
            # Remove unnecessary packages
            "sudo apt-get -y remove telnet rsh-client rsh-redone-client",
            
            # Set strong password policy
            "sudo apt-get -y install libpam-pwquality",
            "sudo sed -i 's/^# minlen.*/minlen = 12/' /etc/security/pwquality.conf",
            "sudo sed -i 's/^# dcredit.*/dcredit = -1/' /etc/security/pwquality.conf",
            "sudo sed -i 's/^# ucredit.*/ucredit = -1/' /etc/security/pwquality.conf",
            "sudo sed -i 's/^# ocredit.*/ocredit = -1/' /etc/security/pwquality.conf",
            "sudo sed -i 's/^# lcredit.*/lcredit = -1/' /etc/security/pwquality.conf",
            
            # Secure /tmp
            "echo 'tmpfs /tmp tmpfs defaults,rw,nosuid,nodev,noexec,relatime 0 0' | sudo tee -a /etc/fstab",
            
            # Audit and log settings
            "sudo apt-get -y install auditd audispd-plugins",
            "sudo systemctl enable auditd",
            "sudo sed -i 's/^#max_log_file.*/max_log_file = 50/' /etc/audit/auditd.conf",
            "sudo sed -i 's/^#space_left_action.*/space_left_action = email/' /etc/audit/auditd.conf",
            "sudo sed -i 's/^#action_mail_acct.*/action_mail_acct = root/' /etc/audit/auditd.conf",
            
            # Restrict compiler access
            "sudo apt-get -y install gcc",  # Install for build purposes, but then restrict
            "sudo chmod o-rx /usr/bin/gcc*",
            
            # Set secure umask
            "echo 'umask 027' | sudo tee -a /etc/bash.bashrc",
            "echo 'umask 027' | sudo tee -a /etc/profile",
            
            # Clean up
            "sudo apt-get -y autoremove",
            "sudo apt-get -y clean"
        ]
    }

    # Kubernetes
    provisioner "shell" {
        inline = [
            # Kubernetes prerequisites
            "sudo swapoff -a",
            "sudo sed -i '/swap/d' /etc/fstab",
            
            # Kernel modules for Kubernetes
            "echo 'overlay' | sudo tee -a /etc/modules-load.d/k8s.conf",
            "echo 'br_netfilter' | sudo tee -a /etc/modules-load.d/k8s.conf",
            
            # Kernel parameters for Kubernetes
            "echo 'net.bridge.bridge-nf-call-iptables = 1' | sudo tee -a /etc/sysctl.d/k8s.conf",
            "echo 'net.bridge.bridge-nf-call-ip6tables = 1' | sudo tee -a /etc/sysctl.d/k8s.conf",
            "echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.d/k8s.conf",
            
            # Apply sysctl changes
            "sudo sysctl --system",
            
            # Configure containerd
            "sudo apt-get install -y containerd",
            "sudo mkdir -p /etc/containerd",
            "containerd config default | sudo tee /etc/containerd/config.toml >/dev/null",
            "sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml",
            "sudo systemctl restart containerd",
            "sudo systemctl enable containerd"
        ]
    }

    # Add additional provisioning scripts here
    # ...
}

Another post to come on how this all comes together to seamlessly deploy a Kubernetes cluster to Proxmox. More to come!