mirror of
https://github.com/freeipa/ansible-freeipa.git
synced 2026-03-27 13:53:06 +00:00
Compare commits
198 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
433d1096f8 | ||
|
|
6a2d007b41 | ||
|
|
b0f58ef3a8 | ||
|
|
3c8d6c7c7a | ||
|
|
3b28050f1e | ||
|
|
2973c80975 | ||
|
|
0f8f55dfd9 | ||
|
|
777f25d91c | ||
|
|
727861cb85 | ||
|
|
e6da214bfb | ||
|
|
68a99ba5f9 | ||
|
|
d936a3794e | ||
|
|
bb0ba1ef2c | ||
|
|
1eb83548fa | ||
|
|
5d7afb5f85 | ||
|
|
f7c45c4f46 | ||
|
|
38a4bf804f | ||
|
|
7077776de3 | ||
|
|
2514158498 | ||
|
|
c6cc4df77b | ||
|
|
b3ee4f9bed | ||
|
|
401d5d5acc | ||
|
|
b971c6c5eb | ||
|
|
de8911af50 | ||
|
|
7e6e6c2dc2 | ||
|
|
668d89cdb2 | ||
|
|
0c1d4efc03 | ||
|
|
eefe91b852 | ||
|
|
bed8bf6661 | ||
|
|
577aeea3f3 | ||
|
|
4775ad9a53 | ||
|
|
81143be96a | ||
|
|
7debaa23ac | ||
|
|
e05dc41e0f | ||
|
|
8bab7d365b | ||
|
|
018337a19b | ||
|
|
bb08884221 | ||
|
|
abef329b8a | ||
|
|
3216f8df37 | ||
|
|
edccf70bf6 | ||
|
|
fd79f95f9b | ||
|
|
e2fcd7767e | ||
|
|
5a14f78d44 | ||
|
|
a3a7ecd817 | ||
|
|
63f016226c | ||
|
|
a58f61792b | ||
|
|
641c550cc3 | ||
|
|
c251632368 | ||
|
|
452d20e28d | ||
|
|
c7699472a6 | ||
|
|
eba457d5ff | ||
|
|
809e423947 | ||
|
|
e5f0ab2fe4 | ||
|
|
f85c60676c | ||
|
|
f9bf0cfec0 | ||
|
|
8f0d983845 | ||
|
|
aed5edae33 | ||
|
|
889b2a5576 | ||
|
|
e9d637c57a | ||
|
|
b3a97eacec | ||
|
|
aa745100e3 | ||
|
|
23faa83a0b | ||
|
|
12729fc2c0 | ||
|
|
31810ad7c0 | ||
|
|
9dcff9a308 | ||
|
|
e500c133c0 | ||
|
|
a5306b2db5 | ||
|
|
8ab3aa06ff | ||
|
|
87ff15a92c | ||
|
|
c8d5cb7ee2 | ||
|
|
2fa4aa60b1 | ||
|
|
4332636fd2 | ||
|
|
266f79b55f | ||
|
|
07b056ad25 | ||
|
|
7db5d59de1 | ||
|
|
e19e16c734 | ||
|
|
0ff119a2a8 | ||
|
|
90f6e14c40 | ||
|
|
e044310dad | ||
|
|
4be7a9fba0 | ||
|
|
98959807d2 | ||
|
|
a16379cfa0 | ||
|
|
672413f4dd | ||
|
|
8af4329fac | ||
|
|
9932b1dc98 | ||
|
|
1c44898e68 | ||
|
|
f44dc55b90 | ||
|
|
65b106449e | ||
|
|
7501c84844 | ||
|
|
d45e6ac399 | ||
|
|
d990832681 | ||
|
|
b998597815 | ||
|
|
d51ee9dc69 | ||
|
|
fdfea1b6fb | ||
|
|
ac92ed1408 | ||
|
|
757b89dfae | ||
|
|
914e4879f8 | ||
|
|
13cff6354b | ||
|
|
4ff5aaa172 | ||
|
|
d82abdbef9 | ||
|
|
5aa80204d5 | ||
|
|
8b8cbdd8c2 | ||
|
|
a06b16f5bc | ||
|
|
dc99b821eb | ||
|
|
796f84357a | ||
|
|
9e6c79abbb | ||
|
|
d3af87c731 | ||
|
|
7011283335 | ||
|
|
0297cbe973 | ||
|
|
1ec0d1e640 | ||
|
|
ba3fe74b60 | ||
|
|
b9151f3069 | ||
|
|
6085fbf77d | ||
|
|
603bd61845 | ||
|
|
1a31f62a6f | ||
|
|
23e07a9a17 | ||
|
|
bd084ad37b | ||
|
|
099eb96b58 | ||
|
|
1276e38895 | ||
|
|
2fa9ed9127 | ||
|
|
766cf5a285 | ||
|
|
3ea452ef6f | ||
|
|
50b16cb33f | ||
|
|
9b0558a953 | ||
|
|
6124dc0cf1 | ||
|
|
423a6b0e12 | ||
|
|
a83bab9425 | ||
|
|
70f4b7d646 | ||
|
|
f2865efb1a | ||
|
|
ce143bad52 | ||
|
|
928fdf4b2d | ||
|
|
0d95b8ebcb | ||
|
|
0efe2c30d2 | ||
|
|
10e9c30af6 | ||
|
|
f770b5d581 | ||
|
|
9b020a56f3 | ||
|
|
09a0077b77 | ||
|
|
3779698e0a | ||
|
|
65adc7860e | ||
|
|
df87ff464a | ||
|
|
4b8358b897 | ||
|
|
68661d6922 | ||
|
|
461bd8b15b | ||
|
|
ef0e368741 | ||
|
|
f0a71eda84 | ||
|
|
d0402d7905 | ||
|
|
eebfdbca7a | ||
|
|
e30bcfd876 | ||
|
|
abf0cc3251 | ||
|
|
9decad4e4f | ||
|
|
03098c218d | ||
|
|
d05ad6b1f2 | ||
|
|
9981e5f84b | ||
|
|
4df2cab42a | ||
|
|
5d6324e2da | ||
|
|
8772379dcc | ||
|
|
29badaecca | ||
|
|
e88aaaf95a | ||
|
|
b54333358d | ||
|
|
c16ceac892 | ||
|
|
d303a81e4c | ||
|
|
d561d8f372 | ||
|
|
33c571ebb6 | ||
|
|
81d1896f0f | ||
|
|
75f5082ad0 | ||
|
|
a05eed6a4b | ||
|
|
cddb861fd9 | ||
|
|
15d3123ed3 | ||
|
|
7a1bf986a8 | ||
|
|
c89f6624b5 | ||
|
|
998a141482 | ||
|
|
d111f0d92b | ||
|
|
5ab9ae21ad | ||
|
|
3c130795e3 | ||
|
|
954c911a85 | ||
|
|
e681f25e5c | ||
|
|
8010d19be9 | ||
|
|
892cb037eb | ||
|
|
40d4150590 | ||
|
|
bc72bbd92e | ||
|
|
ae9c81139b | ||
|
|
d5fdaaf444 | ||
|
|
fdd4b19b18 | ||
|
|
dc62744f6a | ||
|
|
2af7602a8c | ||
|
|
1b74cf1692 | ||
|
|
19fc21cd1b | ||
|
|
804e633f13 | ||
|
|
ad37bed37b | ||
|
|
b00dc5daa5 | ||
|
|
2c278ab39d | ||
|
|
ef2adf54b4 | ||
|
|
a61c046abe | ||
|
|
1fee891aa4 | ||
|
|
1aca0c1304 | ||
|
|
60fd87c567 | ||
|
|
4aab1599bd | ||
|
|
0c36194038 |
@@ -10,10 +10,14 @@ exclude_paths:
|
||||
- molecule/
|
||||
- tests/azure/
|
||||
- meta/runtime.yml
|
||||
- requirements-docker.yml
|
||||
- requirements-podman.yml
|
||||
|
||||
kinds:
|
||||
- playbook: '**/tests/**/test_*.yml'
|
||||
- playbook: '**/playbooks/**/*.yml'
|
||||
- tasks: '**/tasks_*.yml'
|
||||
- tasks: '**/env_*.yml'
|
||||
|
||||
parseable: true
|
||||
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -68,7 +68,7 @@ jobs:
|
||||
python-version: "3.x"
|
||||
- name: Run pylint
|
||||
run: |
|
||||
pip install pylint==2.10.2
|
||||
pip install pylint==2.12.2
|
||||
pylint plugins roles --disable=import-error
|
||||
|
||||
shellcheck:
|
||||
|
||||
@@ -24,7 +24,7 @@ repos:
|
||||
hooks:
|
||||
- id: pydocstyle
|
||||
- repo: https://github.com/pycqa/pylint
|
||||
rev: v2.10.2
|
||||
rev: v2.12.2
|
||||
hooks:
|
||||
- id: pylint
|
||||
args:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ Variable | Description | Required
|
||||
`forwarders` | The list of forwarders dicts. Each `forwarders` dict entry has:| no
|
||||
| `ip_address` - The IPv4 or IPv6 address of the DNS server. | yes
|
||||
| `port` - The custom port that should be used on this server. | no
|
||||
`forward_policy` | The global forwarding policy. It can be one of `only`, `first`, or `none`. | no
|
||||
`forward_policy` \| `forwardpolicy` | The global forwarding policy. It can be one of `only`, `first`, or `none`. | no
|
||||
`allow_sync_ptr` | Allow synchronization of forward (A, AAAA) and reverse (PTR) records (bool). | yes
|
||||
`action` | Work on dnsconfig or member level. It can be one of `member` or `dnsconfig` and defaults to `dnsconfig`. Only `forwarders` can be managed with `action: member`. | no
|
||||
`state` | The state to ensure. It can be one of `present` or `absent`, default: `present`. `absent` can only be used with `action: member` and `forwarders`. | yes
|
||||
|
||||
@@ -110,7 +110,7 @@ Variable | Description | Required
|
||||
`forwarders` \| `idnsforwarders` | Per-zone forwarders. A custom port can be specified for each forwarder. Options | no
|
||||
| `ip_address`: The forwarder IP address. | yes
|
||||
| `port`: The forwarder IP port. | no
|
||||
`forwardpolicy` \| `idnsforwardpolicy` | Per-zone conditional forwarding policy. Possible values are `only`, `first`, `none`. Set to "none" to disable forwarding to global forwarder for this zone. In that case, conditional zone forwarders are disregarded. | no
|
||||
`forwardpolicy` \| `idnsforwardpolicy` \| `forward_policy` | Per-zone conditional forwarding policy. Possible values are `only`, `first`, `none`. Set to "none" to disable forwarding to global forwarder for this zone. In that case, conditional zone forwarders are disregarded. | no
|
||||
`skip_overlap_check` | Force DNS zone creation even if it will overlap with an existing zone. Defaults to False. | no
|
||||
`permission` | Allow DNS Forward Zone to be managed. (bool) | no
|
||||
`action` | Work on group or member level. It can be on of `member` or `dnsforwardzone` and defaults to `dnsforwardzone`. | no
|
||||
|
||||
@@ -100,7 +100,7 @@ Example playbook to add group members to a group:
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
# Add group members sysops and appops to group sysops
|
||||
# Add group members sysops and appops to group ops
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: ops
|
||||
@@ -166,6 +166,7 @@ Variable | Description | Required
|
||||
`membermanager_user` | List of member manager users assigned to this group. Only usable with IPA versions 4.8.4 and up. | no
|
||||
`membermanager_group` | List of member manager groups assigned to this group. Only usable with IPA versions 4.8.4 and up. | no
|
||||
`externalmember` \| `ipaexternalmember` \| `external_member`| List of members of a trusted domain in DOM\\name or name@domain form. | no
|
||||
`idoverrideuser` | List of user ID overrides to manage. Only usable with IPA versions 4.8.7 and up.| no
|
||||
`action` | Work on group or member level. It can be on of `member` or `group` and defaults to `group`. | no
|
||||
`state` | The state to ensure. It can be one of `present` or `absent`, default: `present`. | yes
|
||||
|
||||
|
||||
196
README-idrange.md
Normal file
196
README-idrange.md
Normal file
@@ -0,0 +1,196 @@
|
||||
Idrange module
|
||||
============
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The idrange module allows the management of ID ranges.
|
||||
|
||||
In general it is not necessary to modify or delete ID ranges. If there is no other way to achieve a certain configuration than to modify or delete an ID range it should be done with great care. Because UIDs are stored in the file system and are used for access control it might be possible that users are allowed to access files of other users if an ID range got deleted and reused for a different domain.
|
||||
|
||||
|
||||
Use cases
|
||||
---------
|
||||
|
||||
* Add an ID range from a transitively trusted domain
|
||||
|
||||
If the trusted domain (A) trusts another domain (B) as well and this trust is transitive 'ipa trust-add domain-A' will only create a range for domain A. The ID range for domain B must be added manually.
|
||||
|
||||
* Add an additional ID range for the local domain
|
||||
|
||||
If the ID range of the local domain is exhausted, i.e. no new IDs can be assigned to Posix users or groups by the DNA plugin, a new range has to be created to allow new users and groups to be added. (Currently there is no connection between this range CLI and the DNA plugin, but a future version might be able to modify the configuration of the DNS plugin as well).
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* ID Range management
|
||||
|
||||
|
||||
Supported FreeIPA Versions
|
||||
--------------------------
|
||||
|
||||
FreeIPA versions 4.4.0 and up are supported by the ipaidrange module.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
**Controller**
|
||||
* Ansible version: 2.8+
|
||||
|
||||
**Node**
|
||||
* Supported FreeIPA version (see above)
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Example inventory file
|
||||
|
||||
```ini
|
||||
[ipaserver]
|
||||
ipaserver.test.local
|
||||
```
|
||||
|
||||
Example playbook to ensure a local domain idrange is present:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA idrange.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure an ID Range for the local domain is present.
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: local_domain_id_range
|
||||
base_id: 150000
|
||||
range_size: 200000
|
||||
```
|
||||
|
||||
Example playbook to ensure a local domain idrange is present, with RID and secondary RID base values:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA idrange.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure local idrange is present
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: local_domain_id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
rid_base: 1000000
|
||||
secondary_rid_base: 200000000
|
||||
```
|
||||
|
||||
Example playbook to ensure an AD-trust idrange is present, with range type 'trust-ad' and using domain SID:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA idrange.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure AD-trust idrange is present
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: ad_id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
idrange_type: ipa-ad-trust
|
||||
dom_sid: S-1-5-21-2870384104-3340008087-3140804251
|
||||
```
|
||||
|
||||
Example playbook to ensure an AD-trust idrange is present, with range type 'trust-ad-posix' and using domain SID:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA idrange.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure AD-trust idrange is present
|
||||
ipaidrange:
|
||||
name: ad_posix_id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
idrange_type: ipa-ad-trust-posix
|
||||
dom_name: ad.ipa.test
|
||||
```
|
||||
|
||||
Example playbook to ensure an AD-trust idrange has auto creation of groups set to 'hybrid':
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA idrange.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Modify AD-trust idrange 'auto_private_groups'
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: "{{ ipa_context | default(omit) }}"
|
||||
name: ad_id_range
|
||||
auto_private_groups: "hybrid"
|
||||
```
|
||||
|
||||
Example playbook to make sure an idrange is absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA idrange.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure ID range 'ad_id_range' is absent.
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: ad_id_range
|
||||
state: absent
|
||||
```
|
||||
|
||||
|
||||
Variables
|
||||
---------
|
||||
|
||||
Variable | Description | Required
|
||||
-------- | ----------- | --------
|
||||
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
|
||||
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
|
||||
`ipaapi_context` | The context in which the module will execute. Executing in a server context is preferred. If not provided context will be determined by the execution environment. Valid values are `server` and `client`. | no
|
||||
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no
|
||||
`name` \| `cn` | The list of idrange name strings. | yes
|
||||
`base_id` \| `ipabaseid` | First Posix ID of the range. (int) | yes, if `state: present`
|
||||
`range_size` \| `ipaidrangesize` | Number of IDs in the range. (int) | yes, if `state: present`
|
||||
`rid_base` \| `ipabaserid` | First RID of the corresponding RID range. (int) | no
|
||||
`secondary_rid_base` \| `ipasecondarybaserid` | First RID of the secondary RID range. (int) | no
|
||||
`dom_sid` \| `ipanttrusteddomainsid` | Domain SID of the trusted domain. | no
|
||||
`idrange_type` \| `iparangetype` | ID range type, one of `ipa-ad-trust`, `ipa-ad-trust-posix`, `ipa-local`. Only valid if idrange does not exist. | no
|
||||
`dom_name` \| `ipanttrusteddomainname` | Name of the trusted domain. Can only be used when `ipaapi_context: server`. | no
|
||||
`auto_private_groups` \| `ipaautoprivategroups` | Auto creation of private groups, one of `true`, `false`, `hybrid`. | no
|
||||
`delete_continue` \| `continue` | Continuous mode: don't stop on errors. Valid only if `state` is `absent`. Default: `no` (bool) | no
|
||||
`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no
|
||||
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
DNA plugin in 389-ds will allocate IDs based on the ranges configured for the local domain. Currently the DNA plugin *cannot* be reconfigured itself based on the local ranges set via this family of commands.
|
||||
|
||||
Manual configuration change has to be done in the DNA plugin configuration for the new local range. Specifically, The dnaNextRange attribute of 'cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' has to be modified to match the new range.
|
||||
|
||||
|
||||
Authors
|
||||
=======
|
||||
|
||||
Rafael Guterres Jeffman
|
||||
@@ -293,8 +293,8 @@ Variable | Description | Required
|
||||
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no
|
||||
`name` \| `service` | The list of service name strings. | yes
|
||||
`certificate` \| `usercertificate` | Base-64 encoded service certificate. | no
|
||||
`pac_type` \| `ipakrbauthzdata` | Supported PAC type. It can be one of `MS-PAC`, `PAD`, or `NONE`. | no
|
||||
`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. It can be any of `otp`, `radius`, `pkinit`, or `hardened`. | no
|
||||
`pac_type` \| `ipakrbauthzdata` | Supported PAC type. It can be one of `MS-PAC`, `PAD`, or `NONE`. Use empty string to reset pac_type to the initial value. | no
|
||||
`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. It can be any of `otp`, `radius`, `pkinit` or `hardened`. Use empty string to reset auth_ind to the initial value. | no
|
||||
`requires_pre_auth` \| `ipakrbrequirespreauth` | Pre-authentication is required for the service. Default to true. (bool) | no
|
||||
`ok_as_delegate` \| `ipakrbokasdelegate` | Client credentials may be delegated to the service. Default to false. (bool) | no
|
||||
`ok_to_auth_as_delegate` \| `ipakrboktoauthasdelegate` | The service is allowed to authenticate on behalf of a client. Default to false. (bool) | no
|
||||
|
||||
172
README-servicedelegationrule.md
Normal file
172
README-servicedelegationrule.md
Normal file
@@ -0,0 +1,172 @@
|
||||
Servicedelegationrule module
|
||||
============
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The servicedelegationrule module allows to ensure presence and absence of servicedelegationrules and servicedelegationrule members.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Servicedelegationrule management
|
||||
|
||||
|
||||
Supported FreeIPA Versions
|
||||
--------------------------
|
||||
|
||||
FreeIPA versions 4.4.0 and up are supported by the ipaservicedelegationrule module.
|
||||
|
||||
Host princpals are only usable with IPA versions 4.9.0 and up.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
**Controller**
|
||||
* Ansible version: 2.8+
|
||||
|
||||
**Node**
|
||||
* Supported FreeIPA version (see above)
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Example inventory file
|
||||
|
||||
```ini
|
||||
[ipaserver]
|
||||
ipaserver.test.local
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationrule delegation-rule is present:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationrule
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationrule delegation-rule is present
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationrule delegation-rule member principal test/example.com is present:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationrule
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationrule delegation-rule member principal test/example.com is present
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
principal: test/example.com
|
||||
action: member
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationrule delegation-rule member principal test/example.com is absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationrule
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationrule delegation-rule member principal test/example.com is absent
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
principal: test/example.com
|
||||
action: member
|
||||
state: absent
|
||||
state: absent
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationrule delegation-rule member target delegation-target is present:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationrule
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationrule delegation-rule member target delegation-target is present
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
target: delegation-target
|
||||
action: member
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationrule delegation-rule member target delegation-target is absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationrule
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationrule delegation-rule member target delegation-target is absent
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
target: delegation-target
|
||||
action: member
|
||||
state: absent
|
||||
state: absent
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationrule delegation-rule is absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationrule
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationrule delegation-rule is absent
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
state: absent
|
||||
```
|
||||
|
||||
|
||||
Variables
|
||||
---------
|
||||
|
||||
Variable | Description | Required
|
||||
-------- | ----------- | --------
|
||||
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
|
||||
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
|
||||
`ipaapi_context` | The context in which the module will execute. Executing in a server context is preferred. If not provided context will be determined by the execution environment. Valid values are `server` and `client`. | no
|
||||
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no
|
||||
`name` \| `cn` | The list of servicedelegationrule name strings. | yes
|
||||
`principal` | The list of principals. A principal can be of the format: fqdn, fqdn@REALM, service/fqdn, service/fqdn@REALM, host/fqdn, host/fqdn@REALM, alias$, alias$@REALM, where fqdn and fqdn@REALM are host principals and the same as host/fqdn and host/fqdn@REALM. Host princpals are only usable with IPA versions 4.9.0 and up. | no
|
||||
`target` \| `servicedelegationtarget` | The list of service delegation targets. | no
|
||||
`action` | Work on servicedelegationrule or member level. It can be on of `member` or `servicedelegationrule` and defaults to `servicedelegationrule`. | no
|
||||
`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no
|
||||
|
||||
|
||||
Authors
|
||||
=======
|
||||
|
||||
Thomas Woerner
|
||||
133
README-servicedelegationtarget.md
Normal file
133
README-servicedelegationtarget.md
Normal file
@@ -0,0 +1,133 @@
|
||||
Servicedelegationtarget module
|
||||
============
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The servicedelegationtarget module allows to ensure presence and absence of servicedelegationtargets and servicedelegationtarget members.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Servicedelegationtarget management
|
||||
|
||||
|
||||
Supported FreeIPA Versions
|
||||
--------------------------
|
||||
|
||||
FreeIPA versions 4.4.0 and up are supported by the ipaservicedelegationtarget module.
|
||||
|
||||
Host princpals are only usable with IPA versions 4.9.0 and up.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
**Controller**
|
||||
* Ansible version: 2.8+
|
||||
|
||||
**Node**
|
||||
* Supported FreeIPA version (see above)
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Example inventory file
|
||||
|
||||
```ini
|
||||
[ipaserver]
|
||||
ipaserver.test.local
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationtarget delegation-target is present:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationtarget
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationtarget delegation-target is present
|
||||
ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-target
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationtarget delegation-target member principal test/example.com is present:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationtarget
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationtarget delegation-target member principal test/example.com is present
|
||||
ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-target
|
||||
principal: test/example.com
|
||||
action: member
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationtarget delegation-target member principal test/example.com is absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationtarget
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationtarget delegation-target member principal test/example.com is absent
|
||||
ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-target
|
||||
principal: test/example.com
|
||||
action: member
|
||||
state: absent
|
||||
state: absent
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure servicedelegationtarget delegation-target is absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA servicedelegationtarget
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationtarget delegation-target is absent
|
||||
ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-target
|
||||
state: absent
|
||||
```
|
||||
|
||||
|
||||
Variables
|
||||
---------
|
||||
|
||||
Variable | Description | Required
|
||||
-------- | ----------- | --------
|
||||
`ipaadmin_principal` | The admin principal is a string and defaults to `admin` | no
|
||||
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
|
||||
`ipaapi_context` | The context in which the module will execute. Executing in a server context is preferred. If not provided context will be determined by the execution environment. Valid values are `server` and `client`. | no
|
||||
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to yes. (bool) | no
|
||||
`name` \| `cn` | The list of servicedelegationtarget name strings. | yes
|
||||
`principal` | The list of principals. A principal can be of the format: fqdn, fqdn@REALM, service/fqdn, service/fqdn@REALM, host/fqdn, host/fqdn@REALM, alias$, alias$@REALM, where fqdn and fqdn@REALM are host principals and the same as host/fqdn and host/fqdn@REALM. Host princpals are only usable with IPA versions 4.9.0 and up. | no
|
||||
`action` | Work on servicedelegationtarget or member level. It can be on of `member` or `servicedelegationtarget` and defaults to `servicedelegationtarget`. | no
|
||||
`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no
|
||||
|
||||
|
||||
Authors
|
||||
=======
|
||||
|
||||
Thomas Woerner
|
||||
@@ -105,6 +105,7 @@ Variable | Description | Required
|
||||
`password` | Active Directory domain administrator's password string. | no
|
||||
`server` | Domain controller for the Active Directory domain string. | no
|
||||
`trust_secret` | Shared secret for the trust string. | no
|
||||
`trust_type` | Trust type. Currently, only 'ad' for Active Directory is supported. | no
|
||||
`base_id` | First posix id for the trusted domain integer. | no
|
||||
`range_size` | Size of the ID range reserved for the trusted domain integer. | no
|
||||
`range_type` | Type of trusted domain ID range, It can be one of `ipa-ad-trust` or `ipa-ad-trust-posix`and defaults to `ipa-ad-trust`. | no
|
||||
|
||||
@@ -381,8 +381,8 @@ Variable | Description | Required
|
||||
|
||||
Variable | Description | Required
|
||||
-------- | ----------- | --------
|
||||
`first` \| `givenname` | The first name string. | no
|
||||
`last` \| `sn` | The last name string. | no
|
||||
`first` \| `givenname` | The first name string. Required if user does not exist. | no
|
||||
`last` \| `sn` | The last name string. Required if user does not exist. | no
|
||||
`fullname` \| `cn` | The full name string. | no
|
||||
`displayname` | The display name string. | no
|
||||
`homedir` | The home directory string. | no
|
||||
|
||||
@@ -12,6 +12,7 @@ Features
|
||||
* One-time-password (OTP) support for client installation
|
||||
* Repair mode for clients
|
||||
* Backup and restore, also to and from controller
|
||||
* Smartcard setup for servers and clients
|
||||
* Modules for automembership rule management
|
||||
* Modules for automount key management
|
||||
* Modules for automount location management
|
||||
@@ -28,6 +29,7 @@ Features
|
||||
* Modules for hbacsvcgroup management
|
||||
* Modules for host management
|
||||
* Modules for hostgroup management
|
||||
* Modules for idrange management
|
||||
* Modules for location management
|
||||
* Modules for permission management
|
||||
* Modules for privilege management
|
||||
@@ -36,6 +38,8 @@ Features
|
||||
* Modules for self service management
|
||||
* Modules for server management
|
||||
* Modules for service management
|
||||
* Modules for service delegation rule management
|
||||
* Modules for service delegation target management
|
||||
* Modules for sudocmd management
|
||||
* Modules for sudocmdgroup management
|
||||
* Modules for sudorule management
|
||||
@@ -422,6 +426,8 @@ Roles
|
||||
* [Replica](roles/ipareplica/README.md)
|
||||
* [Client](roles/ipaclient/README.md)
|
||||
* [Backup](roles/ipabackup/README.md)
|
||||
* [SmartCard server](roles/ipasmartcard_server/README.md)
|
||||
* [SmartCard client](roles/ipasmartcard_client/README.md)
|
||||
|
||||
Modules in plugin/modules
|
||||
=========================
|
||||
@@ -442,6 +448,7 @@ Modules in plugin/modules
|
||||
* [ipahbacsvcgroup](README-hbacsvcgroup.md)
|
||||
* [ipahost](README-host.md)
|
||||
* [ipahostgroup](README-hostgroup.md)
|
||||
* [idrange](README-idrange.md)
|
||||
* [ipalocation](README-location.md)
|
||||
* [ipapermission](README-permission.md)
|
||||
* [ipaprivilege](README-privilege.md)
|
||||
@@ -450,6 +457,8 @@ Modules in plugin/modules
|
||||
* [ipaselfservice](README-selfservice.md)
|
||||
* [ipaserver](README-server.md)
|
||||
* [ipaservice](README-service.md)
|
||||
* [ipaservicedelegationrule](README-servicedelegationrule.md)
|
||||
* [ipaservicedelegationtarget](README-servicedelegationtarget.md)
|
||||
* [ipasudocmd](README-sudocmd.md)
|
||||
* [ipasudocmdgroup](README-sudocmdgroup.md)
|
||||
* [ipasudorule](README-sudorule.md)
|
||||
|
||||
30
molecule/c8s-build/Dockerfile
Normal file
30
molecule/c8s-build/Dockerfile
Normal file
@@ -0,0 +1,30 @@
|
||||
FROM quay.io/centos/centos:stream8
|
||||
ENV container=docker
|
||||
|
||||
RUN rm -fv /var/cache/dnf/metadata_lock.pid; \
|
||||
dnf makecache; \
|
||||
dnf --assumeyes install \
|
||||
/usr/bin/python3 \
|
||||
/usr/bin/python3-config \
|
||||
/usr/bin/dnf-3 \
|
||||
sudo \
|
||||
bash \
|
||||
systemd \
|
||||
procps-ng \
|
||||
iproute && \
|
||||
dnf clean all; \
|
||||
(cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
|
||||
rm -f /lib/systemd/system/multi-user.target.wants/*;\
|
||||
rm -f /etc/systemd/system/*.wants/*;\
|
||||
rm -f /lib/systemd/system/local-fs.target.wants/*; \
|
||||
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
|
||||
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
|
||||
rm -f /lib/systemd/system/basic.target.wants/*;\
|
||||
rm -f /lib/systemd/system/anaconda.target.wants/*; \
|
||||
rm -rf /var/cache/dnf/;
|
||||
|
||||
STOPSIGNAL RTMIN+3
|
||||
|
||||
VOLUME ["/sys/fs/cgroup"]
|
||||
|
||||
CMD ["/usr/sbin/init"]
|
||||
19
molecule/c8s-build/molecule.yml
Normal file
19
molecule/c8s-build/molecule.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: c8s-build
|
||||
image: "quay.io/centos/centos:stream8"
|
||||
dockerfile: Dockerfile
|
||||
hostname: ipaserver.test.local
|
||||
dns_servers:
|
||||
- 8.8.8.8
|
||||
volumes:
|
||||
- /sys/fs/cgroup:/sys/fs/cgroup:ro
|
||||
command: /usr/sbin/init
|
||||
privileged: true
|
||||
provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare-build.yml
|
||||
prerun: false
|
||||
@@ -2,8 +2,8 @@
|
||||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: centos-8
|
||||
image: quay.io/ansible-freeipa/upstream-tests:centos-8
|
||||
- name: c8s
|
||||
image: quay.io/ansible-freeipa/upstream-tests:c8s
|
||||
pre_build_image: true
|
||||
hostname: ipaserver.test.local
|
||||
dns_servers:
|
||||
@@ -16,3 +16,4 @@ provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare.yml
|
||||
prerun: false
|
||||
@@ -5,7 +5,6 @@ RUN rm -fv /var/cache/dnf/metadata_lock.pid; \
|
||||
dnf makecache; \
|
||||
dnf --assumeyes install \
|
||||
/usr/bin/python3 \
|
||||
/usr/bin/python3-config \
|
||||
/usr/bin/dnf-3 \
|
||||
sudo \
|
||||
bash \
|
||||
@@ -2,7 +2,7 @@
|
||||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: centos-9-build
|
||||
- name: c9s-build
|
||||
image: "quay.io/centos/centos:stream9"
|
||||
dockerfile: Dockerfile
|
||||
hostname: ipaserver.test.local
|
||||
@@ -16,3 +16,4 @@ provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare-build.yml
|
||||
prerun: false
|
||||
@@ -2,8 +2,8 @@
|
||||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: centos-9
|
||||
image: quay.io/ansible-freeipa/upstream-tests:centos-9
|
||||
- name: c9s
|
||||
image: quay.io/ansible-freeipa/upstream-tests:c9s
|
||||
pre_build_image: true
|
||||
hostname: ipaserver.test.local
|
||||
dns_servers:
|
||||
@@ -16,3 +16,4 @@ provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare.yml
|
||||
prerun: false
|
||||
@@ -16,3 +16,4 @@ provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare-build.yml
|
||||
prerun: false
|
||||
|
||||
@@ -16,3 +16,4 @@ provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare.yml
|
||||
prerun: false
|
||||
|
||||
@@ -1 +1 @@
|
||||
centos-8
|
||||
fedora-latest
|
||||
@@ -16,3 +16,4 @@ provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare-build.yml
|
||||
prerun: false
|
||||
|
||||
@@ -16,3 +16,4 @@ provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare.yml
|
||||
prerun: false
|
||||
|
||||
30
molecule/fedora-rawhide-build/Dockerfile
Normal file
30
molecule/fedora-rawhide-build/Dockerfile
Normal file
@@ -0,0 +1,30 @@
|
||||
FROM fedora:rawhide
|
||||
ENV container=docker
|
||||
|
||||
RUN rm -fv /var/cache/dnf/metadata_lock.pid; \
|
||||
dnf makecache; \
|
||||
dnf --assumeyes install \
|
||||
/usr/bin/python3 \
|
||||
/usr/bin/python3-config \
|
||||
/usr/bin/dnf-3 \
|
||||
sudo \
|
||||
bash \
|
||||
systemd \
|
||||
procps-ng \
|
||||
iproute && \
|
||||
dnf clean all; \
|
||||
(cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
|
||||
rm -f /lib/systemd/system/multi-user.target.wants/*;\
|
||||
rm -f /etc/systemd/system/*.wants/*;\
|
||||
rm -f /lib/systemd/system/local-fs.target.wants/*; \
|
||||
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
|
||||
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
|
||||
rm -f /lib/systemd/system/basic.target.wants/*;\
|
||||
rm -f /lib/systemd/system/anaconda.target.wants/*; \
|
||||
rm -rf /var/cache/dnf/;
|
||||
|
||||
STOPSIGNAL RTMIN+3
|
||||
|
||||
VOLUME ["/sys/fs/cgroup"]
|
||||
|
||||
CMD ["/usr/sbin/init"]
|
||||
@@ -2,9 +2,9 @@
|
||||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: centos-8-build
|
||||
image: "centos:centos8"
|
||||
pre_build_image: true
|
||||
- name: fedora-rawhide-build
|
||||
image: "fedora:rawhide"
|
||||
dockerfile: Dockerfile
|
||||
hostname: ipaserver.test.local
|
||||
dns_servers:
|
||||
- 8.8.8.8
|
||||
@@ -16,3 +16,4 @@ provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare-build.yml
|
||||
prerun: false
|
||||
19
molecule/fedora-rawhide/molecule.yml
Normal file
19
molecule/fedora-rawhide/molecule.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
driver:
|
||||
name: docker
|
||||
platforms:
|
||||
- name: fedora-rawhide
|
||||
image: quay.io/ansible-freeipa/upstream-tests:fedora-rawhide
|
||||
pre_build_image: true
|
||||
hostname: ipaserver.test.local
|
||||
dns_servers:
|
||||
- 127.0.0.1
|
||||
volumes:
|
||||
- /sys/fs/cgroup:/sys/fs/cgroup:ro
|
||||
command: /usr/sbin/init
|
||||
privileged: true
|
||||
provisioner:
|
||||
name: ansible
|
||||
playbooks:
|
||||
prepare: ../resources/playbooks/prepare.yml
|
||||
prerun: false
|
||||
Binary file not shown.
@@ -5,7 +5,7 @@
|
||||
tasks:
|
||||
- name: Ensure aumount key TestKey is renamed to NewKeyName
|
||||
ipaautomountkey:
|
||||
ipaadmin_password: password01
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
automountlocationcn: TestLocation
|
||||
automountmapname: TestMap
|
||||
automountkey: TestKey
|
||||
|
||||
12
playbooks/config/change-ipa-domain-netbios-name.yml
Normal file
12
playbooks/config/change-ipa-domain-netbios-name.yml
Normal file
@@ -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
|
||||
12
playbooks/config/generate-users-groups-sids.yml
Normal file
12
playbooks/config/generate-users-groups-sids.yml
Normal file
@@ -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
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
- name: Playbook to handle global DNS configuration
|
||||
- name: Playbook to handle global IPA configuration
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
gather_facts: no
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
- name: Playbook to handle global DNS configuration
|
||||
- name: Playbook to handle global IPA configuration
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
gather_facts: no
|
||||
|
||||
@@ -6,4 +6,5 @@
|
||||
tasks:
|
||||
- name: Disable global forwarders.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
forward_policy: none
|
||||
|
||||
@@ -6,4 +6,5 @@
|
||||
tasks:
|
||||
- name: Disallow reverse record synchronization.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
allow_sync_ptr: no
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
tasks:
|
||||
- name: Set dnsconfig forwarders.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
forwarders:
|
||||
- ip_address: 8.8.4.4
|
||||
- ip_address: 2001:4860:4860::8888
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
tasks:
|
||||
- name: Set dnsconfig forwarders.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
forwarders:
|
||||
- ip_address: 8.8.4.4
|
||||
- ip_address: 2001:4860:4860::8888
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
tasks:
|
||||
- name: Set dnsconfig.
|
||||
ipadnsconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
forwarders:
|
||||
- ip_address: 8.8.4.4
|
||||
- ip_address: 2001:4860:4860::8888
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
tasks:
|
||||
- name: Ensure that 'host04' has CNAME, with cname_hostname, is absent
|
||||
ipadnsrecord:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
zone_name: example.com
|
||||
name: host04
|
||||
cname_hostname: host04.example.com
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
tasks:
|
||||
- name: Ensure that 'host04' has CNAME, with cname_hostname, is present
|
||||
ipadnsrecord:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
zone_name: example.com
|
||||
name: host04
|
||||
cname_hostname: host04.example.com
|
||||
|
||||
11
playbooks/idrange/idrange-absent.yml
Normal file
11
playbooks/idrange/idrange-absent.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Idrange absent example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure idrange is absent
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: id_range
|
||||
state: absent
|
||||
15
playbooks/idrange/idrange-ad-posix-present.yml
Normal file
15
playbooks/idrange/idrange-ad-posix-present.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
- name: Playbook to manage idrange
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure AD-trust idrange is present
|
||||
ipaidrange:
|
||||
name: id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
rid_base: 1000000
|
||||
idrange_type: ipa-ad-trust-posix
|
||||
dom_name: ad.ipa.test
|
||||
auto_private_groups: "false"
|
||||
16
playbooks/idrange/idrange-ad-present.yml
Normal file
16
playbooks/idrange/idrange-ad-present.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
- name: Playbook to manage idrange
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure AD-trust idrange is present
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: ad_id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
rid_base: 1000000
|
||||
idrange_type: ipa-ad-trust
|
||||
dom_sid: S-1-5-21-2870384104-3340008087-3140804251
|
||||
auto_private_groups: "true"
|
||||
14
playbooks/idrange/idrange-present.yml
Normal file
14
playbooks/idrange/idrange-present.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
- name: Playbook to manage idrange
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure local idrange is present
|
||||
ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
rid_base: 1000000
|
||||
secondary_rid_base: 200000000
|
||||
8
playbooks/install-smartcard-clients.yml
Normal file
8
playbooks/install-smartcard-clients.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
- name: Playbook to setup smartcard for IPA clients
|
||||
hosts: ipaclients
|
||||
become: true
|
||||
|
||||
roles:
|
||||
- role: ipasmartcard_client
|
||||
state: present
|
||||
8
playbooks/install-smartcard-replicas.yml
Normal file
8
playbooks/install-smartcard-replicas.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
- name: Playbook to setup smartcard for IPA replicas
|
||||
hosts: ipareplicas
|
||||
become: true
|
||||
|
||||
roles:
|
||||
- role: ipasmartcard_server
|
||||
state: present
|
||||
8
playbooks/install-smartcard-server.yml
Normal file
8
playbooks/install-smartcard-server.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
- name: Playbook to setup smartcard for IPA server
|
||||
hosts: ipaserver
|
||||
become: true
|
||||
|
||||
roles:
|
||||
- role: ipasmartcard_server
|
||||
state: present
|
||||
8
playbooks/install-smartcard-servers.yml
Normal file
8
playbooks/install-smartcard-servers.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
- name: Playbook to setup smartcard for IPA server and replicas
|
||||
hosts: ipaserver, ipareplicas
|
||||
become: true
|
||||
|
||||
roles:
|
||||
- role: ipasmartcard_server
|
||||
state: present
|
||||
@@ -6,5 +6,6 @@
|
||||
tasks:
|
||||
- name: Ensure privilege "Broad Privilege" is absent
|
||||
ipaprivilege:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: Broad Privilege
|
||||
state: absent
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Servicedelegationrule absent example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationrule test-delegation-rule is absent
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-rule
|
||||
state: absent
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
- name: Servicedelegationrule present example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationrule test-delegation-rule is present
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-rule
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
- name: Servicedelegationrule principal member absent example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure principal member test/example.com is absent in servicedelegationrule test-delegation-rule
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-rule
|
||||
principal: test/example.com
|
||||
action: member
|
||||
state: absent
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
- name: Servicedelegationrule principal member present example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure principal member test/example.com is present in servicedelegationrule test-delegation-rule
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-rule
|
||||
principal: test/example.com
|
||||
action: member
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
- name: Servicedelegationrule absent example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure member test/example.com is absent in servicedelegationrule test-delegation-rule
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-rule
|
||||
principal: test/example.com
|
||||
action: member
|
||||
state: absent
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
- name: Servicedelegationrule member present example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure member test/example.com is present in servicedelegationrule test-delegation-rule
|
||||
ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-rule
|
||||
principal: test/example.com
|
||||
action: member
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Servicedelegationtarget absent example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationtarget test-delegation-target is absent
|
||||
ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-target
|
||||
state: absent
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
- name: Servicedelegationtarget absent example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure member test/example.com is absent in servicedelegationtarget test-delegation-target
|
||||
ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-target
|
||||
principal: test/example.com
|
||||
action: member
|
||||
state: absent
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
- name: Servicedelegationtarget member present example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure member test/example.com is present in servicedelegationtarget test-delegation-target
|
||||
ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-target
|
||||
principal: test/example.com
|
||||
action: member
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
- name: Servicedelegationtarget present example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure servicedelegationtarget test-delegation-target is present
|
||||
ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: test-delegation-target
|
||||
@@ -6,7 +6,7 @@
|
||||
tasks:
|
||||
- name: Ensure sudocmdgroup is absent
|
||||
ipasudocmdgroup:
|
||||
ipaadmin_password: pass1234
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: network
|
||||
state: absent
|
||||
action: sudocmdgroup
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
tasks:
|
||||
- name: Ensure sudocmdgroup sudocmds are present
|
||||
ipasudocmdgroup:
|
||||
ipaadmin_password: pass1234
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: network
|
||||
description: Group of important commands.
|
||||
sudocmd:
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
tasks:
|
||||
- name: Ensure sudorule command is absent
|
||||
ipasudorule:
|
||||
ipaadmin_password: pass1234
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: testrule1
|
||||
state: absent
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
tasks:
|
||||
- name: Add topology segment
|
||||
ipatopologysegment:
|
||||
ipaadmin_password: "{{ ipaadmin_password }}"
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
suffix: "{{ item.suffix }}"
|
||||
name: "{{ item.name | default(omit) }}"
|
||||
left: "{{ item.left }}"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
tasks:
|
||||
- name: Add topology segment
|
||||
ipatopologysegment:
|
||||
ipaadmin_password: "{{ ipaadmin_password }}"
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
suffix: "{{ item.suffix }}"
|
||||
name: "{{ item.name | default(omit) }}"
|
||||
left: "{{ item.left }}"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
tasks:
|
||||
- name: Add topology segment
|
||||
ipatopologysegment:
|
||||
ipaadmin_password: "{{ ipaadmin_password }}"
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
suffix: "{{ item.suffix }}"
|
||||
name: "{{ item.name | default(omit) }}"
|
||||
left: "{{ item.left }}"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
tasks:
|
||||
- name: ensure the trust is present
|
||||
ipatrust:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
realm: windows.local
|
||||
admin: Administrator
|
||||
password: secret_password
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
tasks:
|
||||
- name: ensure the trust is absent
|
||||
ipatrust:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
realm: windows.local
|
||||
state: absent
|
||||
|
||||
@@ -45,3 +45,13 @@ options:
|
||||
type: bool
|
||||
default: true
|
||||
"""
|
||||
|
||||
DELETE_CONTINUE = r"""
|
||||
options:
|
||||
delete_continue:
|
||||
description: |
|
||||
Continuous mode. Don't stop on errors. Valid only if `state` is `absent`.
|
||||
aliases: ["continue"]
|
||||
type: bool
|
||||
default: True
|
||||
"""
|
||||
|
||||
@@ -28,8 +28,8 @@ __metaclass__ = type
|
||||
__all__ = ["gssapi", "netaddr", "api", "ipalib_errors", "Env",
|
||||
"DEFAULT_CONFIG", "LDAP_GENERALIZED_TIME_FORMAT",
|
||||
"kinit_password", "kinit_keytab", "run", "DN", "VERSION",
|
||||
"paths", "get_credentials_if_valid", "Encoding",
|
||||
"load_pem_x509_certificate", "DNSName"]
|
||||
"paths", "tasks", "get_credentials_if_valid", "Encoding",
|
||||
"load_pem_x509_certificate", "DNSName", "getargspec"]
|
||||
|
||||
import sys
|
||||
|
||||
@@ -48,29 +48,32 @@ else:
|
||||
import gssapi
|
||||
from datetime import datetime
|
||||
from contextlib import contextmanager
|
||||
import inspect
|
||||
|
||||
# Import getargspec from inspect or provide own getargspec for
|
||||
# Python 2 compatibility with Python 3.11+.
|
||||
try:
|
||||
from inspect import getargspec
|
||||
except ImportError:
|
||||
from collections import namedtuple
|
||||
from inspect import getfullargspec
|
||||
|
||||
# The code is copied from Python 3.10 inspect.py
|
||||
# Authors: Ka-Ping Yee <ping@lfw.org>
|
||||
# Yury Selivanov <yselivanov@sprymix.com>
|
||||
ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
|
||||
|
||||
def getargspec(func):
|
||||
args, varargs, varkw, defaults, kwonlyargs, _kwonlydefaults, \
|
||||
ann = getfullargspec(func)
|
||||
if kwonlyargs or ann:
|
||||
raise ValueError(
|
||||
"Function has keyword-only parameters or annotations"
|
||||
", use inspect.signature() API which can support them")
|
||||
return ArgSpec(args, varargs, varkw, defaults)
|
||||
|
||||
# ansible-freeipa requires locale to be C, IPA requires utf-8.
|
||||
os.environ["LANGUAGE"] = "C"
|
||||
|
||||
try:
|
||||
from packaging import version
|
||||
except ImportError:
|
||||
# If `packaging` not found, split version string for creating version
|
||||
# object. Although it is not PEP 440 compliant, it will work for stable
|
||||
# FreeIPA releases.
|
||||
import re
|
||||
|
||||
class version: # pylint: disable=invalid-name, too-few-public-methods
|
||||
@staticmethod
|
||||
def parse(version_str):
|
||||
"""
|
||||
Split a version string A.B.C, into a tuple.
|
||||
|
||||
This will not work for `rc`, `dev` or similar version string.
|
||||
"""
|
||||
return tuple(re.split("[-_.]", version_str)) # noqa: W605
|
||||
|
||||
from ipalib import api
|
||||
from ipalib import errors as ipalib_errors # noqa
|
||||
from ipalib.config import Env
|
||||
@@ -84,8 +87,10 @@ else:
|
||||
from ipapython.dn import DN
|
||||
from ipapython.version import VERSION
|
||||
from ipaplatform.paths import paths
|
||||
from ipaplatform.tasks import tasks
|
||||
from ipalib.krb_utils import get_credentials_if_valid
|
||||
from ipapython.dnsutil import DNSName
|
||||
from ipapython import kerberos
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.common.text.converters import jsonify
|
||||
@@ -138,6 +143,13 @@ else:
|
||||
|
||||
return fstore.has_files()
|
||||
|
||||
# Try to import dcerpc
|
||||
try:
|
||||
import ipaserver.dcerpc # pylint: disable=no-member
|
||||
_dcerpc_bindings_installed = True # pylint: disable=invalid-name
|
||||
except ImportError:
|
||||
_dcerpc_bindings_installed = False # pylint: disable=invalid-name
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
@@ -220,6 +232,8 @@ else:
|
||||
ldap_cache: Control use of LDAP cache layer. (bool)
|
||||
|
||||
"""
|
||||
global _dcerpc_bindings_installed # pylint: disable=C0103,W0603
|
||||
|
||||
env = Env()
|
||||
env._bootstrap()
|
||||
env._finalize_core(**dict(DEFAULT_CONFIG))
|
||||
@@ -251,6 +265,7 @@ else:
|
||||
backend = api.Backend.ldap2
|
||||
else:
|
||||
backend = api.Backend.rpcclient
|
||||
_dcerpc_bindings_installed = False
|
||||
|
||||
if not backend.isconnected():
|
||||
backend.connect(ccache=os.environ.get('KRB5CCNAME', None))
|
||||
@@ -288,8 +303,8 @@ else:
|
||||
operation = oper_map.get(oper)
|
||||
if not operation:
|
||||
raise NotImplementedError("Invalid operator: %s" % oper)
|
||||
return operation(version.parse(VERSION),
|
||||
version.parse(requested_version))
|
||||
return operation(tasks.parse_ipa_version(VERSION),
|
||||
tasks.parse_ipa_version(requested_version))
|
||||
|
||||
def date_format(value):
|
||||
accepted_date_formats = [
|
||||
@@ -309,15 +324,49 @@ else:
|
||||
raise ValueError("Invalid date '%s'" % value)
|
||||
|
||||
def compare_args_ipa(module, args, ipa, ignore=None): # noqa
|
||||
"""Compare IPA obj attrs with the command args.
|
||||
"""Compare IPA object attributes against command arguments.
|
||||
|
||||
This function compares IPA objects attributes with the args the
|
||||
module is intending to use to call a command. ignore can be a list
|
||||
of attributes, that should be ignored in the comparison.
|
||||
This is useful to know if a call to IPA server will be needed or not.
|
||||
In order to compare we have to perform slight changes in data formats.
|
||||
This function compares 'ipa' attributes with the 'args' the module
|
||||
is intending to use as parameters to an IPA API command. A list of
|
||||
attribute names that should be ignored during comparison may be
|
||||
provided.
|
||||
|
||||
Returns True if they are the same and False otherwise.
|
||||
The comparison will be performed on every attribute provided in
|
||||
'args'. If the attribute in 'args' or 'ipa' is not a scalar value
|
||||
(including strings) the comparison will be performed as if the
|
||||
attribute is a set of values, so duplicate values will count as a
|
||||
single one. If both values are scalar values, then a direct
|
||||
comparison is performed.
|
||||
|
||||
If an attribute is not available in 'ipa', its value is considered
|
||||
to be a list with an empty string (['']), possibly forcing the
|
||||
conversion of the 'args' attribute to a list for comparison. This
|
||||
allows, for example, the usage of empty strings which should compare
|
||||
as equals to inexistent attributes (None), as is done in IPA API.
|
||||
|
||||
This function is mostly useful to evaluate the need of a call to
|
||||
IPA server when provided arguments are equivalent to the existing
|
||||
values for a given IPA object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
module: AnsibleModule
|
||||
The AnsibleModule used to log debug messages.
|
||||
|
||||
args: dict
|
||||
The set of attributes provided by the playbook task.
|
||||
|
||||
ipa: dict
|
||||
The set of attributes from the IPA object retrieved.
|
||||
|
||||
ignore: list
|
||||
An optional list of attribute names that should be ignored and
|
||||
not evaluated.
|
||||
|
||||
Return
|
||||
------
|
||||
True is returned if all attribute values in 'args' are
|
||||
equivalent to the corresponding attribute value in 'ipa'.
|
||||
"""
|
||||
base_debug_msg = "Ansible arguments and IPA commands differed. "
|
||||
|
||||
@@ -337,52 +386,45 @@ else:
|
||||
filtered_args = [key for key in args if key not in ignore]
|
||||
|
||||
for key in filtered_args:
|
||||
if key not in ipa: # pylint: disable=no-else-return
|
||||
module.debug(
|
||||
base_debug_msg + "Command key not present in IPA: %s" % key
|
||||
)
|
||||
return False
|
||||
arg = args[key]
|
||||
ipa_arg = ipa.get(key, [""])
|
||||
# If ipa_arg is a list and arg is not, replace arg
|
||||
# with list containing arg. Most args in a find result
|
||||
# are lists, but not all.
|
||||
if isinstance(ipa_arg, (list, tuple)):
|
||||
if not isinstance(arg, list):
|
||||
arg = [arg]
|
||||
if len(ipa_arg) != len(arg):
|
||||
module.debug(
|
||||
base_debug_msg
|
||||
+ "List length doesn't match for key %s: %d %d"
|
||||
% (key, len(arg), len(ipa_arg),)
|
||||
)
|
||||
return False
|
||||
# ensure list elements types are the same.
|
||||
if not (
|
||||
isinstance(ipa_arg[0], type(arg[0]))
|
||||
or isinstance(arg[0], type(ipa_arg[0]))
|
||||
):
|
||||
arg = [to_text(_arg) for _arg in arg]
|
||||
try:
|
||||
arg_set = set(arg)
|
||||
ipa_arg_set = set(ipa_arg)
|
||||
except TypeError:
|
||||
if arg != ipa_arg:
|
||||
module.debug(
|
||||
base_debug_msg
|
||||
+ "Different values: %s %s" % (arg, ipa_arg)
|
||||
)
|
||||
return False
|
||||
else:
|
||||
arg = args[key]
|
||||
ipa_arg = ipa[key]
|
||||
# If ipa_arg is a list and arg is not, replace arg
|
||||
# with list containing arg. Most args in a find result
|
||||
# are lists, but not all.
|
||||
if isinstance(ipa_arg, tuple):
|
||||
ipa_arg = list(ipa_arg)
|
||||
if isinstance(ipa_arg, list):
|
||||
if not isinstance(arg, list):
|
||||
arg = [arg]
|
||||
if len(ipa_arg) != len(arg):
|
||||
module.debug(
|
||||
base_debug_msg
|
||||
+ "List length doesn't match for key %s: %d %d"
|
||||
% (key, len(arg), len(ipa_arg),)
|
||||
)
|
||||
return False
|
||||
if isinstance(ipa_arg[0], str) and isinstance(arg[0], int):
|
||||
arg = [to_text(_arg) for _arg in arg]
|
||||
if isinstance(ipa_arg[0], unicode) \
|
||||
and isinstance(arg[0], int):
|
||||
arg = [to_text(_arg) for _arg in arg]
|
||||
try:
|
||||
arg_set = set(arg)
|
||||
ipa_arg_set = set(ipa_arg)
|
||||
except TypeError:
|
||||
if arg != ipa_arg:
|
||||
module.debug(
|
||||
base_debug_msg
|
||||
+ "Different values: %s %s" % (arg, ipa_arg)
|
||||
)
|
||||
return False
|
||||
else:
|
||||
if arg_set != ipa_arg_set:
|
||||
module.debug(
|
||||
base_debug_msg
|
||||
+ "Different set content: %s %s"
|
||||
% (arg_set, ipa_arg_set,)
|
||||
)
|
||||
return False
|
||||
if arg_set != ipa_arg_set:
|
||||
module.debug(
|
||||
base_debug_msg
|
||||
+ "Different set content: %s %s"
|
||||
% (arg_set, ipa_arg_set,)
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
def _afm_convert(value):
|
||||
@@ -397,11 +439,32 @@ else:
|
||||
|
||||
return value
|
||||
|
||||
def module_params_get(module, name):
|
||||
return _afm_convert(module.params.get(name))
|
||||
|
||||
def module_params_get_lowercase(module, name):
|
||||
def module_params_get(module, name, allow_empty_string=False):
|
||||
value = _afm_convert(module.params.get(name))
|
||||
|
||||
# Fail on empty strings in the list or if allow_empty_string is True
|
||||
# if there is another entry in the list together with the empty
|
||||
# string.
|
||||
# Due to an issue in Ansible it is possible to use the empty string
|
||||
# "" for lists with choices, even if the empty list is not part of
|
||||
# the choices.
|
||||
# Ansible issue https://github.com/ansible/ansible/issues/77108
|
||||
if isinstance(value, list):
|
||||
for val in value:
|
||||
if isinstance(val, (str, unicode)) and not val:
|
||||
if not allow_empty_string:
|
||||
module.fail_json(
|
||||
msg="Parameter '%s' contains an empty string" %
|
||||
name)
|
||||
elif len(value) > 1:
|
||||
module.fail_json(
|
||||
msg="Parameter '%s' may not contain another "
|
||||
"entry together with an empty string" % name)
|
||||
|
||||
return value
|
||||
|
||||
def module_params_get_lowercase(module, name, allow_empty_string=False):
|
||||
value = module_params_get(module, name, allow_empty_string)
|
||||
if isinstance(value, list):
|
||||
value = [v.lower() for v in value]
|
||||
if isinstance(value, (str, unicode)):
|
||||
@@ -550,6 +613,89 @@ else:
|
||||
return False
|
||||
return True
|
||||
|
||||
def servicedelegation_normalize_principals(module, principal,
|
||||
check_exists=False):
|
||||
"""
|
||||
Normalize servicedelegation principals.
|
||||
|
||||
The principals can be service and with IPA 4.9.0+ also host principals.
|
||||
"""
|
||||
|
||||
def _normalize_principal_name(name, realm):
|
||||
# Normalize principal name
|
||||
# Copied from ipaserver/plugins/servicedelegation.py
|
||||
try:
|
||||
princ = kerberos.Principal(name, realm=realm)
|
||||
except ValueError as _err:
|
||||
raise ipalib_errors.ValidationError(
|
||||
name='principal',
|
||||
reason="Malformed principal: %s" % str(_err))
|
||||
|
||||
if len(princ.components) == 1 and \
|
||||
not princ.components[0].endswith('$'):
|
||||
nprinc = 'host/' + unicode(princ)
|
||||
else:
|
||||
nprinc = unicode(princ)
|
||||
return nprinc
|
||||
|
||||
def _check_exists(module, _type, name):
|
||||
# Check if item of type _type exists using the show command
|
||||
try:
|
||||
module.ipa_command("%s_show" % _type, name, {})
|
||||
except ipalib_errors.NotFound as e:
|
||||
msg = str(e)
|
||||
if "%s not found" % _type in msg:
|
||||
return False
|
||||
module.fail_json(msg="%s_show failed: %s" % (_type, msg))
|
||||
return True
|
||||
|
||||
ipa_realm = module.ipa_get_realm()
|
||||
_principal = []
|
||||
for _princ in principal:
|
||||
princ = _princ
|
||||
realm = ipa_realm
|
||||
|
||||
# Get principal and realm from _princ if there is a realm
|
||||
if '@' in _princ:
|
||||
princ, realm = _princ.rsplit('@', 1)
|
||||
|
||||
# Lowercase principal
|
||||
princ = princ.lower()
|
||||
|
||||
# Normalize principal
|
||||
try:
|
||||
nprinc = _normalize_principal_name(princ, realm)
|
||||
except ipalib_errors.ValidationError as err:
|
||||
module.fail_json(msg="%s: %s" % (_princ, str(err)))
|
||||
princ = unicode(nprinc)
|
||||
|
||||
# Check that host principal exists
|
||||
if princ.startswith("host/"):
|
||||
if module.ipa_check_version("<", "4.9.0"):
|
||||
module.fail_json(
|
||||
msg="The use of host principals is not supported "
|
||||
"by your IPA version")
|
||||
|
||||
# Get host FQDN (no leading 'host/' and no trailing realm)
|
||||
# (There is no removeprefix and removesuffix in Python2)
|
||||
_host = princ[5:]
|
||||
if _host.endswith("@%s" % realm):
|
||||
_host = _host[:-len(realm) - 1]
|
||||
|
||||
# Seach for host
|
||||
if check_exists and not _check_exists(module, "host", _host):
|
||||
module.fail_json(msg="Host '%s' does not exist" % _host)
|
||||
|
||||
# Check the service principal exists
|
||||
else:
|
||||
if check_exists and \
|
||||
not _check_exists(module, "service", princ):
|
||||
module.fail_json(msg="Service %s does not exist" % princ)
|
||||
|
||||
_principal.append(princ)
|
||||
|
||||
return _principal
|
||||
|
||||
def exit_raw_json(module, **kwargs):
|
||||
"""
|
||||
Print the raw parameters in JSON format, without masking.
|
||||
@@ -569,6 +715,42 @@ else:
|
||||
print(jsonify(kwargs))
|
||||
sys.exit(0)
|
||||
|
||||
def __get_domain_validator():
|
||||
if not _dcerpc_bindings_installed:
|
||||
raise ipalib_errors.NotFound(
|
||||
reason=(
|
||||
'Cannot perform SID validation without Samba 4 support '
|
||||
'installed. Make sure you have installed server-trust-ad '
|
||||
'sub-package of IPA on the server'
|
||||
)
|
||||
)
|
||||
|
||||
# pylint: disable=no-member
|
||||
domain_validator = ipaserver.dcerpc.DomainValidator(api)
|
||||
# pylint: enable=no-member
|
||||
|
||||
if not domain_validator.is_configured():
|
||||
raise ipalib_errors.NotFound(
|
||||
reason=(
|
||||
'Cross-realm trusts are not configured. Make sure you '
|
||||
'have run ipa-adtrust-install on the IPA server first'
|
||||
)
|
||||
)
|
||||
|
||||
return domain_validator
|
||||
|
||||
def get_trusted_domain_sid_from_name(dom_name):
|
||||
"""
|
||||
Given a trust domain name, returns the domain SID.
|
||||
|
||||
Returns unicode string representation for a given trusted domain name
|
||||
or None if SID for the given trusted domain name could not be found.
|
||||
"""
|
||||
domain_validator = __get_domain_validator()
|
||||
sid = domain_validator.get_sid_from_domain_name(dom_name)
|
||||
|
||||
return unicode(sid) if sid is not None else None
|
||||
|
||||
class IPAParamMapping(Mapping):
|
||||
"""
|
||||
Provides IPA API mapping to playbook parameters or computed values.
|
||||
@@ -667,7 +849,10 @@ else:
|
||||
# Check if param_name is actually a param
|
||||
if param_name in self.ansible_module.params:
|
||||
value = self.ansible_module.params_get(param_name)
|
||||
if isinstance(value, bool):
|
||||
if (
|
||||
self.ansible_module.ipa_check_version("<", "4.9.10")
|
||||
and isinstance(value, bool)
|
||||
):
|
||||
value = "TRUE" if value else "FALSE"
|
||||
|
||||
# Since param wasn't a param check if it's a method name
|
||||
@@ -742,6 +927,12 @@ else:
|
||||
ipaapi_ldap_cache=dict(type="bool", default="True"),
|
||||
)
|
||||
|
||||
ipa_module_options_spec = dict(
|
||||
delete_continue=dict(
|
||||
type="bool", default=True, aliases=["continue"]
|
||||
)
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
# Extend argument_spec with ipa_module_base_spec
|
||||
if "argument_spec" in kwargs:
|
||||
@@ -749,6 +940,16 @@ else:
|
||||
_spec.update(self.ipa_module_base_spec)
|
||||
kwargs["argument_spec"] = _spec
|
||||
|
||||
if "ipa_module_options" in kwargs:
|
||||
_update = {
|
||||
k: self.ipa_module_options_spec[k]
|
||||
for k in kwargs["ipa_module_options"]
|
||||
}
|
||||
_spec = kwargs.get("argument_spec", {})
|
||||
_spec.update(_update)
|
||||
kwargs["argument_spec"] = _spec
|
||||
del kwargs["ipa_module_options"]
|
||||
|
||||
# pylint: disable=super-with-arguments
|
||||
super(IPAAnsibleModule, self).__init__(*args, **kwargs)
|
||||
|
||||
@@ -797,7 +998,7 @@ else:
|
||||
finally:
|
||||
temp_kdestroy(ccache_dir, ccache_name)
|
||||
|
||||
def params_get(self, name):
|
||||
def params_get(self, name, allow_empty_string=False):
|
||||
"""
|
||||
Retrieve value set for module parameter.
|
||||
|
||||
@@ -805,11 +1006,13 @@ else:
|
||||
----------
|
||||
name: string
|
||||
The name of the parameter to retrieve.
|
||||
allow_empty_string: bool
|
||||
The parameter allowes to have empty strings in a list
|
||||
|
||||
"""
|
||||
return module_params_get(self, name)
|
||||
return module_params_get(self, name, allow_empty_string)
|
||||
|
||||
def params_get_lowercase(self, name):
|
||||
def params_get_lowercase(self, name, allow_empty_string=False):
|
||||
"""
|
||||
Retrieve value set for module parameter as lowercase, if not None.
|
||||
|
||||
@@ -817,9 +1020,11 @@ else:
|
||||
----------
|
||||
name: string
|
||||
The name of the parameter to retrieve.
|
||||
allow_empty_string: bool
|
||||
The parameter allowes to have empty strings in a list
|
||||
|
||||
"""
|
||||
return module_params_get_lowercase(self, name)
|
||||
return module_params_get_lowercase(self, name, allow_empty_string)
|
||||
|
||||
def params_fail_used_invalid(self, invalid_params, state, action=None):
|
||||
"""
|
||||
@@ -1030,7 +1235,7 @@ else:
|
||||
elif result_handler is not None:
|
||||
if "errors" not in handlers_user_args:
|
||||
# pylint: disable=deprecated-method
|
||||
argspec = inspect.getargspec(result_handler)
|
||||
argspec = getargspec(result_handler)
|
||||
if "errors" in argspec.args:
|
||||
handlers_user_args["errors"] = _errors
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipaautomember
|
||||
short description: Add and delete FreeIPA Auto Membership Rules.
|
||||
short_description: Add and delete FreeIPA Auto Membership Rules.
|
||||
description: Add, modify and delete an IPA Auto Membership Rules.
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
@@ -587,7 +587,6 @@ def main():
|
||||
commands.append([None,
|
||||
'automember_default_group_remove',
|
||||
{'type': automember_type}])
|
||||
ansible_module.warn("commands: %s" % repr(commands))
|
||||
|
||||
else:
|
||||
dn_default_group = [DN(('cn', default_group),
|
||||
|
||||
@@ -112,21 +112,23 @@ class AutomountMap(IPAAnsibleModule):
|
||||
state = self.params_get("state")
|
||||
if state == "present":
|
||||
if len(name) != 1:
|
||||
self.fail_json(msg="Exactly one name must be provided \
|
||||
for state=present.")
|
||||
self.fail_json(msg="Exactly one name must be provided for"
|
||||
" 'state: present'.")
|
||||
if state == "absent":
|
||||
if len(name) == 0:
|
||||
self.fail_json(msg="Argument 'map_type' can not be used with "
|
||||
"state 'absent'")
|
||||
self.fail_json(msg="At least one 'name' must be provided for"
|
||||
" 'state: absent'")
|
||||
invalid = ["desc"]
|
||||
|
||||
self.params_fail_used_invalid(invalid, state)
|
||||
|
||||
def get_args(self, mapname, desc): # pylint: disable=no-self-use
|
||||
_args = {}
|
||||
if mapname:
|
||||
_args["automountmapname"] = mapname
|
||||
if desc:
|
||||
# automountmapname is required for all automountmap operations.
|
||||
if not mapname:
|
||||
self.fail_json(msg="automountmapname cannot be None or empty.")
|
||||
_args = {"automountmapname": mapname}
|
||||
# An empty string is valid and will clear the attribute.
|
||||
if desc is not None:
|
||||
_args["description"] = desc
|
||||
return _args
|
||||
|
||||
|
||||
@@ -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,13 +413,18 @@ 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",
|
||||
}
|
||||
allow_empty_string = ["pac_type", "user_auth_type", "configstring"]
|
||||
reverse_field_map = {v: k for k, v in field_map.items()}
|
||||
|
||||
params = {}
|
||||
for x in field_map:
|
||||
val = ansible_module.params_get(x)
|
||||
val = ansible_module.params_get(
|
||||
x, allow_empty_string=(x in allow_empty_string))
|
||||
|
||||
if val is not None:
|
||||
params[field_map.get(x, x)] = val
|
||||
@@ -392,15 +466,55 @@ 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
|
||||
}
|
||||
# Remove empty string args from params if result arg is not set
|
||||
for k in ["ipakrbauthzdata", "ipauserauthtype", "ipaconfigstring"]:
|
||||
if k not in result and k in params and params[k] == [""]:
|
||||
del params[k]
|
||||
if params \
|
||||
and not compare_args_ipa(ansible_module, params, result):
|
||||
changed = True
|
||||
@@ -435,12 +549,27 @@ def main():
|
||||
elif (
|
||||
isinstance(value, (tuple, list)) and arg_type == "bool"
|
||||
):
|
||||
exit_args[k] = (value[0] == "TRUE")
|
||||
# FreeIPA 4.9.10+ and 4.10 use proper mapping for
|
||||
# boolean values, so we need to convert it to str
|
||||
# for comparison.
|
||||
# See: https://github.com/freeipa/freeipa/pull/6294
|
||||
exit_args[k] = (str(value[0]).upper() == "TRUE")
|
||||
else:
|
||||
if arg_type not in type_map:
|
||||
raise ValueError(
|
||||
"Unexpected attribute type: %s" % arg_type)
|
||||
exit_args[k] = type_map[arg_type](value)
|
||||
# Add empty pac_type and user_auth_type if they are not set
|
||||
for key in ["pac_type", "user_auth_type"]:
|
||||
if key not in exit_args:
|
||||
exit_args[key] = ""
|
||||
# Add empty domain_resolution_order if it is not set
|
||||
if "domain_resolution_order" not in exit_args:
|
||||
exit_args["domain_resolution_order"] = []
|
||||
# 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)
|
||||
|
||||
@@ -32,7 +32,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipadelegation
|
||||
short description: Manage FreeIPA delegations
|
||||
short_description: Manage FreeIPA delegations
|
||||
description: Manage FreeIPA delegations and delegation attributes
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
|
||||
@@ -33,7 +33,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipadnsconfig
|
||||
short description: Manage FreeIPA dnsconfig
|
||||
short_description: Manage FreeIPA dnsconfig
|
||||
description: Manage FreeIPA dnsconfig
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
@@ -54,6 +54,7 @@ options:
|
||||
global forwarders.
|
||||
required: false
|
||||
choices: ['only', 'first', 'none']
|
||||
alias: ["forwardpolicy"]
|
||||
allow_sync_ptr:
|
||||
description:
|
||||
Allow synchronization of forward (A, AAAA) and reverse (PTR) records.
|
||||
@@ -172,7 +173,10 @@ def gen_args(module, state, action, dnsconfig, forwarders, forward_policy,
|
||||
_args['idnsforwardpolicy'] = forward_policy
|
||||
|
||||
if allow_sync_ptr is not None:
|
||||
_args['idnsallowsyncptr'] = 'TRUE' if allow_sync_ptr else 'FALSE'
|
||||
if module.ipa_check_version("<", "4.9.10"):
|
||||
_args['idnsallowsyncptr'] = "TRUE" if allow_sync_ptr else "FALSE"
|
||||
else:
|
||||
_args['idnsallowsyncptr'] = allow_sync_ptr
|
||||
|
||||
return _args
|
||||
|
||||
@@ -189,7 +193,8 @@ def main():
|
||||
forwarders=dict(type='list', default=None, required=False,
|
||||
options=dict(**forwarder_spec)),
|
||||
forward_policy=dict(type='str', required=False, default=None,
|
||||
choices=['only', 'first', 'none']),
|
||||
choices=['only', 'first', 'none'],
|
||||
aliases=["forwardpolicy"]),
|
||||
allow_sync_ptr=dict(type='bool', required=False, default=None),
|
||||
|
||||
# general
|
||||
@@ -197,7 +202,8 @@ def main():
|
||||
choices=["member", "dnsconfig"]),
|
||||
state=dict(type="str", default="present",
|
||||
choices=["present", "absent"]),
|
||||
)
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
ansible_module._ansible_debug = True
|
||||
|
||||
@@ -68,7 +68,7 @@ options:
|
||||
required: false
|
||||
default: only
|
||||
choices: ["only", "first", "none"]
|
||||
aliases: ["idnsforwarders"]
|
||||
aliases: ["idnsforwarders", "forward_policy"]
|
||||
skip_overlap_check:
|
||||
description:
|
||||
- Force DNS zone creation even if it will overlap with an existing zone.
|
||||
@@ -189,7 +189,8 @@ def main():
|
||||
port=dict(type='int', required=False,
|
||||
default=None),
|
||||
)),
|
||||
forwardpolicy=dict(type='str', aliases=["idnsforwardpolicy"],
|
||||
forwardpolicy=dict(type='str',
|
||||
aliases=["idnsforwardpolicy", "forward_policy"],
|
||||
required=False,
|
||||
choices=['only', 'first', 'none']),
|
||||
skip_overlap_check=dict(type='bool', required=False),
|
||||
@@ -343,7 +344,13 @@ def main():
|
||||
|
||||
if state in ['enabled', 'disabled']:
|
||||
if existing_resource is not None:
|
||||
is_enabled = existing_resource["idnszoneactive"][0]
|
||||
# FreeIPA 4.9.10+ and 4.10 use proper mapping for
|
||||
# boolean values, so we need to convert it to str
|
||||
# for comparison.
|
||||
# See: https://github.com/freeipa/freeipa/pull/6294
|
||||
is_enabled = (
|
||||
str(existing_resource["idnszoneactive"][0]).upper()
|
||||
)
|
||||
else:
|
||||
ansible_module.fail_json(
|
||||
msg="dnsforwardzone '%s' not found." % (name))
|
||||
|
||||
@@ -34,7 +34,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipadnsrecord
|
||||
short description: Manage FreeIPA DNS records
|
||||
short_description: Manage FreeIPA DNS records
|
||||
description: Manage FreeIPA DNS records
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
|
||||
@@ -32,7 +32,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipadnszone
|
||||
short description: Manage FreeIPA dnszone
|
||||
short_description: Manage FreeIPA dnszone
|
||||
description: Manage FreeIPA dnszone
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
@@ -418,7 +418,11 @@ class DNSZoneModule(IPAAnsibleModule):
|
||||
is_zone_active = False
|
||||
else:
|
||||
zone = response["result"]
|
||||
is_zone_active = "TRUE" in zone.get("idnszoneactive")
|
||||
# FreeIPA 4.9.10+ and 4.10 use proper mapping for boolean vaalues.
|
||||
# See: https://github.com/freeipa/freeipa/pull/6294
|
||||
is_zone_active = (
|
||||
str(zone.get("idnszoneactive")[0]).upper() == "TRUE"
|
||||
)
|
||||
|
||||
return zone, is_zone_active
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipagroup
|
||||
short description: Manage FreeIPA groups
|
||||
short_description: Manage FreeIPA groups
|
||||
description: Manage FreeIPA groups
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
@@ -97,6 +97,11 @@ options:
|
||||
required: false
|
||||
type: list
|
||||
ailases: ["ipaexternalmember", "external_member"]
|
||||
idoverrideuser:
|
||||
description:
|
||||
- User ID overrides to add
|
||||
required: false
|
||||
type: list
|
||||
action:
|
||||
description: Work on group or member level
|
||||
default: group
|
||||
@@ -184,7 +189,7 @@ RETURN = """
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, \
|
||||
gen_add_list, gen_intersection_list
|
||||
gen_add_list, gen_intersection_list, api_check_param
|
||||
|
||||
|
||||
def find_group(module, name):
|
||||
@@ -223,7 +228,7 @@ def gen_args(description, gid, nomembers):
|
||||
return _args
|
||||
|
||||
|
||||
def gen_member_args(user, group, service, externalmember):
|
||||
def gen_member_args(user, group, service, externalmember, idoverrideuser):
|
||||
_args = {}
|
||||
if user is not None:
|
||||
_args["member_user"] = user
|
||||
@@ -233,6 +238,8 @@ def gen_member_args(user, group, service, externalmember):
|
||||
_args["member_service"] = service
|
||||
if externalmember is not None:
|
||||
_args["member_external"] = externalmember
|
||||
if idoverrideuser is not None:
|
||||
_args["member_idoverrideuser"] = idoverrideuser
|
||||
|
||||
return _args
|
||||
|
||||
@@ -280,6 +287,7 @@ def main():
|
||||
user=dict(required=False, type='list', default=None),
|
||||
group=dict(required=False, type='list', default=None),
|
||||
service=dict(required=False, type='list', default=None),
|
||||
idoverrideuser=dict(required=False, type='list', default=None),
|
||||
membermanager_user=dict(required=False, type='list', default=None),
|
||||
membermanager_group=dict(required=False, type='list',
|
||||
default=None),
|
||||
@@ -312,6 +320,7 @@ def main():
|
||||
gid = ansible_module.params_get("gid")
|
||||
nonposix = ansible_module.params_get("nonposix")
|
||||
external = ansible_module.params_get("external")
|
||||
idoverrideuser = ansible_module.params_get("idoverrideuser")
|
||||
posix = ansible_module.params_get("posix")
|
||||
nomembers = ansible_module.params_get("nomembers")
|
||||
user = ansible_module.params_get("user")
|
||||
@@ -379,6 +388,13 @@ def main():
|
||||
"by your IPA version"
|
||||
)
|
||||
|
||||
has_idoverrideuser = api_check_param(
|
||||
"group_add_member", "idoverrideuser")
|
||||
if idoverrideuser is not None and not has_idoverrideuser:
|
||||
ansible_module.fail_json(
|
||||
msg="Managing a idoverrideuser as part of a group is not "
|
||||
"supported by your IPA version")
|
||||
|
||||
commands = []
|
||||
|
||||
for name in names:
|
||||
@@ -389,6 +405,7 @@ def main():
|
||||
group_add, group_del = [], []
|
||||
service_add, service_del = [], []
|
||||
externalmember_add, externalmember_del = [], []
|
||||
idoverrides_add, idoverrides_del = [], []
|
||||
membermanager_user_add, membermanager_user_del = [], []
|
||||
membermanager_group_add, membermanager_group_del = [], []
|
||||
|
||||
@@ -438,7 +455,7 @@ def main():
|
||||
res_find["objectclass"].append("posixgroup")
|
||||
|
||||
member_args = gen_member_args(
|
||||
user, group, service, externalmember
|
||||
user, group, service, externalmember, idoverrideuser
|
||||
)
|
||||
if not compare_args_ipa(ansible_module, member_args,
|
||||
res_find):
|
||||
@@ -456,6 +473,12 @@ def main():
|
||||
externalmember_del) = gen_add_del_lists(
|
||||
externalmember, res_find.get("member_external"))
|
||||
|
||||
(idoverrides_add,
|
||||
idoverrides_del) = gen_add_del_lists(
|
||||
idoverrideuser,
|
||||
res_find.get("member_idoverrideuser")
|
||||
)
|
||||
|
||||
membermanager_user_add, membermanager_user_del = \
|
||||
gen_add_del_lists(
|
||||
membermanager_user,
|
||||
@@ -483,6 +506,8 @@ def main():
|
||||
service, res_find.get("member_service"))
|
||||
externalmember_add = gen_add_list(
|
||||
externalmember, res_find.get("member_external"))
|
||||
idoverrides_add = gen_add_list(
|
||||
idoverrideuser, res_find.get("member_idoverrideuser"))
|
||||
|
||||
membermanager_user_add = gen_add_list(
|
||||
membermanager_user,
|
||||
@@ -516,6 +541,8 @@ def main():
|
||||
service, res_find.get("member_service"))
|
||||
externalmember_del = gen_intersection_list(
|
||||
externalmember, res_find.get("member_external"))
|
||||
idoverrides_del = gen_intersection_list(
|
||||
idoverrideuser, res_find.get("member_idoverrideuser"))
|
||||
|
||||
membermanager_user_del = gen_intersection_list(
|
||||
membermanager_user, res_find.get("membermanager_user"))
|
||||
@@ -532,10 +559,16 @@ def main():
|
||||
"user": user_add,
|
||||
"group": group_add,
|
||||
}
|
||||
|
||||
del_member_args = {
|
||||
"user": user_del,
|
||||
"group": group_del,
|
||||
}
|
||||
|
||||
if has_idoverrideuser:
|
||||
add_member_args["idoverrideuser"] = idoverrides_add
|
||||
del_member_args["idoverrideuser"] = idoverrides_del
|
||||
|
||||
if has_add_member_service:
|
||||
add_member_args["service"] = service_add
|
||||
del_member_args["service"] = service_del
|
||||
@@ -550,15 +583,16 @@ def main():
|
||||
msg="Cannot add external members to a "
|
||||
"non-external group."
|
||||
)
|
||||
|
||||
# Add members
|
||||
add_members = any([user_add, group_add,
|
||||
add_members = any([user_add, group_add, idoverrides_add,
|
||||
service_add, externalmember_add])
|
||||
if add_members:
|
||||
commands.append(
|
||||
[name, "group_add_member", add_member_args]
|
||||
)
|
||||
# Remove members
|
||||
remove_members = any([user_del, group_del,
|
||||
remove_members = any([user_del, group_del, idoverrides_del,
|
||||
service_del, externalmember_del])
|
||||
if remove_members:
|
||||
commands.append(
|
||||
|
||||
@@ -32,7 +32,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipahbacrule
|
||||
short description: Manage FreeIPA HBAC rules
|
||||
short_description: Manage FreeIPA HBAC rules
|
||||
description: Manage FreeIPA HBAC rules
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
@@ -360,28 +360,28 @@ def main():
|
||||
res_find = {}
|
||||
|
||||
# Generate addition and removal lists
|
||||
if host:
|
||||
if host is not None:
|
||||
host_add, host_del = gen_add_del_lists(
|
||||
host, res_find.get("memberhost_host"))
|
||||
|
||||
if hostgroup:
|
||||
if hostgroup is not None:
|
||||
hostgroup_add, hostgroup_del = gen_add_del_lists(
|
||||
hostgroup, res_find.get("memberhost_hostgroup"))
|
||||
|
||||
if hbacsvc:
|
||||
if hbacsvc is not None:
|
||||
hbacsvc_add, hbacsvc_del = gen_add_del_lists(
|
||||
hbacsvc, res_find.get("memberservice_hbacsvc"))
|
||||
|
||||
if hbacsvcgroup:
|
||||
if hbacsvcgroup is not None:
|
||||
hbacsvcgroup_add, hbacsvcgroup_del = gen_add_del_lists(
|
||||
hbacsvcgroup,
|
||||
res_find.get("memberservice_hbacsvcgroup"))
|
||||
|
||||
if user:
|
||||
if user is not None:
|
||||
user_add, user_del = gen_add_del_lists(
|
||||
user, res_find.get("memberuser_user"))
|
||||
|
||||
if group:
|
||||
if group is not None:
|
||||
group_add, group_del = gen_add_del_lists(
|
||||
group, res_find.get("memberuser_group"))
|
||||
|
||||
@@ -395,7 +395,7 @@ def main():
|
||||
if host:
|
||||
host_add = gen_add_list(
|
||||
host, res_find.get("memberhost_host"))
|
||||
if hostgroup is not None:
|
||||
if hostgroup:
|
||||
hostgroup_add = gen_add_list(
|
||||
hostgroup, res_find.get("memberhost_hostgroup"))
|
||||
|
||||
@@ -472,18 +472,26 @@ def main():
|
||||
# hbacrule_enable is not failing on an enabled hbacrule
|
||||
# Therefore it is needed to have a look at the ipaenabledflag
|
||||
# in res_find.
|
||||
if "ipaenabledflag" not in res_find or \
|
||||
res_find["ipaenabledflag"][0] != "TRUE":
|
||||
# FreeIPA 4.9.10+ and 4.10 use proper mapping for
|
||||
# boolean values, so we need to convert it to str
|
||||
# for comparison.
|
||||
# See: https://github.com/freeipa/freeipa/pull/6294
|
||||
enabled_flag = str(res_find.get("ipaenabledflag", [False])[0])
|
||||
if enabled_flag.upper() != "TRUE":
|
||||
commands.append([name, "hbacrule_enable", {}])
|
||||
|
||||
elif state == "disabled":
|
||||
if res_find is None:
|
||||
ansible_module.fail_json(msg="No hbacrule '%s'" % name)
|
||||
# hbacrule_disable is not failing on an disabled hbacrule
|
||||
# hbacrule_disable is not failing on an enabled hbacrule
|
||||
# Therefore it is needed to have a look at the ipaenabledflag
|
||||
# in res_find.
|
||||
if "ipaenabledflag" not in res_find or \
|
||||
res_find["ipaenabledflag"][0] != "FALSE":
|
||||
# FreeIPA 4.9.10+ and 4.10 use proper mapping for
|
||||
# boolean values, so we need to convert it to str
|
||||
# for comparison.
|
||||
# See: https://github.com/freeipa/freeipa/pull/6294
|
||||
enabled_flag = str(res_find.get("ipaenabledflag", [False])[0])
|
||||
if enabled_flag.upper() != "FALSE":
|
||||
commands.append([name, "hbacrule_disable", {}])
|
||||
|
||||
else:
|
||||
|
||||
@@ -32,7 +32,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipahbacsvc
|
||||
short description: Manage FreeIPA HBAC Services
|
||||
short_description: Manage FreeIPA HBAC Services
|
||||
description: Manage FreeIPA HBAC Services
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
|
||||
@@ -33,7 +33,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipahbacsvcgroup
|
||||
short description: Manage FreeIPA hbacsvcgroups
|
||||
short_description: Manage FreeIPA hbacsvcgroups
|
||||
description: Manage FreeIPA hbacsvcgroups
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
|
||||
@@ -32,7 +32,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipahost
|
||||
short description: Manage FreeIPA hosts
|
||||
short_description: Manage FreeIPA hosts
|
||||
description: Manage FreeIPA hosts
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
@@ -709,7 +709,7 @@ def main():
|
||||
elements='dict', required=False),
|
||||
|
||||
# mod
|
||||
update_password=dict(type='str', default=None,
|
||||
update_password=dict(type='str', default=None, no_log=False,
|
||||
choices=['always', 'on_create']),
|
||||
|
||||
# general
|
||||
@@ -764,7 +764,7 @@ def main():
|
||||
mac_address = ansible_module.params_get("mac_address")
|
||||
sshpubkey = ansible_module.params_get("sshpubkey")
|
||||
userclass = ansible_module.params_get("userclass")
|
||||
auth_ind = ansible_module.params_get("auth_ind")
|
||||
auth_ind = ansible_module.params_get("auth_ind", allow_empty_string=True)
|
||||
requires_pre_auth = ansible_module.params_get("requires_pre_auth")
|
||||
ok_as_delegate = ansible_module.params_get("ok_as_delegate")
|
||||
ok_to_auth_as_delegate = ansible_module.params_get(
|
||||
|
||||
@@ -33,7 +33,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipahostgroup
|
||||
short description: Manage FreeIPA hostgroups
|
||||
short_description: Manage FreeIPA hostgroups
|
||||
description: Manage FreeIPA hostgroups
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
|
||||
340
plugins/modules/ipaidrange.py
Normal file
340
plugins/modules/ipaidrange.py
Normal file
@@ -0,0 +1,340 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Authors:
|
||||
# Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
"metadata_version": "1.0",
|
||||
"supported_by": "community",
|
||||
"status": ["preview"],
|
||||
}
|
||||
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipaidrange
|
||||
short_description: Manage FreeIPA idrange
|
||||
description: Manage FreeIPA idrange
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
- ipamodule_base_docs.delete_continue
|
||||
options:
|
||||
name:
|
||||
description: The list of idrange name strings.
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
base_id:
|
||||
description: First Posix ID of the range.
|
||||
type: int
|
||||
required: false
|
||||
aliases: ["ipabaseid"]
|
||||
range_size:
|
||||
description: Number of IDs in the range.
|
||||
type: int
|
||||
required: false
|
||||
aliases: ["ipaidrangesize"]
|
||||
rid_base:
|
||||
description: First RID of the corresponding RID range.
|
||||
type: int
|
||||
required: false
|
||||
aliases: ["ipabaserid"]
|
||||
secondary_rid_base:
|
||||
description: First RID of the secondary RID range.
|
||||
type: int
|
||||
required: false
|
||||
aliases: ["ipasecondarybaserid"]
|
||||
idrange_type:
|
||||
description: ID range type.
|
||||
type: string
|
||||
required: false
|
||||
choices: ["ipa-ad-trust", "ipa-ad-trust-posix", "ipa-local"]
|
||||
aliases: ["iparangetype"]
|
||||
dom_sid:
|
||||
description: Domain SID of the trusted domain.
|
||||
type: string
|
||||
required: false
|
||||
aliases: ["ipanttrusteddomainsid"]
|
||||
dom_name:
|
||||
description: |
|
||||
Domain name of the trusted domain. Can only be used when
|
||||
`ipaapi_context: server`.
|
||||
type: string
|
||||
required: false
|
||||
aliases: ["ipanttrusteddomainname"]
|
||||
auto_private_groups:
|
||||
description: Auto creation of private groups.
|
||||
type: string
|
||||
required: false
|
||||
choices: ["true", "false", "hybrid"]
|
||||
aliases: ["ipaautoprivategroups"]
|
||||
state:
|
||||
description: The state to ensure.
|
||||
choices: ["present", "absent"]
|
||||
default: present
|
||||
required: true
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
# Ensure local domain idrange is present
|
||||
- ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
rid_base: 1000000
|
||||
secondary_rid_base: 200000000
|
||||
|
||||
# Ensure local domain idrange is absent
|
||||
- ipaidrange:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: id_range
|
||||
state: absent
|
||||
|
||||
# Ensure AD-trust idrange is present
|
||||
- ipaidrange:
|
||||
name: id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
rid_base: 1000000
|
||||
idrange_type: ipa-ad-trust
|
||||
dom_sid: S-1-5-21-2870384104-3340008087-3140804251
|
||||
auto_private_groups: "false"
|
||||
|
||||
# Ensure AD-trust idrange is present, with range type ad-trust-posix,
|
||||
# and using domain name
|
||||
- ipaidrange:
|
||||
name: id_range
|
||||
base_id: 150000000
|
||||
range_size: 200000
|
||||
rid_base: 1000000
|
||||
idrange_type: ipa-ad-trust-posix
|
||||
dom_name: ad.ipa.test
|
||||
auto_private_groups: "hybrid"
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
"""
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, get_trusted_domain_sid_from_name
|
||||
from ansible.module_utils import six
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
|
||||
def find_idrange(module, name):
|
||||
"""Find if a idrange with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("idrange_show", name, {"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
# An exception is raised if idrange name is not found.
|
||||
return None
|
||||
else:
|
||||
return _result["result"]
|
||||
|
||||
|
||||
def gen_args(
|
||||
base_id, range_size, rid_base, secondary_rid_base, idrange_type, dom_sid,
|
||||
dom_name, auto_private_groups
|
||||
):
|
||||
_args = {}
|
||||
# Integer parameters are stored as strings.
|
||||
# Converting them here allows the proper use of compare_args_ipa.
|
||||
if base_id is not None:
|
||||
_args["ipabaseid"] = base_id
|
||||
if range_size is not None:
|
||||
_args["ipaidrangesize"] = range_size
|
||||
if rid_base is not None:
|
||||
_args["ipabaserid"] = rid_base
|
||||
if secondary_rid_base is not None:
|
||||
_args["ipasecondarybaserid"] = secondary_rid_base
|
||||
if idrange_type is not None:
|
||||
_args["iparangetype"] = idrange_type
|
||||
if dom_name is not None:
|
||||
dom_sid = get_trusted_domain_sid_from_name(dom_name)
|
||||
if dom_sid is not None:
|
||||
_args["ipanttrusteddomainsid"] = dom_sid
|
||||
if auto_private_groups is not None:
|
||||
_args["ipaautoprivategroups"] = auto_private_groups
|
||||
return _args
|
||||
|
||||
|
||||
def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"],
|
||||
default=None, required=True),
|
||||
# present
|
||||
base_id=dict(required=False, type='int',
|
||||
aliases=["ipabaseid"], default=None),
|
||||
range_size=dict(required=False, type='int',
|
||||
aliases=["ipaidrangesize"], default=None),
|
||||
rid_base=dict(required=False, type='int',
|
||||
aliases=["ipabaserid"], default=None),
|
||||
secondary_rid_base=dict(required=False, type='int', default=None,
|
||||
aliases=["ipasecondarybaserid"]),
|
||||
idrange_type=dict(required=False, aliases=["iparangetype"],
|
||||
type="str", default=None,
|
||||
choices=["ipa-ad-trust", "ipa-ad-trust-posix",
|
||||
"ipa-local"]),
|
||||
dom_sid=dict(required=False, type='str', default=None,
|
||||
aliases=["ipanttrusteddomainsid"]),
|
||||
dom_name=dict(required=False, type='str', default=None,
|
||||
aliases=["ipanttrusteddomainname"]),
|
||||
auto_private_groups=dict(required=False, type='str', default=None,
|
||||
aliases=["ipaautoprivategroups"],
|
||||
choices=['true', 'false', 'hybrid']),
|
||||
# state
|
||||
state=dict(type="str", default="present",
|
||||
choices=["present", "absent"]),
|
||||
),
|
||||
mutually_exclusive=[
|
||||
["dom_sid", "secondary_rid_base"],
|
||||
["dom_name", "secondary_rid_base"],
|
||||
["dom_sid", "dom_name"],
|
||||
],
|
||||
supports_check_mode=True,
|
||||
ipa_module_options=["delete_continue"],
|
||||
)
|
||||
|
||||
ansible_module._ansible_debug = True
|
||||
|
||||
# Get parameters
|
||||
|
||||
# general
|
||||
names = ansible_module.params_get("name")
|
||||
delete_continue = ansible_module.params_get("delete_continue")
|
||||
|
||||
# present
|
||||
base_id = ansible_module.params_get("base_id")
|
||||
range_size = ansible_module.params_get("range_size")
|
||||
rid_base = ansible_module.params_get("rid_base")
|
||||
secondary_rid_base = ansible_module.params_get("secondary_rid_base")
|
||||
idrange_type = ansible_module.params_get("idrange_type")
|
||||
dom_sid = ansible_module.params_get("dom_sid")
|
||||
dom_name = ansible_module.params_get("dom_name")
|
||||
auto_private_groups = \
|
||||
ansible_module.params_get_lowercase("auto_private_groups")
|
||||
|
||||
# state
|
||||
state = ansible_module.params_get("state")
|
||||
|
||||
# Check parameters
|
||||
|
||||
invalid = []
|
||||
|
||||
if state == "present":
|
||||
if len(names) != 1:
|
||||
ansible_module.fail_json(
|
||||
msg="Only one idrange can be added at a time.")
|
||||
|
||||
if state == "absent":
|
||||
if len(names) < 1:
|
||||
ansible_module.fail_json(msg="No name given.")
|
||||
invalid = [
|
||||
"base_id", "range_size", "idrange_type", "dom_sid", "dom_name",
|
||||
"rid_base", "secondary_rid_base", "auto_private_groups"
|
||||
]
|
||||
|
||||
ansible_module.params_fail_used_invalid(invalid, state)
|
||||
|
||||
# Init
|
||||
|
||||
changed = False
|
||||
exit_args = {}
|
||||
|
||||
range_types = {
|
||||
"Active Directory domain range": "ipa-ad-trust",
|
||||
"Active Directory trust range with POSIX attributes":
|
||||
"ipa-ad-trust-posix",
|
||||
"local domain range": "ipa-local",
|
||||
}
|
||||
|
||||
# Connect to IPA API
|
||||
with ansible_module.ipa_connect():
|
||||
|
||||
commands = []
|
||||
for name in names:
|
||||
# Make sure idrange exists
|
||||
res_find = find_idrange(ansible_module, name)
|
||||
|
||||
# Create command
|
||||
if state == "present":
|
||||
|
||||
# Generate args
|
||||
args = gen_args(
|
||||
base_id, range_size, rid_base, secondary_rid_base,
|
||||
idrange_type, dom_sid, dom_name, auto_private_groups
|
||||
)
|
||||
|
||||
# Found the idrange
|
||||
if res_find is not None:
|
||||
# For all settings is args, check if there are
|
||||
# different settings in the find result.
|
||||
# If yes: modify
|
||||
if not compare_args_ipa(
|
||||
ansible_module, args, res_find, ignore=["iparangetype"]
|
||||
):
|
||||
res_type = range_types.get(
|
||||
res_find.get("iparangetype")[0]
|
||||
)
|
||||
if res_type == "local_id_range":
|
||||
ansible_module.fail_json(
|
||||
"Cannot modify local IPA domain idrange."
|
||||
)
|
||||
|
||||
arg_type = args.get("iparangetype")
|
||||
if arg_type:
|
||||
if arg_type != res_type:
|
||||
ansible_module.fail_json(
|
||||
"Cannot modify idrange type."
|
||||
)
|
||||
del args["iparangetype"]
|
||||
commands.append([name, "idrange_mod", args])
|
||||
else:
|
||||
commands.append([name, "idrange_add", args])
|
||||
|
||||
elif state == "absent":
|
||||
if res_find is not None:
|
||||
commands.append([
|
||||
name,
|
||||
"idrange_del",
|
||||
{"continue": delete_continue or False}
|
||||
])
|
||||
|
||||
else:
|
||||
ansible_module.fail_json(msg="Unkown state '%s'" % state)
|
||||
|
||||
# Execute commands
|
||||
|
||||
changed = ansible_module.execute_ipa_commands(commands)
|
||||
|
||||
# Done
|
||||
|
||||
ansible_module.exit_json(changed=changed, **exit_args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -32,7 +32,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipalocation
|
||||
short description: Manage FreeIPA location
|
||||
short_description: Manage FreeIPA location
|
||||
description: Manage FreeIPA location
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
|
||||
@@ -32,7 +32,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipapermission
|
||||
short description: Manage FreeIPA permission
|
||||
short_description: Manage FreeIPA permission
|
||||
description: Manage FreeIPA permission and permission members
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
|
||||
@@ -35,7 +35,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipaprivilege
|
||||
short description: Manage FreeIPA privilege
|
||||
short_description: Manage FreeIPA privilege
|
||||
description: Manage FreeIPA privilege and privilege members
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
|
||||
@@ -32,7 +32,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipapwpolicy
|
||||
short description: Manage FreeIPA pwpolicies
|
||||
short_description: Manage FreeIPA pwpolicies
|
||||
description: Manage FreeIPA pwpolicies
|
||||
options:
|
||||
ipaadmin_principal:
|
||||
|
||||
@@ -34,7 +34,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: iparole
|
||||
short description: Manage FreeIPA role
|
||||
short_description: Manage FreeIPA role
|
||||
description: Manage FreeIPA role
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
|
||||
@@ -32,7 +32,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipaselfservice
|
||||
short description: Manage FreeIPA selfservices
|
||||
short_description: Manage FreeIPA selfservices
|
||||
description: Manage FreeIPA selfservices and selfservice attributes
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
|
||||
@@ -32,7 +32,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipaserver
|
||||
short description: Manage FreeIPA server
|
||||
short_description: Manage FreeIPA server
|
||||
description: Manage FreeIPA server
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
|
||||
@@ -33,7 +33,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipaservice
|
||||
short description: Manage FreeIPA service
|
||||
short_description: Manage FreeIPA service
|
||||
description: Manage FreeIPA service
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
@@ -50,13 +50,13 @@ options:
|
||||
pac_type:
|
||||
description: Supported PAC type.
|
||||
required: false
|
||||
choices: ["MS-PAC", "PAD", "NONE"]
|
||||
choices: ["MS-PAC", "PAD", "NONE", ""]
|
||||
type: list
|
||||
aliases: ["pac_type", "ipakrbauthzdata"]
|
||||
auth_ind:
|
||||
description: Defines a whitelist for Authentication Indicators.
|
||||
required: false
|
||||
choices: ["otp", "radius", "pkinit", "hardened"]
|
||||
choices: ["otp", "radius", "pkinit", "hardened", ""]
|
||||
aliases: ["krbprincipalauthind"]
|
||||
skip_host_check:
|
||||
description: Skip checking if host object exists.
|
||||
@@ -356,7 +356,7 @@ def init_ansible_module():
|
||||
smb=dict(type="bool", required=False),
|
||||
netbiosname=dict(type="str", required=False),
|
||||
pac_type=dict(type="list", aliases=["ipakrbauthzdata"],
|
||||
choices=["MS-PAC", "PAD", "NONE"]),
|
||||
choices=["MS-PAC", "PAD", "NONE", ""]),
|
||||
auth_ind=dict(type="list",
|
||||
aliases=["krbprincipalauthind"],
|
||||
choices=["otp", "radius", "pkinit", "hardened", ""]),
|
||||
@@ -420,8 +420,8 @@ def main():
|
||||
# service attributes
|
||||
principal = ansible_module.params_get("principal")
|
||||
certificate = ansible_module.params_get("certificate")
|
||||
pac_type = ansible_module.params_get("pac_type")
|
||||
auth_ind = ansible_module.params_get("auth_ind")
|
||||
pac_type = ansible_module.params_get("pac_type", allow_empty_string=True)
|
||||
auth_ind = ansible_module.params_get("auth_ind", allow_empty_string=True)
|
||||
skip_host_check = ansible_module.params_get("skip_host_check")
|
||||
force = ansible_module.params_get("force")
|
||||
requires_pre_auth = ansible_module.params_get("requires_pre_auth")
|
||||
@@ -537,6 +537,15 @@ def main():
|
||||
if remove in args:
|
||||
del args[remove]
|
||||
|
||||
if (
|
||||
"ipakrbauthzdata" in args
|
||||
and (
|
||||
args.get("ipakrbauthzdata", [""]) ==
|
||||
res_find.get("ipakrbauthzdata", [""])
|
||||
)
|
||||
):
|
||||
del args["ipakrbauthzdata"]
|
||||
|
||||
if (
|
||||
"krbprincipalauthind" in args
|
||||
and (
|
||||
|
||||
352
plugins/modules/ipaservicedelegationrule.py
Normal file
352
plugins/modules/ipaservicedelegationrule.py
Normal file
@@ -0,0 +1,352 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
"metadata_version": "1.0",
|
||||
"supported_by": "community",
|
||||
"status": ["preview"],
|
||||
}
|
||||
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipaservicedelegationrule
|
||||
short_description: Manage FreeIPA servicedelegationrule
|
||||
description: |
|
||||
Manage FreeIPA servicedelegationrule and servicedelegationrule members
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
options:
|
||||
name:
|
||||
description: The list of servicedelegationrule name strings.
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
principal:
|
||||
description: |
|
||||
The list of principals. A principal can be of the format:
|
||||
fqdn, fqdn@REALM, service/fqdn, service/fqdn@REALM, host/fqdn,
|
||||
host/fqdn@REALM, alias$, alias$@REALM, where fqdn and fqdn@REALM
|
||||
are host principals and the same as host/fqdn and host/fqd
|
||||
Host princpals are only usable with IPA versions 4.9.0 and up.
|
||||
required: false
|
||||
target:
|
||||
description: |
|
||||
The list of service delegation targets.
|
||||
required: false
|
||||
aliases: ["servicedelegationtarget"]
|
||||
action:
|
||||
description: Work on servicedelegationrule or member level.
|
||||
choices: ["servicedelegationrule", "member"]
|
||||
default: servicedelegationrule
|
||||
required: false
|
||||
state:
|
||||
description: The state to ensure.
|
||||
choices: ["present", "absent"]
|
||||
default: present
|
||||
required: true
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
# Ensure servicedelegationrule delegation-rule is present
|
||||
- ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
|
||||
# Ensure servicedelegationrule delegation-rule member principal
|
||||
# test/example.com is present
|
||||
- ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
principal: test/example.com
|
||||
action: member
|
||||
|
||||
# Ensure servicedelegationrule delegation-rule member principal
|
||||
# test/example.com is absent
|
||||
- ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
principal: test/example.com
|
||||
action: member
|
||||
state: absent
|
||||
|
||||
# Ensure servicedelegationrule delegation-rule member target
|
||||
# test/example.com is present
|
||||
- ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
target: delegation-target
|
||||
action: member
|
||||
|
||||
# Ensure servicedelegationrule delegation-rule member target
|
||||
# test/example.com is absent
|
||||
- ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
target: delegation-target
|
||||
action: member
|
||||
state: absent
|
||||
|
||||
# Ensure servicedelegationrule delegation-rule is absent
|
||||
- ipaservicedelegationrule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-rule
|
||||
state: absent
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
"""
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, gen_add_del_lists, gen_add_list, gen_intersection_list, \
|
||||
servicedelegation_normalize_principals, ipalib_errors
|
||||
from ansible.module_utils import six
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
|
||||
def find_servicedelegationrule(module, name):
|
||||
"""Find if a servicedelegationrule with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("servicedelegationrule_show", name,
|
||||
{"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
# An exception is raised if servicedelegationrule name is not found.
|
||||
return None
|
||||
else:
|
||||
return _result["result"]
|
||||
|
||||
|
||||
def check_targets(module, targets):
|
||||
def _check_exists(module, _type, name):
|
||||
# Check if item of type _type exists using the show command
|
||||
try:
|
||||
module.ipa_command("%s_show" % _type, name, {})
|
||||
except ipalib_errors.NotFound as e:
|
||||
msg = str(e)
|
||||
if "%s not found" % _type in msg:
|
||||
return False
|
||||
module.fail_json(msg="%s_show failed: %s" % (_type, msg))
|
||||
return True
|
||||
|
||||
for _target in targets:
|
||||
if not _check_exists(module, "servicedelegationtarget", _target):
|
||||
module.fail_json(
|
||||
msg="Service delegation target '%s' does not exist" % _target)
|
||||
|
||||
|
||||
def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"], default=None,
|
||||
required=True),
|
||||
# present
|
||||
principal=dict(required=False, type='list', default=None),
|
||||
target=dict(required=False, type='list',
|
||||
aliases=["servicedelegationtarget"], default=None),
|
||||
|
||||
action=dict(type="str", default="servicedelegationrule",
|
||||
choices=["member", "servicedelegationrule"]),
|
||||
# state
|
||||
state=dict(type="str", default="present",
|
||||
choices=["present", "absent"]),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
ansible_module._ansible_debug = True
|
||||
|
||||
# Get parameters
|
||||
|
||||
# general
|
||||
names = ansible_module.params_get("name")
|
||||
|
||||
# present
|
||||
principal = ansible_module.params_get("principal")
|
||||
target = ansible_module.params_get("target")
|
||||
|
||||
action = ansible_module.params_get("action")
|
||||
|
||||
# state
|
||||
state = ansible_module.params_get("state")
|
||||
|
||||
# Check parameters
|
||||
|
||||
invalid = []
|
||||
|
||||
if state == "present":
|
||||
if len(names) != 1:
|
||||
ansible_module.fail_json(
|
||||
msg="Only one servicedelegationrule can be added at a time.")
|
||||
|
||||
if state == "absent":
|
||||
if len(names) < 1:
|
||||
ansible_module.fail_json(msg="No name given.")
|
||||
if action == "servicedelegationrule":
|
||||
invalid = ["principal", "target"]
|
||||
|
||||
ansible_module.params_fail_used_invalid(invalid, state, action)
|
||||
|
||||
# Init
|
||||
|
||||
membertarget = "ipaallowedtarget_servicedelegationtarget"
|
||||
changed = False
|
||||
exit_args = {}
|
||||
|
||||
# Connect to IPA API
|
||||
with ansible_module.ipa_connect():
|
||||
|
||||
# Normalize principals
|
||||
if principal:
|
||||
principal = servicedelegation_normalize_principals(
|
||||
ansible_module, principal, state == "present")
|
||||
if target and state == "present":
|
||||
check_targets(ansible_module, target)
|
||||
|
||||
commands = []
|
||||
principal_add = principal_del = []
|
||||
target_add = target_del = []
|
||||
for name in names:
|
||||
# Make sure servicedelegationrule exists
|
||||
res_find = find_servicedelegationrule(ansible_module, name)
|
||||
|
||||
# Create command
|
||||
if state == "present":
|
||||
|
||||
if action == "servicedelegationrule":
|
||||
# A servicedelegationrule does not have normal options.
|
||||
# There is no servicedelegationtarget-mod command.
|
||||
# Principal members are handled with the _add_member and
|
||||
# _remove_member commands further down.
|
||||
if res_find is None:
|
||||
commands.append([name, "servicedelegationrule_add",
|
||||
{}])
|
||||
res_find = {}
|
||||
|
||||
# Generate addition and removal lists for principal
|
||||
principal_add, principal_del = gen_add_del_lists(
|
||||
principal, res_find.get("memberprincipal"))
|
||||
|
||||
# Generate addition and removal lists for target
|
||||
target_add, target_del = gen_add_del_lists(
|
||||
target, res_find.get(membertarget))
|
||||
|
||||
elif action == "member":
|
||||
if res_find is None:
|
||||
ansible_module.fail_json(
|
||||
msg="No servicedelegationrule '%s'" % name)
|
||||
|
||||
# Reduce add lists for principal
|
||||
# to new entries only that are not in res_find.
|
||||
if principal is not None and \
|
||||
"memberprincipal" in res_find:
|
||||
principal_add = gen_add_list(
|
||||
principal, res_find["memberprincipal"])
|
||||
else:
|
||||
principal_add = principal
|
||||
|
||||
# Reduce add lists for target
|
||||
# to new entries only that are not in res_find.
|
||||
if target is not None and membertarget in res_find:
|
||||
target_add = gen_add_list(
|
||||
target, res_find[membertarget])
|
||||
else:
|
||||
target_add = target
|
||||
|
||||
elif state == "absent":
|
||||
if action == "servicedelegationrule":
|
||||
if res_find is not None:
|
||||
commands.append([name, "servicedelegationrule_del",
|
||||
{}])
|
||||
|
||||
elif action == "member":
|
||||
if res_find is None:
|
||||
ansible_module.fail_json(
|
||||
msg="No servicedelegationrule '%s'" % name)
|
||||
|
||||
# Reduce del lists of principals to the entries only
|
||||
# that are in res_find.
|
||||
if principal is not None:
|
||||
principal_del = gen_intersection_list(
|
||||
principal, res_find.get("memberprincipal"))
|
||||
else:
|
||||
principal_del = principal
|
||||
|
||||
# Reduce del lists of targets to the entries only
|
||||
# that are in res_find.
|
||||
if target is not None:
|
||||
target_del = gen_intersection_list(
|
||||
target, res_find.get(membertarget))
|
||||
else:
|
||||
target_del = target
|
||||
|
||||
else:
|
||||
ansible_module.fail_json(msg="Unkown state '%s'" % state)
|
||||
|
||||
# Handle members
|
||||
|
||||
# Add principal members
|
||||
if principal_add is not None and len(principal_add) > 0:
|
||||
commands.append(
|
||||
[name, "servicedelegationtarget_add_member",
|
||||
{
|
||||
"principal": principal_add,
|
||||
}])
|
||||
# Remove principal members
|
||||
if principal_del is not None and len(principal_del) > 0:
|
||||
commands.append(
|
||||
[name, "servicedelegationtarget_remove_member",
|
||||
{
|
||||
"principal": principal_del,
|
||||
}])
|
||||
|
||||
# Add target members
|
||||
if target_add is not None and len(target_add) > 0:
|
||||
commands.append(
|
||||
[name, "servicedelegationrule_add_target",
|
||||
{
|
||||
"servicedelegationtarget": target_add,
|
||||
}])
|
||||
# Remove target members
|
||||
if target_del is not None and len(target_del) > 0:
|
||||
commands.append(
|
||||
[name, "servicedelegationrule_remove_target",
|
||||
{
|
||||
"servicedelegationtarget": target_del,
|
||||
}])
|
||||
|
||||
# Execute commands
|
||||
|
||||
changed = ansible_module.execute_ipa_commands(
|
||||
commands, fail_on_member_errors=True)
|
||||
|
||||
# Done
|
||||
|
||||
ansible_module.exit_json(changed=changed, **exit_args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
270
plugins/modules/ipaservicedelegationtarget.py
Normal file
270
plugins/modules/ipaservicedelegationtarget.py
Normal file
@@ -0,0 +1,270 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
"metadata_version": "1.0",
|
||||
"supported_by": "community",
|
||||
"status": ["preview"],
|
||||
}
|
||||
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipaservicedelegationtarget
|
||||
short_description: Manage FreeIPA servicedelegationtarget
|
||||
description: |
|
||||
Manage FreeIPA servicedelegationtarget and servicedelegationtarget members
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
options:
|
||||
name:
|
||||
description: The list of servicedelegationtarget name strings.
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
principal:
|
||||
description: |
|
||||
The list of principals. A principal can be of the format:
|
||||
fqdn, fqdn@REALM, service/fqdn, service/fqdn@REALM, host/fqdn,
|
||||
host/fqdn@REALM, alias$, alias$@REALM, where fqdn and fqdn@REALM
|
||||
are host principals and the same as host/fqdn and host/fqdn@REALM.
|
||||
Host princpals are only usable with IPA versions 4.9.0 and up.
|
||||
required: false
|
||||
action:
|
||||
description: Work on servicedelegationtarget or member level.
|
||||
choices: ["servicedelegationtarget", "member"]
|
||||
default: servicedelegationtarget
|
||||
required: false
|
||||
state:
|
||||
description: The state to ensure.
|
||||
choices: ["present", "absent"]
|
||||
default: present
|
||||
required: true
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
# Ensure servicedelegationtarget delegation-target is present
|
||||
- ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-target
|
||||
|
||||
# Ensure servicedelegationtarget delegation-target member principal
|
||||
# test/example.com is present
|
||||
- ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-target
|
||||
principal: test/example.com
|
||||
action: member
|
||||
|
||||
# Ensure servicedelegationtarget delegation-target member principal
|
||||
# test/example.com is absent
|
||||
- ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-target
|
||||
principal: test/example.com
|
||||
action: member
|
||||
state: absent
|
||||
|
||||
# Ensure servicedelegationtarget delegation-target is absent
|
||||
- ipaservicedelegationtarget:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: delegation-target
|
||||
state: absent
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
"""
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, gen_add_del_lists, gen_add_list, gen_intersection_list, \
|
||||
servicedelegation_normalize_principals
|
||||
from ansible.module_utils import six
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
|
||||
def find_servicedelegationtarget(module, name):
|
||||
"""Find if a servicedelegationtarget with the given name already exist."""
|
||||
try:
|
||||
_result = module.ipa_command("servicedelegationtarget_show", name,
|
||||
{"all": True})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
# An exception is raised if servicedelegationtarget name is not found.
|
||||
return None
|
||||
else:
|
||||
return _result["result"]
|
||||
|
||||
|
||||
def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"], default=None,
|
||||
required=True),
|
||||
# present
|
||||
principal=dict(required=False, type='list', default=None),
|
||||
|
||||
action=dict(type="str", default="servicedelegationtarget",
|
||||
choices=["member", "servicedelegationtarget"]),
|
||||
# state
|
||||
state=dict(type="str", default="present",
|
||||
choices=["present", "absent"]),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
ansible_module._ansible_debug = True
|
||||
|
||||
# Get parameters
|
||||
|
||||
# general
|
||||
names = ansible_module.params_get("name")
|
||||
|
||||
# present
|
||||
principal = ansible_module.params_get("principal")
|
||||
|
||||
action = ansible_module.params_get("action")
|
||||
|
||||
# state
|
||||
state = ansible_module.params_get("state")
|
||||
|
||||
# Check parameters
|
||||
|
||||
invalid = []
|
||||
|
||||
if state == "present":
|
||||
if len(names) != 1:
|
||||
ansible_module.fail_json(
|
||||
msg="Only one servicedelegationtarget can be added at a time.")
|
||||
|
||||
if state == "absent":
|
||||
if len(names) < 1:
|
||||
ansible_module.fail_json(msg="No name given.")
|
||||
if action == "servicedelegationtarget":
|
||||
invalid.append("principal")
|
||||
|
||||
ansible_module.params_fail_used_invalid(invalid, state, action)
|
||||
|
||||
# Init
|
||||
|
||||
changed = False
|
||||
exit_args = {}
|
||||
|
||||
# Connect to IPA API
|
||||
with ansible_module.ipa_connect():
|
||||
|
||||
# Normalize principals
|
||||
if principal:
|
||||
principal = servicedelegation_normalize_principals(
|
||||
ansible_module, principal, state == "present")
|
||||
|
||||
commands = []
|
||||
principal_add = principal_del = []
|
||||
for name in names:
|
||||
# Make sure servicedelegationtarget exists
|
||||
res_find = find_servicedelegationtarget(ansible_module, name)
|
||||
|
||||
# Create command
|
||||
if state == "present":
|
||||
|
||||
if action == "servicedelegationtarget":
|
||||
# A servicedelegationtarget does not have normal options.
|
||||
# There is no servicedelegationtarget-mod command.
|
||||
# Principal members are handled with the _add_member and
|
||||
# _remove_member commands further down.
|
||||
if res_find is None:
|
||||
commands.append([name, "servicedelegationtarget_add",
|
||||
{}])
|
||||
res_find = {}
|
||||
|
||||
# Generate addition and removal lists
|
||||
principal_add, principal_del = gen_add_del_lists(
|
||||
principal, res_find.get("memberprincipal"))
|
||||
|
||||
elif action == "member":
|
||||
if res_find is None:
|
||||
ansible_module.fail_json(
|
||||
msg="No servicedelegationtarget '%s'" % name)
|
||||
|
||||
# Reduce add lists for principal
|
||||
# to new entries only that are not in res_find.
|
||||
if principal is not None and \
|
||||
"memberprincipal" in res_find:
|
||||
principal_add = gen_add_list(
|
||||
principal, res_find["memberprincipal"])
|
||||
else:
|
||||
principal_add = principal
|
||||
|
||||
elif state == "absent":
|
||||
if action == "servicedelegationtarget":
|
||||
if res_find is not None:
|
||||
commands.append([name, "servicedelegationtarget_del",
|
||||
{}])
|
||||
|
||||
elif action == "member":
|
||||
if res_find is None:
|
||||
ansible_module.fail_json(
|
||||
msg="No servicedelegationtarget '%s'" % name)
|
||||
|
||||
# Reduce del lists of principal
|
||||
# to the entries only that are in res_find.
|
||||
if principal is not None:
|
||||
principal_del = gen_intersection_list(
|
||||
principal, res_find.get("memberprincipal"))
|
||||
else:
|
||||
principal_del = principal
|
||||
|
||||
else:
|
||||
ansible_module.fail_json(msg="Unkown state '%s'" % state)
|
||||
|
||||
# Handle members
|
||||
|
||||
# Add principal members
|
||||
if principal_add is not None and len(principal_add) > 0:
|
||||
commands.append(
|
||||
[name, "servicedelegationtarget_add_member",
|
||||
{
|
||||
"principal": principal_add,
|
||||
}])
|
||||
# Remove principal members
|
||||
if principal_del is not None and len(principal_del) > 0:
|
||||
commands.append(
|
||||
[name, "servicedelegationtarget_remove_member",
|
||||
{
|
||||
"principal": principal_del,
|
||||
}])
|
||||
|
||||
# Execute commands
|
||||
|
||||
changed = ansible_module.execute_ipa_commands(
|
||||
commands, fail_on_member_errors=True)
|
||||
|
||||
# Done
|
||||
|
||||
ansible_module.exit_json(changed=changed, **exit_args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -33,7 +33,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipasudocmd
|
||||
short description: Manage FreeIPA sudo command
|
||||
short_description: Manage FreeIPA sudo command
|
||||
description: Manage FreeIPA sudo command
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
|
||||
@@ -33,7 +33,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipasudocmdgroup
|
||||
short description: Manage FreeIPA sudocmd groups
|
||||
short_description: Manage FreeIPA sudocmd groups
|
||||
description: Manage FreeIPA sudocmd groups
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
|
||||
@@ -32,7 +32,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipasudorule
|
||||
short description: Manage FreeIPA sudo rules
|
||||
short_description: Manage FreeIPA sudo rules
|
||||
description: Manage FreeIPA sudo rules
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
@@ -162,19 +162,19 @@ EXAMPLES = """
|
||||
hostgroup: cluster
|
||||
action: member
|
||||
|
||||
# Ensure sudo rule for usercategory "all"
|
||||
# Ensure sudo rule for usercategory "all" is enabled
|
||||
- ipasudorule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: allusers
|
||||
usercategory: all
|
||||
action: enabled
|
||||
state: enabled
|
||||
|
||||
# Ensure sudo rule for hostcategory "all"
|
||||
# Ensure sudo rule for hostcategory "all" is enabled
|
||||
- ipasudorule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: allhosts
|
||||
hostcategory: all
|
||||
action: enabled
|
||||
state: enabled
|
||||
|
||||
# Ensure Sudo Rule tesrule1 is absent
|
||||
- ipasudorule:
|
||||
@@ -656,8 +656,12 @@ def main():
|
||||
# sudorule_enable is not failing on an enabled sudorule
|
||||
# Therefore it is needed to have a look at the ipaenabledflag
|
||||
# in res_find.
|
||||
if "ipaenabledflag" not in res_find or \
|
||||
res_find["ipaenabledflag"][0] != "TRUE":
|
||||
# FreeIPA 4.9.10+ and 4.10 use proper mapping for
|
||||
# boolean values, so we need to convert it to str
|
||||
# for comparison.
|
||||
# See: https://github.com/freeipa/freeipa/pull/6294
|
||||
enabled_flag = str(res_find.get("ipaenabledflag", [False])[0])
|
||||
if enabled_flag.upper() != "TRUE":
|
||||
commands.append([name, "sudorule_enable", {}])
|
||||
|
||||
elif state == "disabled":
|
||||
@@ -666,8 +670,12 @@ def main():
|
||||
# sudorule_disable is not failing on an disabled sudorule
|
||||
# Therefore it is needed to have a look at the ipaenabledflag
|
||||
# in res_find.
|
||||
if "ipaenabledflag" not in res_find or \
|
||||
res_find["ipaenabledflag"][0] != "FALSE":
|
||||
# FreeIPA 4.9.10+ and 4.10 use proper mapping for
|
||||
# boolean values, so we need to convert it to str
|
||||
# for comparison.
|
||||
# See: https://github.com/freeipa/freeipa/pull/6294
|
||||
enabled_flag = str(res_find.get("ipaenabledflag", [False])[0])
|
||||
if enabled_flag.upper() != "FALSE":
|
||||
commands.append([name, "sudorule_disable", {}])
|
||||
|
||||
else:
|
||||
|
||||
@@ -32,7 +32,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipatopologysegment
|
||||
short description: Manage FreeIPA topology segments
|
||||
short_description: Manage FreeIPA topology segments
|
||||
description: Manage FreeIPA topology segments
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
|
||||
@@ -32,7 +32,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipatopologysuffix
|
||||
short description: Verify FreeIPA topology suffix
|
||||
short_description: Verify FreeIPA topology suffix
|
||||
description: Verify FreeIPA topology suffix
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user