Active Directory user management with Ansible
Here is a solution I came up with to create Active Directory users and groups with the win_domain_user and win_domain_group module. It is basically a snippet of my Active Directory role.
Default variables
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# defaults/main.yml
active_directory_ensure: present
### USERS
active_directory_domain: 'example.com'
active_directory_email_domain: 'example.com'
active_directory_users: {}
active_directory_user_base_ou: 'OU=users,DC=example,DC=com'
active_directory_update_password: 'on_create'
active_directory_group_action: 'add'
active_directory_password_never_expires_enabled: false
active_directory_user_cannot_change_password_enabled: false
active_directory_account_locked_enabled: false
### GROUPS
active_directory_groups: {}
active_directory_group_base_ou: 'OU=groups,DC=example,DC=com'
active_directory_group_scope: 'global'
Groups
This task will create the AD groups and assign a mail address.
1
2
3
4
5
6
7
8
9
10
11
# tasks/configure_groups.yml
- name: configure active_directory groups
win_domain_group:
state: "{{ item.value.ensure | default(active_directory_ensure) }}"
name: "{{ item.key }}"
description: "{{ item.value.description }}"
path: "{{ item.value.path + ',' + active_directory_group_base_ou }}"
scope: "{{ item.value.scope | default(active_directory_group_scope) }}"
attributes:
mail: "{{ item.value.mail | default(item.key | lower + '@' + active_directory_email_domain) }}"
with_dict: "{{ active_directory_groups | default({}) }}"
Users
I’m using the with_subelements loop so I can deal with a simpler data structure.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# tasks/configure_users.yml
- name: configure active_directory users
win_domain_user:
state: "{{ item.0.ensure | default(active_directory_ensure) }}"
name: "{{ item.0.name }}"
firstname: "{{ item.0.first_name }}"
surname: "{{ item.0.last_name }}"
password: "{{ item.0.password }}"
password_never_expires: "{{ active_directory_password_never_expires_enabled }}"
user_cannot_change_password: "{{ active_directory_user_cannot_change_password_enabled }}"
account_locked: "{{ item.0.locked_enabled | default(active_directory_account_locked_enabled) }}"
path: "{{ item.0.path + ',' + active_directory_user_base_ou }}"
update_password: "{{ item.0.update_password | default(active_directory_update_password) }}"
email: "{{ item.0.email | default(item.0.first_name | lower + '.' + item.0.last_name | lower + '@' + active_directory_email_domain) }}"
upn: "{{ item.0.name + '@' + active_directory_domain }}"
groups_action: "{{ item.0.groups_action | default(active_directory_group_action) }}"
groups:
- "{{ item.1 }}"
with_subelements:
- "{{ active_directory_users | default({}) }}"
- groups
Data
Groups are represented as hashes and I also have some default groups which the corresponding user should be part of.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# groups.yml
active_directory_groups:
# departments
hr:
description: 'human resource'
path: 'OU=departments'
ops:
description: 'operations'
path: 'OU=departments'
# services
jira-users:
description: 'jira users'
path: 'OU=services'
gitlab-users:
description: 'gitlab users'
path: 'OU=services'
active_directory_default_groups:
hr:
- hr
- jira-users
ops:
- ops
- jira-users
- gitlab-users
For users I define an array of hashes. The default groups will for instance add all Human Resource users into the hr and jira-users group.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# users.yml
active_directory_users:
### HR
- name: ahr
first_name: 'a'
last_name: 'hr'
password: 'test1234'
path: 'OU=hr'
groups: ""
- name: bhr
first_name: 'b'
last_name: 'hr'
password: 'test1234'
path: 'OU=hr'
groups: ""
### OPS
- name: aops
first_name: 'a'
last_name: 'ops'
password: 'test1234'
path: 'OU=ops'
groups: ""
Update May 2018: This can be managed more easily and faster since Ansible >2.5 with the flatten function and it is also possibly now to specify ldap attributes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# tasks/configure_users.yml
- name: configure active_directory employees
win_domain_user:
state: "{{ item.ensure | default(active_directory_ensure) }}"
name: "{{ item.name }}"
firstname: "{{ item.first_name }}"
surname: "{{ item.last_name }}"
password: "{{ item.password | default(active_directory_user_default_password) }}"
password_never_expires: "{{ active_directory_password_never_expires_enabled }}"
user_cannot_change_password: "{{ active_directory_user_cannot_change_password_enabled }}"
account_locked: "{{ item.locked_enabled | default(active_directory_account_locked_enabled) }}"
path: "{{ item.0.path + ',' + active_directory_user_base_ou }}"
update_password: "{{ item.update_password | default(active_directory_update_password) }}"
email: "{{ item.email | default(item.first_name | lower + '.' + item.last_name | lower + '@' + active_directory_email_domain) }}"
upn: "{{ item.name + '@' + active_directory_domain }}"
groups_action: "{{ item.groups_action | default(active_directory_group_action) }}"
attributes:
displayName: "{{ item.first_name | capitalize }} {{ item.last_name | capitalize }}"
description: "{{ item.description | default(omit) }}"
loginShell: "{{ item.login_shell | default(active_directory_login_shell) }}"
groups: "{{ item.groups | default(active_directory_default_group) | flatten }}"
with_items:
- "{{ active_directory_users | default({}) }}"
A group every user should be member of:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# groups.yml
# all users should be member of these groups
custom_group_all:
- 'jira-users'
- 'gitlab-users'
active_directory_default_groups:
hr:
- 'hr'
- 'reporting'
- ""
ops:
- 'ops'
- 'test'
- ""
You can also overwrite the groups per user:
1
2
3
4
5
6
7
8
9
10
11
# users.yml
active_directory_users:
### HR
- name: ahr
first_name: 'a'
last_name: 'hr'
password: 'test1234'
path: 'OU=hr'
groups:
- ""
- 'another_group'
Tested with:
- Ansible 2.5.2, 2.4.2
- Windows Server 2012R2