diff -up ansible-freeipa-1.6.3/playbooks/config/change-ipa-domain-netbios-name.yml.ipaconfig_sid ansible-freeipa-1.6.3/playbooks/config/change-ipa-domain-netbios-name.yml --- ansible-freeipa-1.6.3/playbooks/config/change-ipa-domain-netbios-name.yml.ipaconfig_sid 2022-10-07 17:12:51.172335899 +0200 +++ ansible-freeipa-1.6.3/playbooks/config/change-ipa-domain-netbios-name.yml 2022-10-07 17:12:51.172335899 +0200 @@ -0,0 +1,12 @@ +--- +- name: Playbook to change IPA domain netbios name + hosts: ipaserver + become: no + gather_facts: no + + tasks: + - name: Set IPA domain netbios name + ipaconfig: + ipaadmin_password: SomeADMINpassword + enable_sid: yes + netbios_name: IPADOM diff -up ansible-freeipa-1.6.3/playbooks/config/generate-users-groups-sids.yml.ipaconfig_sid ansible-freeipa-1.6.3/playbooks/config/generate-users-groups-sids.yml --- ansible-freeipa-1.6.3/playbooks/config/generate-users-groups-sids.yml.ipaconfig_sid 2022-10-07 17:12:51.172335899 +0200 +++ ansible-freeipa-1.6.3/playbooks/config/generate-users-groups-sids.yml 2022-10-07 17:12:51.172335899 +0200 @@ -0,0 +1,12 @@ +--- +- name: Playbook to ensure SIDs are enabled and users and groups have SIDs + hosts: ipaserver + become: no + gather_facts: no + + tasks: + - name: Enable SID and generate users and groups SIDS + ipaconfig: + ipaadmin_password: SomeADMINpassword + enable_sid: yes + add_sids: yes diff -up ansible-freeipa-1.6.3/plugins/modules/ipaconfig.py.ipaconfig_sid ansible-freeipa-1.6.3/plugins/modules/ipaconfig.py --- ansible-freeipa-1.6.3/plugins/modules/ipaconfig.py.ipaconfig_sid 2022-01-27 14:05:04.000000000 +0100 +++ ansible-freeipa-1.6.3/plugins/modules/ipaconfig.py 2022-10-07 17:18:43.193785596 +0200 @@ -148,6 +148,24 @@ options: required: false type: list aliases: ["ipadomainresolutionorder"] + enable_sid: + description: > + New users and groups automatically get a SID assigned. + Requires IPA 4.9.8+. + required: false + type: bool + netbios_name: + description: > + NetBIOS name of the IPA domain. + Requires IPA 4.9.8+ and 'enable_sid: yes'. + required: false + type: string + add_sids: + description: > + Add SIDs for existing users and groups. + Requires IPA 4.9.8+ and 'enable_sid: yes'. + required: false + type: bool ''' EXAMPLES = ''' @@ -169,6 +187,24 @@ EXAMPLES = ''' ipaadmin_password: SomeADMINpassword defaultshell: /bin/bash maxusername: 64 + +- name: Playbook to enable SID and generate users and groups SIDs + hosts: ipaserver + tasks: + - name: Enable SID and generate users and groups SIDS + ipaconfig: + ipaadmin_password: SomeADMINpassword + enable_sid: yes + add_sids: yes + +- name: Playbook to change IPA domain netbios name + hosts: ipaserver + tasks: + - name: Enable SID and generate users and groups SIDS + ipaconfig: + ipaadmin_password: SomeADMINpassword + enable_sid: yes + netbios_name: IPADOM ''' RETURN = ''' @@ -247,6 +283,14 @@ config: domain_resolution_order: description: list of domains used for short name qualification returned: always + enable_sid: + description: > + new users and groups automatically get a SID assigned. + Requires IPA 4.9.8+. + returned: always + netbios_name: + description: NetBIOS name of the IPA domain. Requires IPA 4.9.8+. + returned: if enable_sid is True ''' @@ -260,6 +304,28 @@ def config_show(module): return _result["result"] +def get_netbios_name(module): + try: + _result = module.ipa_command_no_name("trustconfig_show", {"all": True}) + except Exception: # pylint: disable=broad-except + return None + else: + return _result["result"]["ipantflatname"][0] + + +def is_enable_sid(module): + """When 'enable-sid' is true admin user and admins group have SID set.""" + _result = module.ipa_command("user_show", "admin", {"all": True}) + sid = _result["result"].get("ipantsecurityidentifier", [""]) + if not sid[0].endswith("-500"): + return False + _result = module.ipa_command("group_show", "admins", {"all": True}) + sid = _result["result"].get("ipantsecurityidentifier", [""]) + if not sid[0].endswith("-512"): + return False + return True + + def main(): ansible_module = IPAAnsibleModule( argument_spec=dict( @@ -313,7 +379,10 @@ def main(): aliases=["ipauserauthtype"]), ca_renewal_master_server=dict(type="str", required=False), domain_resolution_order=dict(type="list", required=False, - aliases=["ipadomainresolutionorder"]) + aliases=["ipadomainresolutionorder"]), + enable_sid=dict(type="bool", required=False), + add_sids=dict(type="bool", required=False), + netbios_name=dict(type="str", required=False), ), supports_check_mode=True, ) @@ -344,7 +413,10 @@ def main(): "pac_type": "ipakrbauthzdata", "user_auth_type": "ipauserauthtype", "ca_renewal_master_server": "ca_renewal_master_server", - "domain_resolution_order": "ipadomainresolutionorder" + "domain_resolution_order": "ipadomainresolutionorder", + "enable_sid": "enable_sid", + "netbios_name": "netbios_name", + "add_sids": "add_sids", } reverse_field_map = {v: k for k, v in field_map.items()} @@ -392,11 +464,47 @@ def main(): changed = False exit_args = {} - # Connect to IPA API - with ansible_module.ipa_connect(): + # Connect to IPA API (enable-sid requires context == 'client') + with ansible_module.ipa_connect(context="client"): + has_enable_sid = ansible_module.ipa_command_param_exists( + "config_mod", "enable_sid") result = config_show(ansible_module) + if params: + netbios_name = params.get("netbios_name") + if netbios_name: + netbios_name = netbios_name.upper() + add_sids = params.get("add_sids") + enable_sid = params.get("enable_sid") + required_sid = any([netbios_name, add_sids]) + if required_sid and not enable_sid: + ansible_module.fail_json( + "'enable-sid: yes' required for 'netbios_name' " + "and 'add-sids'." + ) + if enable_sid: + if not has_enable_sid: + ansible_module.fail_json( + "This version of IPA does not support 'enable-sid'.") + if ( + netbios_name + and netbios_name == get_netbios_name(ansible_module) + ): + del params["netbios_name"] + netbios_name = None + if not add_sids and "add_sids" in params: + del params["add_sids"] + if ( + not any([netbios_name, add_sids]) + and is_enable_sid(ansible_module) + ): + del params["enable_sid"] + else: + for param in ["enable_sid", "netbios_name", "add_sids"]: + if param in params: + del params[params] + params = { k: v for k, v in params.items() if k not in result or result[k] != v @@ -441,6 +549,10 @@ def main(): raise ValueError( "Unexpected attribute type: %s" % arg_type) exit_args[k] = type_map[arg_type](value) + # Set enable_sid + if has_enable_sid: + exit_args["enable_sid"] = is_enable_sid(ansible_module) + exit_args["netbios_name"] = get_netbios_name(ansible_module) # Done ansible_module.exit_json(changed=changed, config=exit_args) diff -up ansible-freeipa-1.6.3/README-config.md.ipaconfig_sid ansible-freeipa-1.6.3/README-config.md --- ansible-freeipa-1.6.3/README-config.md.ipaconfig_sid 2022-01-27 14:05:04.000000000 +0100 +++ ansible-freeipa-1.6.3/README-config.md 2022-10-07 17:12:51.172335899 +0200 @@ -65,6 +65,9 @@ Example playbook to read config options: maxusername: 64 ``` + +Example playbook to set global configuration options: + ```yaml --- - name: Playbook to ensure some config options are set @@ -79,6 +82,40 @@ Example playbook to read config options: ``` +Example playbook to enable SID and generate users and groups SIDs: + +```yaml +--- +- name: Playbook to ensure SIDs are enabled and users and groups have SIDs + hosts: ipaserver + become: no + gather_facts: no + + tasks: + - name: Enable SID and generate users and groups SIDS + ipaconfig: + ipaadmin_password: SomeADMINpassword + enable_sid: yes + add_sids: yes +``` + +Example playbook to change IPA domain NetBIOS name: + +```yaml +--- +- name: Playbook to change IPA domain netbios name + hosts: ipaserver + become: no + gather_facts: no + + tasks: + - name: Set IPA domain netbios name + ipaconfig: + ipaadmin_password: SomeADMINpassword + enable_sid: yes + netbios_name: IPADOM +``` + Variables ========= @@ -111,6 +148,9 @@ Variable | Description | Required `user_auth_type` \| `ipauserauthtype` | set default types of supported user authentication (choices: `password`, `radius`, `otp`, `disabled`). Use `""` to clear this variable. | no `domain_resolution_order` \| `ipadomainresolutionorder` | Set list of domains used for short name qualification | no `ca_renewal_master_server` \| `ipacarenewalmasterserver`| Renewal master for IPA certificate authority. | no +`enable_sid` | New users and groups automatically get a SID assigned. Requires IPA 4.9.8+. (bool) | no +`netbios_name` | NetBIOS name of the IPA domain. Requires IPA 4.9.8+ and 'enable_sid: yes'. | no +`add_sids` | Add SIDs for existing users and groups. Requires IPA 4.9.8+ and 'enable_sid: yes'. (bool) | no Return Values @@ -140,6 +180,8 @@ Variable | Description | Returned When   | `user_auth_type` |     | `domain_resolution_order` |     | `ca_renewal_master_server` |   +  | `enable_sid` |   +  | `netbios_name` |   All returned fields take the same form as their namesake input parameters diff -up ansible-freeipa-1.6.3/tests/config/test_config_sid.yml.ipaconfig_sid ansible-freeipa-1.6.3/tests/config/test_config_sid.yml --- ansible-freeipa-1.6.3/tests/config/test_config_sid.yml.ipaconfig_sid 2022-10-07 17:12:51.172335899 +0200 +++ ansible-freeipa-1.6.3/tests/config/test_config_sid.yml 2022-10-07 17:12:51.172335899 +0200 @@ -0,0 +1,70 @@ +--- +- name: Test config + hosts: "{{ ipa_test_host | default('ipaserver') }}" + become: no + gather_facts: no + + tasks: + + # GET CURRENT CONFIG + + - name: Return current values of the global configuration options + ipaconfig: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + register: previous + + # TESTS + - block: + - name: Ensure SID is enabled. + ipaconfig: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + enable_sid: yes + register: result + failed_when: result.failed or previous.config.enable_sid == result.changed + + - name: Ensure SID is enabled, again. + ipaconfig: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + enable_sid: yes + register: result + failed_when: result.failed or result.changed + + - name: Ensure netbios_name is "IPATESTPLAY" + ipaconfig: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + enable_sid: yes + netbios_name: IPATESTPLAY + register: result + failed_when: result.failed or not result.changed + + - name: Ensure netbios_name is "IPATESTPLAY", again + ipaconfig: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + enable_sid: yes + netbios_name: IPATESTPLAY + register: result + failed_when: result.failed or result.changed + + # add_sids is not idempotent as it always tries to generate the missing + # SIDs for users and groups. + - name: Add SIDs to users and groups. + ipaconfig: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + enable_sid: yes + add_sids: yes + + # REVERT TO PREVIOUS CONFIG + always: + # Once SID is enabled, it cannot be reverted. + - name: Revert netbios_name to original configuration + ipaconfig: + ipaadmin_password: SomeADMINpassword + ipaapi_context: "{{ ipa_context | default(omit) }}" + netbios_name: "{{ previous.config.netbios_name | default(omit) }}" + enable_sid: yes