├── README.md ├── inventory ├── linux_domain_join.yml └── roles ├── common ├── handlers │ └── main.yml ├── tasks │ └── main.yml ├── templates │ └── ntp.conf.t1 └── vars │ └── vars.yml └── domain_join ├── tasks └── main.yml ├── templates ├── common-session.j2 ├── krb5.conf.j2 ├── ntp.conf.j2 ├── realmd.conf.j2 └── sssd.conf.j2 └── vars ├── secrets.yml └── vars.yml /README.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | This is an example Ansible playbook that will join a Debian based linux server to an Active Directory domain. Many thanks to [Wolfhaven](http://www.wolffhaven45.com/blog/linux/join_ubuntu_workstation_windows_domain/) for his blog on the topic. -------------------------------------------------------------------------------- /inventory: -------------------------------------------------------------------------------- 1 | [domain_join] 2 | server_to_join -------------------------------------------------------------------------------- /linux_domain_join.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # This playbook joins a linux server (debian/ubunto) to an active directory domain. 4 | 5 | - name: Apply common configuration 6 | hosts: domain_join 7 | become: true 8 | 9 | roles: 10 | - common 11 | 12 | - name: Apply configuration to newly deployed machines 13 | hosts: domain_join 14 | become: true 15 | 16 | roles: 17 | - domain_join 18 | -------------------------------------------------------------------------------- /roles/common/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Handler to handle common notifications. Handlers are called by other plays. 3 | # See http://docs.ansible.com/playbooks_intro.html for more information about handlers. 4 | 5 | - name: restart ntp 6 | service: 7 | name: ntp 8 | state: restarted 9 | -------------------------------------------------------------------------------- /roles/common/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Common features for all linux servers 3 | 4 | - name: Install ntp 5 | apt: 6 | name: ntp 7 | state: present 8 | tags: ntp 9 | 10 | - name: Configure ntp file 11 | template: 12 | src: ntp.conf.t1 13 | dest: /etc/ntp.conf 14 | backup: yes 15 | tags: ntp 16 | notify: restart ntp 17 | become: true 18 | 19 | - name: Start the ntp service 20 | service: 21 | name: ntp 22 | state: started 23 | enabled: yes 24 | tags: ntp 25 | -------------------------------------------------------------------------------- /roles/common/templates/ntp.conf.t1: -------------------------------------------------------------------------------- 1 | driftfile /var/lib/ntp/drift 2 | 3 | restrict 127.0.0.1 4 | restrict -6 ::1 5 | 6 | server {{ ntpserver }} 7 | -------------------------------------------------------------------------------- /roles/common/vars/vars.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ntpserver: ntp.yourdomain.local -------------------------------------------------------------------------------- /roles/domain_join/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks that run after a new deployment 3 | 4 | - name: Load Secrets 5 | include_vars: "secrets.yml" 6 | 7 | - name: Load Variables 8 | include_vars: "vars.yml" 9 | 10 | - name: Install pip 11 | apt: 12 | name: python-pip 13 | state: present 14 | update_cache: yes 15 | 16 | - name: Install pexpect 17 | pip: 18 | name: pexpect 19 | state: present 20 | 21 | - name: Install AD Domain packages 22 | apt: 23 | name: {{ item }} 24 | state: present 25 | update_cache: yes 26 | with_items: 27 | - realmd 28 | - sssd 29 | - adcli 30 | - krb5-user 31 | - sssd-tools 32 | - samba-common 33 | - packagekit 34 | - samba-common-bin 35 | - samba-libs 36 | tags: ad 37 | 38 | - name: Copy realmd.conf 39 | template: 40 | src: realmd.conf.j2 41 | dest: /etc/realmd.conf 42 | owner: root 43 | group: root 44 | mode: 0644 45 | tags: ad 46 | 47 | - name: Copy krb5.conf 48 | template: 49 | src: krb5.conf.j2 50 | dest: /etc/krb5.conf 51 | backup: yes 52 | owner: root 53 | group: root 54 | mode: 0644 55 | tags: ad 56 | 57 | - name: Discover realm 58 | command: /bin/bash -c "/usr/sbin/realm discover {{ realm_domain }}" 59 | register: realm_discover_results 60 | tags: ad 61 | 62 | - name: Discover realm debug 63 | debug: 64 | msg: {{ realm_discover_results.stdout }} 65 | 66 | - name: Create kerberos ticket 67 | expect: 68 | command: /bin/bash -c "/usr/bin/kinit -V {{ kerberos_user }}" 69 | responses: 70 | (?i)Password: "{{ kerberos_user_password }}" 71 | tags: ad 72 | 73 | # Check for existing AD 74 | - name: Checking to see if system is already joined to AD 75 | command: /bin/bash -c "/usr/sbin/realm list" 76 | register: realm_list_results 77 | tags: ad 78 | 79 | - name: Debug realm_list_results 80 | debug: 81 | msg: {{ realm_list_results.stdout }} 82 | 83 | - name: Join system to AD 84 | expect: 85 | command: /bin/bash -c "/usr/sbin/realm join {{ realm_domain }} --computer-ou='{{ realm_ad_ou }}' --user={{ kerberos_user }}" 86 | responses: 87 | (?i)Password: "{{ kerberos_user_password }}" 88 | ignore_errors: yes 89 | when: realm_list_results.stdout == "" 90 | become: true 91 | tags: ad 92 | 93 | - name: Copy suders file for safety 94 | command: cp -f /etc/sudoers /etc/sudoers.tmp 95 | 96 | - name: Create sudoers file backup 97 | command: cp -f /etc/sudoers /etc/sudoers.bak 98 | 99 | - name: Add domain admins group to sudoers 100 | lineinfile: dest=/etc/sudoers.tmp state=present line='%domain\ admins ALL=(ALL:ALL) ALL' regexp='^%domain' 101 | 102 | - name: Final sudoers file check 103 | shell: visudo -q -c -f /etc/sudoers.tmp && cp -f /etc/sudoers.tmp /etc/sudoers 104 | 105 | - name: Copy sssd.conf 106 | template: 107 | src: sssd.conf.j2 108 | dest: /etc/sssd/sssd.conf 109 | owner: root 110 | group: root 111 | mode: 0644 112 | tags: ad 113 | 114 | - name: Copy pam common-session 115 | template: 116 | src: common-session.j2 117 | dest: /etc/pam.d/common-session 118 | owner: root 119 | group: root 120 | mode: 0644 121 | tags: ad 122 | -------------------------------------------------------------------------------- /roles/domain_join/templates/common-session.j2: -------------------------------------------------------------------------------- 1 | # 2 | # /etc/pam.d/common-session - session-related modules common to all services 3 | # 4 | # This file is included from other service-specific PAM config files, 5 | # and should contain a list of modules that define tasks to be performed 6 | # at the start and end of sessions of *any* kind (both interactive and 7 | # non-interactive). 8 | # 9 | # As of pam 1.0.1-6, this file is managed by pam-auth-update by default. 10 | # To take advantage of this, it is recommended that you configure any 11 | # local modules either before or after the default block, and use 12 | # pam-auth-update to manage selection of other modules. See 13 | # pam-auth-update(8) for details. 14 | 15 | # here are the per-package modules (the "Primary" block) 16 | session [default=1] pam_permit.so 17 | # here's the fallback if no module succeeds 18 | session requisite pam_deny.so 19 | # prime the stack with a positive return value if there isn't one already; 20 | # this avoids us returning an error just because nothing sets a success code 21 | # since the modules above will each just jump around 22 | session required pam_permit.so 23 | # The pam_umask module will set the umask according to the system default in 24 | # /etc/login.defs and user settings, solving the problem of different 25 | # umask settings with different shells, display managers, remote sessions etc. 26 | # See "man pam_umask". 27 | session optional pam_umask.so 28 | # and here are more per-package modules (the "Additional" block) 29 | session required pam_unix.so 30 | session optional pam_sss.so 31 | session optional pam_systemd.so 32 | # end of pam-auth-update config 33 | session required pam_mkhomedir.so skel=/etc/skel/ umask=0022 34 | -------------------------------------------------------------------------------- /roles/domain_join/templates/krb5.conf.j2: -------------------------------------------------------------------------------- 1 | [libdefaults] 2 | default_realm = {{ krb5_default_realm }} 3 | 4 | # The following krb5.conf variables are only for MIT Kerberos. 5 | krb4_config = /etc/krb.conf 6 | krb4_realms = /etc/krb.realms 7 | kdc_timesync = 1 8 | ccache_type = 4 9 | forwardable = true 10 | proxiable = true 11 | 12 | # The following encryption type specification will be used by MIT Kerberos 13 | # if uncommented. In general, the defaults in the MIT Kerberos code are 14 | # correct and overriding these specifications only serves to disable new 15 | # encryption types as they are added, creating interoperability problems. 16 | # 17 | # Thie only time when you might need to uncomment these lines and change 18 | # the enctypes is if you have local software that will break on ticket 19 | # caches containing ticket encryption types it doesn't know about (such as 20 | # old versions of Sun Java). 21 | 22 | # default_tgs_enctypes = des3-hmac-sha1 23 | # default_tkt_enctypes = des3-hmac-sha1 24 | # permitted_enctypes = des3-hmac-sha1 25 | 26 | # The following libdefaults parameters are only for Heimdal Kerberos. 27 | v4_instance_resolve = false 28 | v4_name_convert = { 29 | host = { 30 | rcmd = host 31 | ftp = ftp 32 | } 33 | plain = { 34 | something = something-else 35 | } 36 | }NU.ORG = { 37 | fcc-mit-ticketflags = true 38 | 39 | [realms] 40 | 41 | [login] 42 | krb4_convert = true 43 | krb4_get_tickets = false 44 | -------------------------------------------------------------------------------- /roles/domain_join/templates/ntp.conf.j2: -------------------------------------------------------------------------------- 1 | driftfile /var/lib/ntp/drift 2 | 3 | restrict 127.0.0.1 4 | restrict -6 ::1 5 | 6 | server {{ ntpserver }} 7 | -------------------------------------------------------------------------------- /roles/domain_join/templates/realmd.conf.j2: -------------------------------------------------------------------------------- 1 | [active-directory] 2 | os-name = {{ ansible_distribution }} 3 | os-version = {{ ansible_distribution_version }} 4 | 5 | [service] 6 | automatic-install = yes 7 | 8 | [users] 9 | default-home = /home/%u 10 | default-shell = /bin/bash 11 | 12 | [mcbadass.local] 13 | user-principle = yes 14 | fully-qualified-names = no 15 | -------------------------------------------------------------------------------- /roles/domain_join/templates/sssd.conf.j2: -------------------------------------------------------------------------------- 1 | [sssd] 2 | domains = {{ realm_domain }} 3 | config_file_version = 2 4 | services = nss, pam 5 | 6 | [domain/{{ realm_domain }}] 7 | ad_domain = {{ realm_domain }} 8 | krb5_realm = {{ krb5_default_realm }} 9 | realmd_tags = manages-system joined-with-adcli 10 | cache_credentials = True 11 | id_provider = ad 12 | krb5_store_password_if_offline = True 13 | default_shell = /bin/bash 14 | ldap_id_mapping = True 15 | use_fully_qualified_names = False 16 | fallback_homedir = /home/%u 17 | access_provider = ad 18 | 19 | auth_provider = ad 20 | chpass_provider = ad 21 | access_provider = ad 22 | ldap_schema = ad 23 | dyndns_update = true 24 | dyndns_refresh_interval = 43200 25 | dyndns_update_ptr = true 26 | dyndns_ttl = 3600 27 | -------------------------------------------------------------------------------- /roles/domain_join/vars/secrets.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Encrypt this with ansible-vault 3 | kerberos_user: domainjoinuser 4 | kerberos_user_password: domainjoinpassword -------------------------------------------------------------------------------- /roles/domain_join/vars/vars.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | realm_domain: yourdomain.local 4 | # It is important that krb5 domain is in ALL CAPITALS 5 | krb5_default_realm: YOURDOMAIN.LOCAL 6 | realm_ad_ou: OU=Linux,OU=Servers,DC=yourdomain,DC=local --------------------------------------------------------------------------------