mirror of
				https://github.com/kevinveenbirkenbach/computer-playbook.git
				synced 2025-10-31 18:29:21 +00:00 
			
		
		
		
	Huge role refactoring/cleanup. Other commits will propably follow. Because some bugs will exist. Still important for longrun and also for auto docs/help/slideshow generation
This commit is contained in:
		
							
								
								
									
										34
									
								
								roles/service-openldap/tasks/add_user_objects.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								roles/service-openldap/tasks/add_user_objects.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| - name: Gather all users with their current objectClass list | ||||
|   community.general.ldap_search: | ||||
|     server_uri: "{{ ldap_server_uri }}" | ||||
|     bind_dn:    "{{ ldap.dn.administrator.data }}" | ||||
|     bind_pw:    "{{ ldap.bind_credential }}" | ||||
|     dn:         "{{ ldap.dn.ou.users }}" | ||||
|     scope:      subordinate | ||||
|     filter:     "{{ ldap.filters.users.all }}" | ||||
|     attrs: | ||||
|       - dn | ||||
|       - objectClass | ||||
|       - "{{ ldap.user.attributes.id }}" | ||||
|   register: ldap_users_with_classes | ||||
|  | ||||
| - name: Add only missing auxiliary classes | ||||
|   community.general.ldap_attrs: | ||||
|     server_uri: "{{ ldap_server_uri }}" | ||||
|     bind_dn:    "{{ ldap.dn.administrator.data }}" | ||||
|     bind_pw:    "{{ ldap.bind_credential }}" | ||||
|     dn:         "{{ item.dn }}" | ||||
|     attributes: | ||||
|       objectClass: "{{ missing_auxiliary }}" | ||||
|     state: present | ||||
|   async: 60 | ||||
|   poll: 0 | ||||
|   loop: "{{ ldap_users_with_classes.results }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.dn }}" | ||||
|   vars: | ||||
|     missing_auxiliary: >- | ||||
|       {{ (ldap.user.objects.auxiliary.values() | list)  | ||||
|          | difference(item.objectClass | default([])) | ||||
|       }} | ||||
|   when: missing_auxiliary | length > 0 | ||||
							
								
								
									
										11
									
								
								roles/service-openldap/tasks/create_ldif_files.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								roles/service-openldap/tasks/create_ldif_files.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| - name: "Create LDIF files at {{ ldif_host_path }}{{ folder }}" | ||||
|   template: | ||||
|     src: "{{ item }}" | ||||
|     dest: "{{ ldif_host_path }}{{ folder }}/{{ item | basename | regex_replace('\\.j2$', '') }}" | ||||
|     mode: '770' | ||||
|   loop: >- | ||||
|     {{ | ||||
|       lookup('fileglob', role_path ~ '/templates/ldif/' ~ folder ~ '/*.j2', wantlist=True) | ||||
|       | sort | ||||
|     }} | ||||
|   notify: "Import {{ folder }} LDIF files" | ||||
							
								
								
									
										124
									
								
								roles/service-openldap/tasks/main.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								roles/service-openldap/tasks/main.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | ||||
