prole/infrastructure/roles/samba_ad_dc/tasks/main.yml
chrisfu 9b0005aa4c fix(samba_ad_dc): bind to LAN IP only so the DC stops registering junk DNS
The AD DC's smb.conf set no `interfaces` / `bind interfaces only`, so Samba
bound to — and samba_dnsupdate registered into DNS — every interface on the
host. On myrddin that meant the Docker bridge (172.17.0.1) and k3s/flannel
CNI addresses (10.42.0.0, 10.42.0.1) were published as A records for both the
prole.org apex and `myrddin`, alongside the real 10.0.0.3. Clients then
round-robined onto unroutable addresses, producing the long-standing
"resolves, then doesn't" internal DNS flakiness.

Confine Samba to loopback + the LAN service IP:

  interfaces = lo 10.0.0.3
  bind interfaces only = yes

This scopes both service binding and DNS self-registration to the real
address, so the junk records stop being (re)created on restart.

  - smb.conf.j2: emit the two directives, gated on bind-interfaces-only being
    enabled AND a non-loopback IP being present (empty -> directives omitted,
    never binds loopback-only by accident).
  - defaults: samba_ad_dc_lan_ip ("" by default), samba_ad_dc_bind_interfaces_only
    (true), samba_ad_dc_interfaces (lo + lan_ip), all documented.
  - tasks: assert samba_ad_dc_lan_ip is non-empty before deploying smb.conf
    when bind-interfaces-only is on, so a missing value fails fast instead of
    rendering the DC unreachable.
  - group_vars/ad_dc: set samba_ad_dc_lan_ip=10.0.0.3 (myrddin's LAN address).

Deploying notifies the existing Restart samba-ad-dc handler. Pre-existing junk
records must be deleted once by hand; they will not be re-registered after the
restart. Template rendering verified for both the set and empty-IP cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 00:43:28 -07:00

108 lines
3.6 KiB
YAML

---
- name: Install Samba AD DC packages
ansible.builtin.apt:
name:
- samba
- krb5-user
state: present
update_cache: true
- name: Derive child realm from namespace when unset
ansible.builtin.set_fact:
samba_ad_dc_child_id: "{{ derived_id | upper }}"
vars:
prole_ns: "{{ lookup('env', 'PROLE_NAMESPACE') | default(lookup('env', 'NAMESPACE'), true) | default('', true) }}"
derived_id: >-
{{ (prole_ns | regex_findall('^knoe-db-([A-Za-z0-9]+)$') | first)
| default('', true) }}
when:
- samba_ad_dc_child_id is not defined or samba_ad_dc_child_id | length == 0
- derived_id | length > 0
- name: Check if Samba AD is provisioned
ansible.builtin.stat:
path: /var/lib/samba/private/sam.ldb
register: samba_ad_provisioned
- name: Fail if not provisioned (this role does not provision)
ansible.builtin.fail:
msg: |-
Samba AD is not provisioned on this host (missing /var/lib/samba/private/sam.ldb).
Provision the child realm first, for example:
samba-tool domain provision \
--use-rfc2307 \
--realm={{ samba_ad_dc_realm }} \
--domain={{ samba_ad_dc_workgroup }} \
--server-role=dc \
--dns-backend=SAMBA_INTERNAL \
--adminpass='<ansible vault administrator pass>' \
--parent-realm={{ samba_ad_dc_parent_realm }} \
--username='{{ samba_ad_dc_parent_netbios }}\\Administrator'
when: not samba_ad_provisioned.stat.exists
- name: Assert LAN IP is set before binding to specific interfaces
ansible.builtin.assert:
that:
- samba_ad_dc_lan_ip | length > 0
fail_msg: >-
samba_ad_dc_bind_interfaces_only is enabled but samba_ad_dc_lan_ip is empty.
Set the DC's LAN service IP (see inventory/group_vars/ad_dc/vars.yml) so
Samba does not bind to loopback only and make the DC unreachable.
when: samba_ad_dc_bind_interfaces_only | bool
- name: Deploy smb.conf
ansible.builtin.template:
src: smb.conf.j2
dest: /etc/samba/smb.conf
owner: root
group: root
mode: "0644"
notify: Restart samba-ad-dc
- name: Ensure samba-ad-dc enabled and running
ansible.builtin.systemd:
name: samba-ad-dc
enabled: true
state: started
- name: Check for kubeadm Samba group
ansible.builtin.command: >-
samba-tool group show {{ samba_kubeadm_group }}
-U {{ samba_dns_admin_user }}%{{ samba_dns_admin_pass }}
register: samba_kubeadm_group_show
changed_when: false
failed_when: false
when:
- samba_dns_admin_pass is defined
- samba_dns_admin_pass | length > 0
- name: Create kubeadm Samba group when missing
ansible.builtin.command: >-
samba-tool group add {{ samba_kubeadm_group }}
-U {{ samba_dns_admin_user }}%{{ samba_dns_admin_pass }}
when:
- samba_dns_admin_pass is defined
- samba_dns_admin_pass | length > 0
- samba_kubeadm_group_show.rc != 0
- name: List kubeadm Samba group members
ansible.builtin.command: >-
samba-tool group listmembers {{ samba_kubeadm_group }}
-U {{ samba_dns_admin_user }}%{{ samba_dns_admin_pass }}
register: samba_kubeadm_group_members
changed_when: false
when:
- samba_dns_admin_pass is defined
- samba_dns_admin_pass | length > 0
- name: Ensure kubeadm Samba group members
ansible.builtin.command: >-
samba-tool group addmembers {{ samba_kubeadm_group }} {{ item }}
-U {{ samba_dns_admin_user }}%{{ samba_dns_admin_pass }}
loop: "{{ samba_kubeadm_members }}"
when:
- samba_dns_admin_pass is defined
- samba_dns_admin_pass | length > 0
- samba_kubeadm_members | length > 0
- item not in (samba_kubeadm_group_members.stdout_lines | default([]))