This repository has been archived on 2026-08-17. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
debian-configuration/freeipa/docs/install.md
T
beatzaplentyandClaude Sonnet 4.6 89cc8c8cc3 feat(freeipa): add domain-controller setup — Rocky Linux 9 + FreeIPA 4.13
Installs and documents the FreeIPA identity management server at
domain-controller.sweet.home (VMID 108, pve1). Provides Kerberos,
LDAP, and integrated DNS for the SWEET.HOME realm.

New section: freeipa/
- docs/install.md: full step-by-step reproduction procedure including
  Proxmox VM prep (Rocky Linux 9 GenericCloud, SeaBIOS, cloud-init),
  swap setup, static IP, /etc/hosts fix, ipa-server-install flags
- docs/pihole-dns.md: how to configure Pi-hole to forward sweet.home
  queries to the FreeIPA BIND instance
- scripts/install.sh: idempotent install script with pre-flight checks;
  reads passwords from env or interactive prompt (never commits them)
- scripts/configure-pihole-dns.sh: idempotent Pi-hole forwarder setup
- scripts/verify.sh: read-only health check (13 checks, 0 side effects)
- CLAUDE.md: host guardrails for domain-controller

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Jbvxx4xbHVcx1NkK3vtmK
2026-07-27 07:22:05 +10:00

