diff --git a/README.md b/README.md index 92778f4..cf712ba 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,86 @@ -# samba-ad-dc +# Ansible Role: samba_ad_dc + +Ansible role to **install**, **provision**, and optionally **remove** a Samba Active Directory Domain Controller (AD DC) on **Debian-based systems** (e.g., Debian, Ubuntu). + +--- + +## ✅ Features + +- Installs and configures Samba as an AD Domain Controller +- Uses `samba-tool` to provision the domain +- Idempotent: Won't re-provision if already set up +- Reversible: Set `state: absent` to cleanly remove Samba AD DC +- Sets up `/etc/hosts` and DNS resolver +- Separate Kerberos configuration +- Logging of provisioning +- Molecule tests included for both `present` and `absent` states + +--- + +## 📦 Role Variables + +### Main Variables + +| Variable | Description | Default | +|--------------------------|----------------------------------------------|----------------------| +| `samba_ad_dc_state` | `present` to install, `absent` to remove | `present` | +| `samba_realm` | Kerberos Realm (e.g., `EXAMPLE.COM`) | `EXAMPLE.COM` | +| `samba_domain` | NetBIOS domain name (e.g., `EXAMPLE`) | `EXAMPLE` | +| `samba_admin_password` | Admin password for the domain | `StrongAdminPassword123!` | +| `samba_dns_backend` | DNS backend (`SAMBA_INTERNAL`, `BIND9_DLZ`) | `SAMBA_INTERNAL` | +| `samba_hostname` | Hostname for the server | `inventory_hostname` | + +--- + +## 🧰 Example Playbook + +```yaml +- hosts: samba + become: true + roles: + - role: samba_ad_dc + vars: + samba_realm: "CORP.EXAMPLE.COM" + samba_domain: "CORP" + samba_admin_password: "SuperSecretPassw0rd!" + +❌ Remove Samba AD DC +- hosts: samba + become: true + roles: + - role: samba_ad_dc + vars: + samba_ad_dc_state: absent + +📁 Included Tasks + +install.yml: Installs and provisions Samba AD + +remove.yml: Stops and removes Samba AD + +kerberos.yml: Configures Kerberos (/etc/krb5.conf) + +verify.yml: Validates the installation (samba-tool, kinit) + +dns_hosts.yml: Ensures /etc/hosts and DNS resolvers are set + +logging.yml: Logs provisioning output + +📄 Templates + +smb.conf.j2: Samba configuration + +krb5.conf.j2: Kerberos configuration + +🔒 Security Notes + +Passwords should be stored in Ansible Vault for production. + +DNS and Kerberos configuration assumes internal AD DNS — adjust for external resolvers if needed. + +🧩 Compatibility + +OS: Debian 10/11/12+, Ubuntu 20.04/22.04+ + +Ansible: 2.9+ -Ansible role to setup samba active directory \ No newline at end of file diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..59629d7 --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,25 @@ +samba_ad_dc_state: present # or 'absent' + +# AD Provisioning details +samba_realm: "EXAMPLE.COM" +samba_domain: "EXAMPLE" +samba_admin_password: "StrongAdminPassword123!" +samba_dns_backend: "SAMBA_INTERNAL" +samba_hostname: "{{ inventory_hostname }}" + +samba_log_dir: /var/log/samba +samba_provision_log_file: "{{ samba_log_dir }}/ad_provision.log" + +# allows skipping verification when needed +samba_verify: true + +# template for /etc/resolv.conf +samba_dns_nameservers: + - 127.0.0.1 + - 8.8.8.8 +samba_resolv_conf_backup_path: /etc/resolv.conf.ansible.bak + +# Internal state tracking +samba_samdb_path: "/var/lib/samba/private/sam.ldb" +samba_conf_path: "/etc/samba/smb.conf" + diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..e8d8e86 --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: Restart Samba AD DC + service: + name: samba-ad-dc + state: restarted diff --git a/tasks/dns_hosts.yml b/tasks/dns_hosts.yml new file mode 100644 index 0000000..dedb15b --- /dev/null +++ b/tasks/dns_hosts.yml @@ -0,0 +1,29 @@ +--- +- name: Backup original /etc/resolv.conf if not already backed up + copy: + src: /etc/resolv.conf + dest: "{{ samba_resolv_conf_backup_path }}" + remote_src: yes + force: no + when: + - samba_ad_dc_state == "present" + - ansible_virtualization_type != "docker" + +- name: Template /etc/resolv.conf with custom DNS nameservers + template: + src: resolv.conf.j2 + dest: /etc/resolv.conf + owner: root + group: root + mode: '0644' + when: + - samba_ad_dc_state == "present" + - ansible_virtualization_type != "docker" + +- name: Set /etc/hosts entry for Samba AD DC + lineinfile: + path: /etc/hosts + line: "{{ ansible_default_ipv4.address }} {{ samba_hostname }}.{{ samba_realm | lower }} {{ samba_hostname }}" + state: present + create: yes + diff --git a/tasks/dns_hosts_restore.yml b/tasks/dns_hosts_restore.yml new file mode 100644 index 0000000..43cb601 --- /dev/null +++ b/tasks/dns_hosts_restore.yml @@ -0,0 +1,11 @@ +--- +- name: Restore original /etc/resolv.conf from backup + copy: + src: "{{ samba_resolv_conf_backup_path }}" + dest: /etc/resolv.conf + remote_src: yes + force: yes + when: + - samba_ad_dc_state == "absent" + - ansible_virtualization_type != "docker" + - samba_resolv_conf_backup_path is defined diff --git a/tasks/install.yml b/tasks/install.yml new file mode 100644 index 0000000..aa7e228 --- /dev/null +++ b/tasks/install.yml @@ -0,0 +1,47 @@ +--- +- name: Install required packages + apt: + name: + - samba + - krb5-config + - krb5-user + - winbind + - smbclient + - dnsutils + state: present + update_cache: yes + +- name: Stop samba-ad-dc before provisioning (if running) + service: + name: samba-ad-dc + state: stopped + enabled: no + ignore_errors: yes + +- name: Provision AD domain + include_tasks: provision.yml + +- name: Deploy smb.conf + template: + src: smb.conf.j2 + dest: "{{ samba_conf_path }}" + owner: root + group: root + mode: '0644' + notify: Restart Samba AD DC + +- name: Enable and start samba-ad-dc service + service: + name: samba-ad-dc + state: started + enabled: yes + +- name: Configure Kerberos + include_tasks: kerberos.yml + +- name: Set DNS resolver and hosts entry + include_tasks: dns_hosts.yml + +- name: Run verification checks + include_tasks: verify.yml + when: samba_verify | bool diff --git a/tasks/kerberos.yml b/tasks/kerberos.yml new file mode 100644 index 0000000..8faab3d --- /dev/null +++ b/tasks/kerberos.yml @@ -0,0 +1,8 @@ +--- +- name: Configure Kerberos (krb5.conf) + template: + src: krb5.conf.j2 + dest: /etc/krb5.conf + owner: root + group: root + mode: '0644' diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..4d367ec --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,9 @@ +--- + +- name: Install or remove Samba AD DC + include_tasks: install.yml + when: samba_ad_dc_state == 'present' + +- name: Remove Samba AD DC + include_tasks: remove.yml + when: samba_ad_dc_state == 'absent' diff --git a/tasks/provision.yml b/tasks/provision.yml new file mode 100644 index 0000000..a7757ad --- /dev/null +++ b/tasks/provision.yml @@ -0,0 +1,37 @@ +--- +--- +- name: Ensure Samba log directory exists + file: + path: "{{ samba_log_dir }}" + state: directory + owner: root + group: root + mode: '0755' + +- name: Provision the Samba AD DC (with logging) + command: > + samba-tool domain provision + --use-rfc2307 + --realm={{ samba_realm }} + --domain={{ samba_domain }} + --server-role=dc + --dns-backend={{ samba_dns_backend }} + --adminpass={{ samba_admin_password }} + args: + creates: "{{ samba_samdb_path }}" + register: samba_provision_output + no_log: false # You may toggle this if password should be hidden + +- name: Write provisioning output to log + copy: + content: "{{ samba_provision_output.stdout }}" + dest: "{{ samba_provision_log_file }}" + owner: root + group: root + mode: '0644' + +- name: Redact passwords in provisioning log (optional) + replace: + path: "{{ samba_provision_log_file }}" + regexp: "--adminpass=.*" + replace: "--adminpass=********" diff --git a/tasks/remove.yml b/tasks/remove.yml new file mode 100644 index 0000000..c66804b --- /dev/null +++ b/tasks/remove.yml @@ -0,0 +1,39 @@ +--- +- name: Stop Samba AD DC + service: + name: samba-ad-dc + state: stopped + enabled: no + ignore_errors: true + +- name: Remove Samba configuration + file: + path: "{{ samba_conf_path }}" + state: absent + +- name: Remove Samba DB and related files + file: + path: "{{ item }}" + state: absent + loop: + - /var/lib/samba + - /etc/krb5.conf + - /etc/samba + - /var/cache/samba + - /var/log/samba + +- name: Remove Samba-related packages + apt: + name: + - samba + - krb5-config + - krb5-user + - winbind + - smbclient + - dnsutils + state: absent + purge: yes + autoremove: yes + +- name: Restore DNS config + include_tasks: dns_hosts_restore.yml diff --git a/tasks/verify.yml b/tasks/verify.yml new file mode 100644 index 0000000..20f632b --- /dev/null +++ b/tasks/verify.yml @@ -0,0 +1,40 @@ +--- +- name: Verify Samba AD DC setup + when: samba_verify | bool + block: + + - name: Run 'samba-tool domain info' + command: samba-tool domain info 127.0.0.1 + register: domain_info + changed_when: false + + - name: Assert that the domain is provisioned + assert: + that: + - "'Netbios name' in domain_info.stdout" + - "'Server Role: ACTIVE DIRECTORY DOMAIN CONTROLLER' in domain_info.stdout" + + - name: Attempt kinit with administrator + command: echo "{{ samba_admin_password }}" | kinit administrator@{{ samba_realm }} + register: kinit_result + changed_when: false + failed_when: kinit_result.rc != 0 + + - name: Check Kerberos ticket + command: klist + register: klist_result + changed_when: false + + - name: Assert Kerberos ticket exists + assert: + that: + - "'krbtgt/{{ samba_realm }}@{{ samba_realm }}' in klist_result.stdout" + + - name: Check Samba AD DC service status + service_facts: + + - name: Assert samba-ad-dc service is active + assert: + that: + - "'samba-ad-dc' in ansible_facts.services" + - ansible_facts.services['samba-ad-dc'].state == 'running' diff --git a/templates/krb5.conf.j2 b/templates/krb5.conf.j2 new file mode 100644 index 0000000..c7af8c5 --- /dev/null +++ b/templates/krb5.conf.j2 @@ -0,0 +1,17 @@ +[libdefaults] + default_realm = {{ samba_realm }} + dns_lookup_realm = false + dns_lookup_kdc = true + ticket_lifetime = 24h + forwardable = yes + rdns = false + +[realms] + {{ samba_realm }} = { + kdc = {{ samba_hostname }} + admin_server = {{ samba_hostname }} + } + +[domain_realm] + .{{ samba_realm | lower }} = {{ samba_realm }} + {{ samba_realm | lower }} = {{ samba_realm }} diff --git a/templates/resolv.conf.j2 b/templates/resolv.conf.j2 new file mode 100644 index 0000000..5121f74 --- /dev/null +++ b/templates/resolv.conf.j2 @@ -0,0 +1,5 @@ +# Managed by Ansible - Samba AD DC DNS + +{% for ns in samba_dns_nameservers %} +nameserver {{ ns }} +{% endfor %} diff --git a/templates/smb.conf.j2 b/templates/smb.conf.j2 new file mode 100644 index 0000000..4ea2c97 --- /dev/null +++ b/templates/smb.conf.j2 @@ -0,0 +1,15 @@ +[global] + workgroup = {{ samba_domain }} + realm = {{ samba_realm }} + netbios name = {{ samba_hostname | upper }} + server role = active directory domain controller + dns forwarder = 8.8.8.8 + idmap_ldb:use rfc2307 = yes + +[sysvol] + path = /var/lib/samba/sysvol + read only = no + +[netlogon] + path = /var/lib/samba/sysvol/{{ samba_realm | lower }}/scripts + read only = no