diff --git a/data/ssh-keys/hosts/dns.test.ecdsa_key b/data/ssh-keys/hosts/dns.test.ecdsa_key new file mode 100644 index 00000000..c2c1ac50 --- /dev/null +++ b/data/ssh-keys/hosts/dns.test.ecdsa_key @@ -0,0 +1,9 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS +1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTeoDWHkeAxJwxiCAJ5kjCE/xpA3T7L +ZndAyO7/ygQ6CdWArKEFab+X4/adnwttHIA9mMGqUZZGryK9733xGoHhAAAAuIfIVTaHyF +U2AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBN6gNYeR4DEnDGII +AnmSMIT/GkDdPstmd0DI7v/KBDoJ1YCsoQVpv5fj9p2fC20cgD2YwapRlkavIr3vffEage +EAAAAhAKVUVVC5MY9wzbClODWatvgCoUAhdyYWbXXrkv5n+eqKAAAAG1dlbGwga25vd24g +a2V5IGZvciBzc3NkLWNpLgECAwQ= +-----END OPENSSH PRIVATE KEY----- diff --git a/data/ssh-keys/hosts/dns.test.ecdsa_key.pub b/data/ssh-keys/hosts/dns.test.ecdsa_key.pub new file mode 100644 index 00000000..cb4dbe4c --- /dev/null +++ b/data/ssh-keys/hosts/dns.test.ecdsa_key.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBN6gNYeR4DEnDGIIAnmSMIT/GkDdPstmd0DI7v/KBDoJ1YCsoQVpv5fj9p2fC20cgD2YwapRlkavIr3vffEageE= Well known key for sssd-ci. diff --git a/data/ssh-keys/hosts/dns.test.ed25519_key b/data/ssh-keys/hosts/dns.test.ed25519_key new file mode 100644 index 00000000..77aeedef --- /dev/null +++ b/data/ssh-keys/hosts/dns.test.ed25519_key @@ -0,0 +1,9 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS +1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQRJuQU3kf5lhmziK9y/+IMBJjCxrNcF +xsRm3f1aBBN6dWml3zZZ1KyxYr8FtzkMcudRyxt22k1m7u1fZzJjBHocAAAAuL2m1E69pt +ROAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEm5BTeR/mWGbOIr +3L/4gwEmMLGs1wXGxGbd/VoEE3p1aaXfNlnUrLFivwW3OQxy51HLG3baTWbu7V9nMmMEeh +wAAAAgeHhKLEo0Z4fT4bxXp5/d3M1rXK0xRbWJvyWQxm30T6cAAAAbV2VsbCBrbm93biBr +ZXkgZm9yIHNzc2QtY2kuAQIDBAU= +-----END OPENSSH PRIVATE KEY----- diff --git a/data/ssh-keys/hosts/dns.test.ed25519_key.pub b/data/ssh-keys/hosts/dns.test.ed25519_key.pub new file mode 100644 index 00000000..7d72ad54 --- /dev/null +++ b/data/ssh-keys/hosts/dns.test.ed25519_key.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEm5BTeR/mWGbOIr3L/4gwEmMLGs1wXGxGbd/VoEE3p1aaXfNlnUrLFivwW3OQxy51HLG3baTWbu7V9nMmMEehw= Well known key for sssd-ci. diff --git a/data/ssh-keys/hosts/dns.test.rsa_key b/data/ssh-keys/hosts/dns.test.rsa_key new file mode 100644 index 00000000..826c4bc3 --- /dev/null +++ b/data/ssh-keys/hosts/dns.test.rsa_key @@ -0,0 +1,9 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS +1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQQGYjXJprkndh1xohKvKvrfxOgr8VhG +dl3ec1XLsgmY7UACtj1bCmJB3J8jPgeqjytIRlTMRqT44RkQhzD7VUt5AAAAuHlD4At5Q+ +ALAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAZiNcmmuSd2HXGi +Eq8q+t/E6CvxWEZ2Xd5zVcuyCZjtQAK2PVsKYkHcnyM+B6qPK0hGVMxGpPjhGRCHMPtVS3 +kAAAAgB2/QhldZz5re7eO764YSs+cha1f8zTLXU7MhK8RX6SsAAAAbV2VsbCBrbm93biBr +ZXkgZm9yIHNzc2QtY2kuAQIDBAU= +-----END OPENSSH PRIVATE KEY----- diff --git a/data/ssh-keys/hosts/dns.test.rsa_key.pub b/data/ssh-keys/hosts/dns.test.rsa_key.pub new file mode 100644 index 00000000..6030cac4 --- /dev/null +++ b/data/ssh-keys/hosts/dns.test.rsa_key.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAZiNcmmuSd2HXGiEq8q+t/E6CvxWEZ2Xd5zVcuyCZjtQAK2PVsKYkHcnyM+B6qPK0hGVMxGpPjhGRCHMPtVS3k= Well known key for sssd-ci. diff --git a/src/ansible/group_vars/all b/src/ansible/group_vars/all index 6035093e..e282055b 100644 --- a/src/ansible/group_vars/all +++ b/src/ansible/group_vars/all @@ -56,3 +56,20 @@ user: { password: Secret123 } } + +freeipa_packages: { + server: [ freeipa-server, freeipa-server-dns, freeipa-server-trust-ad ], + client: [ freeipa-client, ] +} + +ipa_packages: { + server: [ ipa-server-dns, ipa-server, ipa-server-trust-ad ], + client: [ ipa-client, ] +} + +join_samba: yes +join_ipa: yes +join_ldap: yes +join_ad: no +trust_ipa_samba: yes +trust_ipa_ad: no diff --git a/src/ansible/inventory.yml b/src/ansible/inventory.yml index 0bff1011..52d51623 100644 --- a/src/ansible/inventory.yml +++ b/src/ansible/inventory.yml @@ -39,6 +39,7 @@ all: ansible_connection: podman ansible_host: sssd-wip-base ansible_python_interpreter: /usr/bin/python3 + extended_packageset: yes services: children: client: diff --git a/src/ansible/playbook_image_service.yml b/src/ansible/playbook_image_service.yml index 882ccdb9..edb672ea 100644 --- a/src/ansible/playbook_image_service.yml +++ b/src/ansible/playbook_image_service.yml @@ -19,13 +19,19 @@ gather_facts: no roles: - ipa - - passkey - hosts: client.test gather_facts: no roles: - client - - passkey + +- hosts: client.test, master.ipa.test + gather_facts: no + tasks: + - name: Include passkey + include_role: + name: passkey + when: passkey_support - hosts: nfs.test gather_facts: no diff --git a/src/ansible/playbook_vagrant.yml b/src/ansible/playbook_vagrant.yml index 52ee3f93..ef0d0733 100644 --- a/src/ansible/playbook_vagrant.yml +++ b/src/ansible/playbook_vagrant.yml @@ -2,4 +2,4 @@ - hosts: dc.ad.test gather_facts: yes roles: - - ad + - { role: ad, enable_firewall: yes } diff --git a/src/ansible/playbook_vm.yml b/src/ansible/playbook_vm.yml new file mode 100644 index 00000000..ed44758d --- /dev/null +++ b/src/ansible/playbook_vm.yml @@ -0,0 +1,29 @@ +--- +- hosts: dns + gather_facts: yes + become: yes + roles: + - dns + +- name: Include base + ansible.builtin.import_playbook: playbook_image_base.yml + vars: + passkey_support: "{{ override_passkey_support | default('no') | bool }}" + user_regular_uid: 1024 + ansible_become: yes + +- name: Include services + ansible.builtin.import_playbook: playbook_image_service.yml + vars: + passkey_support: "{{ override_passkey_support | default('no') | bool }}" + user_regular_uid: 1024 + ansible_become: yes + join_ad: "{{ override_join_ad | default('yes') | bool }}" + join_ldap: "{{ override_join_ldap | default('yes') | bool }}" + join_samba: "{{ override_join_samba | default('yes') | bool }}" + join_ipa: "{{ override_join_ipa | default('yes') | bool }}" + +- hosts: ad + gather_facts: yes + roles: + - { role: ad, skip_install: yes, skip_dns: yes, ad_permanent_users: ['Administrator'] } diff --git a/src/ansible/roles/ad/defaults/main.yml b/src/ansible/roles/ad/defaults/main.yml new file mode 100644 index 00000000..7a8276e4 --- /dev/null +++ b/src/ansible/roles/ad/defaults/main.yml @@ -0,0 +1,13 @@ +--- +# Users to be configured that their password never expires +ad_permanent_users: +- Administrator +- vagrant +# Skip vagrant-specific configuration of dns +skip_dns: no +# Skip installation of AD server +skip_addc_install: no +# Skip addition of sudo shcmea and possibly other ones +skip_schema: no +# Open firewall for all incomming traffic. +open_firewall: yes diff --git a/src/ansible/roles/ad/tasks/dns.yml b/src/ansible/roles/ad/tasks/dns.yml new file mode 100644 index 00000000..7cb3417e --- /dev/null +++ b/src/ansible/roles/ad/tasks/dns.yml @@ -0,0 +1,25 @@ +- name: Disable automatic DNS updates + win_regedit: + path: '{{ item.path }}' + name: '{{ item.name }}' + data: '{{ item.value }}' + type: dword + state: present + with_items: + - {path: 'HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters', name: 'DisableDynamicUpdate', value: 1} + - {path: 'HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters', name: 'RegisterDnsARecords', value: 0} + - {path: 'HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters', name: 'UseDynamicDns', value: 0} + +- name: Allow only specific IP address for the DNS server + win_regedit: + path: HKLM:\SYSTEM\CurrentControlSet\Services\DNS\Parameters + name: PublishAddresses + data: "172.16.200.10" + type: string + state: present + +- name: Remove vagrant IP address from DNS + win_shell: | + Get-DnsServerResourceRecord -ZoneName "{{ service.ad.domain }}" -RRType A \ + | Where-Object {$_.RecordData.ipv4address -ne "172.16.200.10"} \ + | Remove-DnsServerResourceRecord -ZoneName "{{ service.ad.domain }}" -Force diff --git a/src/ansible/roles/ad/tasks/install.yml b/src/ansible/roles/ad/tasks/install.yml new file mode 100644 index 00000000..7a4d2747 --- /dev/null +++ b/src/ansible/roles/ad/tasks/install.yml @@ -0,0 +1,32 @@ +- name: Install Active Directory Services + win_feature: + name: '{{ item }}' + include_management_tools: yes + include_sub_features: yes + state: present + with_items: + - AD-Domain-Services + - DNS + +- name: 'Create new AD forest {{ service.ad.domain }}' + win_shell: | + Import-Module ADDSDeployment + + Install-ADDSForest \ + -DomainName "{{ service.ad.domain }}" \ + -CreateDnsDelegation:$false \ + -DomainNetbiosName "{{ service.ad.netbios }}" \ + -ForestMode "WinThreshold" \ + -DomainMode "WinThreshold" \ + -Force:$true \ + -InstallDns:$true \ + -NoRebootOnCompletion:$true \ + -SafeModeAdministratorPassword \ + (ConvertTo-SecureString '{{ service.ad.safe_password }}' -AsPlainText -Force) + register: installation + args: + creates: 'C:\Windows\NTDS' + +- name: Reboot machine + win_reboot: + when: installation.changed diff --git a/src/ansible/roles/ad/tasks/main.yml b/src/ansible/roles/ad/tasks/main.yml index dd7a9558..febadcdc 100644 --- a/src/ansible/roles/ad/tasks/main.yml +++ b/src/ansible/roles/ad/tasks/main.yml @@ -5,6 +5,7 @@ action: allow enabled: yes state: present + when: open_firewall - name: Set the default SSH shell to PowerShell win_regedit: @@ -14,38 +15,32 @@ type: string state: present -- name: Install Active Directory Services - win_feature: - name: '{{ item }}' - include_management_tools: yes - include_sub_features: yes - state: present - with_items: - - AD-Domain-Services - - DNS - -- name: 'Create new AD forest {{ service.ad.domain }}' - win_shell: | - Import-Module ADDSDeployment +- name: Detect cygwin + win_stat: + path: 'C:\cygwin64\etc' + register: cygwin - Install-ADDSForest \ - -DomainName "{{ service.ad.domain }}" \ - -CreateDnsDelegation:$false \ - -DomainNetbiosName "{{ service.ad.netbios }}" \ - -ForestMode "WinThreshold" \ - -DomainMode "WinThreshold" \ - -Force:$true \ - -InstallDns:$true \ - -NoRebootOnCompletion:$true \ - -SafeModeAdministratorPassword \ - (ConvertTo-SecureString '{{ service.ad.safe_password }}' -AsPlainText -Force) - register: installation - args: - creates: 'C:\Windows\NTDS' +- name: Configure shell for cygwin + win_lineinfile: + path: 'C:\cygwin64\etc\nsswitch.conf' + line: "db_shell: /cygdrive/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe" + when: cygwin.stat.exists + register: configured_cygwin -- name: Reboot machine +- name: Reboot machine to apply changes in cygwin config win_reboot: - when: installation.changed + when: configured_cygwin.changed and skip_addc_install + +- name: 'Install AD server' + include_tasks: 'install.yml' + when: not skip_addc_install + +- name: Install management tools + win_feature: + name: + - RSAT-AD-Tools + include_sub_features: yes + include_management_tools: yes - name: Make sure Active Directory Web Services is running win_service: @@ -53,21 +48,9 @@ start_mode: auto state: started -- name: Copy sudo schema to guest - win_copy: - src: '{{ item }}.schema' - dest: 'C:\{{ item }}.schema' - with_items: - - sudo - -- name: Install additional schemas - win_shell: | - ldifde -i -f C:\{{ item }}.schema -c dc=X {{ service.ad.suffix }} -b "Administrator" "{{ service.ad.netbios }}" "vagrant" - register: schema - failed_when: schema.rc != 0 and schema.stdout is not search('ENTRY_EXISTS') - changed_when: schema.rc == 0 - with_items: - - sudo +- name: 'Add sudo schema and possibly other' + include_tasks: 'schema.yml' + when: not skip_schema - name: Set Password Never Expires for system users win_shell: | @@ -84,32 +67,14 @@ register: result failed_when: "result.rc != 255 and result.rc != 0" changed_when: "result.rc == 0" + until: "result.rc == 0" + # The AD is sometimes not ready to proccess requests so we retry + # to make it stable. + retries: 5 + delay: 60 with_items: - - Administrator - - vagrant - -- name: Disable automatic DNS updates - win_regedit: - path: '{{ item.path }}' - name: '{{ item.name }}' - data: '{{ item.value }}' - type: dword - state: present - with_items: - - {path: 'HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters', name: 'DisableDynamicUpdate', value: 1} - - {path: 'HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters', name: 'RegisterDnsARecords', value: 0} - - {path: 'HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters', name: 'UseDynamicDns', value: 0} - -- name: Allow only specific IP address for the DNS server - win_regedit: - path: HKLM:\SYSTEM\CurrentControlSet\Services\DNS\Parameters - name: PublishAddresses - data: "172.16.200.10" - type: string - state: present + - "{{ ad_permanent_users }}" -- name: Remove vagrant IP address from DNS - win_shell: | - Get-DnsServerResourceRecord -ZoneName "{{ service.ad.domain }}" -RRType A \ - | Where-Object {$_.RecordData.ipv4address -ne "172.16.200.10"} \ - | Remove-DnsServerResourceRecord -ZoneName "{{ service.ad.domain }}" -Force +- name: 'Configure DNS on vagrant AD' + include_tasks: 'dns.yml' + when: not skip_dns diff --git a/src/ansible/roles/ad/tasks/schema.yml b/src/ansible/roles/ad/tasks/schema.yml new file mode 100644 index 00000000..f115112d --- /dev/null +++ b/src/ansible/roles/ad/tasks/schema.yml @@ -0,0 +1,15 @@ +- name: Copy sudo schema to guest + win_copy: + src: '{{ item }}.schema' + dest: 'C:\{{ item }}.schema' + with_items: + - sudo + +- name: Install additional schemas + win_shell: | + ldifde -i -f C:\{{ item }}.schema -c dc=X {{ service.ad.suffix }} -b "Administrator" "{{ service.ad.domain }}" "{{ ansible_password }}" + register: schema + failed_when: schema.rc != 0 and schema.stdout is not search('ENTRY_EXISTS') + changed_when: schema.rc == 0 + with_items: + - sudo diff --git a/src/ansible/roles/client/tasks/main.yml b/src/ansible/roles/client/tasks/main.yml index c7cb50b9..c5a8bbbc 100644 --- a/src/ansible/roles/client/tasks/main.yml +++ b/src/ansible/roles/client/tasks/main.yml @@ -1,3 +1,7 @@ +- name: Set domains + set_fact: + domains: [] + - name: Create /enrollment directory file: path: /enrollment @@ -7,50 +11,125 @@ mode: '0700' - name: Join IPA domain - shell: | - /usr/sbin/ipa-client-install --unattended --no-ntp \ - --domain {{ service.ipa.domain | quote }} \ - --principal admin \ - --password {{ service.ipa.password | quote }} - args: - creates: /etc/ipa/ca.crt - -- name: Copy IPA keytab to /enrollment/ipa.keytab - copy: - src: /etc/krb5.keytab - dest: '/enrollment/ipa.keytab' - mode: 0600 - remote_src: yes + block: + - name: Run ipa-client-install + shell: | + /usr/sbin/ipa-client-install --unattended --no-ntp \ + --domain {{ service.ipa.domain | quote }} \ + --principal admin \ + --password {{ service.ipa.password | quote }} + args: + creates: /etc/ipa/ca.crt -- name: Cleanup after joining the IPA domain - file: - path: '{{ item }}' - state: absent - with_items: - - /etc/krb5.conf - - /etc/krb5.keytab - - /etc/sssd/sssd.conf + - name: Stat /enrollment/ipa.keytab + stat: + path: /enrollment/ipa.keytab + register: enrollment_ipa + + - name: Copy IPA keytab to /enrollment/ipa.keytab + copy: + src: /etc/krb5.keytab + dest: '/enrollment/ipa.keytab' + mode: 0600 + remote_src: yes + when: not enrollment_ipa.stat.exists + + - name: Cleanup after joining the IPA domain + file: + path: '{{ item }}' + state: absent + with_items: + - /etc/krb5.conf + - /etc/krb5.keytab + - /etc/sssd/sssd.conf + + - name: Add ipa to domains + set_fact: + domains: "{{ domains + [service.ipa.domain] }}" + when: join_ipa - name: Join Samba domain - command: realm join {{ service.samba.domain | quote }} - args: - stdin: '{{ service.samba.password }}' - -- name: Copy Samba keytab to /enrollment/samba.keytab - copy: - src: /etc/krb5.keytab - dest: /enrollment/samba.keytab - mode: 0600 - remote_src: yes + block: + - name: Stat /enrollment/samba.keytab to detect that we are already joined + stat: + path: /enrollment/samba.keytab + register: enrollment_samba_1 -- name: Cleanup after joining the Samba domain - file: - path: '{{ item }}' - state: absent - with_items: - - /etc/krb5.conf - - /etc/krb5.keytab - - /etc/sssd/sssd.conf + - name: Realm join Samba domain + command: realm join {{ service.samba.domain | quote }} --verbose + args: + stdin: '{{ service.samba.password }}' + when: not enrollment_samba_1.stat.exists + + - name: Stat /enrollment/samba.keytab + stat: + path: /enrollment/samba.keytab + register: enrollment_samba + + - name: Copy Samba keytab to /enrollment/samba.keytab + copy: + src: /etc/krb5.keytab + dest: /enrollment/samba.keytab + mode: 0600 + remote_src: yes + when: not enrollment_samba.stat.exists + + - name: Cleanup after joining the Samba domain + file: + path: '{{ item }}' + state: absent + with_items: + - /etc/krb5.conf + - /etc/krb5.keytab + - /etc/sssd/sssd.conf + + - name: Add samba to domains + set_fact: + domains: "{{ domains + [service.samba.domain] }}" + when: join_samba + +- name: Join ldap domain + block: + - name: Add ldap to domains + set_fact: + domains: "{{ domains + [service.ldap.domain] }}" + when: join_ldap + +- name: Join AD + block: + - name: Stat /enrollment/ad.keytab to detect that we are already joined + stat: + path: /enrollment/ad.keytab + register: enrollment_ad_1 + + - name: Join AD domain + command: realm join {{ service.ad.domain | quote }} --verbose + args: + stdin: '{{ service.ad.safe_password }}' + when: not enrollment_ad_1.stat.exists + + - name: Stat /enrollment/ad.keytab + stat: + path: /enrollment/ad.keytab + register: enrollment_ad + + - name: Copy AD keytab to /enrollment/ad.keytab + copy: + src: /etc/krb5.keytab + dest: /enrollment/ad.keytab + mode: 0600 + remote_src: yes + when: not enrollment_ad.stat.exists + + - name: Cleanup after joining the AD domain + file: + path: '{{ item }}' + state: absent + with_items: + - /etc/krb5.conf + - /etc/krb5.keytab + - /etc/sssd/sssd.conf + when: join_ad - name: Stop SSSD service: @@ -82,3 +161,7 @@ else exit 0 fi + +- name: Show configured domains + debug: + msg: "domains = {{ ', '.join(domains) }}" diff --git a/src/ansible/roles/client/templates/sssd.conf b/src/ansible/roles/client/templates/sssd.conf index 6ea90e5c..b1d7e9b9 100644 --- a/src/ansible/roles/client/templates/sssd.conf +++ b/src/ansible/roles/client/templates/sssd.conf @@ -1,9 +1,10 @@ [sssd] config_file_version = 2 services = nss, pam -domains = {{ service.ldap.domain }}, {{ service.samba.domain }}, {{ service.ipa.domain }} +domains = {{ ", ".join(domains) }} user = root +{% if join_ldap %} [domain/{{ service.ldap.domain }}] id_provider = ldap ldap_uri = _srv_ @@ -11,7 +12,9 @@ ldap_tls_reqcert = demand ldap_tls_cacert = /data/certs/ca.crt dns_discovery_domain = {{ service.ldap.domain }} use_fully_qualified_names = true +{% endif %} +{% if join_ipa %} [domain/{{ service.ipa.domain }}] id_provider = ipa access_provider = ipa @@ -21,7 +24,9 @@ ipa_hostname = {{ service.client.fqn }} krb5_keytab = /enrollment/ipa.keytab ldap_krb5_keytab = /enrollment/ipa.keytab use_fully_qualified_names = true +{% endif %} +{% if join_samba %} [domain/{{ service.samba.domain }}] id_provider = ad access_provider = ad @@ -31,3 +36,4 @@ ad_hostname = {{ service.client.fqn }} krb5_keytab = /enrollment/samba.keytab ldap_krb5_keytab = /enrollment/samba.keytab use_fully_qualified_names = true +{% endif %} diff --git a/src/ansible/roles/common/tasks/main.yml b/src/ansible/roles/common/tasks/main.yml index eafeedcf..481d3e96 100644 --- a/src/ansible/roles/common/tasks/main.yml +++ b/src/ansible/roles/common/tasks/main.yml @@ -1,3 +1,7 @@ +- name: Set data path + set_fact: + data_path: '{{ role_path }}/../../../../data' + - name: Set /usr/bin/python to python3 alternatives: name: python @@ -12,9 +16,15 @@ group: root mode: 0600 +- name: Create /data + file: + path: '/data' + state: directory + mode: 0700 + - name: Copy common data synchronize: - src: '{{ playbook_dir }}/../../data/' + src: '{{ data_path }}/' dest: /data/ # synchronize rsync option --chown was ignored for some reason @@ -48,16 +58,25 @@ - name: Copy root user ssh keys copy: - src: '{{ playbook_dir }}/../../data/ssh-keys/{{ item.src }}' + src: '{{ data_path }}/ssh-keys/{{ item.src }}' dest: '/root/.ssh/{{ item.dest }}' owner: 'root' group: 'root' mode: '0600' with_items: - { src: 'root.id_rsa', dest: 'id_rsa' } - - { src: 'root.id_rsa.pub', dest: 'authorized_keys' } - { src: 'root.id_rsa.pub', dest: 'id_rsa.pub' } +- name: Append or create authorized_keys + lineinfile: + dest: "/root/.ssh/authorized_keys" + line: "{{ lookup('file', '{{ data_path }}/ssh-keys/root.id_rsa.pub') }}" + create: yes + state: present + owner: 'root' + group: 'root' + mode: '0600' + - name: 'Create wheel group' group: name: wheel @@ -94,7 +113,7 @@ - name: Copy ci user ssh keys copy: - src: '{{ playbook_dir }}/../../data/ssh-keys/{{ item.src }}' + src: '{{ data_path }}/ssh-keys/{{ item.src }}' dest: '/home/{{ user.regular.name }}/.ssh/{{ item.dest }}' owner: '{{ user.regular.name }}' group: '{{ user.regular.name }}' diff --git a/src/ansible/roles/dns/tasks/main.yml b/src/ansible/roles/dns/tasks/main.yml new file mode 100644 index 00000000..61ac6ff9 --- /dev/null +++ b/src/ansible/roles/dns/tasks/main.yml @@ -0,0 +1,30 @@ +- name: Install dnsmasq package + package: + name: + - dnsmasq + state: present + +- name: Place dnsmasq config + template: + src: etc.dnsmasq.conf.j2 + dest: /etc/dnsmasq.conf + owner: root + group: root + mode: 0600 + register: config + +- name: Gather the package facts + package_facts: + +- name: Disable systemd-resolved (if present) + service: + name: systemd-resolved + enabled: false + state: stopped + when: "'systemd-resolved' in ansible_facts.packages" + +- name: Restart dnsmasq service + service: + name: dnsmasq + enabled: true + state: restarted diff --git a/src/ansible/roles/dns/templates/etc.dnsmasq.conf.j2 b/src/ansible/roles/dns/templates/etc.dnsmasq.conf.j2 new file mode 100644 index 00000000..389cc95d --- /dev/null +++ b/src/ansible/roles/dns/templates/etc.dnsmasq.conf.j2 @@ -0,0 +1,78 @@ +# This config is specific to downstream ci and does not +# handle multiple AD DCs and other setups yet. +# TODO: Add all AD servers +# TODO: Remove meta_ip dependency (from idm-ci). +# TODO: Generalize this for all machines. +# dnsmasq config +listen-address=::1,127.0.0.53,127.0.0.1,{{ hostvars['dns.test']['meta_ip'] }} +log-queries +log-facility=- +local=/test/ +domain=test + +# Disable caching so we always query AD and IPA DNS +cache-size=0 + +# These zones have their own DNS server +{% if 'master.ipa.test' in hostvars %} +server=/ipa.test/{{ hostvars['master.ipa.test']['meta_ip'] }} +{% endif %} +{% if 'dc.samba.test' in hostvars %} +server=/samba.test/{{ hostvars['dc.samba.test']['meta_ip'] }} +{% endif %} +{% if 'dc.ad.test' in hostvars %} +server=/ad.test/{{ hostvars['dc.ad.test']['meta_ip'] }} +{% endif %} + + +#{% for host in vars['hostvars'] %} +#address=/{{ host }}/{{ hostvars[host]['meta_ip'] }} +#{% endfor %} + + +# Add A records for LDAP, client and other machines without own DNS server +{% if 'master.ldap.test' in hostvars %} +address=/master.ldap.test/{{ hostvars['master.ldap.test']['meta_ip'] }} +{% endif %} +{% if 'client.test' in hostvars %} +address=/client.test/{{ hostvars['client.test']['meta_ip'] }} +{% endif %} +{# For nfs and kdc we plan to put them alternatively on the ldap machine to save resources. #} +{% if 'nfs.test' in hostvars %} +address=/nfs.test/{{ hostvars['nfs.test']['meta_ip'] }} +{% elif 'master.ldap.test' in hostvars %} +address=/nfs.test/{{ hostvars['master.ldap.test']['meta_ip'] }} +{% endif %} +{% if 'kdc.test' in hostvars %} +address=/kdc.test/{{ hostvars['kdc.test']['meta_ip'] }} +{% elif 'master.ldap.test' in hostvars %} +address=/kdc.test/{{ hostvars['master.ldap.test']['meta_ip'] }} +{% endif %} + +# Add SRV record for LDAP +{% if 'master.ldap.test' in hostvars %} +srv-host=_ldap._tcp.ldap.test,master.ldap.test,389 +{% endif %} + +# Add PTR records for all machines +{% if 'master.ipa.test' in hostvars %} +ptr-record={{ hostvars['master.ipa.test']['meta_ip'].split('.') | reverse | join(".") }}.in-addr.arpa,master.ipa.test +{% endif %} +{% if 'master.ldap.test' in hostvars %} +ptr-record={{ hostvars['master.ldap.test']['meta_ip'].split('.') | reverse | join(".") }}.in-addr.arpa,master.ldap.test +{% endif %} +{% if 'dc.samba.test' in hostvars %} +ptr-record={{ hostvars['dc.samba.test']['meta_ip'].split('.') | reverse | join(".") }}.in-addr.arpa,dc.samba.test +{% endif %} +{% if 'client.test' in hostvars %} +ptr-record={{ hostvars['client.test']['meta_ip'].split('.') | reverse | join(".") }}.in-addr.arpa,client.test +{% endif %} +{% if 'dc.ad.test' in hostvars %} +ptr-record={{ hostvars['dc.ad.test']['meta_ip'].split('.') | reverse | join(".") }}.in-addr.arpa,dc.ad.test +{% endif %} +{% if 'kdc.test' in hostvars %} +ptr-record={{ hostvars['kdc.test']['meta_ip'].split('.') | reverse | join(".") }}.in-addr.arpa,kdc.test +{% endif %} +{% if 'nfs.test' in hostvars %} +ptr-record={{ hostvars['nfs.test']['meta_ip'].split('.') | reverse | join(".") }}.in-addr.arpa,nfs.test +{% endif %} diff --git a/src/ansible/roles/facts/tasks/Fedora.yml b/src/ansible/roles/facts/tasks/Fedora.yml index ecfbb043..a75e6764 100644 --- a/src/ansible/roles/facts/tasks/Fedora.yml +++ b/src/ansible/roles/facts/tasks/Fedora.yml @@ -8,5 +8,6 @@ buildroot: yes debuginfo: yes passkey_support: Yes + ipa: '{{ freeipa_packages }}' ca_trust_dir: /etc/pki/ca-trust/source/anchors/ ca_trust_update: update-ca-trust diff --git a/src/ansible/roles/facts/tasks/RedHat.yml b/src/ansible/roles/facts/tasks/RedHat.yml index 0a8ee855..9c22287a 100644 --- a/src/ansible/roles/facts/tasks/RedHat.yml +++ b/src/ansible/roles/facts/tasks/RedHat.yml @@ -9,3 +9,9 @@ set_fact: buildroot: no debuginfo: no + ipa: '{{ ipa_packages }}' + +- name: Set distribution specific facts for RHEL 7 + set_fact: + passkey_support: No + when: ansible_distribution_major_version == '7' diff --git a/src/ansible/roles/ipa/tasks/main.yml b/src/ansible/roles/ipa/tasks/main.yml index e9c7bf91..127fa37c 100644 --- a/src/ansible/roles/ipa/tasks/main.yml +++ b/src/ansible/roles/ipa/tasks/main.yml @@ -39,6 +39,9 @@ ipa automountmap-del default auto.direct args: stdin: '{{ service.ipa.password }}' + register: automountmapdel + failed_when: + - 'automountmapdel.rc != 0 and "automount map not found" not in automountmapdel.stderr' - name: Create pw-never-expires group shell: | @@ -46,6 +49,9 @@ ipa group-add pw-never-expires args: stdin: '{{ service.ipa.password }}' + register: pwneverexpires + failed_when: + - 'pwneverexpires.rc != 0 and "already exists" not in pwneverexpires.stderr' - name: Create pw-never-expires password policy shell: | @@ -53,6 +59,9 @@ ipa pwpolicy-add pw-never-expires --maxlife=0 --minlife=0 --priority=0 args: stdin: '{{ service.ipa.password }}' + register: policy + failed_when: + - 'policy.rc != 0 and "already used by pw-never-expires" not in policy.stderr' - name: Add admin to pw-never-expires group shell: | @@ -60,6 +69,9 @@ ipa group-add-member pw-never-expires --users=admin args: stdin: '{{ service.ipa.password }}' + register: member + failed_when: + - 'member.rc != 0 and "This entry is already a member" not in member.stdout' - name: Reset admin password to apply pw-never-expires policy shell: | @@ -70,6 +82,16 @@ {{ service.ipa.password }} {{ service.ipa.password }} +- name: 'Check trust with other domains' + shell: | + kinit admin + ipa trust-find + args: + stdin: | + {{ service.ipa.password }} + register: trust + failed_when: False + - name: 'Setup trust with {{ service.samba.domain }}' shell: | kinit admin @@ -78,3 +100,20 @@ stdin: | {{ service.ipa.password }} {{ service.samba.password }} + when: + - 'service.samba.domain not in trust.stdout' + - join_samba + - trust_ipa_samba + +- name: 'Setup trust with {{ service.ad.domain }}' + shell: | + kinit admin + ipa trust-add {{ service.ad.domain | quote }} --admin Administrator --password + args: + stdin: | + {{ service.ad.safe_password }} + {{ service.ad.safe_password }} + when: + - 'service.ad.domain not in trust.stdout' + - join_ad + - trust_ipa_ad diff --git a/src/ansible/roles/kdc/tasks/main.yml b/src/ansible/roles/kdc/tasks/main.yml index 69aef449..4c513b38 100644 --- a/src/ansible/roles/kdc/tasks/main.yml +++ b/src/ansible/roles/kdc/tasks/main.yml @@ -15,6 +15,8 @@ - name: Create Kerberos database shell: | /usr/sbin/kdb5_util -P "{{ service.kdc.master_password }}" create -s + args: + creates: "/var/kerberos/krb5kdc/principal" - name: Start Kerberos services service: diff --git a/src/ansible/roles/ldap/tasks/main.yml b/src/ansible/roles/ldap/tasks/main.yml index df5e517e..3b04aeb9 100644 --- a/src/ansible/roles/ldap/tasks/main.yml +++ b/src/ansible/roles/ldap/tasks/main.yml @@ -27,6 +27,9 @@ changetype: modify add: aci aci: (targetattr=*)(version 3.0; acl "Enable anyone read"; allow (read, search, compare)(userdn="ldap:///anyone");) + register: ldapmod + failed_when: + - 'ldapmod.rc != 0 and "ldap_modify: Type or value exists" not in ldapmod.stderr' - name: 'Install additional schema: passkey' shell: | diff --git a/src/ansible/roles/packages/tasks/Debian.yml b/src/ansible/roles/packages/tasks/Debian.yml index 23473ca8..5cdd8143 100644 --- a/src/ansible/roles/packages/tasks/Debian.yml +++ b/src/ansible/roles/packages/tasks/Debian.yml @@ -61,7 +61,7 @@ - realmd - sssd - sssd-* - when: "'base_client' in group_names" + when: "'base_client' in group_names or 'client' in group_names" - name: Install packages for NFS base image block: @@ -71,7 +71,7 @@ update_cache: yes name: - nfs-kernel-server - when: "'base_nfs' in group_names" + when: "'base_nfs' in group_names or 'nfs' in group_names" - name: Install packages for KDC base image block: @@ -83,7 +83,7 @@ - krb5-admin-server - krb5-config - krb5-kdc - when: "'base_kdc' in group_names" + when: "'base_kdc' in group_names or 'kdc' in group_names" - name: Install packages for Keycloak base image block: diff --git a/src/ansible/roles/packages/tasks/Fedora.yml b/src/ansible/roles/packages/tasks/Fedora.yml index d738bffe..5fb60c3d 100644 --- a/src/ansible/roles/packages/tasks/Fedora.yml +++ b/src/ansible/roles/packages/tasks/Fedora.yml @@ -1,3 +1,7 @@ +- name: Select packageset + set_fact: + extended_packageset: "{{ extended_packageset | default('no') }}" + - name: Install packages for ground base image block: - name: Install dnf plugins @@ -6,78 +10,116 @@ name: - dnf-plugins-core + - name: Install systemd and minimal set of packages + dnf: + state: present + name: + - authselect + - bind-utils + - expect + - firewalld + - net-tools + - openldap-clients + - openssh-clients + - openssh-server + - passwd + - policycoreutils + - policycoreutils-python-utils + - python3-pip + - sudo + - systemd + disable_gpg_check: yes + when: "'base_ground' in group_names" + +- name: Install extended set of packages + block: - name: Install additional repositories shell: | dnf config-manager --add-repo {{ item }} with_items: - https://cli.github.com/packages/rpm/gh-cli.repo - - - name: Install systemd and common tools + - name: Install additional packages dnf: state: present name: - - authselect - bash-completion - bind-utils - dbus-tools - - dnf-plugins-core - e2fsprogs - expect - findutils - firewalld - gdb - gdb-gdbserver - - gh - - git - iputils - ldb-tools - man - - mc - net-tools - - openldap-clients - - openssh-clients - - openssh-server - passwd - policycoreutils - policycoreutils-python-utils - python3-pip - rsync - - sudo - - systemd - tcpdump + - wget + - which + - wireshark-cli + - gh + - git + - mc - tig - tmate - tmux - vim - - wget - - which - - wireshark-cli - when: "'base_ground' in group_names" + disable_gpg_check: yes + when: + - "'base_ground' in group_names" + - extended_packageset - name: Install packages for client base image block: + - name: Install ipa client + dnf: + state: present + name: '{{ ipa.client }}' + - name: Install SSSD and its dependencies dnf: state: present name: - - freeipa-client - nfs-utils - realmd - sssd - sssd-* + - name: Install debug information for selected packages - shell: | - dnf debuginfo-install -y \ - dbus \ - glibc \ - libcmocka \ - libdhash \ - libini_config \ - libldb \ - libtalloc \ - libtevent + command: dnf debuginfo-install -y {{ item }} + with_items: + - dbus + - glibc + - libcmocka + - libdhash + - libini_config + - libldb + - libtalloc + - libtevent + ignore_errors: yes when: debuginfo - when: "'base_client' in group_names" + + - name: Install test dependencies on client + dnf: + state: present + name: + - ldb-tools + - net-tools + - wireshark-cli + - tcpdump + - autofs + - krb5-workstation + disable_gpg_check: yes + when: + - 'not extended_packageset' + when: "'base_client' in group_names or 'client' in group_names" - name: Install packages for LDAP base image block: @@ -87,18 +129,15 @@ name: - acl - 389-ds-base - when: "'base_ldap' in group_names" + when: "'base_ldap' in group_names or 'ldap' in group_names or 'ipa' in group_names" - name: Install packages for IPA base image block: - name: Install IPA dnf: state: present - name: - - freeipa-server - - freeipa-server-dns - - freeipa-server-trust-ad - when: "'base_ipa' in group_names" + name: '{{ ipa.server }}' + when: "'base_ipa' in group_names or 'ipa' in group_names" - name: Install packages for Samba base image block: @@ -108,7 +147,7 @@ name: - samba-dc - samba-winbind-clients - when: "'base_samba' in group_names" + when: "'base_samba' in group_names or 'samba' in group_names" - name: Install packages for NFS base image block: @@ -117,7 +156,7 @@ state: present name: - nfs-utils - when: "'base_nfs' in group_names" + when: "'base_nfs' in group_names or 'nfs' in group_names" - name: Install packages for KDC base image block: @@ -128,7 +167,7 @@ - krb5-libs - krb5-server - krb5-workstation - when: "'base_kdc' in group_names" + when: "'base_kdc' in group_names or 'kdc' in group_names" - name: Install packages that are shared with IPA and client base images block: @@ -140,7 +179,7 @@ - openssl-devel - umockdev when: passkey_support - when: "'base_client' in group_names or 'base_ipa' in group_names" + when: "'base_client' in group_names or 'client' in group_names or 'base_ipa' in group_names or 'ipa' in group_names" - name: Install packages for Keycloak base image block: diff --git a/src/ansible/roles/packages/tasks/RedHat.yml b/src/ansible/roles/packages/tasks/RedHat.yml deleted file mode 100644 index cfecca6d..00000000 --- a/src/ansible/roles/packages/tasks/RedHat.yml +++ /dev/null @@ -1,6 +0,0 @@ -- name: 'Packages are the same as in CentOS {{ ansible_distribution_major_version }}' - include_tasks: '{{ include_centos }}' - loop_control: - loop_var: include_centos - with_first_found: - - files: '{{ "CentOS" | distro_includes(ansible_distribution_major_version) }}' diff --git a/src/ansible/roles/packages/tasks/RedHat8.yml b/src/ansible/roles/packages/tasks/RedHat8.yml new file mode 100644 index 00000000..920fd4d1 --- /dev/null +++ b/src/ansible/roles/packages/tasks/RedHat8.yml @@ -0,0 +1,13 @@ +- name: Enable idm module + command: yum module enable idm:DL1 -y + when: ansible_distribution_major_version == '8' + +- name: Install EPEL repository + dnf: + state: present + name: + - epel-release + when: extended_packageset + +- name: 'Packages are the same as in Fedora' + include_tasks: 'Fedora.yml' diff --git a/src/ansible/roles/packages/tasks/Ubuntu.yml b/src/ansible/roles/packages/tasks/Ubuntu.yml index f4601bd1..50baadc3 100644 --- a/src/ansible/roles/packages/tasks/Ubuntu.yml +++ b/src/ansible/roles/packages/tasks/Ubuntu.yml @@ -59,7 +59,7 @@ - libssl-dev - umockdev when: passkey_support - when: "'base_client' in group_names" + when: "'base_client' in group_names or 'client' in group_names or 'base_ipa' in group_names or 'ipa' in group_names" - name: Install packages for NFS base image block: @@ -69,7 +69,7 @@ update_cache: yes name: - nfs-kernel-server - when: "'base_nfs' in group_names" + when: "'base_nfs' in group_names or 'nfs' in group_names" - name: Install packages for KDC base image block: @@ -81,7 +81,7 @@ - krb5-admin-server - krb5-config - krb5-kdc - when: "'base_kdc' in group_names" + when: "'base_kdc' in group_names or 'kdc' in group_names" - name: Install packages for Keycloak base image block: diff --git a/src/ansible/roles/packages/tasks/main.yml b/src/ansible/roles/packages/tasks/main.yml index df738f5f..11bf8d31 100644 --- a/src/ansible/roles/packages/tasks/main.yml +++ b/src/ansible/roles/packages/tasks/main.yml @@ -9,6 +9,7 @@ shell: | if [ -f /usr/bin/apt ]; then rm -rf /var/lib/apt/lists/* - else + fi + if [ -f /usr/bin/dnf ]; then dnf clean all fi diff --git a/src/ansible/roles/ssh_server/tasks/main.yml b/src/ansible/roles/ssh_server/tasks/main.yml index 969a665b..6f93f4bc 100644 --- a/src/ansible/roles/ssh_server/tasks/main.yml +++ b/src/ansible/roles/ssh_server/tasks/main.yml @@ -11,3 +11,9 @@ name: '{{ systemd.services.sshd }}' enabled: yes state: restarted + register: restart_res + until: "restart_res is not failed" + # The ssh service restart sometimes gets stuck on VMs in openstack, + # so we retry to make it more robust. + retries: 5 + delay: 30 diff --git a/src/tools/gen-ssh-keys.sh b/src/tools/gen-ssh-keys.sh index 11ddde34..f528cf11 100755 --- a/src/tools/gen-ssh-keys.sh +++ b/src/tools/gen-ssh-keys.sh @@ -16,7 +16,7 @@ set -xe mkdir -p $OUT mkdir -p $OUT/hosts -for name in client ldap ipa samba nfs kdc master.keycloak.test; do +for name in client ldap ipa samba nfs kdc dns master.keycloak.test; do for type in ecdsa ed25519 rsa; do ssh-keygen -C "Well known key for sssd-ci." -t ecdsa -f "$OUT/hosts/$name.${type}_key" -N "" <<< y done