Files
iac-homelab/cloud-init/user-data-alpine.yml.tftpl
Damien 842c24acd8 Unlock user account on Alpine
Use `passwd -u` workaround for reliable unlocking
2026-06-10 10:41:40 +02:00

71 lines
2.4 KiB
Plaintext

#cloud-config
# 1. Hostname configuration
hostname: ${hostname}
fqdn: ${hostname}
preserve_hostname: false
# 2. User creation
# On Alpine, the privilege escalation group is "wheel" (not "sudo").
# Keep the default shell (ash/busybox) to stay lightweight.
#
# IMPORTANT: lock_passwd MUST be false on Alpine.
# cloud-init's default (lock_passwd: true) sets shadow to "!", which Alpine's
# OpenSSH (compiled without PAM) interprets as "account locked" and refuses
# pubkey auth with "User ... not allowed because account is locked".
# Setting lock_passwd: false lets cloud-init use "*" instead: no password
# login possible, but pubkey works.
users:
- name: ${username}
sudo: ALL=(ALL) NOPASSWD:ALL
groups: wheel
shell: /bin/ash
lock_passwd: false
ssh_authorized_keys:
- ${ssh_key}
# 3. Base system files (DNS + apk repos, written before package_update)
# Alpine has no netplan/systemd-resolved, so we write resolv.conf ourselves.
write_files:
- path: /etc/resolv.conf
owner: root:root
permissions: '0644'
content: |
nameserver ${dns_server}
- path: /etc/apk/repositories
owner: root:root
permissions: '0644'
content: |
http://dl-cdn.alpinelinux.org/alpine/edge/main
http://dl-cdn.alpinelinux.org/alpine/edge/community
# 4. System update (apk)
package_update: true
package_upgrade: true
# 5. Package installation
# - qemu-guest-agent: main repo (required so Proxmox/Terraform can read the VM IP)
# - tailscale: community repo
packages:
- qemu-guest-agent
- curl
- sudo
- tailscale
# 6. Services & configuration (OpenRC, not systemd)
# Intentional order: qemu-guest-agent first to unblock Terraform as soon as possible.
runcmd:
# Enable and start qemu-guest-agent via OpenRC
- [ rc-update, add, qemu-guest-agent, default ]
- [ rc-service, qemu-guest-agent, start ]
# Unlock the user account: cloud-init's lock_passwd: false is unreliable on
# Alpine (passwd -u refuses on passwordless accounts), so we force the shadow
# entry to "*" ourselves. "*" means: no password login possible, but pubkey
# auth works (unlike "!" which sshd treats as locked).
- [ sh, -c, "sed -i 's/^${username}:!:/${username}:*:/' /etc/shadow" ]
# Enable and start Tailscale via OpenRC
- [ rc-update, add, tailscale, default ]
- [ rc-service, tailscale, start ]
# Register the node with the tailnet
- [ tailscale, up, --authkey=${tailscale_auth_key}, --hostname=${vm_name} ]