| --- | ||||
| - name: "include docker-compose role" | ||||
|   include_role:  | ||||
|     name: docker-compose | ||||
|  | ||||
| - name: Create {{domains | get_domain(application_id)}}.conf if LDAP is exposed to internet | ||||
|   template:  | ||||
|     src:  "nginx.stream.conf.j2"  | ||||
|     dest: "{{nginx.directories.streams}}{{domains | get_domain(application_id)}}.conf" | ||||
|   notify: restart nginx | ||||
|   when: applications[application_id].network.public | bool | ||||
|  | ||||
| - name: Remove {{domains | get_domain(application_id)}}.conf if LDAP is not exposed to internet | ||||
|   file: | ||||
|     path: "{{ nginx.directories.streams }}{{ domains | get_domain(application_id) }}.conf" | ||||
|     state: absent | ||||
|   when: not applications[application_id].network.public | bool | ||||
|  | ||||
| - name: create docker network for LDAP, so that other applications can access it | ||||
|   docker_network: | ||||
|     name: central_ldap | ||||
|     state: present | ||||
|     ipam_config: | ||||
|       - subnet: "{{ networks.local.central_ldap.subnet }}" | ||||
|  | ||||
| - name: "Reset LDAP admin passwords" | ||||
|   include_tasks: reset_admin_passwords.yml | ||||
|   when: applications[application_id].network.local | ||||
|  | ||||
| - name: "create directory {{ldif_host_path}}{{item}}" | ||||
|   file: | ||||
|     path: "{{ldif_host_path}}{{item}}" | ||||
|     state: directory | ||||
|     mode: 0755 | ||||
|   loop: "{{ldif_types}}" | ||||
|  | ||||
| - name: "Process all LDIF types" | ||||
|   include_tasks: create_ldif_files.yml | ||||
|   loop: | ||||
|     - configuration | ||||
|   loop_control: | ||||
|     loop_var: folder | ||||
|  | ||||
| - name: flush LDIF handlers | ||||
|   meta: flush_handlers | ||||
|  | ||||
| - name: install python-ldap | ||||
|   community.general.pacman: | ||||
|     name: | ||||
|       - python-ldap | ||||
|     state: present | ||||
|  | ||||
| - name: "Include Nextcloud Schema" | ||||
|   include_tasks: schemas/nextcloud.yml | ||||
|  | ||||
| - name: "Include openssh-lpk Schema" | ||||
|   include_tasks: schemas/openssh_lpk.yml | ||||
|  | ||||
| ############################################################################### | ||||
| # 1) Create the LDAP entry if it does not yet exist | ||||
| ############################################################################### | ||||
| - name: Ensure LDAP users exist | ||||
|   community.general.ldap_entry: | ||||
|     dn:           "{{ ldap.user.attributes.id }}={{ item.key }},{{ ldap.dn.ou.users }}" | ||||
|     server_uri:   "{{ ldap_server_uri }}" | ||||
|     bind_dn:      "{{ ldap.dn.administrator.data }}" | ||||
|     bind_pw:      "{{ ldap.bind_credential }}" | ||||
|     objectClass:  "{{ ldap.user.objects.structural }}" | ||||
|     attributes: | ||||
|       uid:           "{{ item.value.username }}" | ||||
|       sn:            "{{ item.value.sn  | default(item.key) }}" | ||||
|       cn:            "{{ item.value.cn  | default(item.key) }}" | ||||
|       userPassword:  "{SSHA}{{ item.value.password }}" | ||||
|       loginShell:    /bin/bash | ||||
|       homeDirectory: "/home/{{ item.key }}" | ||||
|       uidNumber:     "{{ item.value.uid | int }}" | ||||
|       gidNumber:     "{{ item.value.gid | int }}" | ||||
|     state: present            # ↳ creates but never updates | ||||
|   async: 60 | ||||
|   poll: 0 | ||||
|   loop: "{{ users | dict2items }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.key }}" | ||||
|  | ||||
| ############################################################################### | ||||
| # 2) Keep the objectClass list AND the mail attribute up-to-date | ||||
| ############################################################################### | ||||
| - name: Ensure required objectClass values and mail address are present | ||||
|   community.general.ldap_attrs: | ||||
|     dn: "{{ ldap.user.attributes.id }}={{ item.key }},{{ ldap.dn.ou.users }}" | ||||
|     server_uri: "{{ ldap_server_uri }}" | ||||
|     bind_dn: "{{ ldap.dn.administrator.data }}" | ||||
|     bind_pw: "{{ ldap.bind_credential }}" | ||||
|     attributes: | ||||
|       objectClass: "{{ ldap.user.objects.structural }}" | ||||
|       mail:        "{{ item.value.email }}" | ||||
|     state: exact | ||||
|   async: 60 | ||||
|   poll: 0 | ||||
|   loop: "{{ users | dict2items }}" | ||||
|   loop_control: | ||||
|     label: "{{ item.key }}" | ||||
|  | ||||
| - name: "Ensure container for application roles exists" | ||||
|   community.general.ldap_entry: | ||||
|     dn: "{{ ldap.dn.ou.roles }}" | ||||
|     server_uri: "{{ ldap_server_uri }}" | ||||
|     bind_dn:  "{{ ldap.dn.administrator.data }}" | ||||
|     bind_pw:  "{{ ldap.bind_credential }}" | ||||
|     objectClass: organizationalUnit | ||||
|     attributes: | ||||
|       ou: roles | ||||
|       description: Container for application access profiles | ||||
|     state: present | ||||
|  | ||||
| - name: "Process all LDIF types" | ||||
|   include_tasks: create_ldif_files.yml | ||||
|   loop: | ||||
|     - data | ||||
|   loop_control: | ||||
|     loop_var: folder | ||||
|  | ||||
| - name: "Add Objects to all users" | ||||
|   include_tasks: add_user_objects.yml | ||||
							
								
								
									
										57
									
								
								roles/service-openldap/tasks/reset_admin_passwords.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								roles/service-openldap/tasks/reset_admin_passwords.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| --- | ||||