249 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# FreeIPA Install Procedure
Full reproduction guide for `domain-controller.sweet.home`. Tested on
Rocky Linux 9.8 (GenericCloud), VMID 108, `pve1.sweet.home`.
## Prerequisites
- Proxmox node with `local-zfs` storage and internet access from guests
- Rocky Linux 9 GenericCloud image downloaded (see step 1)
- SSH access to Proxmox node as a user with `sudo` for `qm`/`pvesm`
- The operator's SSH public key available to inject via cloud-init
---
## Step 1 — Download Rocky Linux 9 GenericCloud image
On the Proxmox node, download to your ISO/image store:
```bash
wget -O /mnt/pve/server-iso/Rocky-9-GenericCloud.latest.x86_64.qcow2 \
https://download.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2
```
The image is ~617 MB. The Proxmox storage must be configured to accept
both ISO images and disk images (set "Content" to include "Disk image"
in the Proxmox UI for that storage).
---
## Step 2 — Prepare the VM in Proxmox
Use an existing VM or create a new one. The config used for VMID 108:
- **CPU**: 2 cores, x86-64-v2-AES
- **RAM**: 2048 MB
- **Disk**: 32 GB on `local-zfs`
- **BIOS**: SeaBIOS (GenericCloud uses MBR — not UEFI)
- **Network**: virtio on `vmbr0`, firewall enabled
- **QEMU guest agent**: enabled
If rebuilding an existing VM (e.g. replacing a prior OS):
```bash
# On pve1 — stop the VM
sudo qm stop <VMID>
# Remove existing disks from config
sudo qm set <VMID> --delete scsi0,efidisk0
# Switch to SeaBIOS if the VM was UEFI
sudo qm set <VMID> --bios seabios
# Free old disk volumes from storage
sudo pvesm free local-zfs:vm-<VMID>-disk-0
sudo pvesm free local-zfs:vm-<VMID>-disk-1
```
### Import the Rocky image and configure cloud-init
```bash
# Import image as a new disk
sudo qm importdisk <VMID> /mnt/pve/server-iso/Rocky-9-GenericCloud.latest.x86_64.qcow2 local-zfs
# Check what disk name was assigned
sudo qm config <VMID> # look for unused0: local-zfs:vm-<VMID>-disk-N
# Attach as scsi0 (adjust disk name from above)
sudo qm set <VMID> --scsi0 local-zfs:vm-<VMID>-disk-0,iothread=1
# Resize to 32 GB
sudo qm disk resize <VMID> scsi0 32G
# Add cloud-init drive
sudo qm set <VMID> --ide2 local-zfs:cloudinit
# Write SSH public key to a temp file
echo 'ssh-rsa AAAA... wayne@stream' > /tmp/admin-key.pub
# (use the key from variables.nix adminSshKey)
# Configure cloud-init
sudo qm set <VMID> \
--ciuser wayne \
--sshkeys /tmp/admin-key.pub \
--ipconfig0 ip=dhcp \
--nameserver 192.168.2.253 \
--searchdomain sweet.home
# Set boot order
sudo qm set <VMID> --boot order=scsi0
# Start VM
sudo qm start <VMID>
```
### Note on SSH key mismatch
The GenericCloud image injects the cloud-init SSH key on first boot.
If you need to add an additional key (e.g. from a different machine)
after first boot, mount the disk via nbd while the VM is stopped:
```bash
sudo qm stop <VMID>
sudo qemu-nbd --connect=/dev/nbd1 --format=raw /dev/zvol/rpool/data/vm-<VMID>-disk-0
# wait 2s, then:
sudo mount /dev/nbd1p4 /mnt/vm # p4 is the root partition on Rocky 9 GenericCloud
sudo tee -a /mnt/vm/home/wayne/.ssh/authorized_keys <<< 'ssh-ed25519 AAAA... extra-key'
sudo umount /mnt/vm
sudo qemu-nbd --disconnect /dev/nbd1
sudo qm start <VMID>
```
Rocky 9 GenericCloud partition layout: `p1`=BIOS boot (2M),
`p2`=EFI (100M), `p3`=/boot (1G), `p4`=/ (rest).
---
## Step 3 — First-boot system preparation
SSH in as `wayne` once cloud-init has completed (usually 6090 s):
```bash
ssh wayne@<VM-IP>
```
### Add swap (required — FreeIPA needs headroom beyond 1.7 GB RAM)
```bash
sudo dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progress
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap defaults 0 0' | sudo tee -a /etc/fstab
```
### Set static IP via NetworkManager
```bash
CON=$(nmcli -t -f NAME con show --active | head -1)
sudo nmcli con mod "$CON" \
ipv4.method manual \
ipv4.addresses 192.168.2.138/24 \
ipv4.gateway 192.168.2.254 \
ipv4.dns 192.168.2.253 \
ipv4.dns-search sweet.home
sudo nmcli con up "$CON"
```
### Fix /etc/hosts (cloud-init maps FQDN to 127.0.0.1 — IPA requires real IP)
```bash
sudo sed -i '/domain-controller/d' /etc/hosts
echo '192.168.2.138 domain-controller.sweet.home domain-controller' \
| sudo tee -a /etc/hosts
# Prevent cloud-init from resetting this on reboot
sudo sed -i 's/manage_etc_hosts: true/manage_etc_hosts: false/' \
/etc/cloud/cloud.cfg
```
---
## Step 4 — Install FreeIPA packages
```bash
sudo dnf install -y ipa-server ipa-server-dns
```
This pulls ~200 packages including 389-ds, Dogtag PKI, BIND, and MIT
Kerberos. Takes 510 minutes depending on mirror speed.
---
## Step 5 — Run the unattended install
Generate strong passwords (min 8 chars; store them in your password manager):
```bash
DM_PASS=$(openssl rand -base64 24 | tr -dc 'A-Za-z0-9' | head -c 24)
ADMIN_PASS=$(openssl rand -base64 24 | tr -dc 'A-Za-z0-9' | head -c 24)
echo "Directory Manager: $DM_PASS"
echo "IPA Admin: $ADMIN_PASS"
# Save both in your password manager NOW before proceeding
```
Run the installer (takes 1520 minutes):
```bash
sudo ipa-server-install \
--realm=SWEET.HOME \
--domain=sweet.home \
--hostname=domain-controller.sweet.home \
--ds-password="$DM_PASS" \
--admin-password="$ADMIN_PASS" \
--setup-dns \
--forwarder=192.168.2.253 \
--no-dnssec-validation \
--no-ntp \
--unattended
```
Key flags:
- `--setup-dns` — install BIND as IPA's authoritative DNS for `sweet.home`
- `--forwarder=192.168.2.253` — forward non-sweet.home queries to Pi-hole
- `--no-dnssec-validation` — skip DNSSEC (home lab has no DNSSEC chain)
- `--no-ntp` — Proxmox handles time sync for guests; don't install chrony
---
## Step 6 — Verify
```bash
# All services should show RUNNING
ipactl status
# Get a Kerberos ticket and confirm
echo "$ADMIN_PASS" | kinit admin
klist
# Check DNS SRV records are in place
dig +short _kerberos._udp.sweet.home SRV @127.0.0.1
# Expected: 0 100 88 domain-controller.sweet.home.
```
---
## Step 7 — Configure Pi-hole to forward sweet.home DNS
See `docs/pihole-dns.md` and `scripts/configure-pihole-dns.sh`.
The short version — add to Pi-hole's custom dnsmasq config:
```
server=/sweet.home/192.168.2.138
```
---
## Step 8 — Back up the CA certificate
```bash
# On domain-controller (encrypted with Directory Manager password)
ls -lh /root/cacert.p12
# Copy to a safe location
scp root@domain-controller:/root/cacert.p12 ~/backups/ipa-cacert.p12
```
This file is required if you ever set up a replica or need to
re-issue service certificates.