ansible/roles/ipa/server/tasks/main.yml
Michal Konecny b86cb7dd7c [ipa/server] Add ipa_host to corresponding ipa roles
Signed-off-by: Michal Konecny <mkonecny@redhat.com>
2024-11-06 18:46:41 +01:00

789 lines
21 KiB
YAML

---
# Configuration for IPA
- name: On rhel8 hosts enable the correct idm module
ansible.builtin.copy:
src: "{{ item }}"
dest: /etc/dnf/modules.d/{{ item }}
mode: "0644"
with_items:
- 389-ds.module
- idm.module
- pki-core.module
- pki-deps.module
when: ansible_distribution_major_version|int >= 8 and ansible_distribution == 'RedHat'
tags:
- ipa/server
- config
- name: Install needed packages
ansible.builtin.package:
name: "{{ item }}"
state: present
with_items:
- haveged
- ipa-server
- ipa-server-dns
- ipa-fas
tags:
- ipa/server
- packages
when: ansible_distribution_major_version|int >= 9 and ansible_distribution == 'RedHat'
# TODO: need pynag for monitoring, not yet in rhel9.
- name: Enable haveged
ansible.builtin.service:
name: haveged
state: started
enabled: yes
tags:
- ipa/server
- config
- name: Copy LDIF file for working around annoying IPA bug in initial sync
ansible.builtin.copy:
src: fix_sasl.ldif
dest: /usr/share/ipa/fix_sasl.ldif
mode: "0644"
tags:
- ipa/server
- config
- name: Install IPA
ansible.builtin.command:
argv:
- ipa-server-install
- --realm={{ ipa_realm }}
- --domain={{ ipa_realm }}
- --ds-password={{ ipa_dm_password }}
- --admin-password={{ ipa_admin_password }}
- --mkhomedir
- --no-ntp
- --unattended
- --no-ssh
- --no-sshd
- --log-file=/var/log/ipainstall.log
creates: /etc/ipa/default.conf
tags:
- ipa/server
- config
when: >
ipa_initial and ansible_distribution_major_version|int > 8 and
ansible_distribution == 'RedHat'
- name: Install IPA vault
ansible.builtin.command:
argv:
- ipa-kra-install
- --password={{ ipa_dm_password }}
- --unattended
- --log-file=/var/log/ipakrainstall.log
creates: /var/log/ipakrainstall.log
tags:
- ipa/server
- config
when: ipa_initial
- name: Create LDIF directory
ansible.builtin.file:
path: /root/ldif
state: directory
owner: root
group: root
mode: "0750"
tags:
- ipa/server
- config
- name: Copy LDIF files
ansible.builtin.copy:
src: "{{ item }}"
dest: /root/ldif/{{ item }}
mode: "0644"
with_items:
- grant_anonymous_replication_view.ldif
- grant_fas_sync.ldif
- use_id_fp_o.ldif
- replica-install.ldif
tags:
- ipa/server
- config
# During the ipa-replica-install /var/log/ipainstall.log is created
# Let's check if the file is available and prevent breaking replica
# by running ipa-replica-install more than once
- name: Check if /var/log/ipainstall.log is available
ansible.builtin.stat:
path: /var/log/ipainstall.log
register: check_replica
tags:
- ipa/server
- config
- name: Ask admin if they are OK reinstalling this ipa server replica
ansible.builtin.pause:
prompt: |
"Do you want to reinstall replica for {{ item }} (ignored for master node and any node with /var/log/ipainstall.log)? (yes/no)" # no qa yaml-length
register: confirm_replica
with_items: "{{ play_hosts }}"
tags:
- ipa/server
- config
- name: Save the confirmation results to other hosts
ansible.builtin.set_fact:
confirm_replica: "{{ item.user_input }}"
with_items: "{{ hostvars[play_hosts.0].confirm_replica.results }}"
when: item.item == inventory_hostname
tags:
- ipa/server
- config
- name: Configure replication
when:
- not ipa_initial
- not check_replica.stat.exists
- confirm_replica | default('no') | bool
tags:
- ipa/server
- config
block:
# The ipa-client-install makes the ipa-replica-install fail
# on RHEL 9 with: "Your system is partly configured."
# This will clean the previous installation and allows
# the replica to be deployed.
- name: Clean client installation
ansible.builtin.command:
argv:
- ipa-server-install
- --uninstall
- --unattended
changed_when: true
when: ansible_distribution_major_version|int >= 9
- name: Get admin ticket on ipa master
ansible.builtin.shell: set -o pipefail && echo "{{ ipa_admin_password }}" | kinit admin
delegate_to: "{{ ipa_server }}"
changed_when: false
# Replication agreement needs to be removed from ipa cluster
# before installing the replica
- name: Remove the replication agreement for the replica
ansible.builtin.command: "ipa server-del --force {{ inventory_hostname }}"
delegate_to: "{{ ipa_server }}"
changed_when: true
- name: Deploy replica
ansible.builtin.command:
argv:
- ipa-replica-install
- --setup-ca
- --admin-password={{ ipa_admin_password }}
- --no-host-dns
- --mkhomedir
- --no-ntp
- --unattended
- --no-ssh
- --no-sshd
- --skip-conncheck
- --force-join
- --log-file=/var/log/ipainstall.log
- --domain={{ ipa_realm }}
- --server={{ ipa_server }}
- --dirsrv-config-file=/root/ldif/replica-install.ldif
when: ansible_distribution_major_version|int >= 8
changed_when: true
- name: Disable rewrites
ansible.builtin.template:
src: ipa-rewrite.conf
dest: /etc/httpd/conf.d/ipa-rewrite.conf
mode: "0644"
notify:
- reload httpd
tags:
- ipa/server
- config
- name: Disable the compat tree
ansible.builtin.shell: |
set -o pipefail
echo "{{ ipa_dm_password }}" | ipa-compat-manage disable
tags:
- ipa/server
- config
register: output
changed_when: "'Disabling plugin' in output.stdout"
failed_when: "'Plugin is already disabled' not in output.stdout and output.rc != 0"
notify:
- restart ipa
- name: Disable the nis tree
ansible.builtin.shell: |
set -o pipefail
echo "{{ ipa_dm_password }}" | ipa-nis-manage disable
tags:
- ipa/server
- config
register: output
changed_when: "'Disabling plugin' in output.stdout"
failed_when: "'Plugin is already disabled' not in output.stdout and output.rc != 0"
notify:
- restart ipa
- name: Set the expiration date for the admin user
community.general.ipa_user:
name: admin
password: "{{ ipa_admin_password }}"
# Password expiration date will be a Friday 13th in 30 years. I'm sure we'll remember that.
krbpasswordexpiration: "2050-05-13 00:00:00"
update_password: on_create
ipa_pass: "{{ ipa_admin_password }}"
ipa_host: "{{ inventory_hostname }}"
tags:
- ipa/server
- config
- name: Get admin ticket
ansible.builtin.shell: |
set -o pipefail
echo "{{ ipa_admin_password }}" | kinit admin
changed_when: false
tags:
- ipa/server
- config
- krb5
# Reason for removing the next task: we don't store so much private information
# now, and we can't disallow people from seeing other people's email address on
# a case-by-case basis, it's either everyone or hand-picked services, but users
# can't choose to let other users see their info or not.
#
# - name: Disable default permissions so we don't break our privacy policy
# command:
# argv:
# - ipa
# - permission-mod
# - System: Read User Addressbook Attributes
# - --bindtype=permission
# tags:
# - ipa/server
# - config
# register: output
# changed_when: "'Modified permission' in output.stdout"
# failed_when: "'no modifications to be performed' not in output.stderr and output.rc != 0"
#
# # Because of the previous task, we must explicitely allow users to read their own data
# - name: Allow users to read their own data
# command:
# argv:
# - ipa
# - selfservice-add
# - "Users can read their own addressbook attributes"
# - --permissions=read
# - --attrs=mail
# - --attrs=userCertificate
# - --attrs=ipaCertmapData
# tags:
# - ipa/server
# - config
# register: output
# changed_when: "'Added selfservice' in output.stdout"
# failed_when: "'already exists' not in output.stderr and output.rc != 0"
# Set the default value back
- name: Restore the default permission on user addressbook attributes
ansible.builtin.command:
argv:
- ipa
- permission-mod
- "System: Read User Addressbook Attributes"
- --bindtype=all
tags:
- ipa/server
- config
register: output
changed_when: "'Modified permission' in output.stdout"
failed_when: "'no modifications to be performed' not in output.stderr and output.rc != 0"
- name: Configure password policy
community.general.ipa_pwpolicy:
minpwdlife: 0
maxpwdlife: 0
historylength: 0
minclasses: 0
minlength: 0
maxfailcount: 0
ipa_pass: "{{ ipa_admin_password }}"
ipa_host: "{{ inventory_hostname }}"
tags:
- ipa/server
- config
- name: Create fas_sync user
community.general.ipa_user:
name: fas_sync
givenname: FAS
sn: Sync
ipa_pass: "{{ ipa_admin_password }}"
ipa_host: "{{ inventory_hostname }}"
tags:
- ipa/server
- config
# Certificate generation
- name: Make a directory to store certificate profiles
ansible.builtin.file:
path: /etc/ipa/certprofiles
state: directory
mode: "0755"
tags:
- ipa/server
- config
- name: Warn admins that this is not the canonical source
ansible.builtin.copy:
dest: /etc/ipa/certprofiles/README
content: >
"This is just a dump of the server values, which are accessible with ipa certprofile-find"
mode: "0644"
tags:
- ipa/server
- config
- name: Copy the certificate profile for users
ansible.builtin.template:
src: userCerts.conf
dest: /etc/ipa/certprofiles/userCerts.conf
mode: "0644"
tags:
- ipa/server
- config
- name: Create the certificate profile
ansible.builtin.command:
argv:
- ipa
- certprofile-import
- userCerts
- --desc=Profile for user certificates
- --store=true
- --file=/etc/ipa/certprofiles/userCerts.conf
tags:
- ipa/server
- config
register: create_output
changed_when: "'already exists' not in create_output.stderr"
failed_when: "'already exists' not in create_output.stderr and create_output.rc != 0"
- name: Update the certificate profile
ansible.builtin.command:
argv:
- ipa
- certprofile-mod
- userCerts
- --desc=Profile for user certificates
- --store=true
- --file=/etc/ipa/certprofiles/userCerts.conf
tags:
- ipa/server
- config
changed_when: true
when: "ipa_initial and 'already exists' in create_output.stderr"
# Create a new ACL linking the new profile and ipausers group (that all users are members of)
- name: Create the CA ACL for the new certificate profile
ansible.builtin.command: ipa caacl-add userCerts
tags:
- ipa/server
- config
register: output
changed_when: "'already exists' not in output.stderr"
failed_when: "'already exists' not in output.stderr and output.rc != 0"
- name: Add the ipausers group to the CA ACL
ansible.builtin.command: ipa caacl-add-user userCerts --group ipausers
tags:
- ipa/server
- config
register: output
changed_when: "'is already a member' not in output.stdout"
failed_when: "'is already a member' not in output.stdout and output.rc != 0"
- name: Add the ipausers group to the CA ACL
ansible.builtin.command: ipa caacl-add-profile userCerts --certprofile userCerts
tags:
- ipa/server
- config
register: output
changed_when: "'is already a member' not in output.stdout"
failed_when: "'is already a member' not in output.stdout and output.rc != 0"
# HBAC
- name: Don't allow all users to log into all hosts
ansible.builtin.command: ipa hbacrule-disable allow_all
changed_when: true
tags:
- ipa/server
- config
register: output
# Noggin user setup
- name: Register the proper noggin admin password
ansible.builtin.set_fact:
noggin_password: >
"{{ (env == 'production') | ternary(noggin_admin_password, noggin_stg_admin_password) }}"
tags:
- ipa/server
- config
- name: Create noggin user
community.general.ipa_user:
name: noggin
givenname: Noggin
sn: User
password: >
"{{ (env == 'production') | ternary(noggin_admin_password, noggin_stg_admin_password) }}"
# Password expiration date will be a Friday 13th in 30 years. I'm sure we'll remember that.
# (if unset, IPA will assume the password is expired because it hasn't been set by the user
# themselves)
krbpasswordexpiration: "2050-05-13 00:00:00"
update_password: on_create
ipa_pass: "{{ ipa_admin_password }}"
ipa_host: "{{ inventory_hostname }}"
tags:
- ipa/server
- config
- name: Create the noggin privilege
ansible.builtin.command:
argv:
- ipa
- privilege-add
- Self-service Portal Administrators
- --desc=Noggin admin users
tags:
- ipa/server
- config
register: output
changed_when: "'already exists' not in output.stderr"
failed_when: "'already exists' not in output.stderr and output.rc != 0"
- name: Setup the noggin privilege
ansible.builtin.command:
argv:
- ipa
- privilege-add-permission
- Self-service Portal Administrators
- "--permissions=System: Modify Users"
- "--permissions=System: Change User password"
- "--permissions=System: Add Stage User"
- "--permissions=System: Read Stage Users"
- "--permissions=System: Modify Stage User"
- "--permissions=System: Modify User RDN"
- "--permissions=System: Remove Stage User"
- "--permissions=System: Add Users"
- "--permissions=System: Add User to default group"
tags:
- ipa/server
- config
register: output
changed_when: "'Number of permissions added 0' not in output.stdout"
failed_when: "'Number of permissions added 0' not in output.stdout and output.rc != 0"
- name: Create the noggin role
community.general.ipa_role:
name: "Self-service Portal Administrator"
description: "Noggin admin user"
privilege:
- "Self-service Portal Administrators"
user:
- noggin
ipa_host: "{{ inventory_hostname }}"
ipa_user: admin
ipa_pass: "{{ ipa_admin_password }}"
validate_certs: no
tags:
- ipa/server
- config
# User selfservice permissions
- name: Setup the selfservice permission for passwords
# When ansible-freeipa is upgraded, we'll get ipaselfservice
# ipaselfservice:
# ipaadmin_password: "{{ipa_admin_password}}"
# name: "Users can modify their own password"
# permission: write
# attribute:
# - userPassword
# - krbPrincipalKey
# - sambaLMPassword
# - sambaNTPassword
ansible.builtin.command:
argv:
- ipa
- selfservice-add
- "Users can modify their own password"
- --permissions=write
- --attrs=userPassword
- --attrs=krbPrincipalKey
- --attrs=sambaLMPassword
- --attrs=sambaNTPassword
register: output
changed_when: "'Added selfservice' in output.stdout"
failed_when: "'already exists' not in output.stderr and output.rc != 0"
tags:
- ipa/server
- config
- name: Setup the selfservice permission for addressbook attributes
# When ansible-freeipa is upgraded, we'll get ipaselfservice
# ipaselfservice:
# ipaadmin_password: "{{ipa_admin_password}}"
# name: "User Self service"
# permission: write
# attribute:
# - givenname
# - sn
# - cn
# - displayname
# - gecos
ansible.builtin.command:
argv:
- ipa
- selfservice-add
- "User Self service"
- --permissions=write
- --attrs=givenName
- --attrs=sn
- --attrs=cn
- --attrs=displayName
- --attrs=gecos
register: output
changed_when: "'Added selfservice' in output.stdout"
failed_when: "'already exists' not in output.stderr and output.rc != 0"
tags:
- ipa/server
- config
# Let people in the sysadmin-main group manage registering users (Stage Users)
# through Noggin:
- name: Create the stage users managers privilege
ansible.builtin.command:
argv:
- ipa
- privilege-add
- Stage User Managers
- --desc=Manage registering users in Noggin
tags:
- ipa/server
- config
register: output
changed_when: "'already exists' not in output.stderr"
failed_when: "'already exists' not in output.stderr and output.rc != 0"
- name: Setup the stage users managers privilege
ansible.builtin.command:
argv:
- ipa
- privilege-add-permission
- Stage User Managers
- "--permissions=System: Read Stage Users"
- "--permissions=System: Modify Stage User"
- "--permissions=System: Remove Stage User"
tags:
- ipa/server
- config
register: output
changed_when: "'Number of permissions added 0' not in output.stdout"
failed_when: "'Number of permissions added 0' not in output.stdout and output.rc != 0"
- name: Create the stage users managers role
community.general.ipa_role:
name: "Stage User Managers"
description: "Manage registering users in Noggin"
privilege:
- "Stage User Managers"
group:
- sysadmin-main
ipa_host: "{{ inventory_hostname }}"
ipa_user: admin
ipa_pass: "{{ ipa_admin_password }}"
validate_certs: no
tags:
- ipa/server
- config
# Add the missing topology segments that are missed during replication
# Ignore any failure as that means that segment is already in place
- name: Add the missing segments for ca suffix
ansible.builtin.command:
argv:
- ipa
- topologysegment-add
- "--leftnode={{ inventory_hostname }}"
- "--rightnode={{ item }}"
- "ca"
- "{{ inventory_hostname + '-' + item }}"
with_items: "{{ (env == 'production') | ternary(groups['ipa'], groups['ipa_stg']) }}"
ignore_errors: true # noqa ignore-errors
register: output
changed_when: "'Segment already exists' not in output.stdout"
tags:
- ipa/server
- config
# Add the missing topology segments that are missed during replication
# Ignore any failure as that means that segment is already in place
- name: Add the missing segments for domain suffix
ansible.builtin.command:
argv:
- ipa
- topologysegment-add
- "--leftnode={{ inventory_hostname }}"
- "--rightnode={{ item }}"
- "domain"
- "{{ inventory_hostname + '-' + item }}"
with_items: "{{ (env == 'production') | ternary(groups['ipa'], groups['ipa_stg']) }}"
ignore_errors: true # noqa ignore-errors
register: output
changed_when: "'Segment already exists' not in output.stdout"
tags:
- ipa/server
- config
- name: Destroy admin ticket
ansible.builtin.command: kdestroy -A
changed_when: true
tags:
- ipa/server
- config
- krb5
- name: Copy the new krb5 logrotate config
ansible.builtin.copy:
src: logrotate_krb5kdc
dest: /etc/logrotate.d/krb5kdc
mode: '0644'
backup: yes
- name: Include script.yml
ansible.builtin.import_tasks: scripts.yml
# User groups
- name: Set the members of the admin group
community.general.ipa_group:
name: admins
user:
- admin
- fas_sync
- arrfab
ipa_host: "{{ inventory_hostname }}"
ipa_user: admin
ipa_pass: "{{ ipa_admin_password }}"
validate_certs: no
tags:
- ipa/server
- config
- name: Create the sysadmin-main group
community.general.ipa_group:
ipa_pass: "{{ ipa_admin_password }}"
name: sysadmin-main
description: Fedora Main Sysadmin Group
ipa_host: "{{ inventory_hostname }}"
tags:
- ipa/server
- config
# This is a special one, in that it needs to apply on each master since it's non-replicated.
- name: Grant access to replication status
ansible.builtin.command:
argv:
- ldapmodify
- -Y EXTERNAL
- -H {{ ipa_ldap_socket }}
- -f /root/ldif/{{ item }}
with_items:
- grant_anonymous_replication_view.ldif
- grant_fas_sync.ldif
- use_id_fp_o.ldif
tags:
- ipa/server
- config
register: grant_repl_status_output
changed_when: "'Type or value exists' not in grant_repl_status_output.stderr"
failed_when: |
"'Type or value exists' not in grant_repl_status_output.stderr and
'modifying entry' not in grant_repl_status_output.stdout"
# Make some httpd changes
- name: Configure referer override
ansible.builtin.template:
src: referer-override.conf
dest: /etc/httpd/conf.d/referer-override.conf
mode: "0644"
notify:
- reload apache
tags:
- ipa/server
- config
- name: Update xmlrpc_uri
ansible.builtin.lineinfile:
dest: /etc/ipa/default.conf
regexp: 'xmlrpc_uri ='
line: 'xmlrpc_uri = https://{{ inventory_hostname }}/ipa/xml'
tags:
- ipa/server
- config
# The httpd service should not be started with systemd, the ipa service will
# start it. If systemd starts it, it will run before IPA is available and
# KdcProxy will be disabled because it can't reach LDAP.
- name: Disable the httpd service
ansible.builtin.service:
name: httpd
enabled: no
tags:
- ipa/server
- config
- name: Set cron for daily data only backups
ansible.builtin.copy:
src: data-only-backup.sh
dest: "/etc/cron.daily/data-only-backup.sh"
mode: "0755"
tags:
- ipa/server
- config
- name: Copy sweeper script to /usr/local/bin/
ansible.builtin.copy:
src: sweeper.py
dest: /usr/local/bin/sweeper
mode: "0755"
tags:
- ipa/server
- config
- name: Set sweeper script on a cron schedule
ansible.builtin.cron:
name: "clean up mod_auth_gssapi tokens"
hour: "3"
minute: "0"
user: root
job: "/usr/local/bin/sweeper -g /run/ipa/ccaches/ > /dev/null"
tags:
- ipa/server
- config