| # Reset both Database and Configuration Admin passwords in LDAP via LDAPI | ||||
| # roles/service-openldap/tasks/reset_admin_passwords.yml | ||||
|  | ||||
| - name: "Query available LDAP databases" | ||||
|   shell: | | ||||
|     docker exec {{ applications[application_id].hostname }} \ | ||||
|       ldapsearch -Y EXTERNAL -H ldapi:/// -LLL -b cn=config "(olcDatabase=*)" dn | ||||
|   register: ldap_databases | ||||
|  | ||||
| - name: "Determine data backend DN (mdb)" | ||||
|   set_fact: | ||||
|     data_backend_dn: >- | ||||
|       {{ ldap_databases.stdout_lines | ||||
|          | select('search','^dn: olcDatabase=.*mdb') | ||||
|          | map('regex_replace','^dn: ','') | ||||
|          | list | ||||
|          | first }} | ||||
|  | ||||
| - name: "Determine config backend DN" | ||||
|   set_fact: | ||||
|     config_backend_dn: >- | ||||
|       {{ ldap_databases.stdout_lines | ||||
|          | select('search','^dn: olcDatabase=\{[0-9]+\}config,cn=config$') | ||||
|          | map('regex_replace','^dn: ','') | ||||
|          | list | ||||
|          | first }} | ||||
|  | ||||
| - name: "Generate hash for Database Admin password" | ||||
|   shell: | | ||||
|     docker exec {{ applications[application_id].hostname }} \ | ||||
|       slappasswd -s "{{ ldap.bind_credential }}" | ||||
|   register: database_admin_pw_hash | ||||
|  | ||||
| - name: "Reset Database Admin password in LDAP (olcRootPW)" | ||||
|   shell: | | ||||
|     docker exec -i {{ applications[application_id].hostname }} ldapmodify -Y EXTERNAL -H ldapi:/// <<EOF | ||||
|     dn: {{ data_backend_dn }} | ||||
|     changetype: modify | ||||
|     replace: olcRootPW | ||||
|     olcRootPW: {{ database_admin_pw_hash.stdout }} | ||||
|     EOF | ||||
|  | ||||
| - name: "Generate hash for Configuration Admin password" | ||||
|   shell: | | ||||
|     docker exec {{ applications[application_id].hostname }} \ | ||||
|       slappasswd -s "{{ applications[application_id].credentials.administrator_password }}" | ||||
|   register: config_admin_pw_hash | ||||
|  | ||||
| - name: "Reset Configuration Admin password in LDAP (olcRootPW)" | ||||
|   shell: | | ||||
|     docker exec -i {{ applications[application_id].hostname }} ldapmodify -Y EXTERNAL -H ldapi:/// <<EOF | ||||
|     dn: {{ config_backend_dn }} | ||||
|     changetype: modify | ||||
|     replace: olcRootPW | ||||
|     olcRootPW: {{ config_admin_pw_hash.stdout }} | ||||
|     EOF | ||||
							
								
								
									
										32
									
								
								roles/service-openldap/tasks/schemas/nextcloud.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								roles/service-openldap/tasks/schemas/nextcloud.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| - name: "pkgmgr install" | ||||
