usr_smb_r_<name> / usr_smb_rw_<name> (user groups):
- Server creates /data/smb-shares/<name>/ with smb-<name> system user,
setgid directory, and Samba share stanzas [usr-<name>-r/rw] on startup
- Auto-generates credentials and stores them in IPA group descriptions
(cifs://<host>:<samba-user>:<password>) so no out-of-band secret distribution
- Client mounts //ipa/<share> at ~/‹name› for logged-in members;
rw membership wins over r when user is in both groups
- Revert: unmounts and rmdir the mount point on group leave
dev_ssh_<userid> (host group):
- Reads IPA user's SSH public keys (ipasshpubkey / --all output)
- Writes them into /home/<userid>/.ssh/authorized_keys in an
ansipa-managed section (preserves manually-added keys)
- Home dir is created if it doesn't exist (user may not have logged in yet)
- Revert: removes only the ansipa-managed section on group leave
- Enables same-key SSH access from any registered device to enrolled hosts
Also: add cifs-utils + openssh-server to Ansible package list
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DHops6PU4c2Mv5UyhUj8Ms
Fixes found during a complete archiso → FreeIPA DC → client enrollment →
ansipa policy deployment test cycle (Rocky 9 client VM, FreeIPA in Docker):
arch-autoinstall.sh:
- Add openssh to pacstrap — was missing, breaking headless/automated installs
- Enable sshd at boot and set PermitRootLogin yes for post-install access
ansipa-install-packages.sh:
- Fix broken uninstall logic: three always-true conditions caused every package
removal to be silently skipped; replace with a state-file-based approach that
tracks packages installed by ansipa and removes only those when the IPA group
disappears
ansipa-enforce-policies.sh:
- Add usr_admin policy: creates /etc/sudoers.d/ansipa-usr-admin granting full
sudo to the FreeIPA usr_admin user group on every enrolled host; reverted
when the IPA group is deleted
- Add usr_prt_<printer> policy: auto-adds CUPS printers for FreeIPA user group
members at login; printer URI stored in IPA group description; per-user ACL;
reverted when group is deleted or membership ends
deploy-ansipa-policies.yml:
- Document usr_admin and usr_prt_* policies in header comment
- Install cups package on clients (required for printer policy)
FreeIPA container (image/):
- Add docker-env.service: extracts IPA_*/SMB_*/LUKS_*/KEYCLOAK_* env vars from
/proc/1/environ into /etc/container.env on container start; services read from
there rather than relying on PassEnvironment (which is lost on container restart)
- Add run.sh: wrapper that starts FreeIPA with --cgroupns host, required on cgroup
v2 hosts (WSL2, recent Linux) because Docker Compose schema does not expose
cgroupns_mode; also wires LUKS_KEY_UPLOAD_PASSWORD which the SMB service needs
- Dockerfile: copy + enable docker-env.service; add glibc-langpack-en for locale
- ansipa-smb.service: use EnvironmentFile=/etc/container.env (via docker-env.service)
instead of PassEnvironment; add docker-env.service dependency
- ipa-first-boot.service: add docker-env.service dependency + EnvironmentFile
- ipa-first-boot.sh: add --skip-mem-check (container has limited cgroup memory
visibility); remove --no-reverse from non-DNS path (was invalid without DNS)
- docker-compose.yml: add prominent cgroupns note explaining when to use run.sh
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DHops6PU4c2Mv5UyhUj8Ms
Host groups named policy-daemon-enable-<unit> and
policy-daemon-disable-<unit> are now matched by a wildcard case arm in
the group parser — no per-service configuration required.
Enforcement (every 30 min via existing timer):
enable: systemctl enable --now <unit>; state written to
/var/lib/ansipa-policies/daemon-enabled
disable: systemctl disable --now <unit>; state written to
/var/lib/ansipa-policies/daemon-disabled
revert: when a host leaves a group the opposite action is applied
on the next run (enable→disable, disable→enable)
conflict: unit in both lists is skipped with a warning
The .service suffix is optional — _svc_unit() appends it when the name
contains no dot, so all systemd unit types work as-is.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Container (ansipa image):
- Add samba + cronie to Dockerfile; expose ports 445/139
- ansipa-smb-setup.sh: idempotent setup of smbd + scanupload user +
/data/scan-results/{archive,alerts}/ on every container start
- ansipa-smb.service: runs setup before smb.service on each boot
- ansipa-check-scans.sh: hourly cron on server; analyses archive logs for
ClamAV/rkhunter/chkrootkit findings and writes <host>/<date>.alert files
- docker-compose.yml: add SMB_SCAN_PASSWORD env var + port mappings
- .env.example: document SMB_SCAN_PASSWORD
Client (policy-security-scan):
- Scan script now uploads log to //ipa-server/ansipa-scans/archive/<host>/
via smbclient after each run
Client (policy-scan-notify — new policy group):
- ansipa-fetch-alerts.sh: root timer (10 min) downloads alerts from SMB into
~/administration/<hostname>/ for each active login session; deletes server
alert when user removes local file (acknowledgment)
- ansipa-scan-notify.sh: user daemon started via /etc/profile.d/ansipa-notify.sh;
sends notify-send every 10 min while *.alert files remain in ~/administration/
- deploy-ansipa-policies.yml: installs samba-client, deploys SMB creds file
(/etc/ansipa-smb.creds, 0600), and deploys both notification scripts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>