roles/samba-dc: Deploy a Samba AD DC

The *samba-dc* role installs Samba on the managed node and configures it
as an Active Directory Domain controller. A custom module,
`samba_domain` handles the provisioning using `samba-tool domain
provision` in an idempotent way.
jenkins-master
Dustin 2018-01-02 23:38:24 -06:00
parent ec524416c6
commit 42ce2434ad
7 changed files with 222 additions and 0 deletions

View File

@ -0,0 +1 @@
samba_dc_use_rfc2307: true

View File

@ -0,0 +1,7 @@
- name: restore samba file contexts
command: restorecon -RF /var/lib/samba
- name: display generated admin password
debug:
var=samba_dc_provision.admin_password
- name: save firewalld configuration
command: firewall-cmd --runtime-to-permanent

View File

@ -0,0 +1,124 @@
# vim: set ft=python :
import errno
import os
import subprocess
def get_samba_paths(samba='samba'):
lines = []
paths = {}
cmd = [samba, '--show-build']
with open(os.devnull, 'r') as nul:
p = subprocess.Popen(
cmd, stdin=nul, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
out, err = p.communicate()
in_paths = False
for line in out.splitlines():
out += line
if line.startswith(b'Paths:'):
in_paths = True
continue
if in_paths:
if line.startswith(b' '):
parts = line.decode().split(':', 1)
if len(parts) != 2:
raise ValueError(
'Unexpected output from samba: {}'.format(line)
)
paths[parts[0].strip()] = parts[1].strip()
else:
in_paths = False
if p.returncode != 0:
raise subprocess.CalledProcessError(p.returncode, cmd, out, err)
return paths
def main():
module = AnsibleModule(
argument_spec=dict(
realm=dict(
required=True,
),
domain=dict(
required=False,
),
use_rfc2307=dict(
required=False,
type='bool',
default=True,
),
dns_backend=dict(
required=False,
choices=[
'BIND9_DLZ',
'SAMBA_INTERNAL',
],
),
),
supports_check_mode=True,
)
realm = module.params['realm']
domain = module.params['domain'] or realm.split('.')[0]
use_rfc2307 = module.params['use_rfc2307']
dns_backend = module.params['dns_backend']
samba_tool = module.get_bin_path('samba-tool', required=True)
samba = module.get_bin_path('samba', required=True)
try:
samba_paths = get_samba_paths(samba)
except OSError as e:
module.fail_json(msg='Error running samba: {}'.format(e))
except subprocess.CalledProcessError as e:
module.fail_json(
msg='Error running samba: {}'.format(e),
stdout=e.stdout,
stderr=e.stderr,
)
changed = not os.path.isdir(os.path.join(
samba_paths['STATEDIR'],
'sysvol',
realm.lower(),
))
if changed and not module.check_mode:
try:
os.unlink(samba_paths['CONFIGFILE'])
except OSError as e:
if e.errno != errno.ENOENT:
raise
cmd = [
samba_tool,
'domain',
'provision',
'--realm={}'.format(realm),
'--domain={}'.format(domain),
]
if use_rfc2307:
cmd.append('--use-rfc2307')
if dns_backend:
cmd += ('--dns-backend', dns_backend)
rc, out, err = module.run_command(cmd, check_rc=True)
admin_password = ''
domain_sid = ''
for line in err.splitlines():
if line.startswith('Admin password:'):
admin_password = line.split(':', 1)[1].lstrip()
if line.startswith('DOMAIN SID:'):
domain_sid = line.split(':', 1)[1].lstrip()
module.exit_json(
changed=True,
rc=rc,
admin_password=admin_password,
domain_sid=domain_sid,
)
module.exit_json(changed=changed)
from ansible.module_utils.basic import *
if __name__ == '__main__':
main()

View File

@ -0,0 +1,60 @@
- name: load distribution-specific values
include_vars: '{{ item }}'
with_first_found:
- '{{ ansible_distribution }}.yml'
- defaults.yml
tags:
- always
- name: ensure packages are installed
package:
name={{ samba_dc_packages|join(',') }}
state=present
tags:
- install
- name: ensure selinux file contexts are correct
sefcontext:
target={{ item.path }}
setype={{ item.setype }}
state=present
with_items: '{{ samba_selinux_contexts }}'
notify: restore samba file contexts
- name: ensure kerberos is configured
template:
src=krb5.conf.j2
dest=/etc/krb5.conf.d/samba.conf
- name: ensure domain is provisioned
samba_domain:
realm={{ krb5_realm }}
domain={{ netbios_domain|d(omit) }}
use_rfc2307={{ samba_dc_use_rfc2307 }}
dns_backend={{ samba_dc_dns_backend|d(omit) }}
register: samba_dc_provision
notify:
- restore samba file contexts
- display generated admin password
- name: ensure samba starts at boot
service:
name=samba
enabled=yes
- name: ensure samba is running
service:
name=samba
state=started
- name: ensure firewall is configured for samba
firewalld:
service={{ item if '/' not in item else omit }}
port={{ item if '/' in item else omit }}
state=enabled
permanent=no
immediate=yes
with_items: '{{ samba_firewall }}'
notify: save firewalld configuration
when: host_users_firewalld|d(true)|bool
tags:
- firewalld

View File

@ -0,0 +1,4 @@
[libdefaults]
default_realm = {{ krb5_realm }}
dns_lookup_realm = false
dns_lookup_kdc = true

View File

@ -0,0 +1,7 @@
samba_dc_packages:
- krb5-workstation
- openldap-clients
- samba-dc
- samba-dc-bind-dlz
- samba-winbind-clients
- tdb-tools

View File

@ -0,0 +1,19 @@
samba_selinux_contexts:
- path: /var/lib/samba/bind-dns/dns.keytab
setype: named_conf_t
- path: /var/lib/samba/bind-dns/named.conf.*
setype: named_conf_t
- path: /var/lib/samba/bind-dns/dns(/.*)?
setype: named_var_run_t
samba_firewall:
- dns
- kerberos
- 135/tcp
- ldap
- 389/udp
- samba
- kpasswd
- ldaps
- 3268/tcp
- 3269/tcp
- 49152-65535/tcp