|   include_role: | ||||
|     name: pkgmgr-install | ||||
|   vars: | ||||
|     package_name: ldapsm | ||||
|  | ||||
| - name: Ensure custom LDAP schema snippet via ldapsm | ||||
|   vars: | ||||
|     schema_name: "nextcloud" | ||||
|     attribute_defs: | ||||
|       - "( 1.3.6.1.4.1.99999.1 NAME '{{ ldap.user.attributes.nextcloud_quota }}' DESC 'Quota for Nextcloud' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )" | ||||
|     objectclass_defs: | ||||
|       - "( 1.3.6.1.4.1.99999.2 NAME 'nextcloudUser' DESC 'Auxiliary class for Nextcloud attributes' AUXILIARY MAY ( {{ ldap.user.attributes.nextcloud_quota }} ) )" | ||||
|   command: > | ||||
|     ldapsm | ||||
|       -s {{ ldap_server_uri }} | ||||
|       -D '{{ ldap_bind_dn }}' | ||||
|       -W '{{ ldap_bind_pw }}' | ||||
|       -n {{ schema_name }} | ||||
|       {% for at in attribute_defs %} | ||||
|       -a "{{ at }}" | ||||
|       {% endfor %} | ||||
|       {% for oc in objectclass_defs %} | ||||
|       -c "{{ oc }}" | ||||
|       {% endfor %} | ||||
|   register: ldapsm_result | ||||
|   changed_when: "'Created schema entry' in ldapsm_result.stdout" | ||||
|   check_mode: no | ||||
|  | ||||
| - name: Show ldapsm output | ||||
|   debug: | ||||
|     var: ldapsm_result.stdout_lines | ||||
							
								
								
									
										40
									
								
								roles/service-openldap/tasks/schemas/openssh_lpk.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								roles/service-openldap/tasks/schemas/openssh_lpk.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| - name: Install ldapsm | ||||
|   include_role: | ||||
|     name: pkgmgr-install | ||||
|   vars: | ||||
|     package_name: ldapsm | ||||
|  | ||||
| - name: Ensure OpenSSH-LPK schema via ldapsm | ||||
|   vars: | ||||
|     schema_name: "openssh-lpk" | ||||
|     attribute_defs: | ||||
|       - "( 1.3.6.1.4.1.24552.1.1 NAME '{{ ldap.user.attributes.ssh_public_key }}' DESC 'OpenSSH Public Key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )" | ||||
|       - "( 1.3.6.1.4.1.24552.1.2 NAME 'sshFingerprint' DESC 'OpenSSH Public Key Fingerprint' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )" | ||||
|     objectclass_defs: | ||||
|       - >- | ||||
|         ( 1.3.6.1.4.1.24552.2.1 | ||||
|           NAME '{{ ldap.user.objects.auxiliary.ssh_public_key }}' | ||||
|           DESC 'Auxiliary class for OpenSSH public keys' | ||||
|           SUP top | ||||
|           AUXILIARY | ||||
|           MAY ( {{ ldap.user.attributes.ssh_public_key }} $ sshFingerprint ) ) | ||||
|  | ||||
|   command: > | ||||
|     ldapsm | ||||
|       -s {{ ldap_server_uri }} | ||||
|       -D '{{ ldap_bind_dn }}' | ||||
|       -W '{{ ldap_bind_pw }}' | ||||
|       -n {{ schema_name }} | ||||
|       {% for at in attribute_defs %} | ||||
|       -a "{{ at }}" | ||||
|       {% endfor %} | ||||
|       {% for oc in objectclass_defs %} | ||||
|       -c "{{ oc }}" | ||||
|       {% endfor %} | ||||
|   register: opensshlpk_ldapsm | ||||
|   changed_when: "'Created schema entry' in opensshlpk_ldapsm.stdout" | ||||
|   check_mode: no | ||||
|  | ||||
| - name: Show ldapsm output for openssh-lpk | ||||
|   debug: | ||||
|     var: opensshlpk_ldapsm.stdout_lines | ||||
		Reference in New Issue
	
	Block a user