71 lines
2.4 KiB
Plaintext
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} ]
|