mirror of
https://github.com/freeipa/ansible-freeipa.git
synced 2026-03-29 23:03:05 +00:00
Compare commits
472 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf779e43bb | ||
|
|
1a48a0fb63 | ||
|
|
ed3a0d5a1b | ||
|
|
d58b492f1d | ||
|
|
88d4a36e17 | ||
|
|
6fa8223662 | ||
|
|
c9e8656494 | ||
|
|
a791c6a0ca | ||
|
|
9cbccdade9 | ||
|
|
42c07d6336 | ||
|
|
a728a8d43e | ||
|
|
bd3266e9f1 | ||
|
|
48063d2b3a | ||
|
|
5d08214516 | ||
|
|
ef0b7e80f0 | ||
|
|
a33fcf45f8 | ||
|
|
c4b273c896 | ||
|
|
62d34d0a22 | ||
|
|
3ed0c229c4 | ||
|
|
c089c010e6 | ||
|
|
cfbdd83a64 | ||
|
|
fef1bdcf8e | ||
|
|
411d363d91 | ||
|
|
1555132d85 | ||
|
|
57ad57dda3 | ||
|
|
dab64c7cf6 | ||
|
|
b7145bc2cc | ||
|
|
c9f1da5d6b | ||
|
|
f4070f6a30 | ||
|
|
ad9a03ece6 | ||
|
|
1bfe6888a4 | ||
|
|
51ddaa6491 | ||
|
|
f56861cc15 | ||
|
|
c4de680497 | ||
|
|
7b2701b985 | ||
|
|
694c717829 | ||
|
|
083396e133 | ||
|
|
9a8a1db38f | ||
|
|
8f9c344bc1 | ||
|
|
067b683b81 | ||
|
|
51f64e4393 | ||
|
|
45700bc02b | ||
|
|
d04a12e522 | ||
|
|
4e9ec11b23 | ||
|
|
2d93051101 | ||
|
|
1a7b279d78 | ||
|
|
be228d1df3 | ||
|
|
ce95c638be | ||
|
|
876f39a6c5 | ||
|
|
950840e050 | ||
|
|
87e1edf575 | ||
|
|
09250cb2c5 | ||
|
|
872c9e4cb2 | ||
|
|
efe9c68600 | ||
|
|
0d9873b81c | ||
|
|
5b91703bd7 | ||
|
|
180afd7586 | ||
|
|
7f16914032 | ||
|
|
306522acd8 | ||
|
|
a155324188 | ||
|
|
8ec5b1fe21 | ||
|
|
316255d524 | ||
|
|
36b7a18e40 | ||
|
|
a32fcb3765 | ||
|
|
2d4cad6c1b | ||
|
|
a4b8e10a40 | ||
|
|
98681bd4d2 | ||
|
|
2882e2426a | ||
|
|
f056775d95 | ||
|
|
ad5450cd6f | ||
|
|
e75d82131d | ||
|
|
99e468ad60 | ||
|
|
3cc111782c | ||
|
|
b429b4495e | ||
|
|
0f99ef2199 | ||
|
|
1c8f1c28e1 | ||
|
|
47d5211185 | ||
|
|
4a18ad03c8 | ||
|
|
966797dbee | ||
|
|
892c0dd6f0 | ||
|
|
645a234d92 | ||
|
|
5cbc8b7ada | ||
|
|
5e5fbd87bf | ||
|
|
35ded3bf53 | ||
|
|
209c6365ea | ||
|
|
a69446021b | ||
|
|
b861a61857 | ||
|
|
6faff2ac11 | ||
|
|
82c0161245 | ||
|
|
ecab42b9f5 | ||
|
|
183ea7fd79 | ||
|
|
a4087a755b | ||
|
|
fb3ff6d63d | ||
|
|
ee92d99243 | ||
|
|
a649a8dfe1 | ||
|
|
80abf635c3 | ||
|
|
24e05d1df4 | ||
|
|
065e902182 | ||
|
|
96f5f5c86e | ||
|
|
476d9d5057 | ||
|
|
049024bbb2 | ||
|
|
ec03ad2bf9 | ||
|
|
64c43c1ec0 | ||
|
|
b1eb32993d | ||
|
|
2ee7139560 | ||
|
|
10d072a8c4 | ||
|
|
0ec89eb53c | ||
|
|
cf27a98c61 | ||
|
|
fd3e87771a | ||
|
|
e03752955f | ||
|
|
338df6e60e | ||
|
|
3f3e495ab3 | ||
|
|
b05aec98c5 | ||
|
|
867f7ed520 | ||
|
|
3cc17a43aa | ||
|
|
2b0b7db086 | ||
|
|
87afc56ee6 | ||
|
|
61caa57801 | ||
|
|
6b5acd9b0c | ||
|
|
78b5e66da4 | ||
|
|
f6c376a68f | ||
|
|
691fbd083e | ||
|
|
77cd20bc10 | ||
|
|
16ce5f21de | ||
|
|
dcf9c7d8ce | ||
|
|
c715d3aad2 | ||
|
|
0d1e9d3f49 | ||
|
|
b30ae1c9b5 | ||
|
|
bfeefaf454 | ||
|
|
0c23ae5b37 | ||
|
|
3b4367cf89 | ||
|
|
e96f92c36f | ||
|
|
683a894876 | ||
|
|
2761c7e8d9 | ||
|
|
7d3921e510 | ||
|
|
6000aac687 | ||
|
|
e8354932b4 | ||
|
|
a3089484b1 | ||
|
|
1469ac6058 | ||
|
|
308d970b6c | ||
|
|
7b470ceb60 | ||
|
|
77f5d8751f | ||
|
|
3292252802 | ||
|
|
414dc06c86 | ||
|
|
d2f9fe6325 | ||
|
|
d7c02d1347 | ||
|
|
cc6a80fa88 | ||
|
|
fe6edbabdb | ||
|
|
434905432d | ||
|
|
9f773ff5ac | ||
|
|
e95bec1803 | ||
|
|
ea709ebc4d | ||
|
|
add89c25ee | ||
|
|
9108065ea7 | ||
|
|
6cac891287 | ||
|
|
fc5fc9d9ef | ||
|
|
670740bdc0 | ||
|
|
529deae407 | ||
|
|
a945862540 | ||
|
|
8240d9beb6 | ||
|
|
6da6110432 | ||
|
|
1d8deb8e2d | ||
|
|
b3856a1e2c | ||
|
|
410682a01d | ||
|
|
ee59ec2142 | ||
|
|
d043a3bdd1 | ||
|
|
5062ac2b09 | ||
|
|
292e2eb60e | ||
|
|
baa7cae8bf | ||
|
|
6b7633976c | ||
|
|
9a32359a5d | ||
|
|
82e176af95 | ||
|
|
2a1ecdbd83 | ||
|
|
f8b5851610 | ||
|
|
b760863847 | ||
|
|
e3bf82d873 | ||
|
|
76ca587d76 | ||
|
|
5c630d6021 | ||
|
|
483d51b418 | ||
|
|
ba353a9b16 | ||
|
|
56560855b4 | ||
|
|
a8d44e2c52 | ||
|
|
b175c78c95 | ||
|
|
198298b2d0 | ||
|
|
d5269c83e6 | ||
|
|
9d47ffc2b9 | ||
|
|
feadbfce95 | ||
|
|
a9257e7f44 | ||
|
|
d204b6d480 | ||
|
|
c645841444 | ||
|
|
f2a0edeb25 | ||
|
|
45baf5c108 | ||
|
|
deec31c3ab | ||
|
|
fea480b348 | ||
|
|
defd1e4e92 | ||
|
|
adc262bcb0 | ||
|
|
72b4b89116 | ||
|
|
473ed03e26 | ||
|
|
d546b4614d | ||
|
|
872537f4de | ||
|
|
d6658347c9 | ||
|
|
062b53a676 | ||
|
|
470d0ddc1b | ||
|
|
2e707a48cb | ||
|
|
971d40c3a9 | ||
|
|
7d89af48b6 | ||
|
|
03ce096fbb | ||
|
|
91edff3b21 | ||
|
|
84c0188023 | ||
|
|
1f91730b17 | ||
|
|
99c7acbe5f | ||
|
|
14706cc49e | ||
|
|
dde5b06b97 | ||
|
|
c7e83685e3 | ||
|
|
882d60515d | ||
|
|
27cbd40182 | ||
|
|
c5ba88d725 | ||
|
|
1a5c62fe9c | ||
|
|
67d6455db6 | ||
|
|
a4b71700f7 | ||
|
|
5f5807b49c | ||
|
|
b670d29d30 | ||
|
|
9de235474b | ||
|
|
a55b4a241a | ||
|
|
c68348b5d3 | ||
|
|
76aad71974 | ||
|
|
3b73ad6b27 | ||
|
|
789d6eea14 | ||
|
|
422651e6ff | ||
|
|
8459e1c454 | ||
|
|
0bb0d99aa4 | ||
|
|
d859ddc7fe | ||
|
|
460adff1ba | ||
|
|
a823c0b09c | ||
|
|
624e0d3435 | ||
|
|
1c17f426ac | ||
|
|
01287288a7 | ||
|
|
58725364c1 | ||
|
|
9423eb81b7 | ||
|
|
ef11e75944 | ||
|
|
932856df67 | ||
|
|
118d754d69 | ||
|
|
ef5ae121c8 | ||
|
|
9007cffdd9 | ||
|
|
6601ee3af5 | ||
|
|
b34062cabd | ||
|
|
2cfa9af586 | ||
|
|
f2632d8c90 | ||
|
|
f82b93a801 | ||
|
|
57c303d816 | ||
|
|
165c3f06b7 | ||
|
|
300292c050 | ||
|
|
15454c3a48 | ||
|
|
d962939a61 | ||
|
|
66dbfce0f7 | ||
|
|
b22207d6ee | ||
|
|
1062e0fe99 | ||
|
|
1148476cf5 | ||
|
|
9eb07f7024 | ||
|
|
0faf8c86ca | ||
|
|
9f3a2d42d0 | ||
|
|
c2475304ec | ||
|
|
2a817a989d | ||
|
|
03e9dd3f00 | ||
|
|
62d49e4e9e | ||
|
|
446107f1cb | ||
|
|
7627c57c4a | ||
|
|
4cfa28eea7 | ||
|
|
e42f1c118b | ||
|
|
78e94864b0 | ||
|
|
ea3142ba44 | ||
|
|
b3f85d49df | ||
|
|
12ee8a9201 | ||
|
|
72d9fea37a | ||
|
|
99289fc33e | ||
|
|
d12c3748a7 | ||
|
|
8906cfc81b | ||
|
|
3f91a53b2e | ||
|
|
d1e518385e | ||
|
|
b4aa4a2af8 | ||
|
|
732133a460 | ||
|
|
4a342685af | ||
|
|
1a80954475 | ||
|
|
55393307b8 | ||
|
|
88645e5c4a | ||
|
|
ae4aaf51f0 | ||
|
|
32f681dba2 | ||
|
|
bd04171a56 | ||
|
|
065db1b359 | ||
|
|
8c81ac0f5f | ||
|
|
d4c34a28df | ||
|
|
f1d2d63f2b | ||
|
|
b89dd0d036 | ||
|
|
aa43583149 | ||
|
|
e152259757 | ||
|
|
a65b24c172 | ||
|
|
a1667babf4 | ||
|
|
08ffa7c466 | ||
|
|
0f724598a8 | ||
|
|
1239109e43 | ||
|
|
4baeaa1e68 | ||
|
|
923cd9f5b1 | ||
|
|
c3f48d2851 | ||
|
|
3c413cfdfd | ||
|
|
e932f65b7c | ||
|
|
c633b2dc88 | ||
|
|
c37be7416c | ||
|
|
97a7232bdc | ||
|
|
e3ba5c75cb | ||
|
|
b2dfd11058 | ||
|
|
0f0c098fa2 | ||
|
|
29dccf3d8a | ||
|
|
9b6fd8cce0 | ||
|
|
10b3f4610c | ||
|
|
b7e39ce7e9 | ||
|
|
07b9c7dc40 | ||
|
|
3773e300f0 | ||
|
|
68c52b564a | ||
|
|
5a07782cbe | ||
|
|
1ba397e783 | ||
|
|
767b4d36a6 | ||
|
|
2e6041d0a7 | ||
|
|
a4c890ab3b | ||
|
|
903e002e85 | ||
|
|
0dc49d0706 | ||
|
|
18008d3ff2 | ||
|
|
aba9add595 | ||
|
|
4353ad72e4 | ||
|
|
4ad3c84cae | ||
|
|
7e92fec884 | ||
|
|
1a8df6e955 | ||
|
|
77c6770bfc | ||
|
|
169e772f29 | ||
|
|
44e2718aa1 | ||
|
|
c1827807c6 | ||
|
|
5c1c4d83c2 | ||
|
|
38e874fddb | ||
|
|
495677df38 | ||
|
|
6e44b4d034 | ||
|
|
9c71d91a2e | ||
|
|
9271b84df8 | ||
|
|
2621b311f9 | ||
|
|
9480841b12 | ||
|
|
461a9ec092 | ||
|
|
706eb15291 | ||
|
|
f8ca8a7b87 | ||
|
|
c808ad6e34 | ||
|
|
17606651eb | ||
|
|
320168071f | ||
|
|
aa4cc3bf45 | ||
|
|
fa86cd2944 | ||
|
|
49dbf9fd6c | ||
|
|
f194e919a0 | ||
|
|
69a2be7b51 | ||
|
|
684dfd9cf3 | ||
|
|
aebb4456ab | ||
|
|
3877fb689f | ||
|
|
9a8d756ad6 | ||
|
|
1bf7fb7233 | ||
|
|
5382c625b2 | ||
|
|
61277c0898 | ||
|
|
cd36d32fea | ||
|
|
0411b12bbb | ||
|
|
b2ea0d79be | ||
|
|
b7c0954553 | ||
|
|
87d0812396 | ||
|
|
49ad4cbfe1 | ||
|
|
2f8911eba5 | ||
|
|
031b6f2f16 | ||
|
|
35210b3646 | ||
|
|
d1ce1526d2 | ||
|
|
0161fea4df | ||
|
|
757c0a142b | ||
|
|
f4fcf1b578 | ||
|
|
4da89de1d4 | ||
|
|
0ad7635332 | ||
|
|
0ba404733d | ||
|
|
3c1c3ebe55 | ||
|
|
95d961ccf6 | ||
|
|
1c1d26c404 | ||
|
|
43e548a25d | ||
|
|
58c936a189 | ||
|
|
af87a2d923 | ||
|
|
87aae5b396 | ||
|
|
97a0aa8d1a | ||
|
|
3850c6a0e0 | ||
|
|
d4d714dcf4 | ||
|
|
9cb4a51592 | ||
|
|
f64663519e | ||
|
|
ca036d424a | ||
|
|
40dc47ec72 | ||
|
|
8f2e96cb2c | ||
|
|
d2d04615b4 | ||
|
|
4ac5d820fc | ||
|
|
57bedd84a3 | ||
|
|
bf2eb2200d | ||
|
|
65732f33c1 | ||
|
|
bb31fbd67e | ||
|
|
187d7e73ab | ||
|
|
9920c7604c | ||
|
|
5e935eb85b | ||
|
|
c8ca316474 | ||
|
|
93c134b68b | ||
|
|
19758959e4 | ||
|
|
0fa28ba1fa | ||
|
|
44e19ada63 | ||
|
|
daa007c0d5 | ||
|
|
9836f83589 | ||
|
|
3f9acecaf3 | ||
|
|
e7e6572e02 | ||
|
|
489eb5780f | ||
|
|
5978033427 | ||
|
|
07c8bb1efb | ||
|
|
f03ad35563 | ||
|
|
e62089ed70 | ||
|
|
973319b44c | ||
|
|
83117a204b | ||
|
|
75d481c6ff | ||
|
|
fe364cc2db | ||
|
|
71f3f11031 | ||
|
|
5865d41dc4 | ||
|
|
98ba88214f | ||
|
|
5a2675e375 | ||
|
|
3c6e15aa37 | ||
|
|
f2d698b8d2 | ||
|
|
8d90c74b28 | ||
|
|
70030fd3e5 | ||
|
|
fb0b19ed01 | ||
|
|
64ee210c91 | ||
|
|
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 |
@@ -10,10 +10,17 @@ exclude_paths:
|
||||
- molecule/
|
||||
- tests/azure/
|
||||
- meta/runtime.yml
|
||||
- requirements-docker.yml
|
||||
- requirements-podman.yml
|
||||
|
||||
kinds:
|
||||
- playbook: '**/tests/**/test_*.yml'
|
||||
- playbook: '**/playbooks/**/*.yml'
|
||||
- playbook: '**/tests/ca-less/install_*_without_ca.yml'
|
||||
- playbook: '**/tests/ca-less/clean_up_certificates.yml'
|
||||
- playbook: '**/tests/external-signed-ca-with-automatic-copy/install-server-with-external-ca-with-automatic-copy.yml'
|
||||
- playbook: '**/tests/external-signed-ca-with-manual-copy/install-server-with-external-ca-with-manual-copy.yml'
|
||||
- playbook: '**/tests/user/create_users_json.yml'
|
||||
- tasks: '**/tasks_*.yml'
|
||||
- tasks: '**/env_*.yml'
|
||||
|
||||
@@ -26,6 +33,9 @@ skip_list:
|
||||
- '305' # Use shell only when shell functionality is required
|
||||
- '306' # risky-shell-pipe
|
||||
- yaml # yamllint should be executed separately.
|
||||
- experimental # Do not run any experimental tests
|
||||
- name[template] # Allow Jinja templating inside task names
|
||||
- var-naming
|
||||
|
||||
use_default_rules: true
|
||||
|
||||
|
||||
4
.github/workflows/ansible-test.yml
vendored
4
.github/workflows/ansible-test.yml
vendored
@@ -8,10 +8,8 @@ jobs:
|
||||
name: Verify ansible-test sanity
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3.1.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install virtualenv using pip
|
||||
run: pip install virtualenv
|
||||
- name: Run ansible-test
|
||||
run: bash tests/sanity/sanity.sh
|
||||
|
||||
51
.github/workflows/docs.yml
vendored
51
.github/workflows/docs.yml
vendored
@@ -4,58 +4,65 @@ on:
|
||||
- push
|
||||
- pull_request
|
||||
jobs:
|
||||
check_docs_29:
|
||||
name: Check Ansible Documentation with Ansible 2.9.
|
||||
check_docs_oldest_supported:
|
||||
name: Check Ansible Documentation with ansible-core 2.13.
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3.1.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v4.3.0
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install Ansible 2.9
|
||||
- name: Install Ansible 2.13
|
||||
run: |
|
||||
python -m pip install "ansible < 2.10"
|
||||
python -m pip install "ansible-core >=2.13,<2.14"
|
||||
- name: Run ansible-doc-test
|
||||
run: |
|
||||
ANSIBLE_LIBRARY="." ANSIBLE_DOC_FRAGMENT_PLUGINS="." python utils/ansible-doc-test -v roles plugins
|
||||
|
||||
check_docs_2_11:
|
||||
name: Check Ansible Documentation with ansible-core 2.11.
|
||||
check_docs_previous:
|
||||
name: Check Ansible Documentation with ansible-core 2.14.
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3.1.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v4.3.0
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install Ansible 2.11
|
||||
- name: Install Ansible 2.14
|
||||
run: |
|
||||
python -m pip install "ansible-core >=2.11,<2.12"
|
||||
python -m pip install "ansible-core >=2.14,<2.15"
|
||||
- name: Run ansible-doc-test
|
||||
run: |
|
||||
ANSIBLE_LIBRARY="." ANSIBLE_DOC_FRAGMENT_PLUGINS="." python utils/ansible-doc-test -v roles plugins
|
||||
|
||||
check_docs_2_12:
|
||||
name: Check Ansible Documentation with ansible-core 2.12.
|
||||
check_docs_current:
|
||||
name: Check Ansible Documentation with ansible-core 2.15.
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3.1.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v4.3.0
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install Ansible 2.12
|
||||
- name: Install Ansible 2.15
|
||||
run: |
|
||||
python -m pip install "ansible-core >=2.12,<2.13"
|
||||
python -m pip install "ansible-core >=2.15,<2.16"
|
||||
- name: Run ansible-doc-test
|
||||
run: |
|
||||
python -m pip install "ansible-core >=2.12,<2.13"
|
||||
ANSIBLE_LIBRARY="." ANSIBLE_DOC_FRAGMENT_PLUGINS="." python utils/ansible-doc-test -v roles plugins
|
||||
|
||||
check_docs_latest:
|
||||
check_docs_ansible_latest:
|
||||
name: Check Ansible Documentation with latest Ansible version.
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3.1.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v4.3.0
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install Ansible-latest
|
||||
|
||||
52
.github/workflows/lint.yml
vendored
52
.github/workflows/lint.yml
vendored
@@ -8,36 +8,40 @@ jobs:
|
||||
name: Verify ansible-lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3.1.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v4.3.0
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Run ansible-lint
|
||||
run: |
|
||||
pip install ansible-core==2.11.6 ansible-lint
|
||||
find playbooks roles tests -name '*.yml' ! -name "env_*" ! -name "tasks_*" -exec ansible-lint --force-color {} \+
|
||||
env:
|
||||
ANSIBLE_MODULE_UTILS: plugins/module_utils
|
||||
ANSIBLE_LIBRARY: plugins/modules
|
||||
ANSIBLE_DOC_FRAGMENT_PLUGINS: plugins/doc_fragments
|
||||
pip install "ansible-core >=2.15,<2.16" ansible-lint
|
||||
utils/build-galaxy-release.sh -ki
|
||||
cd .galaxy-build
|
||||
ansible-lint
|
||||
|
||||
yamllint:
|
||||
name: Verify yamllint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3.1.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v4.3.0
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Run yaml-lint
|
||||
uses: ibiqlik/action-yamllint@v1
|
||||
uses: ibiqlik/action-yamllint@v3.1.1
|
||||
|
||||
pydocstyle:
|
||||
name: Verify pydocstyle
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3.1.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v4.3.0
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Run pydocstyle
|
||||
@@ -49,32 +53,38 @@ jobs:
|
||||
name: Verify flake8
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3.1.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v4.3.0
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Run flake8
|
||||
run: |
|
||||
pip install flake8
|
||||
pip install flake8 flake8-bugbear
|
||||
flake8
|
||||
|
||||
pylint:
|
||||
name: Verify pylint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- uses: actions/checkout@v3.1.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v4.3.0
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Run pylint
|
||||
run: |
|
||||
pip install pylint==2.12.2
|
||||
pip install pylint==2.14.4 wrapt==1.14.0
|
||||
pylint plugins roles --disable=import-error
|
||||
|
||||
shellcheck:
|
||||
name: Shellcheck
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3.1.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Run ShellCheck
|
||||
uses: ludeeus/action-shellcheck@1.1.0
|
||||
uses: ludeeus/action-shellcheck@master
|
||||
|
||||
4
.github/workflows/readme.yml
vendored
4
.github/workflows/readme.yml
vendored
@@ -8,7 +8,9 @@ jobs:
|
||||
name: Verify readme
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3.1.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Run readme test
|
||||
run: |
|
||||
error=0
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,5 +1,11 @@
|
||||
*.pyc
|
||||
*.retry
|
||||
*.swp
|
||||
|
||||
# collection files
|
||||
freeipa-ansible_freeipa*.tar.gz
|
||||
redhat-rhel_idm*.tar.gz
|
||||
importer_result.json
|
||||
|
||||
# ignore virtual environments
|
||||
/.tox/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
repos:
|
||||
- repo: https://github.com/ansible/ansible-lint.git
|
||||
rev: v5.3.2
|
||||
rev: v6.6.1
|
||||
hooks:
|
||||
- id: ansible-lint
|
||||
always_run: false
|
||||
@@ -11,20 +11,20 @@ repos:
|
||||
entry: |
|
||||
env ANSIBLE_LIBRARY=./plugins/modules ANSIBLE_MODULE_UTILS=./plugins/module_utils ANSIBLE_DOC_FRAGMENT_PLUGINS=./plugins/doc_fragments ansible-lint
|
||||
- repo: https://github.com/adrienverge/yamllint.git
|
||||
rev: v1.26.1
|
||||
rev: v1.28.0
|
||||
hooks:
|
||||
- id: yamllint
|
||||
files: \.(yaml|yml)$
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 3.9.2
|
||||
- repo: https://github.com/pycqa/flake8
|
||||
rev: 5.0.3
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://gitlab.com/pycqa/pydocstyle
|
||||
rev: 6.1.1
|
||||
- repo: https://github.com/pycqa/pydocstyle
|
||||
rev: 6.0.0
|
||||
hooks:
|
||||
- id: pydocstyle
|
||||
- repo: https://github.com/pycqa/pylint
|
||||
rev: v2.12.2
|
||||
rev: v2.14.4
|
||||
hooks:
|
||||
- id: pylint
|
||||
args:
|
||||
|
||||
@@ -54,6 +54,21 @@ Example playbook to ensure presence of an automount map:
|
||||
desc: "this is a map for servers in the DMZ"
|
||||
```
|
||||
|
||||
Automount maps can contain a submount key, which defines a mount location within the map the references another map. On FreeIPA, this is known as an indirect map. An indirect automount map is equivalent to adding a proper automount key to a map, referencyng another map (this second map is the indirect map). Use `parent` and `mount` parameters to create an indirect automount map with ansible-freeipa, without the need to directly manage the automount keys.
|
||||
|
||||
Example playbook to ensure an indirect automount map is present:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to add an indirect automount map
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: auto.indirect
|
||||
location: DMZ
|
||||
parent: auto.DMZ
|
||||
mount: dmz_indirect
|
||||
```
|
||||
|
||||
Example playbook to ensure auto.DMZi is absent:
|
||||
|
||||
```yaml
|
||||
@@ -81,16 +96,14 @@ Variable | Description | Required
|
||||
`ipaadmin_password` | The admin password is a string and is required if there is no admin ticket available on the node | no
|
||||
`name` \| `mapname` \| `map` \| `automountmapname` | Name of the map to manage | yes
|
||||
`location` \| `automountlocation` \| `automountlocationcn` | Location name. | yes
|
||||
`parentmap` | Parent map of the indirect map. Can only be used when creating new maps. Default: auto.master | no
|
||||
`mount` | Indirect map mount point, relative to parent map. | yes, if `parent` is used.
|
||||
`desc` \| `description` | Description of the map | yes
|
||||
`state` | The state to ensure. It can be one of `present`, or `absent`, default: `present`. | no
|
||||
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
Creation of indirect mount points are not supported.
|
||||
|
||||
Authors
|
||||
=======
|
||||
|
||||
Chris Procter
|
||||
- Chris Procter
|
||||
- Rafael Jeffman
|
||||
|
||||
175
README-cert.md
Normal file
175
README-cert.md
Normal file
@@ -0,0 +1,175 @@
|
||||
Cert module
|
||||
============
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The cert module makes it possible to request, revoke and retrieve SSL certificates for hosts, services and users.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Certificate request
|
||||
* Certificate hold/release
|
||||
* Certificate revocation
|
||||
* Certificate retrieval
|
||||
|
||||
|
||||
Supported FreeIPA Versions
|
||||
--------------------------
|
||||
|
||||
FreeIPA versions 4.4.0 and up are supported by the ipacert module.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
**Controller**
|
||||
* Ansible version: 2.8+
|
||||
* Some tool to generate a certificate signing request (CSR) might be needed, like `openssl`.
|
||||
|
||||
**Node**
|
||||
* Supported FreeIPA version (see above)
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Example inventory file
|
||||
|
||||
```ini
|
||||
[ipaserver]
|
||||
ipaserver.test.local
|
||||
```
|
||||
|
||||
Example playbook to request a new certificate for a service:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Certificate request
|
||||
hosts: ipaserver
|
||||
|
||||
tasks:
|
||||
- name: Request a certificate for a web server
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
state: requested
|
||||
csr: |
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIGYMEwCAQAwGTEXMBUGA1UEAwwOZnJlZWlwYSBydWxlcyEwKjAFBgMrZXADIQBs
|
||||
HlqIr4b/XNK+K8QLJKIzfvuNK0buBhLz3LAzY7QDEqAAMAUGAytlcANBAF4oSCbA
|
||||
5aIPukCidnZJdr491G4LBE+URecYXsPknwYb+V+ONnf5ycZHyaFv+jkUBFGFeDgU
|
||||
SYaXm/gF8cDYjQI=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
principal: HTTP/www.example.com
|
||||
register: cert
|
||||
```
|
||||
|
||||
Example playbook to revoke an existing certificate:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Revoke certificate
|
||||
hosts: ipaserver
|
||||
|
||||
tasks:
|
||||
- name Revoke a certificate
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
serial_number: 123456789
|
||||
state: revoked
|
||||
```
|
||||
|
||||
Example to hold a certificate (alias for revoking a certificate with reason `certificateHold (6)`):
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Hold a certificate
|
||||
hosts: ipaserver
|
||||
|
||||
tasks:
|
||||
- name: Hold certificate
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
serial_number: 0xAB1234
|
||||
state: held
|
||||
```
|
||||
|
||||
Example playbook to release hold of certificate (may be used with any revoked certificates, despite of the rovoke reason):
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Release hold
|
||||
hosts: ipaserver
|
||||
|
||||
tasks:
|
||||
- name: Take a revoked certificate off hold
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
serial_number: 0xAB1234
|
||||
state: released
|
||||
```
|
||||
|
||||
Example playbook to retrieve a certificate and save it to a file in the target node:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Retriev certificate
|
||||
hosts: ipaserver
|
||||
|
||||
tasks:
|
||||
- name: Retrieve a certificate and save it to file 'cert.pem'
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
certificate_out: cert.pem
|
||||
state: retrieved
|
||||
```
|
||||
|
||||
|
||||
ipacert
|
||||
-------
|
||||
|
||||
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
|
||||
`csr` | X509 certificate signing request, in PEM format. | yes, if `state: requested`
|
||||
`principal` | Host/service/user principal for the certificate. | yes, if `state: requested`
|
||||
`add` \| `add_principal` | Automatically add the principal if it doesn't exist (service principals only). (bool) | no
|
||||
`profile_id` \| `profile` | Certificate Profile to use | no
|
||||
`ca` | Name of the issuing certificate authority. | no
|
||||
`chain` | Include certificate chain in output. (bool) | no
|
||||
`serial_number` | Certificate serial number. (int) | yes, if `state` is `retrieved`, `held`, `released` or `revoked`.
|
||||
`revocation_reason` \| `reason` | Reason for revoking the certificate. Use one of the reason strings, or the corresponding value: "unspecified" (0), "keyCompromise" (1), "cACompromise" (2), "affiliationChanged" (3), "superseded" (4), "cessationOfOperation" (5), "certificateHold" (6), "removeFromCRL" (8), "privilegeWithdrawn" (9), "aACompromise" (10) | yes, if `state: revoked`
|
||||
`certificate_out` | Write certificate (chain if `chain` is set) to this file, on the target node. | no
|
||||
`state` | The state to ensure. It can be one of `requested`, `held`, `released`, `revoked`, or `retrieved`. `held` is the same as revoke with reason "certificateHold" (6). `released` is the same as `cert-revoke-hold` on IPA CLI, releasing the hold status of a certificate. | yes
|
||||
|
||||
|
||||
Return Values
|
||||
=============
|
||||
|
||||
Values are returned only if `state` is `requested` or `retrieved` and if `certificate_out` is not defined.
|
||||
|
||||
Variable | Description | Returned When
|
||||
-------- | ----------- | -------------
|
||||
`certificate` | Certificate fields and data. (dict) <br>Options: | if `state` is `requested` or `retrieved` and if `certificate_out` is not defined
|
||||
| `certificate` - Issued X509 certificate in PEM encoding. Will include certificate chain if `chain: true`. (list) | always
|
||||
| `san_dnsname` - X509 Subject Alternative Name. | When DNSNames are present in the Subject Alternative Name extension of the issued certificate.
|
||||
| `issuer` - X509 distinguished name of issuer. | always
|
||||
| `subject` - X509 distinguished name of certificate subject. | always
|
||||
| `serial_number` - Serial number of the issued certificate. (int) | always
|
||||
| `revoked` - Revoked status of the certificate. (bool) | if certificate was revoked
|
||||
| `owner_user` - The username that owns the certificate. | if `state: retrieved` and certificate is owned by a user
|
||||
| `owner_host` - The host that owns the certificate. | if `state: retrieved` and certificate is owned by a host
|
||||
| `owner_service` - The service that owns the certificate. | if `state: retrieved` and certificate is owned by a service
|
||||
| `valid_not_before` - Time when issued certificate becomes valid, in GeneralizedTime format (YYYYMMDDHHMMSSZ) | always
|
||||
| `valid_not_after` - Time when issued certificate ceases to be valid, in GeneralizedTime format (YYYYMMDDHHMMSSZ) | always
|
||||
|
||||
|
||||
Authors
|
||||
=======
|
||||
|
||||
Sam Morris
|
||||
Rafael Jeffman
|
||||
@@ -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
|
||||
=========
|
||||
|
||||
@@ -108,9 +145,12 @@ Variable | Description | Required
|
||||
`selinuxusermaporder` \| `ipaselinuxusermaporder`| Set ordered list in increasing priority of SELinux users | no
|
||||
`selinuxusermapdefault`\| `ipaselinuxusermapdefault` | Set default SELinux user when no match is found in SELinux map rule | no
|
||||
`pac_type` \| `ipakrbauthzdata` | set default types of PAC supported for services (choices: `MS-PAC`, `PAD`, `nfs:NONE`). Use `""` to clear this variable. | no
|
||||
`user_auth_type` \| `ipauserauthtype` | set default types of supported user authentication (choices: `password`, `radius`, `otp`, `disabled`). Use `""` to clear this variable. | no
|
||||
`user_auth_type` \| `ipauserauthtype` | set default types of supported user authentication (choices: `password`, `radius`, `otp`, `pkinit`, `hardened`, `idp`, `disabled`, `""`). An additional check ensures that only types can be used that are supported by the IPA version. 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. Cannot be deactivated once activated. Requires IPA 4.9.8+. (bool) | no
|
||||
`netbios_name` | NetBIOS name of the IPA domain. Requires IPA 4.9.8+ and SID generation to be activated. | no
|
||||
`add_sids` | Add SIDs for existing users and groups. Requires IPA 4.9.8+ and SID generation to be activated. (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
|
||||
|
||||
|
||||
105
README-group.md
105
README-group.md
@@ -8,6 +8,9 @@ The group module allows to ensure presence and absence of groups and members of
|
||||
|
||||
The group module is as compatible as possible to the Ansible upstream `ipa_group` module, but additionally offers to add users to a group and also to remove users from a group.
|
||||
|
||||
## Note
|
||||
Ensuring presence (adding) of several groups with mixed types (`external`, `nonposix` and `posix`) requires a fix in FreeIPA. The module implements a workaround to automatically use `client` context if the fix is not present in the target node FreeIPA and if more than one group is provided to the task using the `groups` parameter. If `ipaapi_context` is forced to be `server`, the module will fail in this case.
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
@@ -71,6 +74,62 @@ Example playbook to add groups:
|
||||
name: appops
|
||||
```
|
||||
|
||||
These three `ipagroup` module calls can be combined into one with the `groups` variable:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to handle groups
|
||||
hosts: ipaserver
|
||||
|
||||
tasks:
|
||||
- name: Ensure groups ops, sysops and appops are present
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: ops
|
||||
gidnumber: 1234
|
||||
- name: sysops
|
||||
user:
|
||||
- pinky
|
||||
- name: appops
|
||||
```
|
||||
|
||||
You can also alternatively use a json file containing the groups, here `groups_present.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"groups": [
|
||||
{
|
||||
"name": "group1",
|
||||
"description": "description group1"
|
||||
},
|
||||
{
|
||||
"name": "group2",
|
||||
"description": "description group2"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
And ensure the presence of the groups with this example playbook:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Tests
|
||||
hosts: ipaserver
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
- name: Include groups_present.json
|
||||
include_vars:
|
||||
file: groups_present.json
|
||||
|
||||
- name: Groups present
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups: "{{ groups }}"
|
||||
```
|
||||
|
||||
Example playbook to add users to a group:
|
||||
|
||||
```yaml
|
||||
@@ -112,11 +171,11 @@ Example playbook to add group members to a group:
|
||||
Example playbook to add members from a trusted realm to an external group:
|
||||
|
||||
```yaml
|
||||
--
|
||||
---
|
||||
- name: Playbook to handle groups.
|
||||
hosts: ipaserver
|
||||
became: true
|
||||
|
||||
|
||||
tasks:
|
||||
- name: Create an external group and add members from a trust to it.
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -127,6 +186,24 @@ Example playbook to add members from a trusted realm to an external group:
|
||||
- WINIPA\\Developers
|
||||
```
|
||||
|
||||
Example playbook to add nonposix and external groups:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to add nonposix and external groups
|
||||
hosts: ipaserver
|
||||
|
||||
tasks:
|
||||
- name: Add nonposix group sysops and external group appops
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: sysops
|
||||
nonposix: true
|
||||
- name: appops
|
||||
external: true
|
||||
```
|
||||
|
||||
Example playbook to remove groups:
|
||||
|
||||
```yaml
|
||||
@@ -136,13 +213,29 @@ Example playbook to remove groups:
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
# Remove goups sysops, appops and ops
|
||||
# Remove groups sysops, appops and ops
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: sysops,appops,ops
|
||||
state: absent
|
||||
```
|
||||
|
||||
Example playbook to ensure groups are absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to handle groups
|
||||
hosts: ipaserver
|
||||
|
||||
tasks:
|
||||
- name: Ensure groups ops and sysops are absent
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: ops
|
||||
- name: sysops
|
||||
state: absent
|
||||
```
|
||||
|
||||
Variables
|
||||
=========
|
||||
@@ -152,8 +245,10 @@ 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
|
||||
`ipaapi_ldap_cache` | Use LDAP cache for IPA connection. The bool setting defaults to <br/>. (bool) | no
|
||||
`name` \| `cn` | The list of group name strings. | no
|
||||
`groups` | The list of group dicts. Each `groups` dict entry can contain group variables.<br>There is one required option in the `groups` dict:| no
|
||||
| `name` - The group name string of the entry. | yes
|
||||
`description` | The group description string. | no
|
||||
`gid` \| `gidnumber` | The GID integer. | no
|
||||
`posix` | Create a non-POSIX group or change a non-POSIX to a posix group. `nonposix`, `posix` and `external` are mutually exclusive. (bool) | no
|
||||
|
||||
@@ -335,7 +335,7 @@ Variable | Description | Required
|
||||
-------- | ----------- | --------
|
||||
`description` | The host description. | no
|
||||
`locality` | Host locality (e.g. "Baltimore, MD"). | no
|
||||
`location` \| `ns_host_location` | Host location (e.g. "Lab 2"). | no
|
||||
`location` \| `ns_host_location` | Host physical location hint (e.g. "Lab 2"). | no
|
||||
`platform` \| `ns_hardware_platform` | Host hardware platform (e.g. "Lenovo T61"). | no
|
||||
`os` \| `ns_os_version` | Host operating system and version (e.g. "Fedora 9"). | no
|
||||
`password` \| `user_password` \| `userpassword` | Password used in bulk enrollment for absent or not enrolled hosts. | no
|
||||
@@ -354,7 +354,7 @@ Variable | Description | Required
|
||||
`mac_address` \| `macaddress` | List of hardware MAC addresses. | no
|
||||
`sshpubkey` \| `ipasshpubkey` | List of SSH public keys | no
|
||||
`userclass` \| `class` | Host category (semantics placed on this attribute are for local interpretation) | no
|
||||
`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. Use 'otp' to allow OTP-based 2FA authentications. Use 'radius' to allow RADIUS-based 2FA authentications. Use empty string to reset auth_ind to the initial value. Other values may be used for custom configurations. choices: ["radius", "otp", "pkinit", "hardened", ""] | no
|
||||
`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. Use 'otp' to allow OTP-based 2FA authentications. Use 'radius' to allow RADIUS-based 2FA authentications. Use empty string to reset auth_ind to the initial value. Other values may be used for custom configurations. An additional check ensures that only types can be used that are supported by the IPA version. Choices: ["radius", "otp", "pkinit", "hardened", "idp", ""] | no
|
||||
`requires_pre_auth` \| `ipakrbrequirespreauth` | Pre-authentication is required for the service (bool) | no
|
||||
`ok_as_delegate` \| `ipakrbokasdelegate` | Client credentials may be delegated to the service (bool) | no
|
||||
`ok_to_auth_as_delegate` \| `ipakrboktoauthasdelegate` | The service is allowed to authenticate on behalf of a client (bool) | no
|
||||
@@ -372,8 +372,8 @@ There are only return values if one or more random passwords have been generated
|
||||
Variable | Description | Returned When
|
||||
-------- | ----------- | -------------
|
||||
`host` | Host dict with random password. (dict) <br>Options: | If random is yes and host did not exist or update_password is yes
|
||||
| `randompassword` - The generated random password | If only one host is handled by the module
|
||||
| `name` - The host name of the host that got a new random password. (dict) <br> Options: <br> `randompassword` - The generated random password | If several hosts are handled by the module
|
||||
| `randompassword` - The generated random password | If only one host is handled by the module without using the `hosts` parameter.
|
||||
| `name` - The host name of the host that got a new random password. (dict) <br> Options: <br> `randompassword` - The generated random password | If several hosts are handled by the module with the `hosts` parameter.
|
||||
|
||||
|
||||
Authors
|
||||
|
||||
179
README-netgroup.md
Normal file
179
README-netgroup.md
Normal file
@@ -0,0 +1,179 @@
|
||||
Netgroup module
|
||||
============
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The netgroup module allows to ensure presence and absence of netgroups.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Netgroup management
|
||||
|
||||
|
||||
Supported FreeIPA Versions
|
||||
--------------------------
|
||||
|
||||
FreeIPA versions 4.4.0 and up are supported by the ipanetgroup 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 make sure netgroup "my_netgroup1" is present:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA netgroup.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure netgroup my_netgroup1 is present
|
||||
ipanetgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my_netgroup1
|
||||
description: My netgroup 1
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure netgroup "my_netgroup1" is absent:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA netgroup.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure netgroup my_netgroup1 is absent
|
||||
ipanetgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my_netgroup1
|
||||
state: absent
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure netgroup is present with user "user1"
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA netgroup.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure netgroup is present with user "user1"
|
||||
ipanetgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestNetgroup1
|
||||
user: user1
|
||||
action: member
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure netgroup user, "user1", is absent
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA netgroup.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure netgroup user, "user1", is absent
|
||||
ipanetgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestNetgroup1
|
||||
user: "user1"
|
||||
action: member
|
||||
state: absent
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure netgroup is present with members
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA netgroup.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure netgroup members are present
|
||||
ipanetgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestNetgroup1
|
||||
user: user1,user2
|
||||
group: group1
|
||||
host: host1
|
||||
hostgroup: ipaservers
|
||||
netgroup: admins
|
||||
action: member
|
||||
```
|
||||
|
||||
|
||||
Example playbook to make sure 2 netgroups TestNetgroup1, admins are absent
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to manage IPA netgroup.
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure netgroups are absent
|
||||
ipanetgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name:
|
||||
- TestNetgroup1
|
||||
- admins
|
||||
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 netgroup name strings. | yes
|
||||
`description` | Netgroup description | no
|
||||
`nisdomain` | NIS domain name | no
|
||||
`nomembers` | Suppress processing of membership attributes. (bool) | no
|
||||
`user` | List of user name strings assigned to this netgroup. | no
|
||||
`group` | List of group name strings assigned to this netgroup. | no
|
||||
`host` | List of host name strings assigned to this netgroup. | no
|
||||
`hostgroup` | List of hostgroup name strings assigned to this netgroup. | no
|
||||
`netgroup` | List of netgroup name strings assigned to this netgroup. | no
|
||||
`action` | Work on group or member level. It can be on of `member` or `netgroup` and defaults to `netgroup`. | no
|
||||
`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. | no
|
||||
|
||||
|
||||
Authors
|
||||
=======
|
||||
|
||||
Denis Karpelevich
|
||||
@@ -87,6 +87,36 @@ Example playbook to ensure maxlife is set to 49 in global policy:
|
||||
maxlife: 49
|
||||
```
|
||||
|
||||
Example playbook to ensure password grace period is set to 3 in global policy:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to handle pwpolicies
|
||||
hosts: ipaserver
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
# Ensure maxlife is set to 49 in global policy
|
||||
- ipapwpolicy:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
gracelimit: 3
|
||||
```
|
||||
|
||||
Example playbook to ensure password grace period is set to unlimited in global policy:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Playbook to handle pwpolicies
|
||||
hosts: ipaserver
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
# Ensure maxlife is set to 49 in global policy
|
||||
- ipapwpolicy:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
gracelimit: -1
|
||||
```
|
||||
|
||||
|
||||
Variables
|
||||
=========
|
||||
@@ -98,15 +128,20 @@ Variable | Description | Required
|
||||
`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 pwpolicy name strings. If name is not given, `global_policy` will be used automatically. | no
|
||||
`maxlife` \| `krbmaxpwdlife` | Maximum password lifetime in days. (int) | no
|
||||
`minlife` \| `krbminpwdlife` | Minimum password lifetime in hours. (int) | no
|
||||
`history` \| `krbpwdhistorylength` | Password history size. (int) | no
|
||||
`minclasses` \| `krbpwdmindiffchars` | Minimum number of character classes. (int) | no
|
||||
`minlength` \| `krbpwdminlength` | Minimum length of password. (int) | no
|
||||
`priority` \| `cospriority` | Priority of the policy, higher number means lower priority. (int) | no
|
||||
`maxfail` \| `krbpwdmaxfailure` | Consecutive failures before lockout. (int) | no
|
||||
`failinterval` \| `krbpwdfailurecountinterval` | Period after which failure count will be reset in seconds. (int) | no
|
||||
`lockouttime` \| `krbpwdlockoutduration` | Period for which lockout is enforced in seconds. (int) | no
|
||||
`maxlife` \| `krbmaxpwdlife` | Maximum password lifetime in days. (int or "") | no
|
||||
`minlife` \| `krbminpwdlife` | Minimum password lifetime in hours. (int or "") | no
|
||||
`history` \| `krbpwdhistorylength` | Password history size. (int or "") | no
|
||||
`minclasses` \| `krbpwdmindiffchars` | Minimum number of character classes. (int or "") | no
|
||||
`minlength` \| `krbpwdminlength` | Minimum length of password. (int or "") | no
|
||||
`priority` \| `cospriority` | Priority of the policy, higher number means lower priority. (int or "") | no
|
||||
`maxfail` \| `krbpwdmaxfailure` | Consecutive failures before lockout. (int or "") | no
|
||||
`failinterval` \| `krbpwdfailurecountinterval` | Period after which failure count will be reset in seconds. (int or "") | no
|
||||
`lockouttime` \| `krbpwdlockoutduration` | Period for which lockout is enforced in seconds. (int or "") | no
|
||||
`maxrepeat` \| `ipapwdmaxrepeat` | Maximum number of same consecutive characters. Requires IPA 4.9+ (int or "") | no
|
||||
`maxsequence` \| `ipapwdmaxsequence` | The maximum length of monotonic character sequences (abcd). Requires IPA 4.9+ (int or "") | no
|
||||
`dictcheck` \| `ipapwdictcheck` | Check if the password is a dictionary word. Requires IPA 4.9+. (bool or "") | no
|
||||
`usercheck` \| `ipapwdusercheck` | Check if the password contains the username. Requires IPA 4.9+. (bool or "") | no
|
||||
`gracelimit` \| `passwordgracelimit` | Number of LDAP authentications allowed after expiration. Requires IPA 4.9.10 (int or "") | no
|
||||
`state` | The state to ensure. It can be one of `present` or `absent`, default: `present`. | yes
|
||||
|
||||
|
||||
|
||||
@@ -249,14 +249,14 @@ Variable | Description | Required
|
||||
`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 server name strings. | yes
|
||||
`location` \| `ipalocation_location` | The server location string. Only in state: present. "" for location reset. | no
|
||||
`service_weight` \| `ipaserviceweight` | Weight for server services. Type Values 0 to 65535, -1 for weight reset. Only in state: present. (int) | no
|
||||
`hidden` | Set hidden state of a server. Only in state: present. (bool) | no
|
||||
`no_members` | Suppress processing of membership attributes. Only in state: present. (bool) | no
|
||||
`delete_continue` \| `continue` | Continuous mode: Don't stop on errors. Only in state: absent. (bool) | no
|
||||
`ignore_last_of_role` | Skip a check whether the last CA master or DNS server is removed. Only in state: absent. (bool) | no
|
||||
`ignore_topology_disconnect` | Ignore topology connectivity problems after removal. Only in state: absent. (bool) | no
|
||||
`force` | Force server removal even if it does not exist. Will always result in changed. Only in state: absent. (bool) | no
|
||||
`location` \| `ipalocation_location` | The server DNS location. Only available with 'state: present'. Use "" for location reset. | no
|
||||
`service_weight` \| `ipaserviceweight` | Weight for server services. Type Values 0 to 65535, -1 for weight reset. Only available with 'state: present'. (int) | no
|
||||
`hidden` | Set hidden state of a server. Only available with 'state: present'. (bool) | no
|
||||
`no_members` | Suppress processing of membership attributes. Only avialable with 'state: present'. (bool) | no
|
||||
`delete_continue` \| `continue` | Continuous mode: Don't stop on errors. Only available with 'state: absent'. (bool) | no
|
||||
`ignore_last_of_role` | Skip a check whether the last CA master or DNS server is removed. Only available with 'state: absent'. (bool) | no
|
||||
`ignore_topology_disconnect` | Ignore topology connectivity problems after removal. Only available with 'state: absent'. (bool) | no
|
||||
`force` | Force server removal even if it does not exist. Will always result in changed. Only available with 'state: absent'. (bool) | no
|
||||
`state` | The state to ensure. It can be one of `present`, `absent`, default: `present`. `present` is only working with existing servers. | no
|
||||
|
||||
|
||||
|
||||
@@ -294,7 +294,7 @@ Variable | Description | Required
|
||||
`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`. 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
|
||||
`auth_ind` \| `krbprincipalauthind` | Defines an allow list for Authentication Indicators. It can be any of `otp`, `radius`, `pkinit`, `hardened`, `idp` or `""`. An additional check ensures that only types can be used that are supported by the IPA version. 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
|
||||
|
||||
@@ -129,6 +129,7 @@ Variable | Description | Required
|
||||
`nomembers` | Suppress processing of membership attributes. (bool) | no
|
||||
`host` | List of host name strings assigned to this sudorule. | no
|
||||
`hostgroup` | List of host group name strings assigned to this sudorule. | no
|
||||
`hostmask` | List of host masks of allowed hosts | no
|
||||
`user` | List of user name strings assigned to this sudorule. | no
|
||||
`group` | List of user group name strings assigned to this sudorule. | no
|
||||
`allow_sudocmd` | List of sudocmd name strings assigned to the allow group of this sudorule. | no
|
||||
|
||||
@@ -58,6 +58,7 @@ Example playbook to ensure a user is present:
|
||||
last: Acme
|
||||
uid: 10001
|
||||
gid: 100
|
||||
gecos: "The Pinky"
|
||||
phone: "+555123457"
|
||||
email: pinky@acme.com
|
||||
passwordexpiration: "2023-01-19 23:59:59"
|
||||
@@ -352,6 +353,33 @@ Example playbook to ensure users are absent:
|
||||
state: absent
|
||||
```
|
||||
|
||||
When using FreeIPA 4.8.0+, SMB logon script, profile, home directory and home drive can be set for users.
|
||||
|
||||
In the example playbook to set SMB attributes note that `smb_profile_path` and `smb_home_dir` use paths in UNC format, which includes backslashes ('\\`). If the paths are quoted, the backslash needs to be escaped becoming "\\", so the path `\\server\dir` becomes `"\\\\server\\dir"`. If the paths are unquoted the slashes do not have to be escaped.
|
||||
|
||||
The YAML specification states that a colon (':') is a key separator and a dash ('-') is an item marker, only with a space after them, so using both unquoted as part of a path should not be a problem. If a space is needed after a colon or a dash, then a quoted string must be used as in `"user - home"`. For the `smb_home_drive` attribute is is recomended that a quoted string is used, to improve readability.
|
||||
|
||||
Example playbook to set SMB attributes:
|
||||
|
||||
```yaml
|
||||
---
|
||||
- name: Plabook to handle users
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure user 'smbuser' is present with smb attributes
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: smbuser
|
||||
first: SMB
|
||||
last: User
|
||||
smb_logon_script: N:\logonscripts\startup
|
||||
smb_profile_path: \\server\profiles\some_profile
|
||||
smb_home_dir: \\users\home\smbuser
|
||||
smb_home_drive: "U:"
|
||||
```
|
||||
|
||||
|
||||
Variables
|
||||
=========
|
||||
@@ -381,8 +409,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
|
||||
@@ -393,8 +421,10 @@ Variable | Description | Required
|
||||
`passwordexpiration` \| `krbpasswordexpiration` | The kerberos password expiration date. Possible formats: `YYYYMMddHHmmssZ`, `YYYY-MM-ddTHH:mm:ssZ`, `YYYY-MM-ddTHH:mmZ`, `YYYY-MM-ddZ`, `YYYY-MM-dd HH:mm:ssZ` or `YYYY-MM-dd HH:mmZ`. The trailing 'Z' can be skipped. Only usable with IPA versions 4.7 and up. | no
|
||||
`password` | The user password string. | no
|
||||
`random` | Generate a random user password | no
|
||||
`uid` \| `uidnumber` | The UID integer. | no
|
||||
`gid` \| `gidnumber` | The GID integer. | no
|
||||
`uid` \| `uidnumber` | User ID Number (system will assign one if not provided). | no
|
||||
`gid` \| `gidnumber` | Group ID Number. | no
|
||||
`gecos` | GECOS | no
|
||||
`street` | Street address | no
|
||||
`city` | City | no
|
||||
`userstate` \| `st` | State/Province | no
|
||||
`postalcode` \| `zip` | Postalcode/ZIP | no
|
||||
@@ -407,7 +437,7 @@ Variable | Description | Required
|
||||
`manager` | List of manager user names. | no
|
||||
`carlicense` | List of car licenses. | no
|
||||
`sshpubkey` \| `ipasshpubkey` | List of SSH public keys. | no
|
||||
`userauthtype` | List of supported user authentication types. Choices: `password`, `radius`, `otp` and ``. Use empty string to reset userauthtype to the initial value. | no
|
||||
`userauthtype` \| `ipauserauthtype` | List of supported user authentication types. Choices: `password`, `radius`, `otp`, `pkinit`, `hardened`, `idp` and `""`. An additional check ensures that only types can be used that are supported by the IPA version. Use empty string to reset userauthtype to the initial value. | no
|
||||
`userclass` | User category. (semantics placed on this attribute are for local interpretation). | no
|
||||
`radius` | RADIUS proxy configuration | no
|
||||
`radiususer` | RADIUS proxy username | no
|
||||
@@ -415,6 +445,8 @@ Variable | Description | Required
|
||||
`employeenumber` | Employee Number | no
|
||||
`employeetype` | Employee Type | no
|
||||
`preferredlanguage` | Preferred Language | no
|
||||
`idp` \| `ipaidpconfiglink` | External IdP configuration | no
|
||||
`idp_user_id` \| `ipaidpsub` | A string that identifies the user at external IdP | no
|
||||
`certificate` | List of base-64 encoded user certificates. | no
|
||||
`certmapdata` | List of certificate mappings. Either `data` or `certificate` or `issuer` together with `subject` need to be specified. Only usable with IPA versions 4.5 and up. <br>Options: | no
|
||||
| `certificate` - Base-64 encoded user certificate, not usable with other certmapdata options. | no
|
||||
@@ -422,6 +454,10 @@ Variable | Description | Required
|
||||
| `subject` - Subject of the certificate, only usable together with `issuer` option. | no
|
||||
| `data` - Certmap data, not usable with other certmapdata options. | no
|
||||
`noprivate` | Do not create user private group. (bool) | no
|
||||
`smb_logon_script` \| `ipantlogonscript` | SMB logon script path. Requires FreeIPA version 4.8.0+. | no
|
||||
`smb_profile_path:` \| `ipantprofilepath` | SMB profile path, in UNC format. Requires FreeIPA version 4.8.0+. | no
|
||||
`smb_home_dir` \| `ipanthomedirectory` | SMB Home Directory, in UNC format. Requires FreeIPA version 4.8.0+. | no
|
||||
`smb_home_drive` \| `ipanthomedirectorydrive` | SMB Home Directory Drive, a single upercase letter (A-Z) followed by a colon (:), for example "U:". Requires FreeIPA version 4.8.0+. | no
|
||||
`nomembers` | Suppress processing of membership attributes. (bool) | no
|
||||
|
||||
|
||||
@@ -434,11 +470,12 @@ There are only return values if one or more random passwords have been generated
|
||||
Variable | Description | Returned When
|
||||
-------- | ----------- | -------------
|
||||
`user` | User dict with random password. (dict) <br>Options: | If random is yes and user did not exist or update_password is yes
|
||||
| `randompassword` - The generated random password | If only one user is handled by the module
|
||||
| `name` - The user name of the user that got a new random password. (dict) <br> Options: <br> `randompassword` - The generated random password | If several users are handled by the module
|
||||
| `randompassword` - The generated random password | If only one user is handled by the module without using the `users` parameter.
|
||||
| `name` - The user name of the user that got a new random password. (dict) <br> Options: <br> `randompassword` - The generated random password | If several users are handled by the module with the `users` parameter.
|
||||
|
||||
|
||||
Authors
|
||||
=======
|
||||
|
||||
Thomas Woerner
|
||||
Rafael Jeffman
|
||||
|
||||
@@ -222,8 +222,8 @@ Variable | Description | Required
|
||||
`password_file` \| `vault_password_file` \| `old_password_file`| File containing Base64 encoded Vault password. | no
|
||||
`new_password` | Vault new password. | no
|
||||
`new_password_file` | File containing Base64 encoded new Vault password. | no
|
||||
`public_key ` \| `vault_public_key` \| `ipavaultpublickey` | Base64 encoded vault public key. | no
|
||||
`public_key_file` \| `vault_public_key_file` | Path to file with public key. | no
|
||||
`public_key ` \| `vault_public_key` \| `ipavaultpublickey` \| `new_public_key` | Base64 encoded vault public key. | no
|
||||
`public_key_file` \| `vault_public_key_file` \| `new_public_key_file` | Path to file with public key. | no
|
||||
`private_key `\| `vault_private_key` \| `ipavaultprivatekey` | Base64 encoded vault private key. Used only to retrieve data. | no
|
||||
`private_key_file` \| `vault_private_key_file` | Path to file with private key. Used only to retrieve data. | no
|
||||
`salt` \| `vault_salt` \| `ipavaultsalt` | Vault salt. | no
|
||||
|
||||
@@ -17,6 +17,7 @@ Features
|
||||
* Modules for automount key management
|
||||
* Modules for automount location management
|
||||
* Modules for automount map management
|
||||
* Modules for certificate management
|
||||
* Modules for config management
|
||||
* Modules for delegation management
|
||||
* Modules for dns config management
|
||||
@@ -31,6 +32,7 @@ Features
|
||||
* Modules for hostgroup management
|
||||
* Modules for idrange management
|
||||
* Modules for location management
|
||||
* Modules for netgroup management
|
||||
* Modules for permission management
|
||||
* Modules for privilege management
|
||||
* Modules for pwpolicy management
|
||||
@@ -68,7 +70,6 @@ Requirements
|
||||
|
||||
**Controller**
|
||||
* Ansible version: 2.8+ (ansible-freeipa is an Ansible Collection)
|
||||
* /usr/bin/kinit is required on the controller if a one time password (OTP) is used
|
||||
|
||||
**Node**
|
||||
* Supported FreeIPA version (see above)
|
||||
@@ -288,7 +289,7 @@ ipaserver_domain=test.local
|
||||
ipaserver_realm=TEST.LOCAL
|
||||
```
|
||||
|
||||
For enhanced security it is possible to use a auto-generated one-time-password (OTP). This will be generated on the controller using the (first) server.
|
||||
For enhanced security it is possible to use a auto-generated one-time-password (OTP). This will be generated on the (first) server.
|
||||
|
||||
To enable the generation of the one-time-password:
|
||||
```yaml
|
||||
@@ -436,6 +437,7 @@ Modules in plugin/modules
|
||||
* [ipaautomountkey](README-automountkey.md)
|
||||
* [ipaautomountlocation](README-automountlocation.md)
|
||||
* [ipaautomountmap](README-automountmap.md)
|
||||
* [ipacert](README-cert.md)
|
||||
* [ipaconfig](README-config.md)
|
||||
* [ipadelegation](README-delegation.md)
|
||||
* [ipadnsconfig](README-dnsconfig.md)
|
||||
@@ -450,6 +452,7 @@ Modules in plugin/modules
|
||||
* [ipahostgroup](README-hostgroup.md)
|
||||
* [idrange](README-idrange.md)
|
||||
* [ipalocation](README-location.md)
|
||||
* [ipanetgroup](README-netgroup.md)
|
||||
* [ipapermission](README-permission.md)
|
||||
* [ipaprivilege](README-privilege.md)
|
||||
* [ipapwpolicy](README-pwpolicy.md)
|
||||
|
||||
@@ -13,8 +13,8 @@ homepage: "https://github.com/freeipa/ansible-freeipa"
|
||||
issues: "https://github.com/freeipa/ansible-freeipa/issues"
|
||||
|
||||
readme: "README.md"
|
||||
license: "GPL-3.0-or-later"
|
||||
|
||||
license:
|
||||
- "GPL-3.0-or-later"
|
||||
tags:
|
||||
- "linux"
|
||||
- "system"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: ensure map TestMap is absent
|
||||
- name: Ensure map TestMap is absent
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestMap
|
||||
14
playbooks/automount/automount-map-indirect-map.yml
Normal file
14
playbooks/automount/automount-map-indirect-map.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
- name: Managed automount maps
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
- name: Playbook to add an indirect automount map
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: auto.indirect
|
||||
location: DMZ
|
||||
parent: auto.DMZ
|
||||
mount: dmz_indirect
|
||||
@@ -4,7 +4,7 @@
|
||||
become: no
|
||||
|
||||
tasks:
|
||||
- name: ensure map TestMap is present
|
||||
- name: Ensure map TestMap is present
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestMap
|
||||
14
playbooks/cert/cert-hold.yml
Normal file
14
playbooks/cert/cert-hold.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
- name: Certificate manage example
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
gather_facts: false
|
||||
module_defaults:
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: client
|
||||
|
||||
tasks:
|
||||
- name: Temporarily hold a certificate
|
||||
ipacert:
|
||||
serial_number: 12345
|
||||
state: held
|
||||
15
playbooks/cert/cert-release.yml
Normal file
15
playbooks/cert/cert-release.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
- name: Certificate manage example
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
gather_facts: false
|
||||
module_defaults:
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: client
|
||||
|
||||
tasks:
|
||||
- name: Release a certificate hold
|
||||
ipacert:
|
||||
serial_number: 12345
|
||||
state: released
|
||||
26
playbooks/cert/cert-request-host.yml
Normal file
26
playbooks/cert/cert-request-host.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
- name: Certificate manage example
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
gather_facts: false
|
||||
module_defaults:
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: client
|
||||
|
||||
tasks:
|
||||
- name: Request a certificate for a host
|
||||
ipacert:
|
||||
csr: |
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIBWjCBxAIBADAbMRkwFwYDVQQDDBBob3N0LmV4YW1wbGUuY29tMIGfMA0GCSqG
|
||||
SIb3DQEBAQUAA4GNADCBiQKBgQCzR3Vd4Cwl0uVgwB3+wxz+4JldFk3x526bPeuK
|
||||
g8EEc+rEHILzJWeXC8ywCYPOgK9n7hrdMfVQiIx3yHYrY+0IYuLehWow4o1iJEf5
|
||||
urPNAP9K9C4Y7MMXzzoQmoWR3IFQQpOYwvWOtiZfvrhmtflnYEGLE2tgz53gOQHD
|
||||
NnbCCwIDAQABoAAwDQYJKoZIhvcNAQELBQADgYEAgF+6YC39WhnvmFgNz7pjAh5E
|
||||
2ea3CgG+zrzAyiSBGG6WpXEjqMRnAQxciQNGxQacxjwWrscZidZzqg8URJPugewq
|
||||
tslYB1+RkZn+9UWtfnWvz89+xnOgco7JlytnbH10Nfxt5fXXx13rY0tl54jBtk2W
|
||||
422eYZ12wb4gjNcQy3A=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
principal: host/host.example.com
|
||||
state: requested
|
||||
23
playbooks/cert/cert-request-service.yml
Normal file
23
playbooks/cert/cert-request-service.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
- name: Certificate manage example
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
gather_facts: false
|
||||
module_defaults:
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: client
|
||||
|
||||
tasks:
|
||||
- name: Request a certificate for a service
|
||||
ipacert:
|
||||
csr: |
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIGYMEwCAQAwGTEXMBUGA1UEAwwOZnJlZWlwYSBydWxlcyEwKjAFBgMrZXADIQBs
|
||||
HlqIr4b/XNK+K8QLJKIzfvuNK0buBhLz3LAzY7QDEqAAMAUGAytlcANBAF4oSCbA
|
||||
5aIPukCidnZJdr491G4LBE+URecYXsPknwYb+V+ONnf5ycZHyaFv+jkUBFGFeDgU
|
||||
SYaXm/gF8cDYjQI=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
principal: HTTP/www.example.com
|
||||
add: true
|
||||
state: requested
|
||||
27
playbooks/cert/cert-request-user.yml
Normal file
27
playbooks/cert/cert-request-user.yml
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
- name: Certificate manage example
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
gather_facts: false
|
||||
module_defaults:
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: client
|
||||
|
||||
tasks:
|
||||
- name: Request a certificate for a user with a specific profile
|
||||
ipacert:
|
||||
csr: |
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIBejCB5AIBADAQMQ4wDAYDVQQDDAVwaW5reTCBnzANBgkqhkiG9w0BAQEFAAOB
|
||||
jQAwgYkCgYEA7uChccy1Is1FTM0SF23WPYW472E3ozeLh2kzhKR9Ni6FLmeEGgu7
|
||||
/hicR1VwvXHYkNwI1tpW9LqxRVvgr6vheqHySljrBcoRfshfYvKejp03l2327Bfq
|
||||
BNxXqLcHylNEyg8SH0u63bWyxtgoDBfdZwdGAhYuJ+g4ev79J5eYoB0CAwEAAaAr
|
||||
MCkGCSqGSIb3DQEJDjEcMBowGAYHKoZIzlYIAQQNDAtoZWxsbyB3b3JsZDANBgkq
|
||||
hkiG9w0BAQsFAAOBgQADCi5BHDv1mrBFDWqYytFpQ1mrvr/mdax3AYXxNL2UEV8j
|
||||
AqZAFTEnJXL/u1eVQtI1yotqxakyUBN4XZBP2CBgJRO93Mtry8cgvU1sPdU8Mavx
|
||||
5gSnlP74Hio2ziscWWydlxpYxFx0gkKvu+0nyIpz954SVYwQ2wwk5FRqZnxI5w==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
principal: pinky
|
||||
profile: IECUserRoles
|
||||
state: requested
|
||||
16
playbooks/cert/cert-retrieve.yml
Normal file
16
playbooks/cert/cert-retrieve.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
- name: Certificate manage example
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
gather_facts: false
|
||||
module_defaults:
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: client
|
||||
|
||||
tasks:
|
||||
- name: Retrieve a certificate
|
||||
ipacert:
|
||||
serial_number: 12345
|
||||
state: retrieved
|
||||
register: cert_retrieved
|
||||
18
playbooks/cert/cert-revoke.yml
Normal file
18
playbooks/cert/cert-revoke.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
- name: Certificate manage example
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
gather_facts: false
|
||||
module_defaults:
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ipaapi_context: client
|
||||
|
||||
tasks:
|
||||
- name: Permanently revoke a certificate issued by a lightweight sub-CA
|
||||
ipacert:
|
||||
serial_number: 12345
|
||||
ca: vpn-ca
|
||||
# reason: keyCompromise (1)
|
||||
reason: 1
|
||||
state: revoked
|
||||
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
|
||||
@@ -11,5 +11,5 @@
|
||||
register: serverconfig
|
||||
|
||||
- name: Display current configuration.
|
||||
debug:
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ serverconfig }}"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
- name: Playbook to handle global DNS configuration
|
||||
- name: Playbook to handle global IPA configuration
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
gather_facts: no
|
||||
|
||||
tasks:
|
||||
- name: set ca_renewal_master_server
|
||||
- name: Set ca_renewal_master_server
|
||||
ipaconfig:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
ca_renewal_master_server: carenewal.example.com
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
- name: dnszone present
|
||||
- name: All dnszone parameters
|
||||
hosts: ipaserver
|
||||
become: true
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
- name: dnszone present
|
||||
- name: Dnszone present
|
||||
hosts: ipaserver
|
||||
become: true
|
||||
|
||||
|
||||
@@ -11,5 +11,5 @@
|
||||
register: result
|
||||
|
||||
- name: Zone name inferred from `name_from_ip`
|
||||
debug:
|
||||
ansible.builtin.debug:
|
||||
msg: "Zone created: {{ result.dnszone.name }}"
|
||||
|
||||
32
playbooks/group/add-groups.yml
Normal file
32
playbooks/group/add-groups.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
- name: Playbook to handle multiple groups
|
||||
hosts: ipaserver
|
||||
|
||||
tasks:
|
||||
- name: Create multiple groups ops, sysops
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: ops
|
||||
gidnumber: 1234
|
||||
- name: sysops
|
||||
|
||||
- name: Add user and group members to groups sysops and appops
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: sysops
|
||||
user:
|
||||
- user1
|
||||
- name: appops
|
||||
group:
|
||||
- group2
|
||||
|
||||
- name: Create multiple non-POSIX and external groups
|
||||
ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: nongroup
|
||||
nonposix: true
|
||||
- name: extgroup
|
||||
external: true
|
||||
@@ -14,5 +14,5 @@
|
||||
register: ipahost
|
||||
|
||||
- name: Print generated random password
|
||||
debug:
|
||||
ansible.builtin.debug:
|
||||
var: ipahost.host.randompassword
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
register: ipahost
|
||||
|
||||
- name: Print generated random password
|
||||
debug:
|
||||
ansible.builtin.debug:
|
||||
var: ipahost.host.randompassword
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
register: ipahost
|
||||
|
||||
- name: Print generated random password for host01.example.com
|
||||
debug:
|
||||
ansible.builtin.debug:
|
||||
var: ipahost.host["host01.example.com"].randompassword
|
||||
|
||||
- name: Print generated random password for host02.example.com
|
||||
debug:
|
||||
ansible.builtin.debug:
|
||||
var: ipahost.host["host02.example.com"].randompassword
|
||||
|
||||
12
playbooks/netgroup/netgroup-absent.yml
Normal file
12
playbooks/netgroup/netgroup-absent.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
- name: Netgroup absent example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
gather_facts: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure netgroup my_netgroup1 is absent
|
||||
ipanetgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my_netgroup1
|
||||
state: absent
|
||||
14
playbooks/netgroup/netgroup-member-absent.yml
Normal file
14
playbooks/netgroup/netgroup-member-absent.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
- name: Netgroup absent example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
gather_facts: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure netgroup user, "user1", is absent
|
||||
ipanetgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestNetgroup1
|
||||
user: "user1"
|
||||
action: member
|
||||
state: absent
|
||||
13
playbooks/netgroup/netgroup-member-present.yml
Normal file
13
playbooks/netgroup/netgroup-member-present.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
- name: Netgroup member present example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
gather_facts: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure netgroup is present with user "user1"
|
||||
ipanetgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestNetgroup1
|
||||
user: user1
|
||||
action: member
|
||||
12
playbooks/netgroup/netgroup-present.yml
Normal file
12
playbooks/netgroup/netgroup-present.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
- name: Netgroup present example
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
gather_facts: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure netgroup my_netgroup1 is present
|
||||
ipanetgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my_netgroup1
|
||||
description: My netgroup 1
|
||||
11
playbooks/pwpolicy/pwpolicy_grace_limit.yml
Normal file
11
playbooks/pwpolicy/pwpolicy_grace_limit.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
- name: Playbook to manage password policy
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
gather_facts: no
|
||||
|
||||
tasks:
|
||||
- name: Set password policy grace limit.
|
||||
ipapwpolicy:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
gracelimit: 3
|
||||
14
playbooks/pwpolicy/pwpolicy_password_check.yml
Normal file
14
playbooks/pwpolicy/pwpolicy_password_check.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
- name: Playbook to manage password policy
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
gather_facts: no
|
||||
|
||||
tasks:
|
||||
- name: Set password checking parameters.
|
||||
ipapwpolicy:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
maxrepeat: 2
|
||||
maxsequence: 3
|
||||
dictcheck: yes
|
||||
usercheck: yes
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
- name: Playbook to manage sudorule
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
gather_facts: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure hostmask network is absent in sudorule
|
||||
ipasudorule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: testrule1
|
||||
hostmask: 192.168.122.37/24
|
||||
action: member
|
||||
state: absent
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
- name: Playbook to manage sudorule
|
||||
hosts: ipaserver
|
||||
become: no
|
||||
gather_facts: no
|
||||
|
||||
tasks:
|
||||
- name: Ensure hostmask network is present in sudorule
|
||||
ipasudorule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: testrule1
|
||||
hostmask: 192.168.122.37/24
|
||||
action: member
|
||||
@@ -4,7 +4,7 @@
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
- name: ensure the trust is present
|
||||
- name: Ensure the trust is present
|
||||
ipatrust:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
realm: windows.local
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
- name: ensure the trust is absent
|
||||
- name: Ensure the trust is absent
|
||||
ipatrust:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
realm: windows.local
|
||||
|
||||
12
playbooks/user/add-user-external-idp.yml
Normal file
12
playbooks/user/add-user-external-idp.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
- name: Playbook to handle users
|
||||
hosts: ipaserver
|
||||
become: true
|
||||
|
||||
tasks:
|
||||
- name: Create user associated with an external IdP
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: idpuser
|
||||
idp: keycloak
|
||||
idp_user_id: idpuser@exemple.com
|
||||
@@ -15,5 +15,5 @@
|
||||
register: ipauser
|
||||
|
||||
- name: Print generated random password
|
||||
debug:
|
||||
ansible.builtin.debug:
|
||||
var: ipauser.user.randompassword
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
register: ipauser
|
||||
|
||||
- name: Print generated random password for user1
|
||||
debug:
|
||||
ansible.builtin.debug:
|
||||
var: ipauser.user.user1.randompassword
|
||||
|
||||
- name: Print generated random password for user2
|
||||
debug:
|
||||
ansible.builtin.debug:
|
||||
var: ipauser.user.user2.randompassword
|
||||
|
||||
17
playbooks/user/smb-attributes.yml
Normal file
17
playbooks/user/smb-attributes.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
- name: Plabook to handle users
|
||||
hosts: ipaserver
|
||||
become: false
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
- name: Ensure user 'smbuser' is present with smb attributes
|
||||
ipauser:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: smbuser
|
||||
first: SMB
|
||||
last: User
|
||||
smb_logon_script: N:\logonscripts\startup
|
||||
smb_profile_path: \\server\profiles\some_profile
|
||||
smb_home_dir: \\users\home\smbuser
|
||||
smb_home_drive: "U:"
|
||||
@@ -15,5 +15,5 @@
|
||||
register: result
|
||||
no_log: true
|
||||
- name: Display retrieved data.
|
||||
debug:
|
||||
ansible.builtin.debug:
|
||||
msg: "Data: {{ result.vault.data }}"
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
register: result
|
||||
no_log: true
|
||||
- name: Display retrieved data.
|
||||
debug:
|
||||
ansible.builtin.debug:
|
||||
msg: "Data: {{ result.vault.data }}"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
tasks:
|
||||
- name: Copy file containing password to server.
|
||||
copy:
|
||||
ansible.builtin.copy:
|
||||
src: "{{ playbook_dir }}/password.txt"
|
||||
dest: "{{ ansible_facts['env'].HOME }}/password.txt"
|
||||
owner: "{{ ansible_user }}"
|
||||
@@ -20,6 +20,6 @@
|
||||
vault_type: symmetric
|
||||
vault_password_file: "{{ ansible_facts['env'].HOME }}/password.txt"
|
||||
- name: Remove file containing password from server.
|
||||
file:
|
||||
ansible.builtin.file:
|
||||
path: "{{ ansible_facts['env'].HOME }}/password.txt"
|
||||
state: absent
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
tasks:
|
||||
- name: Copy public key file to server.
|
||||
copy:
|
||||
ansible.builtin.copy:
|
||||
src: "{{ playbook_dir }}/public.pem"
|
||||
dest: "{{ ansible_facts['env'].HOME }}/public.pem"
|
||||
owner: "{{ ansible_user }}"
|
||||
@@ -25,6 +25,6 @@
|
||||
vault_type: asymmetric
|
||||
vault_public_key_file: "{{ ansible_facts['env'].HOME }}/public.pem"
|
||||
- name: Remove public key file from server.
|
||||
file:
|
||||
ansible.builtin.file:
|
||||
path: "{{ ansible_facts['env'].HOME }}/public.pem"
|
||||
state: absent
|
||||
|
||||
@@ -30,15 +30,18 @@ options:
|
||||
ipaadmin_principal:
|
||||
description: The admin principal.
|
||||
default: admin
|
||||
type: str
|
||||
ipaadmin_password:
|
||||
description: The admin password.
|
||||
required: false
|
||||
type: str
|
||||
ipaapi_context:
|
||||
description: |
|
||||
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.
|
||||
choices: ["server", "client"]
|
||||
type: str
|
||||
required: false
|
||||
ipaapi_ldap_cache:
|
||||
description: Use LDAP cache for IPA connection.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,8 +3,9 @@
|
||||
# Authors:
|
||||
# Mark Hahl <mhahl@redhat.com>
|
||||
# Jake Reynolds <jakealexis@gmail.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2021 Red Hat
|
||||
# Copyright (C) 2021-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -34,21 +35,24 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The automember rule
|
||||
required: true
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["cn"]
|
||||
description:
|
||||
description: A description of this auto member rule
|
||||
required: false
|
||||
type: str
|
||||
automember_type:
|
||||
description: Grouping to which the rule applies
|
||||
required: true
|
||||
required: false
|
||||
type: str
|
||||
choices: ["group", "hostgroup"]
|
||||
exclusive:
|
||||
@@ -56,7 +60,7 @@ options:
|
||||
type: list
|
||||
elements: dict
|
||||
aliases: ["automemberexclusiveregex"]
|
||||
options:
|
||||
suboptions:
|
||||
key:
|
||||
description: The attribute of the regex
|
||||
type: str
|
||||
@@ -70,7 +74,7 @@ options:
|
||||
type: list
|
||||
elements: dict
|
||||
aliases: ["automemberinclusiveregex"]
|
||||
options:
|
||||
suboptions:
|
||||
key:
|
||||
description: The attribute of the regex
|
||||
type: str
|
||||
@@ -82,10 +86,12 @@ options:
|
||||
users:
|
||||
description: Users to rebuild membership for.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
hosts:
|
||||
description: Hosts to rebuild membership for.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
no_wait:
|
||||
description: Don't wait for rebuilding membership.
|
||||
@@ -95,16 +101,18 @@ options:
|
||||
type: str
|
||||
action:
|
||||
description: Work on automember or member level
|
||||
type: str
|
||||
default: automember
|
||||
choices: ["member", "automember"]
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent", "rebuilt", "orphans_removed"]
|
||||
author:
|
||||
- Mark Hahl
|
||||
- Jake Reynolds
|
||||
- Thomas Woerner
|
||||
- Mark Hahl (@mhahl)
|
||||
- Jake Reynolds (@jake2184)
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -208,7 +216,6 @@ EXAMPLES = """
|
||||
RETURN = """
|
||||
"""
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import (
|
||||
IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, ipalib_errors, DN
|
||||
)
|
||||
@@ -315,7 +322,8 @@ def main():
|
||||
aliases=["automemberinclusiveregex"],
|
||||
default=None,
|
||||
options=dict(
|
||||
key=dict(type="str", required=True),
|
||||
key=dict(type="str", required=True,
|
||||
no_log=False),
|
||||
expression=dict(type="str", required=True)
|
||||
),
|
||||
elements="dict",
|
||||
@@ -324,12 +332,13 @@ def main():
|
||||
aliases=["automemberexclusiveregex"],
|
||||
default=None,
|
||||
options=dict(
|
||||
key=dict(type="str", required=True),
|
||||
key=dict(type="str", required=True,
|
||||
no_log=False),
|
||||
expression=dict(type="str", required=True)
|
||||
),
|
||||
elements="dict",
|
||||
required=False),
|
||||
name=dict(type="list", aliases=["cn"],
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
default=None, required=False),
|
||||
description=dict(type="str", default=None),
|
||||
automember_type=dict(type='str', required=False,
|
||||
@@ -341,8 +350,8 @@ def main():
|
||||
state=dict(type="str", default="present",
|
||||
choices=["present", "absent", "rebuilt",
|
||||
"orphans_removed"]),
|
||||
users=dict(type="list", default=None),
|
||||
hosts=dict(type="list", default=None),
|
||||
users=dict(type="list", elements="str", default=None),
|
||||
hosts=dict(type="list", elements="str", default=None),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
|
||||
# Authors:
|
||||
# Chris Procter <cprocter@redhat.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2021 Red Hat
|
||||
# Copyright (C) 2021-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -34,39 +35,43 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: ipaautomountkey
|
||||
author: chris procter
|
||||
author:
|
||||
- Chris Procter (@chr15p))
|
||||
- Thomas Woerner (@t-woerner)
|
||||
short_description: Manage FreeIPA autommount map
|
||||
description:
|
||||
- Add, delete, and modify an IPA automount map
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
options:
|
||||
ipaadmin_principal:
|
||||
description: The admin principal
|
||||
default: admin
|
||||
ipaadmin_password:
|
||||
description: The admin password
|
||||
required: False
|
||||
location:
|
||||
description: automount location map is in
|
||||
type: str
|
||||
required: True
|
||||
choices: ["automountlocationcn", "automountlocation"]
|
||||
aliases: ["automountlocationcn", "automountlocation"]
|
||||
mapname:
|
||||
description: automount map to be managed
|
||||
choices: ["map", "automountmapname", "automountmap"]
|
||||
type: str
|
||||
aliases: ["map", "automountmapname", "automountmap"]
|
||||
required: True
|
||||
key:
|
||||
description: automount key to be managed
|
||||
type: str
|
||||
required: True
|
||||
choices: ["name", "automountkey"]
|
||||
newkey:
|
||||
aliases: ["name", "automountkey"]
|
||||
rename:
|
||||
description: key to change to if state is 'renamed'
|
||||
required: True
|
||||
choices: ["newname", "newautomountkey"]
|
||||
type: str
|
||||
required: False
|
||||
aliases: ["new_name", "newautomountkey"]
|
||||
info:
|
||||
description: Mount information for the key
|
||||
required: True
|
||||
choices: ["information", "automountinformation"]
|
||||
type: str
|
||||
required: False
|
||||
aliases: ["information", "automountinformation"]
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
required: False
|
||||
default: present
|
||||
choices: ["present", "absent", "renamed"]
|
||||
@@ -193,7 +198,7 @@ def main():
|
||||
state=dict(
|
||||
type='str',
|
||||
choices=['present', 'absent', 'renamed'],
|
||||
required=None,
|
||||
required=False,
|
||||
default='present',
|
||||
),
|
||||
location=dict(
|
||||
@@ -215,6 +220,7 @@ def main():
|
||||
type="str",
|
||||
aliases=["name", "automountkey"],
|
||||
required=True,
|
||||
no_log=False,
|
||||
),
|
||||
info=dict(
|
||||
type="str",
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Authors:
|
||||
# Chris Procter <cprocter@redhat.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2021 Red Hat
|
||||
# Copyright (C) 2021-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,7 +33,9 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: ipaautomountlocation
|
||||
author: chris procter
|
||||
author:
|
||||
- Chris Procter (@chr15p)
|
||||
- Thomas Woerner (@t-woerner)
|
||||
short_description: Manage FreeIPA autommount locations
|
||||
description:
|
||||
- Add and delete an IPA automount location
|
||||
@@ -42,10 +45,13 @@ options:
|
||||
name:
|
||||
description: The automount location to be managed
|
||||
required: true
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["cn","location"]
|
||||
state:
|
||||
description: State to ensure
|
||||
required: false
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent"]
|
||||
'''
|
||||
@@ -116,9 +122,8 @@ def main():
|
||||
default='present',
|
||||
choices=['present', 'absent']
|
||||
),
|
||||
name=dict(type="list",
|
||||
name=dict(type="list", elements="str",
|
||||
aliases=["cn", "location"],
|
||||
default=None,
|
||||
required=True
|
||||
),
|
||||
),
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Authors:
|
||||
# Chris Procter <cprocter@redhat.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2021 Red Hat
|
||||
# Copyright (C) 2021-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -33,31 +34,45 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: ipaautomountmap
|
||||
author: Chris Procter
|
||||
author:
|
||||
- Chris Procter (@chr15p)
|
||||
- Thomas Woerner (@t-woerner)
|
||||
- Rafael Jeffman (@rjeffman)
|
||||
short_description: Manage FreeIPA autommount map
|
||||
description:
|
||||
- Add, delete, and modify an IPA automount map
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
options:
|
||||
ipaadmin_principal:
|
||||
description: The admin principal.
|
||||
default: admin
|
||||
ipaadmin_password:
|
||||
description: The admin password.
|
||||
required: false
|
||||
automountlocation:
|
||||
description: automount location map is anchored to
|
||||
choices: ["location", "automountlocationcn"]
|
||||
type: str
|
||||
aliases: ["location", "automountlocationcn"]
|
||||
required: True
|
||||
name:
|
||||
description: automount map to be managed.
|
||||
choices: ["mapname", "map", "automountmapname"]
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["mapname", "map", "automountmapname"]
|
||||
required: True
|
||||
desc:
|
||||
description: description of automount map.
|
||||
choices: ["description"]
|
||||
type: str
|
||||
aliases: ["description"]
|
||||
required: false
|
||||
parentmap:
|
||||
description: |
|
||||
Parent map of the indirect map. Can only be used when creating
|
||||
new maps.
|
||||
type: str
|
||||
required: false
|
||||
mount:
|
||||
description: Indirect map mount point, relative to parent map.
|
||||
type: str
|
||||
required: false
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
required: false
|
||||
default: present
|
||||
choices: ["present", "absent"]
|
||||
@@ -71,6 +86,14 @@ EXAMPLES = '''
|
||||
location: DMZ
|
||||
desc: "this is a map for servers in the DMZ"
|
||||
|
||||
- name: ensure indirect map exists
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: auto.INDIRECT
|
||||
location: DMZ
|
||||
parentmap: auto.DMZ
|
||||
mount: indirect
|
||||
|
||||
- name: remove a map named auto.DMZ in location DMZ if it exists
|
||||
ipaautomountmap:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -106,6 +129,35 @@ class AutomountMap(IPAAnsibleModule):
|
||||
else:
|
||||
return response["result"]
|
||||
|
||||
def get_indirect_map_keys(self, location, name):
|
||||
"""Check if 'name' is an indirect map for 'parentmap'."""
|
||||
try:
|
||||
maps = self.ipa_command("automountmap_find", location, {})
|
||||
except Exception: # pylint: disable=broad-except
|
||||
return []
|
||||
|
||||
result = []
|
||||
for check_map in maps.get("result", []):
|
||||
_mapname = check_map['automountmapname'][0]
|
||||
keys = self.ipa_command(
|
||||
"automountkey_find",
|
||||
location,
|
||||
{
|
||||
"automountmapautomountmapname": _mapname,
|
||||
"all": True
|
||||
}
|
||||
)
|
||||
cmp_value = (
|
||||
name if _mapname == "auto.master" else "ldap:{0}".format(name)
|
||||
)
|
||||
result.extend([
|
||||
(location, _mapname, key.get("automountkey")[0])
|
||||
for key in keys.get("result", [])
|
||||
for mount_info in key.get("automountinformation", [])
|
||||
if cmp_value in mount_info
|
||||
])
|
||||
return result
|
||||
|
||||
def check_ipa_params(self):
|
||||
invalid = []
|
||||
name = self.params_get("name")
|
||||
@@ -114,15 +166,27 @@ class AutomountMap(IPAAnsibleModule):
|
||||
if len(name) != 1:
|
||||
self.fail_json(msg="Exactly one name must be provided for"
|
||||
" 'state: present'.")
|
||||
mount = self.params_get("mount") or False
|
||||
parentmap = self.params_get("parentmap")
|
||||
if parentmap:
|
||||
if not mount:
|
||||
self.fail_json(
|
||||
msg="Must provide 'mount' parameter for indirect map."
|
||||
)
|
||||
elif parentmap != "auto.master" and mount[0] == "/":
|
||||
self.fail_json(
|
||||
msg="mount point is relative to parent map, "
|
||||
"cannot begin with '/'"
|
||||
)
|
||||
if state == "absent":
|
||||
if len(name) == 0:
|
||||
self.fail_json(msg="At least one 'name' must be provided for"
|
||||
" 'state: absent'")
|
||||
invalid = ["desc"]
|
||||
invalid = ["desc", "parentmap", "mount"]
|
||||
|
||||
self.params_fail_used_invalid(invalid, state)
|
||||
|
||||
def get_args(self, mapname, desc): # pylint: disable=no-self-use
|
||||
def get_args(self, mapname, desc, parentmap, mount):
|
||||
# automountmapname is required for all automountmap operations.
|
||||
if not mapname:
|
||||
self.fail_json(msg="automountmapname cannot be None or empty.")
|
||||
@@ -130,6 +194,11 @@ class AutomountMap(IPAAnsibleModule):
|
||||
# An empty string is valid and will clear the attribute.
|
||||
if desc is not None:
|
||||
_args["description"] = desc
|
||||
# indirect map attributes
|
||||
if parentmap is not None:
|
||||
_args["parentmap"] = parentmap
|
||||
if mount is not None:
|
||||
_args["key"] = mount
|
||||
return _args
|
||||
|
||||
def define_ipa_commands(self):
|
||||
@@ -137,28 +206,102 @@ class AutomountMap(IPAAnsibleModule):
|
||||
state = self.params_get("state")
|
||||
location = self.params_get("location")
|
||||
desc = self.params_get("desc")
|
||||
mount = self.params_get("mount")
|
||||
parentmap = self.params_get("parentmap")
|
||||
|
||||
for mapname in name:
|
||||
automountmap = self.get_automountmap(location, mapname)
|
||||
|
||||
is_indirect_map = any([parentmap, mount])
|
||||
|
||||
if state == "present":
|
||||
args = self.get_args(mapname, desc)
|
||||
args = self.get_args(mapname, desc, parentmap, mount)
|
||||
if automountmap is None:
|
||||
self.commands.append([location, "automountmap_add", args])
|
||||
if is_indirect_map:
|
||||
if (
|
||||
parentmap and
|
||||
self.get_automountmap(location, parentmap) is None
|
||||
):
|
||||
self.fail_json(msg="Parent map does not exist.")
|
||||
self.commands.append(
|
||||
[location, "automountmap_add_indirect", args]
|
||||
)
|
||||
else:
|
||||
self.commands.append(
|
||||
[location, "automountmap_add", args]
|
||||
)
|
||||
else:
|
||||
if not compare_args_ipa(self, args, automountmap):
|
||||
has_changes = not compare_args_ipa(
|
||||
self, args, automountmap, ['parentmap', 'key']
|
||||
)
|
||||
if is_indirect_map:
|
||||
map_config = (
|
||||
location, parentmap or "auto.master", mount
|
||||
)
|
||||
indirects = self.get_indirect_map_keys(
|
||||
location, mapname
|
||||
)
|
||||
if map_config not in indirects or has_changes:
|
||||
self.fail_json(
|
||||
msg="Indirect maps can only be created, "
|
||||
"not modified."
|
||||
)
|
||||
elif has_changes:
|
||||
self.commands.append(
|
||||
[location, "automountmap_mod", args]
|
||||
)
|
||||
|
||||
if state == "absent":
|
||||
elif state == "absent":
|
||||
def find_keys(parent_loc, parent_map, parent_key):
|
||||
return self.ipa_command(
|
||||
"automountkey_show",
|
||||
parent_loc,
|
||||
{
|
||||
"automountmapautomountmapname": parent_map,
|
||||
"automountkey": parent_key,
|
||||
}
|
||||
).get("result")
|
||||
|
||||
if automountmap is not None:
|
||||
indirects = self.get_indirect_map_keys(location, mapname)
|
||||
# Remove indirect map configurations for this map
|
||||
self.commands.extend([
|
||||
(
|
||||
ploc,
|
||||
"automountkey_del",
|
||||
{
|
||||
"automountmapautomountmapname": pmap,
|
||||
"automountkey": pkey,
|
||||
}
|
||||
)
|
||||
for ploc, pmap, pkey in indirects
|
||||
if find_keys(ploc, pmap, pkey)
|
||||
])
|
||||
# Remove map
|
||||
self.commands.append([
|
||||
location,
|
||||
"automountmap_del",
|
||||
{"automountmapname": [mapname]}
|
||||
])
|
||||
|
||||
# ensure commands are unique and automountkey commands are
|
||||
# executed first in the list
|
||||
def hashable_dict(dictionaire):
|
||||
return tuple(
|
||||
(k, tuple(v) if isinstance(v, (list, tuple)) else v)
|
||||
for k, v in dictionaire.items()
|
||||
)
|
||||
|
||||
cmds = [
|
||||
(name, cmd, hashable_dict(args))
|
||||
for name, cmd, args in self.commands
|
||||
]
|
||||
self.commands = [
|
||||
(name, cmd, dict(args))
|
||||
for name, cmd, args in
|
||||
sorted(set(cmds), key=lambda cmd: cmd[1])
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
ipa_module = AutomountMap(
|
||||
@@ -169,12 +312,10 @@ def main():
|
||||
),
|
||||
location=dict(type="str",
|
||||
aliases=["automountlocation", "automountlocationcn"],
|
||||
default=None,
|
||||
required=True
|
||||
),
|
||||
name=dict(type="list",
|
||||
name=dict(type="list", elements="str",
|
||||
aliases=["mapname", "map", "automountmapname"],
|
||||
default=None,
|
||||
required=True
|
||||
),
|
||||
desc=dict(type="str",
|
||||
@@ -182,6 +323,10 @@ def main():
|
||||
required=False,
|
||||
default=None
|
||||
),
|
||||
parentmap=dict(
|
||||
type="str", required=False, default=None
|
||||
),
|
||||
mount=dict(type="str", required=False, default=None),
|
||||
),
|
||||
)
|
||||
changed = False
|
||||
|
||||
571
plugins/modules/ipacert.py
Normal file
571
plugins/modules/ipacert.py
Normal file
@@ -0,0 +1,571 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Authors:
|
||||
# Sam Morris <sam@robots.org.uk>
|
||||
# Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2021 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: ipacert
|
||||
short description: Manage FreeIPA certificates
|
||||
description: Manage FreeIPA certificates
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
options:
|
||||
csr:
|
||||
description: |
|
||||
X509 certificate signing request, in RFC 7468 PEM encoding.
|
||||
Only available if `state: requested`, required if `csr_file` is not
|
||||
provided.
|
||||
type: str
|
||||
csr_file:
|
||||
description: |
|
||||
Path to file with X509 certificate signing request, in RFC 7468 PEM
|
||||
encoding. Only available if `state: requested`, required if `csr_file`
|
||||
is not provided.
|
||||
type: str
|
||||
principal:
|
||||
description: |
|
||||
Host/service/user principal for the certificate.
|
||||
Required if `state: requested`. Only available if `state: requested`.
|
||||
type: str
|
||||
add:
|
||||
description: |
|
||||
Automatically add the principal if it doesn't exist (service
|
||||
principals only). Only available if `state: requested`.
|
||||
type: bool
|
||||
aliases: ["add_principal"]
|
||||
required: false
|
||||
ca:
|
||||
description: Name of the issuing certificate authority.
|
||||
type: str
|
||||
required: false
|
||||
serial_number:
|
||||
description: |
|
||||
Certificate serial number. Cannot be used with `state: requested`.
|
||||
Required for all states, except `requested`.
|
||||
type: int
|
||||
profile:
|
||||
description: Certificate Profile to use.
|
||||
type: str
|
||||
aliases: ["profile_id"]
|
||||
required: false
|
||||
revocation_reason:
|
||||
description: |
|
||||
Reason for revoking the certificate. Use one of the reason strings,
|
||||
or the corresponding value: "unspecified" (0), "keyCompromise" (1),
|
||||
"cACompromise" (2), "affiliationChanged" (3), "superseded" (4),
|
||||
"cessationOfOperation" (5), "certificateHold" (6), "removeFromCRL" (8),
|
||||
"privilegeWithdrawn" (9), "aACompromise" (10).
|
||||
Use only if `state: revoked`. Required if `state: revoked`.
|
||||
type: raw
|
||||
aliases: ['reason']
|
||||
certificate_out:
|
||||
description: |
|
||||
Write certificate (chain if `chain` is set) to this file, on the target
|
||||
node.. Use only when `state` is `requested` or `retrieved`.
|
||||
type: str
|
||||
required: false
|
||||
state:
|
||||
description: |
|
||||
The state to ensure. `held` is the same as revoke with reason
|
||||
"certificateHold" (6). `released` is the same as `cert-revoke-hold`
|
||||
on IPA CLI, releasing the hold status of a certificate.
|
||||
choices: ["requested", "held", "released", "revoked", "retrieved"]
|
||||
required: true
|
||||
type: str
|
||||
author:
|
||||
authors:
|
||||
- Sam Morris (@yrro)
|
||||
- Rafael Guterres Jeffman (@rjeffman)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
- name: Request a certificate for a web server
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
state: requested
|
||||
csr: |
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIGYMEwCAQAwGTEXMBUGA1UEAwwOZnJlZWlwYSBydWxlcyEwKjAFBgMrZXADIQBs
|
||||
HlqIr4b/XNK+K8QLJKIzfvuNK0buBhLz3LAzY7QDEqAAMAUGAytlcANBAF4oSCbA
|
||||
5aIPukCidnZJdr491G4LBE+URecYXsPknwYb+V+ONnf5ycZHyaFv+jkUBFGFeDgU
|
||||
SYaXm/gF8cDYjQI=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
principal: HTTP/www.example.com
|
||||
register: cert
|
||||
|
||||
- name: Request certificate for a user, with an appropriate profile.
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
csr: |
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIBejCB5AIBADAQMQ4wDAYDVQQDDAVwaW5reTCBnzANBgkqhkiG9w0BAQEFAAOB
|
||||
jQAwgYkCgYEA7uChccy1Is1FTM0SF23WPYW472E3ozeLh2kzhKR9Ni6FLmeEGgu7
|
||||
/hicR1VwvXHYkNwI1tpW9LqxRVvgr6vheqHySljrBcoRfshfYvKejp03l2327Bfq
|
||||
BNxXqLcHylNEyg8SH0u63bWyxtgoDBfdZwdGAhYuJ+g4ev79J5eYoB0CAwEAAaAr
|
||||
MCkGCSqGSIb3DQEJDjEcMBowGAYHKoZIzlYIAQQNDAtoZWxsbyB3b3JsZDANBgkq
|
||||
hkiG9w0BAQsFAAOBgQADCi5BHDv1mrBFDWqYytFpQ1mrvr/mdax3AYXxNL2UEV8j
|
||||
AqZAFTEnJXL/u1eVQtI1yotqxakyUBN4XZBP2CBgJRO93Mtry8cgvU1sPdU8Mavx
|
||||
5gSnlP74Hio2ziscWWydlxpYxFx0gkKvu+0nyIpz954SVYwQ2wwk5FRqZnxI5w==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
principal: pinky
|
||||
profile_id: IECUserRoles
|
||||
state: requested
|
||||
|
||||
- name: Temporarily hold a certificate
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
serial_number: 12345
|
||||
state: held
|
||||
|
||||
- name: Remove a certificate hold
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
state: released
|
||||
serial_number: 12345
|
||||
|
||||
- name: Permanently revoke a certificate issued by a lightweight sub-CA
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
state: revoked
|
||||
ca: vpn-ca
|
||||
serial_number: 0x98765
|
||||
reason: keyCompromise
|
||||
|
||||
- name: Retrieve a certificate
|
||||
ipacert:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
serial_number: 12345
|
||||
state: retrieved
|
||||
register: cert_retrieved
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
certificate:
|
||||
description: Certificate fields and data.
|
||||
returned: |
|
||||
if `state` is `requested` or `retrived` and `certificate_out`
|
||||
is not defined.
|
||||
type: dict
|
||||
contains:
|
||||
certificate:
|
||||
description: |
|
||||
Issued X509 certificate in PEM encoding. Will include certificate
|
||||
chain if `chain: true` is used.
|
||||
type: list
|
||||
elements: str
|
||||
returned: always
|
||||
issuer:
|
||||
description: X509 distinguished name of issuer.
|
||||
type: str
|
||||
sample: CN=Certificate Authority,O=EXAMPLE.COM
|
||||
returned: always
|
||||
serial_number:
|
||||
description: Serial number of the issued certificate.
|
||||
type: int
|
||||
sample: 902156300
|
||||
returned: always
|
||||
valid_not_after:
|
||||
description: |
|
||||
Time when issued certificate ceases to be valid,
|
||||
in GeneralizedTime format (YYYYMMDDHHMMSSZ).
|
||||
type: str
|
||||
returned: always
|
||||
valid_not_before:
|
||||
description: |
|
||||
Time when issued certificate becomes valid, in
|
||||
GeneralizedTime format (YYYYMMDDHHMMSSZ).
|
||||
type: str
|
||||
returned: always
|
||||
subject:
|
||||
description: X509 distinguished name of certificate subject.
|
||||
type: str
|
||||
sample: CN=www.example.com,O=EXAMPLE.COM
|
||||
returned: always
|
||||
san_dnsname:
|
||||
description: X509 Subject Alternative Name.
|
||||
type: list
|
||||
elements: str
|
||||
sample: ['www.example.com', 'other.example.com']
|
||||
returned: |
|
||||
when DNSNames are present in the Subject Alternative Name
|
||||
extension of the issued certificate.
|
||||
revoked:
|
||||
description: Revoked status of the certificate.
|
||||
type: bool
|
||||
returned: always
|
||||
owner_user:
|
||||
description: The username that owns the certificate.
|
||||
type: str
|
||||
returned: when `state` is `retrieved`
|
||||
owner_host:
|
||||
description: The host that owns the certificate.
|
||||
type: str
|
||||
returned: when `state` is `retrieved`
|
||||
owner_service:
|
||||
description: The service that owns the certificate.
|
||||
type: str
|
||||
returned: when `state` is `retrieved`
|
||||
"""
|
||||
|
||||
import base64
|
||||
import time
|
||||
import ssl
|
||||
|
||||
from ansible.module_utils import six
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.ansible_freeipa_module import (
|
||||
IPAAnsibleModule, certificate_loader, write_certificate_list,
|
||||
)
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
# Reasons are defined in RFC 5280 sec. 5.3.1; removeFromCRL is not present in
|
||||
# this list; run the module with state=released instead.
|
||||
REVOCATION_REASONS = {
|
||||
'unspecified': 0,
|
||||
'keyCompromise': 1,
|
||||
'cACompromise': 2,
|
||||
'affiliationChanged': 3,
|
||||
'superseded': 4,
|
||||
'cessationOfOperation': 5,
|
||||
'certificateHold': 6,
|
||||
'removeFromCRL': 8,
|
||||
'privilegeWithdrawn': 9,
|
||||
'aACompromise': 10,
|
||||
}
|
||||
|
||||
|
||||
def gen_args(
|
||||
module, principal=None, add_principal=None, ca=None, chain=None,
|
||||
profile=None, certificate_out=None, reason=None
|
||||
):
|
||||
args = {}
|
||||
if principal is not None:
|
||||
args['principal'] = principal
|
||||
if add_principal is not None:
|
||||
args['add'] = add_principal
|
||||
if ca is not None:
|
||||
args['cacn'] = ca
|
||||
if profile is not None:
|
||||
args['profile_id'] = profile
|
||||
if certificate_out is not None:
|
||||
args['out'] = certificate_out
|
||||
if chain:
|
||||
args['chain'] = True
|
||||
if ca:
|
||||
args['cacn'] = ca
|
||||
if reason is not None:
|
||||
args['revocation_reason'] = get_revocation_reason(module, reason)
|
||||
return args
|
||||
|
||||
|
||||
def get_revocation_reason(module, reason):
|
||||
"""Ensure revocation reasion is a valid integer code."""
|
||||
reason_int = -1
|
||||
|
||||
try:
|
||||
reason_int = int(reason)
|
||||
except ValueError:
|
||||
reason_int = REVOCATION_REASONS.get(reason, -1)
|
||||
|
||||
if reason_int not in REVOCATION_REASONS.values():
|
||||
module.fail_json(msg="Invalid revocation reason: %s" % reason)
|
||||
|
||||
return reason_int
|
||||
|
||||
|
||||
def parse_cert_timestamp(dt):
|
||||
"""Ensure time is in GeneralizedTime format (YYYYMMDDHHMMSSZ)."""
|
||||
return time.strftime(
|
||||
"%Y%m%d%H%M%SZ",
|
||||
time.strptime(dt, "%a %b %d %H:%M:%S %Y UTC")
|
||||
)
|
||||
|
||||
|
||||
def result_handler(_module, result, _command, _name, _args, exit_args, chain):
|
||||
"""Split certificate into fields."""
|
||||
if chain:
|
||||
exit_args['certificate'] = [
|
||||
ssl.DER_cert_to_PEM_cert(c)
|
||||
for c in result['result'].get('certificate_chain', [])
|
||||
]
|
||||
else:
|
||||
exit_args['certificate'] = [
|
||||
ssl.DER_cert_to_PEM_cert(
|
||||
base64.b64decode(result['result']['certificate'])
|
||||
)
|
||||
]
|
||||
|
||||
exit_args['san_dnsname'] = [
|
||||
str(dnsname)
|
||||
for dnsname in result['result'].get('san_dnsname', [])
|
||||
]
|
||||
|
||||
exit_args.update({
|
||||
key: result['result'][key]
|
||||
for key in [
|
||||
'issuer', 'subject', 'serial_number',
|
||||
'revoked', 'revocation_reason'
|
||||
]
|
||||
if key in result['result']
|
||||
})
|
||||
exit_args.update({
|
||||
key: result['result'][key][0]
|
||||
for key in ['owner_user', 'owner_host', 'owner_service']
|
||||
if key in result['result']
|
||||
})
|
||||
|
||||
exit_args.update({
|
||||
key: parse_cert_timestamp(result['result'][key])
|
||||
for key in ['valid_not_after', 'valid_not_before']
|
||||
if key in result['result']
|
||||
})
|
||||
|
||||
|
||||
def do_cert_request(
|
||||
module, csr, principal, add_principal=None, ca=None, profile=None,
|
||||
chain=None, certificate_out=None
|
||||
):
|
||||
"""Request a certificate."""
|
||||
args = gen_args(
|
||||
module, principal=principal, ca=ca, chain=chain,
|
||||
add_principal=add_principal, profile=profile,
|
||||
)
|
||||
exit_args = {}
|
||||
commands = [[to_text(csr), "cert_request", args]]
|
||||
changed = module.execute_ipa_commands(
|
||||
commands,
|
||||
result_handler=result_handler,
|
||||
exit_args=exit_args,
|
||||
chain=chain
|
||||
)
|
||||
|
||||
if certificate_out is not None:
|
||||
certs = (
|
||||
certificate_loader(cert.encode("utf-8"))
|
||||
for cert in exit_args['certificate']
|
||||
)
|
||||
write_certificate_list(certs, certificate_out)
|
||||
exit_args = {}
|
||||
|
||||
return changed, exit_args
|
||||
|
||||
|
||||
def do_cert_revoke(ansible_module, serial_number, reason=None, ca=None):
|
||||
"""Revoke a certificate."""
|
||||
_ign, cert = do_cert_retrieve(ansible_module, serial_number, ca)
|
||||
if not cert or cert.get('revoked', False):
|
||||
return False, cert
|
||||
|
||||
args = gen_args(ansible_module, ca=ca, reason=reason)
|
||||
|
||||
commands = [[serial_number, "cert_revoke", args]]
|
||||
changed = ansible_module.execute_ipa_commands(commands)
|
||||
|
||||
return changed, cert
|
||||
|
||||
|
||||
def do_cert_release(ansible_module, serial_number, ca=None):
|
||||
"""Release hold on certificate."""
|
||||
_ign, cert = do_cert_retrieve(ansible_module, serial_number, ca)
|
||||
revoked = cert.get('revoked', True)
|
||||
reason = cert.get('revocation_reason', -1)
|
||||
if cert and not revoked:
|
||||
return False, cert
|
||||
|
||||
if revoked and reason != 6: # can only release held certificates
|
||||
ansible_module.fail_json(
|
||||
msg="Cannot release hold on certificate revoked with"
|
||||
" reason: %d" % reason
|
||||
)
|
||||
args = gen_args(ansible_module, ca=ca)
|
||||
|
||||
commands = [[serial_number, "cert_remove_hold", args]]
|
||||
changed = ansible_module.execute_ipa_commands(commands)
|
||||
|
||||
return changed, cert
|
||||
|
||||
|
||||
def do_cert_retrieve(
|
||||
module, serial_number, ca=None, chain=None, outfile=None
|
||||
):
|
||||
"""Retrieve a certificate with 'cert-show'."""
|
||||
args = gen_args(module, ca=ca, chain=chain, certificate_out=outfile)
|
||||
exit_args = {}
|
||||
commands = [[serial_number, "cert_show", args]]
|
||||
module.execute_ipa_commands(
|
||||
commands,
|
||||
result_handler=result_handler,
|
||||
exit_args=exit_args,
|
||||
chain=chain,
|
||||
)
|
||||
if outfile is not None:
|
||||
exit_args = {}
|
||||
|
||||
return False, exit_args
|
||||
|
||||
|
||||
def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# requested
|
||||
csr=dict(type="str"),
|
||||
csr_file=dict(type="str"),
|
||||
principal=dict(type="str"),
|
||||
add_principal=dict(type="bool", required=False, aliases=["add"]),
|
||||
profile_id=dict(type="str", aliases=["profile"], required=False),
|
||||
# revoked
|
||||
revocation_reason=dict(type="raw", aliases=["reason"]),
|
||||
# general
|
||||
serial_number=dict(type="int"),
|
||||
ca=dict(type="str"),
|
||||
chain=dict(type="bool", required=False),
|
||||
certificate_out=dict(type="str", required=False),
|
||||
# state
|
||||
state=dict(
|
||||
type="str",
|
||||
required=True,
|
||||
choices=[
|
||||
"requested", "held", "released", "revoked", "retrieved"
|
||||
]
|
||||
),
|
||||
),
|
||||
mutually_exclusive=[["csr", "csr_file"]],
|
||||
required_if=[
|
||||
('state', 'requested', ['principal']),
|
||||
('state', 'retrieved', ['serial_number']),
|
||||
('state', 'held', ['serial_number']),
|
||||
('state', 'released', ['serial_number']),
|
||||
('state', 'revoked', ['serial_number', 'revocation_reason']),
|
||||
],
|
||||
supports_check_mode=False,
|
||||
)
|
||||
|
||||
ansible_module._ansible_debug = True
|
||||
|
||||
# Get parameters
|
||||
|
||||
# requested
|
||||
csr = ansible_module.params_get("csr")
|
||||
csr_file = ansible_module.params_get("csr_file")
|
||||
principal = ansible_module.params_get("principal")
|
||||
add_principal = ansible_module.params_get("add_principal")
|
||||
profile = ansible_module.params_get("profile_id")
|
||||
|
||||
# revoked
|
||||
reason = ansible_module.params_get("revocation_reason")
|
||||
|
||||
# general
|
||||
serial_number = ansible_module.params.get("serial_number")
|
||||
ca = ansible_module.params_get("ca")
|
||||
chain = ansible_module.params_get("chain")
|
||||
certificate_out = ansible_module.params_get("certificate_out")
|
||||
|
||||
# state
|
||||
state = ansible_module.params_get("state")
|
||||
|
||||
# Check parameters
|
||||
|
||||
if ansible_module.params_get("ipaapi_context") == "server":
|
||||
ansible_module.fail_json(
|
||||
msg="Context 'server' for ipacert is not yet supported."
|
||||
)
|
||||
|
||||
invalid = []
|
||||
if state == "requested":
|
||||
invalid = ["serial_number", "revocation_reason"]
|
||||
if csr is None and csr_file is None:
|
||||
ansible_module.fail_json(
|
||||
msg="Required 'csr' or 'csr_file' with 'state: requested'.")
|
||||
else:
|
||||
invalid = [
|
||||
"csr", "principal", "add_principal", "profile"
|
||||
"certificate_out"
|
||||
]
|
||||
if state in ["released", "held"]:
|
||||
invalid.extend(["revocation_reason", "certificate_out", "chain"])
|
||||
if state == "retrieved":
|
||||
invalid.append("revocation_reason")
|
||||
if state == "revoked":
|
||||
invalid.extend(["certificate_out", "chain"])
|
||||
elif state == "held":
|
||||
reason = 6 # certificateHold
|
||||
|
||||
ansible_module.params_fail_used_invalid(invalid, state)
|
||||
|
||||
# Init
|
||||
|
||||
changed = False
|
||||
exit_args = {}
|
||||
|
||||
# Connect to IPA API
|
||||
# If executed on 'server' contexot, cert plugin uses the IPA RA agent
|
||||
# TLS client certificate/key, which users are not able to access,
|
||||
# resulting in a 'permission denied' exception when attempting to connect
|
||||
# the CA service. Therefore 'client' context in forced for this module.
|
||||
with ansible_module.ipa_connect(context="client"):
|
||||
|
||||
if state == "requested":
|
||||
if csr_file is not None:
|
||||
with open(csr_file, "rt") as csr_in:
|
||||
csr = "".join(csr_in.readlines())
|
||||
changed, exit_args = do_cert_request(
|
||||
ansible_module,
|
||||
csr,
|
||||
principal,
|
||||
add_principal,
|
||||
ca,
|
||||
profile,
|
||||
chain,
|
||||
certificate_out
|
||||
)
|
||||
|
||||
elif state in ("held", "revoked"):
|
||||
changed, exit_args = do_cert_revoke(
|
||||
ansible_module, serial_number, reason, ca)
|
||||
|
||||
elif state == "released":
|
||||
changed, exit_args = do_cert_release(
|
||||
ansible_module, serial_number, ca)
|
||||
|
||||
elif state == "retrieved":
|
||||
changed, exit_args = do_cert_retrieve(
|
||||
ansible_module, serial_number, ca, chain, certificate_out)
|
||||
|
||||
# Done
|
||||
|
||||
ansible_module.exit_json(changed=changed, certificate=exit_args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
# Authors:
|
||||
# Chris Procter <cprocter@redhat.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2020 Red Hat
|
||||
# Copyright (C) 2020-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,8 +33,10 @@ ANSIBLE_METADATA = {
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: ipa_config
|
||||
author: chris procter
|
||||
module: ipaconfig
|
||||
author:
|
||||
- Chris Procter (@chr15p)
|
||||
- Thomas Woerner (@t-woerner)
|
||||
short_description: Modify IPA global config options
|
||||
description:
|
||||
- Modify IPA global config options
|
||||
@@ -43,48 +46,60 @@ options:
|
||||
maxusername:
|
||||
description: Set the maximum username length between 1-255
|
||||
required: false
|
||||
type: int
|
||||
aliases: ['ipamaxusernamelength']
|
||||
maxhostname:
|
||||
description: Set the maximum hostname length between 64-255
|
||||
required: false
|
||||
type: int
|
||||
aliases: ['ipamaxhostnamelength']
|
||||
homedirectory:
|
||||
description: Set the default location of home directories
|
||||
required: false
|
||||
type: str
|
||||
aliases: ['ipahomesrootdir']
|
||||
defaultshell:
|
||||
description: Set the default shell for new users
|
||||
required: false
|
||||
type: str
|
||||
aliases: ['ipadefaultloginshell', 'loginshell']
|
||||
defaultgroup:
|
||||
description: Set the default group for new users
|
||||
required: false
|
||||
type: str
|
||||
aliases: ['ipadefaultprimarygroup']
|
||||
emaildomain:
|
||||
description: Set the default e-mail domain
|
||||
required: false
|
||||
type: str
|
||||
aliases: ['ipadefaultemaildomain']
|
||||
searchtimelimit:
|
||||
description:
|
||||
- Set maximum amount of time (seconds) for a search
|
||||
- values -1 to 2147483647 (-1 or 0 is unlimited)
|
||||
required: false
|
||||
type: int
|
||||
aliases: ['ipasearchtimelimit']
|
||||
searchrecordslimit:
|
||||
description:
|
||||
- Set maximum number of records to search
|
||||
- values -1 to 2147483647 (-1 or 0 is unlimited)
|
||||
required: false
|
||||
type: int
|
||||
aliases: ['ipasearchrecordslimit']
|
||||
usersearch:
|
||||
description:
|
||||
- Set comma-separated list of fields to search for user search
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ['ipausersearchfields']
|
||||
groupsearch:
|
||||
description:
|
||||
- Set comma-separated list of fields to search for group search
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ['ipagroupsearchfields']
|
||||
enable_migration:
|
||||
description: Enable migration mode
|
||||
@@ -95,22 +110,26 @@ options:
|
||||
description: Set default group objectclasses (comma-separated list)
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ['ipagroupobjectclasses']
|
||||
userobjectclasses:
|
||||
description: Set default user objectclasses (comma-separated list)
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ['ipauserobjectclasses']
|
||||
pwdexpnotify:
|
||||
description:
|
||||
- Set number of days's notice of impending password expiration
|
||||
- values 0 to 2147483647
|
||||
required: false
|
||||
type: int
|
||||
aliases: ['ipapwdexpadvnotify']
|
||||
configstring:
|
||||
description: Set extra hashes to generate in password plug-in
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
choices:
|
||||
- "AllowNThash"
|
||||
- "KDC:Disable Last Success"
|
||||
@@ -122,32 +141,56 @@ options:
|
||||
description: Set order in increasing priority of SELinux users
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ['ipaselinuxusermaporder']
|
||||
selinuxusermapdefault:
|
||||
description: Set default SELinux user when no match found in map rule
|
||||
required: false
|
||||
type: str
|
||||
aliases: ['ipaselinuxusermapdefault']
|
||||
pac_type:
|
||||
description: set default types of PAC supported for services
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
choices: ["MS-PAC", "PAD", "nfs:NONE", ""]
|
||||
aliases: ["ipakrbauthzdata"]
|
||||
user_auth_type:
|
||||
description: set default types of supported user authentication
|
||||
required: false
|
||||
type: list
|
||||
choices: ["password", "radius", "otp", "disabled", ""]
|
||||
elements: str
|
||||
choices: ["password", "radius", "otp", "pkinit", "hardened", "idp",
|
||||
"disabled", ""]
|
||||
aliases: ["ipauserauthtype"]
|
||||
ca_renewal_master_server:
|
||||
description: Renewal master for IPA certificate authority.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
domain_resolution_order:
|
||||
description: set list of domains used for short name qualification
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipadomainresolutionorder"]
|
||||
enable_sid:
|
||||
description: >
|
||||
New users and groups automatically get a SID assigned.
|
||||
Cannot be deactivated once activated. Requires IPA 4.9.8+.
|
||||
required: false
|
||||
type: bool
|
||||
netbios_name:
|
||||
description: >
|
||||
NetBIOS name of the IPA domain. Requires IPA 4.9.8+
|
||||
and SID generation to be activated.
|
||||
required: false
|
||||
type: str
|
||||
add_sids:
|
||||
description: >
|
||||
Add SIDs for existing users and groups. Requires IPA 4.9.8+
|
||||
and SID generation to be activated.
|
||||
required: false
|
||||
type: bool
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
@@ -169,6 +212,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 = '''
|
||||
@@ -176,38 +237,48 @@ config:
|
||||
description: Dict of all global config options
|
||||
returned: When no options are set
|
||||
type: dict
|
||||
options:
|
||||
contains:
|
||||
maxusername:
|
||||
description: maximum username length
|
||||
type: int
|
||||
returned: always
|
||||
maxhostname:
|
||||
description: maximum hostname length
|
||||
type: int
|
||||
returned: always
|
||||
homedirectory:
|
||||
description: default location of home directories
|
||||
type: str
|
||||
returned: always
|
||||
defaultshell:
|
||||
description: default shell for new users
|
||||
type: str
|
||||
returned: always
|
||||
defaultgroup:
|
||||
description: default group for new users
|
||||
type: str
|
||||
returned: always
|
||||
emaildomain:
|
||||
description: default e-mail domain
|
||||
type: str
|
||||
returned: always
|
||||
searchtimelimit:
|
||||
description: maximum amount of time (seconds) for a search
|
||||
type: int
|
||||
returned: always
|
||||
searchrecordslimit:
|
||||
description: maximum number of records to search
|
||||
type: int
|
||||
returned: always
|
||||
usersearch:
|
||||
description: comma-separated list of fields to search in user search
|
||||
description: list of fields to search in user search
|
||||
type: list
|
||||
elements: str
|
||||
returned: always
|
||||
groupsearch:
|
||||
description: comma-separated list of fields to search in group search
|
||||
description: list of fields to search in group search
|
||||
type: list
|
||||
elements: str
|
||||
returned: always
|
||||
enable_migration:
|
||||
description: Enable migration mode
|
||||
@@ -216,37 +287,59 @@ config:
|
||||
groupobjectclasses:
|
||||
description: default group objectclasses (comma-separated list)
|
||||
type: list
|
||||
elements: str
|
||||
returned: always
|
||||
userobjectclasses:
|
||||
description: default user objectclasses (comma-separated list)
|
||||
type: list
|
||||
elements: str
|
||||
returned: always
|
||||
pwdexpnotify:
|
||||
description: number of days's notice of impending password expiration
|
||||
type: str
|
||||
returned: always
|
||||
configstring:
|
||||
description: extra hashes to generate in password plug-in
|
||||
type: list
|
||||
elements: str
|
||||
returned: always
|
||||
selinuxusermaporder:
|
||||
description: order in increasing priority of SELinux users
|
||||
type: list
|
||||
elements: str
|
||||
returned: always
|
||||
selinuxusermapdefault:
|
||||
description: default SELinux user when no match is found in map rule
|
||||
type: str
|
||||
returned: always
|
||||
pac_type:
|
||||
description: default types of PAC supported for services
|
||||
type: list
|
||||
elements: str
|
||||
returned: always
|
||||
user_auth_type:
|
||||
description: default types of supported user authentication
|
||||
type: str
|
||||
returned: always
|
||||
ca_renewal_master_server:
|
||||
description: master for IPA certificate authority.
|
||||
type: str
|
||||
returned: always
|
||||
domain_resolution_order:
|
||||
description: list of domains used for short name qualification
|
||||
type: list
|
||||
elements: str
|
||||
returned: always
|
||||
enable_sid:
|
||||
description: >
|
||||
new users and groups automatically get a SID assigned.
|
||||
Requires IPA 4.9.8+.
|
||||
type: str
|
||||
returned: always
|
||||
netbios_name:
|
||||
description: NetBIOS name of the IPA domain. Requires IPA 4.9.8+.
|
||||
type: str
|
||||
returned: if enable_sid is True
|
||||
'''
|
||||
|
||||
|
||||
@@ -260,6 +353,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(
|
||||
@@ -281,39 +396,46 @@ def main():
|
||||
aliases=['ipasearchtimelimit']),
|
||||
searchrecordslimit=dict(type="int", required=False,
|
||||
aliases=['ipasearchrecordslimit']),
|
||||
usersearch=dict(type="list", required=False,
|
||||
usersearch=dict(type="list", elements="str", required=False,
|
||||
aliases=['ipausersearchfields']),
|
||||
groupsearch=dict(type="list", required=False,
|
||||
groupsearch=dict(type="list", elements="str", required=False,
|
||||
aliases=['ipagroupsearchfields']),
|
||||
enable_migration=dict(type="bool", required=False,
|
||||
aliases=['ipamigrationenabled']),
|
||||
groupobjectclasses=dict(type="list", required=False,
|
||||
groupobjectclasses=dict(type="list", elements="str",
|
||||
required=False,
|
||||
aliases=['ipagroupobjectclasses']),
|
||||
userobjectclasses=dict(type="list", required=False,
|
||||
userobjectclasses=dict(type="list", elements="str", required=False,
|
||||
aliases=['ipauserobjectclasses']),
|
||||
pwdexpnotify=dict(type="int", required=False,
|
||||
aliases=['ipapwdexpadvnotify']),
|
||||
configstring=dict(type="list", required=False,
|
||||
configstring=dict(type="list", elements="str", required=False,
|
||||
aliases=['ipaconfigstring'],
|
||||
choices=["AllowNThash",
|
||||
"KDC:Disable Last Success",
|
||||
"KDC:Disable Lockout",
|
||||
"KDC:Disable Default Preauth for SPNs",
|
||||
""]), # noqa E128
|
||||
selinuxusermaporder=dict(type="list", required=False,
|
||||
selinuxusermaporder=dict(type="list", elements="str",
|
||||
required=False,
|
||||
aliases=['ipaselinuxusermaporder']),
|
||||
selinuxusermapdefault=dict(type="str", required=False,
|
||||
aliases=['ipaselinuxusermapdefault']),
|
||||
pac_type=dict(type="list", required=False,
|
||||
pac_type=dict(type="list", elements="str", required=False,
|
||||
aliases=["ipakrbauthzdata"],
|
||||
choices=["MS-PAC", "PAD", "nfs:NONE", ""]),
|
||||
user_auth_type=dict(type="list", required=False,
|
||||
user_auth_type=dict(type="list", elements="str", required=False,
|
||||
choices=["password", "radius", "otp",
|
||||
"pkinit", "hardened", "idp",
|
||||
"disabled", ""],
|
||||
aliases=["ipauserauthtype"]),
|
||||
ca_renewal_master_server=dict(type="str", required=False),
|
||||
domain_resolution_order=dict(type="list", required=False,
|
||||
aliases=["ipadomainresolutionorder"])
|
||||
domain_resolution_order=dict(type="list", elements="str",
|
||||
required=False,
|
||||
aliases=["ipadomainresolutionorder"]),
|
||||
enable_sid=dict(type="bool", required=False),
|
||||
add_sids=dict(type="bool", required=False),
|
||||
netbios_name=dict(type="str", required=False),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
@@ -344,7 +466,10 @@ def main():
|
||||
"pac_type": "ipakrbauthzdata",
|
||||
"user_auth_type": "ipauserauthtype",
|
||||
"ca_renewal_master_server": "ca_renewal_master_server",
|
||||
"domain_resolution_order": "ipadomainresolutionorder"
|
||||
"domain_resolution_order": "ipadomainresolutionorder",
|
||||
"enable_sid": "enable_sid",
|
||||
"netbios_name": "netbios_name",
|
||||
"add_sids": "add_sids",
|
||||
}
|
||||
allow_empty_string = ["pac_type", "user_auth_type", "configstring"]
|
||||
reverse_field_map = {v: k for k, v in field_map.items()}
|
||||
@@ -394,11 +519,61 @@ 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:
|
||||
# Verify ipauserauthtype(s)
|
||||
if "ipauserauthtype" in params and params["ipauserauthtype"]:
|
||||
_invalid = ansible_module.ipa_command_invalid_param_choices(
|
||||
"config_mod", "ipauserauthtype", params["ipauserauthtype"])
|
||||
if _invalid:
|
||||
ansible_module.fail_json(
|
||||
msg="The use of userauthtype '%s' is not "
|
||||
"supported by your IPA version" % "','".join(_invalid))
|
||||
|
||||
enable_sid = params.get("enable_sid")
|
||||
sid_is_enabled = has_enable_sid and is_enable_sid(ansible_module)
|
||||
|
||||
if sid_is_enabled and enable_sid is False:
|
||||
ansible_module.fail_json(msg="SID cannot be disabled.")
|
||||
|
||||
netbios_name = params.get("netbios_name")
|
||||
add_sids = params.get("add_sids")
|
||||
if has_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 any([netbios_name, add_sids]):
|
||||
if sid_is_enabled:
|
||||
params["enable_sid"] = True
|
||||
else:
|
||||
if not enable_sid:
|
||||
ansible_module.fail_json(
|
||||
msg="SID generation must be enabled for "
|
||||
"'netbios_name' and 'add_sids'. Use "
|
||||
"'enable_sid: yes'."
|
||||
)
|
||||
else:
|
||||
if sid_is_enabled and "enable_sid" in params:
|
||||
del params["enable_sid"]
|
||||
|
||||
else:
|
||||
if any([enable_sid, netbios_name, add_sids is not None]):
|
||||
ansible_module.fail_json(
|
||||
msg="This version of IPA does not support enable_sid, "
|
||||
"add_sids or netbios_name setting through the "
|
||||
"config module"
|
||||
)
|
||||
params = {
|
||||
k: v for k, v in params.items()
|
||||
if k not in result or result[k] != v
|
||||
@@ -458,6 +633,10 @@ def main():
|
||||
# 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)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2020 Red Hat
|
||||
# Copyright (C) 2020-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,40 +32,52 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The list of delegation name strings.
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["aciname"]
|
||||
permission:
|
||||
description: Permissions to grant (read, write). Default is write.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["permissions"]
|
||||
attribute:
|
||||
description: Attribute list to which the delegation applies
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["attrs"]
|
||||
membergroup:
|
||||
description: User group to apply delegation to
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["memberof"]
|
||||
group:
|
||||
description: User group ACI grants access to
|
||||
type: str
|
||||
required: false
|
||||
action:
|
||||
description: Work on delegation or member level.
|
||||
type: str
|
||||
choices: ["delegation", "member"]
|
||||
default: delegation
|
||||
required: false
|
||||
state:
|
||||
description: The state to ensure.
|
||||
type: str
|
||||
choices: ["present", "absent"]
|
||||
default: present
|
||||
required: true
|
||||
required: false
|
||||
author:
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -143,13 +155,13 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["aciname"], default=None,
|
||||
name=dict(type="list", elements="str", aliases=["aciname"],
|
||||
required=True),
|
||||
# present
|
||||
permission=dict(required=False, type='list',
|
||||
permission=dict(required=False, type='list', elements="str",
|
||||
aliases=["permissions"], default=None),
|
||||
attribute=dict(required=False, type='list', aliases=["attrs"],
|
||||
default=None),
|
||||
attribute=dict(required=False, type='list', elements="str",
|
||||
aliases=["attrs"], default=None),
|
||||
membergroup=dict(type="str", aliases=["memberof"], default=None),
|
||||
group=dict(type="str", default=None),
|
||||
action=dict(type="str", default="delegation",
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
# Authors:
|
||||
# Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2019 Red Hat
|
||||
# Copyright (C) 2019-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -33,7 +34,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
|
||||
@@ -41,20 +42,25 @@ options:
|
||||
forwarders:
|
||||
description: The list of global DNS forwarders.
|
||||
required: false
|
||||
options:
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
ip_address:
|
||||
description: The forwarder nameserver IP address list (IPv4 and IPv6).
|
||||
type: str
|
||||
required: true
|
||||
port:
|
||||
description: The port to forward requests to.
|
||||
type: int
|
||||
required: false
|
||||
forward_policy:
|
||||
description:
|
||||
Global forwarding policy. Set to "none" to disable any configured
|
||||
global forwarders.
|
||||
type: str
|
||||
required: false
|
||||
choices: ['only', 'first', 'none']
|
||||
alias: ["forwardpolicy"]
|
||||
aliases: ["forwardpolicy"]
|
||||
allow_sync_ptr:
|
||||
description:
|
||||
Allow synchronization of forward (A, AAAA) and reverse (PTR) records.
|
||||
@@ -64,14 +70,19 @@ options:
|
||||
description: |
|
||||
Work on dnsconfig or member level. It can be one of `member` or
|
||||
`dnsconfig`. Only `forwarders` can be managed with `action: member`.
|
||||
type: str
|
||||
default: "dnsconfig"
|
||||
choices: ["member", "dnsconfig"]
|
||||
state:
|
||||
description: |
|
||||
The state to ensure. It can be one of `present` or `absent`.
|
||||
`absent` can only be used with `action: member` and `forwarders`.
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent"]
|
||||
author:
|
||||
- Rafael Guterres Jeffman (@rjeffman)
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -183,14 +194,15 @@ def gen_args(module, state, action, dnsconfig, forwarders, forward_policy,
|
||||
|
||||
def main():
|
||||
forwarder_spec = dict(
|
||||
ip_address=dict(type=str, required=True),
|
||||
port=dict(type=int, required=False, default=None)
|
||||
ip_address=dict(type="str", required=True),
|
||||
port=dict(type="int", required=False, default=None)
|
||||
)
|
||||
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# dnsconfig
|
||||
forwarders=dict(type='list', default=None, required=False,
|
||||
forwarders=dict(type='list', elements="dict", default=None,
|
||||
required=False,
|
||||
options=dict(**forwarder_spec)),
|
||||
forward_policy=dict(type='str', required=False, default=None,
|
||||
choices=['only', 'first', 'none'],
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
# Authors:
|
||||
# Chris Procter <cprocter@redhat.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2019 Red Hat
|
||||
# Copyright (C) 2019-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,53 +33,68 @@ ANSIBLE_METADATA = {
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: ipa_dnsforwardzone
|
||||
author: chris procter
|
||||
module: ipadnsforwardzone
|
||||
author:
|
||||
- Chris Procter (@chr15p)
|
||||
- Thomas Woerner (@t-woerner)
|
||||
short_description: Manage FreeIPA DNS Forwarder Zones
|
||||
description:
|
||||
- Add and delete an IPA DNS Forwarder Zones using IPA API
|
||||
- Add and delete an IPA DNS Forwarder Zones using IPA API
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- The DNS zone name which needs to be managed.
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
action:
|
||||
description: |
|
||||
Work on dnsforwardzone or member level. It can be one of `member` or
|
||||
`dnsforwardzone`.
|
||||
type: str
|
||||
default: "dnsforwardzone"
|
||||
choices: ["member", "dnsforwardzone"]
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
required: false
|
||||
default: present
|
||||
choices: ["present", "absent", "enabled", "disabled"]
|
||||
forwarders:
|
||||
description:
|
||||
- List of the DNS servers to forward to
|
||||
type: list
|
||||
elements: dict
|
||||
aliases: ["idnsforwarders"]
|
||||
options:
|
||||
suboptions:
|
||||
ip_address:
|
||||
description: Forwarder IP address (either IPv4 or IPv6).
|
||||
required: false
|
||||
type: string
|
||||
required: true
|
||||
type: str
|
||||
port:
|
||||
description: Forwarder port.
|
||||
required: false
|
||||
type: int
|
||||
forwardpolicy:
|
||||
description: Per-zone conditional forwarding policy
|
||||
type: str
|
||||
required: false
|
||||
default: only
|
||||
choices: ["only", "first", "none"]
|
||||
aliases: ["idnsforwarders", "forward_policy"]
|
||||
aliases: ["idnsforwardpolicy", "forward_policy"]
|
||||
skip_overlap_check:
|
||||
description:
|
||||
- Force DNS zone creation even if it will overlap with an existing zone.
|
||||
type: bool
|
||||
required: false
|
||||
default: false
|
||||
permission:
|
||||
description:
|
||||
- Allow DNS Forward Zone to be managed.
|
||||
required: false
|
||||
type: bool
|
||||
aliases: ["managedby"]
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
@@ -180,7 +196,7 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"], default=None,
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
required=True),
|
||||
forwarders=dict(type="list", default=None, required=False,
|
||||
aliases=["idnsforwarders"], elements='dict',
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
# Authors:
|
||||
# Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2020 Red Hat
|
||||
# Copyright (C) 2020-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -34,7 +35,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
|
||||
@@ -42,19 +43,24 @@ options:
|
||||
records:
|
||||
description: The list of user dns records dicts
|
||||
required: false
|
||||
options:
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
name:
|
||||
description: The DNS record name to manage.
|
||||
type: str
|
||||
aliases: ["record_name"]
|
||||
required: true
|
||||
zone_name:
|
||||
description: |
|
||||
The DNS zone name to which DNS record needs to be managed.
|
||||
Required if not provided globally.
|
||||
type: str
|
||||
aliases: ["dnszone"]
|
||||
required: false
|
||||
record_type:
|
||||
description: The type of DNS record.
|
||||
type: str
|
||||
choices: ["A", "AAAA", "A6", "AFSDB", "CERT", "CNAME", "DLV", "DNAME",
|
||||
"DS", "KX", "LOC", "MX", "NAPTR", "NS", "PTR", "SRV",
|
||||
"SSHFP", "TLSA", "TXT", "URI"]
|
||||
@@ -63,6 +69,7 @@ options:
|
||||
description: Manage DNS record name with these values.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
record_ttl:
|
||||
description: Set the TTL for the record.
|
||||
required: false
|
||||
@@ -73,92 +80,132 @@ options:
|
||||
type: bool
|
||||
a_rec:
|
||||
description: Raw A record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["a_record"]
|
||||
aaaa_rec:
|
||||
description: Raw AAAA record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["aaaa_record"]
|
||||
a6_rec:
|
||||
description: Raw A6 record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["a6_record"]
|
||||
afsdb_rec:
|
||||
description: Raw AFSDB record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["afsdb_record"]
|
||||
cert_rec:
|
||||
description: Raw CERT record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["cert_record"]
|
||||
cname_rec:
|
||||
description: Raw CNAME record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["cname_record"]
|
||||
dlv_rec:
|
||||
description: Raw DLV record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["dlv_record"]
|
||||
dname_rec:
|
||||
description: Raw DNAM record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["dname_record"]
|
||||
ds_rec:
|
||||
description: Raw DS record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["ds_record"]
|
||||
kx_rec:
|
||||
description: Raw KX record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["kx_record"]
|
||||
loc_rec:
|
||||
description: Raw LOC record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["loc_record"]
|
||||
mx_rec:
|
||||
description: Raw MX record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["mx_record"]
|
||||
naptr_rec:
|
||||
description: Raw NAPTR record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["naptr_record"]
|
||||
ns_rec:
|
||||
description: Raw NS record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["ns_record"]
|
||||
ptr_rec:
|
||||
description: Raw PTR record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["ptr_record"]
|
||||
srv_rec:
|
||||
description: Raw SRV record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["srv_record"]
|
||||
sshfp_rec:
|
||||
description: Raw SSHFP record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["sshfp_record"]
|
||||
tlsa_rec:
|
||||
description: Raw TLSA record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["tlsa_record"]
|
||||
txt_rec:
|
||||
description: Raw TXT record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["txt_record"]
|
||||
uri_rec:
|
||||
description: Raw URI record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["uri_record"]
|
||||
ip_address:
|
||||
description: IP adresses for A or AAAA records.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
a_ip_address:
|
||||
description: IP adresses for A records.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
a_create_reverse:
|
||||
description: |
|
||||
Create reverse record for A records.
|
||||
@@ -168,7 +215,7 @@ options:
|
||||
aaaa_ip_address:
|
||||
description: IP adresses for AAAA records.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
aaaa_create_reverse:
|
||||
description: |
|
||||
Create reverse record for AAAA records.
|
||||
@@ -185,6 +232,7 @@ options:
|
||||
a6_data:
|
||||
description: A6 record data.
|
||||
required: false
|
||||
type: str
|
||||
afsdb_subtype:
|
||||
description: AFSDB Subtype
|
||||
required: false
|
||||
@@ -192,7 +240,7 @@ options:
|
||||
afsdb_hostname:
|
||||
description: AFSDB Hostname
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
cert_type:
|
||||
description: CERT Certificate Type
|
||||
required: false
|
||||
@@ -208,13 +256,13 @@ options:
|
||||
cert_certificate_or_crl:
|
||||
description: CERT Certificate or Certificate Revocation List (CRL).
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
cname_hostname:
|
||||
description: A hostname which this alias hostname points to.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
dlv_key_tag:
|
||||
description: DS Key Tag
|
||||
description: DLV Key Tag
|
||||
required: false
|
||||
type: int
|
||||
dlv_algorithm:
|
||||
@@ -228,11 +276,11 @@ options:
|
||||
dlv_digest:
|
||||
description: DLV Digest
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
dname_target:
|
||||
description: DNAME Target
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
ds_key_tag:
|
||||
description: DS Key Tag
|
||||
required: false
|
||||
@@ -248,7 +296,7 @@ options:
|
||||
ds_digest:
|
||||
description: DS Digest
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
kx_preference:
|
||||
description: |
|
||||
Preference given to this exchanger. Lower values are more preferred.
|
||||
@@ -257,7 +305,7 @@ options:
|
||||
kx_exchanger:
|
||||
description: A host willing to act as a key exchanger.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
loc_lat_deg:
|
||||
description: LOC Degrees Latitude
|
||||
required: false
|
||||
@@ -274,6 +322,7 @@ options:
|
||||
description: LOC Direction Latitude
|
||||
required: false
|
||||
choices: ["N", "S"]
|
||||
type: str
|
||||
loc_lon_deg:
|
||||
description: LOC Degrees Longitude
|
||||
required: false
|
||||
@@ -290,6 +339,7 @@ options:
|
||||
description: LOC Direction Longitude
|
||||
required: false
|
||||
choices: ["E", "W"]
|
||||
type: str
|
||||
loc_altitude:
|
||||
description: LOC Altitude
|
||||
required: false
|
||||
@@ -314,7 +364,7 @@ options:
|
||||
mx_exchanger:
|
||||
description: A host willing to act as a mail exchanger.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
naptr_order:
|
||||
description: NAPTR Order
|
||||
required: false
|
||||
@@ -326,27 +376,27 @@ options:
|
||||
naptr_flags:
|
||||
description: NAPTR Flags
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
naptr_service:
|
||||
description: NAPTR Service
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
naptr_regexp:
|
||||
description: NAPTR Regular Expression
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
naptr_replacement:
|
||||
description: NAPTR Replacement
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
ns_hostname:
|
||||
description: NS Hostname
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
ptr_hostname:
|
||||
description: The hostname this reverse record points to.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
srv_priority:
|
||||
description: |
|
||||
Lower number means higher priority. Clients will attempt to contact
|
||||
@@ -366,7 +416,7 @@ options:
|
||||
The domain name of the target host or '.' if the service is decidedly
|
||||
not available at this domain.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
sshfp_algorithm:
|
||||
description: SSHFP Algorithm
|
||||
required: False
|
||||
@@ -378,11 +428,11 @@ options:
|
||||
sshfp_fingerprint:
|
||||
description: SSHFP Fingerprint
|
||||
required: False
|
||||
type: string
|
||||
type: str
|
||||
txt_data:
|
||||
description: TXT Text Data
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
tlsa_cert_usage:
|
||||
description: TLSA Certificate Usage
|
||||
required: false
|
||||
@@ -398,11 +448,11 @@ options:
|
||||
tlsa_cert_association_data:
|
||||
description: TLSA Certificate Association Data
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
uri_target:
|
||||
description: Target Uniform Resource Identifier according to RFC 3986.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
uri_priority:
|
||||
description: |
|
||||
Lower number means higher priority. Clients will attempt to contact
|
||||
@@ -413,27 +463,31 @@ options:
|
||||
description: Relative weight for entries with the same priority.
|
||||
required: false
|
||||
type: int
|
||||
name:
|
||||
description: The DNS record name to manage.
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["record_name"]
|
||||
required: false
|
||||
zone_name:
|
||||
description: |
|
||||
The DNS zone name to which DNS record needs to be managed.
|
||||
Required if not provided globally.
|
||||
type: str
|
||||
aliases: ["dnszone"]
|
||||
required: false
|
||||
name:
|
||||
description: The DNS record name to manage.
|
||||
aliases: ["record_name"]
|
||||
required: true
|
||||
record_type:
|
||||
description: The type of DNS record.
|
||||
required: false
|
||||
type: str
|
||||
choices: ["A", "AAAA", "A6", "AFSDB", "CERT", "CNAME", "DLV", "DNAME",
|
||||
"DS", "KX", "LOC", "MX", "NAPTR", "NS", "PTR", "SRV", "SSHFP",
|
||||
"TLSA", "TXT", "URI"]
|
||||
"DS", "KX", "LOC", "MX", "NAPTR", "NS", "PTR", "SRV",
|
||||
"SSHFP", "TLSA", "TXT", "URI"]
|
||||
default: "A"
|
||||
record_value:
|
||||
description: Manage DNS record name with this values.
|
||||
description: Manage DNS record name with these values.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
record_ttl:
|
||||
description: Set the TTL for the record.
|
||||
required: false
|
||||
@@ -444,99 +498,132 @@ options:
|
||||
type: bool
|
||||
a_rec:
|
||||
description: Raw A record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["a_record"]
|
||||
aaaa_rec:
|
||||
description: Raw AAAA record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["aaaa_record"]
|
||||
a6_rec:
|
||||
description: Raw A6 record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["a6_record"]
|
||||
afsdb_rec:
|
||||
description: Raw AFSDB record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["afsdb_record"]
|
||||
cert_rec:
|
||||
description: Raw CERT record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["cert_record"]
|
||||
cname_rec:
|
||||
description: Raw CNAME record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["cname_record"]
|
||||
dlv_rec:
|
||||
description: Raw DLV record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["dlv_record"]
|
||||
dname_rec:
|
||||
description: Raw DNAM record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["dname_record"]
|
||||
ds_rec:
|
||||
description: Raw DS record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["ds_record"]
|
||||
kx_rec:
|
||||
description: Raw KX record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["kx_record"]
|
||||
loc_rec:
|
||||
description: Raw LOC record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["loc_record"]
|
||||
mx_rec:
|
||||
description: Raw MX record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["mx_record"]
|
||||
naptr_rec:
|
||||
description: Raw NAPTR record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["naptr_record"]
|
||||
ns_rec:
|
||||
description: Raw NS record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["ns_record"]
|
||||
ptr_rec:
|
||||
description: Raw PTR record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["ptr_record"]
|
||||
srv_rec:
|
||||
description: Raw SRV record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["srv_record"]
|
||||
sshfp_rec:
|
||||
description: Raw SSHFP record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["sshfp_record"]
|
||||
tlsa_rec:
|
||||
description: Raw TLSA record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["tlsa_record"]
|
||||
txt_rec:
|
||||
description: Raw TXT record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["txt_record"]
|
||||
uri_rec:
|
||||
description: Raw URI record.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["uri_record"]
|
||||
ip_address:
|
||||
description: IP adresses for A ar AAAA.
|
||||
description: IP adresses for A or AAAA records.
|
||||
required: false
|
||||
type: string
|
||||
create_reverse:
|
||||
description: |
|
||||
Create reverse record for A or AAAA record types.
|
||||
There is no equivalent to remove reverse records.
|
||||
type: bool
|
||||
required: false
|
||||
aliases: ["reverse"]
|
||||
type: str
|
||||
a_ip_address:
|
||||
description: IP adresses for A records.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
a_create_reverse:
|
||||
description: |
|
||||
Create reverse record for A records.
|
||||
@@ -546,13 +633,24 @@ options:
|
||||
aaaa_ip_address:
|
||||
description: IP adresses for AAAA records.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
aaaa_create_reverse:
|
||||
description: |
|
||||
Create reverse record for AAAA records.
|
||||
There is no equivalent to remove reverse records.
|
||||
type: bool
|
||||
required: false
|
||||
create_reverse:
|
||||
description: |
|
||||
Create reverse record for A or AAAA record types.
|
||||
There is no equivalent to remove reverse records.
|
||||
type: bool
|
||||
required: false
|
||||
aliases: ["reverse"]
|
||||
a6_data:
|
||||
description: A6 record data.
|
||||
required: false
|
||||
type: str
|
||||
afsdb_subtype:
|
||||
description: AFSDB Subtype
|
||||
required: false
|
||||
@@ -560,7 +658,7 @@ options:
|
||||
afsdb_hostname:
|
||||
description: AFSDB Hostname
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
cert_type:
|
||||
description: CERT Certificate Type
|
||||
required: false
|
||||
@@ -574,13 +672,13 @@ options:
|
||||
required: false
|
||||
type: int
|
||||
cert_certificate_or_crl:
|
||||
description: CERT Certificate/CRL
|
||||
description: CERT Certificate or Certificate Revocation List (CRL).
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
cname_hostname:
|
||||
description: A hostname which this alias hostname points to.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
dlv_key_tag:
|
||||
description: DS Key Tag
|
||||
required: false
|
||||
@@ -596,11 +694,11 @@ options:
|
||||
dlv_digest:
|
||||
description: DLV Digest
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
dname_target:
|
||||
description: DNAME Target
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
ds_key_tag:
|
||||
description: DS Key Tag
|
||||
required: false
|
||||
@@ -616,7 +714,7 @@ options:
|
||||
ds_digest:
|
||||
description: DS Digest
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
kx_preference:
|
||||
description: |
|
||||
Preference given to this exchanger. Lower values are more preferred.
|
||||
@@ -625,7 +723,7 @@ options:
|
||||
kx_exchanger:
|
||||
description: A host willing to act as a key exchanger.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
loc_lat_deg:
|
||||
description: LOC Degrees Latitude
|
||||
required: false
|
||||
@@ -642,6 +740,7 @@ options:
|
||||
description: LOC Direction Latitude
|
||||
required: false
|
||||
choices: ["N", "S"]
|
||||
type: str
|
||||
loc_lon_deg:
|
||||
description: LOC Degrees Longitude
|
||||
required: false
|
||||
@@ -658,6 +757,7 @@ options:
|
||||
description: LOC Direction Longitude
|
||||
required: false
|
||||
choices: ["E", "W"]
|
||||
type: str
|
||||
loc_altitude:
|
||||
description: LOC Altitude
|
||||
required: false
|
||||
@@ -682,7 +782,7 @@ options:
|
||||
mx_exchanger:
|
||||
description: A host willing to act as a mail exchanger.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
naptr_order:
|
||||
description: NAPTR Order
|
||||
required: false
|
||||
@@ -694,31 +794,31 @@ options:
|
||||
naptr_flags:
|
||||
description: NAPTR Flags
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
naptr_service:
|
||||
description: NAPTR Service
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
naptr_regexp:
|
||||
description: NAPTR Regular Expression
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
naptr_replacement:
|
||||
description: NAPTR Replacement
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
ns_hostname:
|
||||
description: NS Hostname
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
ptr_hostname:
|
||||
description: The hostname this reverse record points to.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
srv_priority:
|
||||
description: |
|
||||
Lower number means higher priority. Clients will attempt to contact the
|
||||
server with the lowest-numbered priority they can reach.
|
||||
Lower number means higher priority. Clients will attempt to contact
|
||||
the server with the lowest-numbered priority they can reach.
|
||||
required: false
|
||||
type: int
|
||||
srv_weight:
|
||||
@@ -731,26 +831,26 @@ options:
|
||||
type: int
|
||||
srv_target:
|
||||
description: |
|
||||
The domain name of the target host or '.' if the service is decidedly not
|
||||
available at this domain.
|
||||
The domain name of the target host or '.' if the service is decidedly
|
||||
not available at this domain.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
sshfp_algorithm:
|
||||
description: SSHFP Algorithm
|
||||
required: false
|
||||
required: False
|
||||
type: int
|
||||
sshfp_fp_type:
|
||||
description: SSHFP Fingerprint Type
|
||||
required: false
|
||||
required: False
|
||||
type: int
|
||||
sshfp_fingerprint:
|
||||
description: SSHFP Fingerprint
|
||||
required: false
|
||||
type: string
|
||||
required: False
|
||||
type: str
|
||||
txt_data:
|
||||
description: TXT Text Data
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
tlsa_cert_usage:
|
||||
description: TLSA Certificate Usage
|
||||
required: false
|
||||
@@ -766,15 +866,15 @@ options:
|
||||
tlsa_cert_association_data:
|
||||
description: TLSA Certificate Association Data
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
uri_target:
|
||||
description: Target Uniform Resource Identifier according to RFC 3986.
|
||||
required: false
|
||||
type: string
|
||||
type: str
|
||||
uri_priority:
|
||||
description: |
|
||||
Lower number means higher priority. Clients will attempt to contact the
|
||||
URI with the lowest-numbered priority they can reach.
|
||||
Lower number means higher priority. Clients will attempt to contact
|
||||
the URI with the lowest-numbered priority they can reach.
|
||||
required: false
|
||||
type: int
|
||||
uri_weight:
|
||||
@@ -783,11 +883,12 @@ options:
|
||||
type: int
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent"]
|
||||
|
||||
choices: ["present", "absent", "disabled"]
|
||||
author:
|
||||
- Rafael Guterres Jeffman
|
||||
- Rafael Guterres Jeffman (@rjeffman)
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -866,8 +967,13 @@ RETURN = """
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, is_ipv4_addr, is_ipv6_addr, ipalib_errors
|
||||
import dns.reversename
|
||||
import dns.resolver
|
||||
try:
|
||||
import dns.reversename
|
||||
import dns.resolver
|
||||
except ImportError as _err:
|
||||
MODULE_IMPORT_ERROR = str(_err)
|
||||
else:
|
||||
MODULE_IMPORT_ERROR = None
|
||||
|
||||
from ansible.module_utils import six
|
||||
|
||||
@@ -1015,29 +1121,49 @@ def configure_module():
|
||||
"DLV", "DNAME", "DS", "KX", "LOC", "MX",
|
||||
"NAPTR", "NS", "PTR", "SRV", "SSHFP", "TLSA",
|
||||
"TXT", "URI"]),
|
||||
record_value=dict(type='list', required=False),
|
||||
record_value=dict(type='list', elements='str', required=False),
|
||||
record_ttl=dict(type='int', required=False),
|
||||
del_all=dict(type='bool', required=False),
|
||||
a_rec=dict(type='list', required=False, aliases=['a_record']),
|
||||
aaaa_rec=dict(type='list', required=False, aliases=['aaaa_record']),
|
||||
a6_rec=dict(type='list', required=False, aliases=['a6_record']),
|
||||
afsdb_rec=dict(type='list', required=False, aliases=['afsdb_record']),
|
||||
cert_rec=dict(type='list', required=False, aliases=['cert_record']),
|
||||
cname_rec=dict(type='list', required=False, aliases=['cname_record']),
|
||||
dlv_rec=dict(type='list', required=False, aliases=['dlv_record']),
|
||||
dname_rec=dict(type='list', required=False, aliases=['dname_record']),
|
||||
ds_rec=dict(type='list', required=False, aliases=['ds_record']),
|
||||
kx_rec=dict(type='list', required=False, aliases=['kx_record']),
|
||||
loc_rec=dict(type='list', required=False, aliases=['loc_record']),
|
||||
mx_rec=dict(type='list', required=False, aliases=['mx_record']),
|
||||
naptr_rec=dict(type='list', required=False, aliases=['naptr_record']),
|
||||
ns_rec=dict(type='list', required=False, aliases=['ns_record']),
|
||||
ptr_rec=dict(type='list', required=False, aliases=['ptr_record']),
|
||||
srv_rec=dict(type='list', required=False, aliases=['srv_record']),
|
||||
sshfp_rec=dict(type='list', required=False, aliases=['sshfp_record']),
|
||||
tlsa_rec=dict(type='list', required=False, aliases=['tlsa_record']),
|
||||
txt_rec=dict(type='list', required=False, aliases=['txt_record']),
|
||||
uri_rec=dict(type='list', required=False, aliases=['uri_record']),
|
||||
a_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['a_record']),
|
||||
aaaa_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['aaaa_record']),
|
||||
a6_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['a6_record']),
|
||||
afsdb_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['afsdb_record']),
|
||||
cert_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['cert_record']),
|
||||
cname_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['cname_record']),
|
||||
dlv_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['dlv_record']),
|
||||
dname_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['dname_record']),
|
||||
ds_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['ds_record']),
|
||||
kx_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['kx_record']),
|
||||
loc_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['loc_record']),
|
||||
mx_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['mx_record']),
|
||||
naptr_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['naptr_record']),
|
||||
ns_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['ns_record']),
|
||||
ptr_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['ptr_record']),
|
||||
srv_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['srv_record']),
|
||||
sshfp_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['sshfp_record']),
|
||||
tlsa_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['tlsa_record']),
|
||||
txt_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['txt_record']),
|
||||
uri_rec=dict(type='list', elements='str', required=False,
|
||||
aliases=['uri_record']),
|
||||
ip_address=dict(type='str', required=False),
|
||||
create_reverse=dict(type='bool', required=False, aliases=['reverse']),
|
||||
a_ip_address=dict(type='str', required=False),
|
||||
@@ -1048,16 +1174,16 @@ def configure_module():
|
||||
afsdb_subtype=dict(type='int', required=False),
|
||||
afsdb_hostname=dict(type='str', required=False),
|
||||
cert_type=dict(type='int', required=False),
|
||||
cert_key_tag=dict(type='int', required=False),
|
||||
cert_key_tag=dict(type='int', required=False, no_log=True),
|
||||
cert_algorithm=dict(type='int', required=False),
|
||||
cert_certificate_or_crl=dict(type='str', required=False),
|
||||
cname_hostname=dict(type='str', required=False),
|
||||
dlv_key_tag=dict(type='int', required=False),
|
||||
dlv_key_tag=dict(type='int', required=False, no_log=True),
|
||||
dlv_algorithm=dict(type='int', required=False),
|
||||
dlv_digest_type=dict(type='int', required=False),
|
||||
dlv_digest=dict(type='str', required=False),
|
||||
dname_target=dict(type='str', required=False),
|
||||
ds_key_tag=dict(type='int', required=False),
|
||||
ds_key_tag=dict(type='int', required=False, no_log=True),
|
||||
ds_algorithm=dict(type='int', required=False),
|
||||
ds_digest_type=dict(type='int', required=False),
|
||||
ds_digest=dict(type='str', required=False),
|
||||
@@ -1066,11 +1192,11 @@ def configure_module():
|
||||
loc_lat_deg=dict(type='int', required=False),
|
||||
loc_lat_min=dict(type='int', required=False),
|
||||
loc_lat_sec=dict(type='float', required=False),
|
||||
loc_lat_dir=dict(type='str', required=False),
|
||||
loc_lat_dir=dict(type='str', required=False, choices=["N", "S"]),
|
||||
loc_lon_deg=dict(type='int', required=False),
|
||||
loc_lon_min=dict(type='int', required=False),
|
||||
loc_lon_sec=dict(type='float', required=False),
|
||||
loc_lon_dir=dict(type='str', required=False),
|
||||
loc_lon_dir=dict(type='str', required=False, choices=["E", "W"]),
|
||||
loc_altitude=dict(type='float', required=False),
|
||||
loc_size=dict(type='float', required=False),
|
||||
loc_h_precision=dict(type='float', required=False),
|
||||
@@ -1105,10 +1231,14 @@ def configure_module():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["record_name"], default=None,
|
||||
required=False),
|
||||
name=dict(type="list", elements="str", aliases=["record_name"],
|
||||
default=None, required=False),
|
||||
|
||||
# Use elements="str" and not elements="dict" for records:
|
||||
# elements="dict" will create dicts with all unused parameters
|
||||
# set to None. This breaks the module logic.
|
||||
records=dict(type="list",
|
||||
elements="dict",
|
||||
default=None,
|
||||
options=dict(
|
||||
# Here name is a simple string
|
||||
@@ -1131,6 +1261,9 @@ def configure_module():
|
||||
|
||||
ansible_module._ansible_debug = True
|
||||
|
||||
if MODULE_IMPORT_ERROR is not None:
|
||||
ansible_module.fail_json(msg=MODULE_IMPORT_ERROR)
|
||||
|
||||
return ansible_module
|
||||
|
||||
|
||||
@@ -1261,15 +1394,16 @@ def gen_args(entry):
|
||||
|
||||
if record_value is not None:
|
||||
record_type = entry['record_type']
|
||||
rec = "{}record".format(record_type.lower())
|
||||
rec = "{0}record".format(record_type.lower())
|
||||
args[rec] = ensure_data_is_list(record_value)
|
||||
|
||||
else:
|
||||
for field in _RECORD_FIELDS:
|
||||
record_value = entry.get(field) or entry.get("%sord" % field)
|
||||
if record_value is not None:
|
||||
# pylint: disable=use-maxsplit-arg
|
||||
record_type = field.split('_')[0]
|
||||
rec = "{}record".format(record_type.lower())
|
||||
rec = "{0}record".format(record_type.lower())
|
||||
args[rec] = ensure_data_is_list(record_value)
|
||||
|
||||
records = {
|
||||
@@ -1436,6 +1570,14 @@ def main():
|
||||
msg="Only one record can be added at a time.")
|
||||
|
||||
if records is not None:
|
||||
# Remove all keys that have a None value from the dicts in records
|
||||
# list.
|
||||
# This is needed after setting elements="dict" for records and makes
|
||||
# it behave like before with elements=None.
|
||||
for record in records:
|
||||
for key in list(record):
|
||||
if record[key] is None:
|
||||
del record[key]
|
||||
names = records
|
||||
|
||||
# Init
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
# Authors:
|
||||
# Sergio Oliveira Campos <seocam@redhat.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2020 Red Hat
|
||||
# Copyright (C) 2020-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,16 +33,17 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The zone name string.
|
||||
required: true
|
||||
required: false
|
||||
type: list
|
||||
alises: ["zone_name"]
|
||||
elements: str
|
||||
aliases: ["zone_name"]
|
||||
name_from_ip:
|
||||
description: |
|
||||
Derive zone name from reverse of IP (PTR).
|
||||
@@ -51,17 +53,22 @@ options:
|
||||
forwarders:
|
||||
description: The list of global DNS forwarders.
|
||||
required: false
|
||||
options:
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
ip_address:
|
||||
description: The forwarder nameserver IP address list (IPv4 and IPv6).
|
||||
type: str
|
||||
required: true
|
||||
port:
|
||||
description: The port to forward requests to.
|
||||
type: int
|
||||
required: false
|
||||
forward_policy:
|
||||
description:
|
||||
Global forwarding policy. Set to "none" to disable any configured
|
||||
global forwarders.
|
||||
type: str
|
||||
required: false
|
||||
choices: ['only', 'first', 'none']
|
||||
allow_sync_ptr:
|
||||
@@ -71,6 +78,7 @@ options:
|
||||
type: bool
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent", "enabled", "disabled"]
|
||||
name_server:
|
||||
@@ -89,7 +97,7 @@ options:
|
||||
description: Allow dynamic updates
|
||||
required: false
|
||||
type: bool
|
||||
alises: ["dynamicupdate"]
|
||||
aliases: ["dynamicupdate"]
|
||||
dnssec:
|
||||
description: Allow inline DNSSEC signing of records in the zone
|
||||
required: false
|
||||
@@ -97,11 +105,13 @@ options:
|
||||
allow_transfer:
|
||||
description: List of IP addresses or networks which are allowed to transfer the zone
|
||||
required: false
|
||||
type: bool
|
||||
type: list
|
||||
elements: str
|
||||
allow_query:
|
||||
description: List of IP addresses or networks which are allowed to issue queries
|
||||
required: false
|
||||
type: bool
|
||||
type: list
|
||||
elements: str
|
||||
refresh:
|
||||
description: SOA record refresh time
|
||||
required: false
|
||||
@@ -141,6 +151,9 @@ options:
|
||||
description: Force DNS zone creation even if nameserver is not resolvable
|
||||
required: false
|
||||
type: bool
|
||||
author:
|
||||
- Sergio Oliveira Campos (@seocam)
|
||||
- Thomas Woerner (@t-woerner)
|
||||
""" # noqa: E501
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -195,13 +208,14 @@ dnszone:
|
||||
description: DNS Zone dict with zone name infered from `name_from_ip`.
|
||||
returned:
|
||||
If `state` is `present`, `name_from_ip` is used, and a zone was created.
|
||||
options:
|
||||
type: dict
|
||||
contains:
|
||||
name:
|
||||
description: The name of the zone created, inferred from `name_from_ip`.
|
||||
type: str
|
||||
returned: always
|
||||
"""
|
||||
|
||||
from ipapython.dnsutil import DNSName # noqa: E402
|
||||
from ansible.module_utils.ansible_freeipa_module import (
|
||||
IPAAnsibleModule,
|
||||
is_ip_address,
|
||||
@@ -210,8 +224,9 @@ from ansible.module_utils.ansible_freeipa_module import (
|
||||
ipalib_errors,
|
||||
compare_args_ipa,
|
||||
IPAParamMapping,
|
||||
DNSName,
|
||||
netaddr
|
||||
) # noqa: E402
|
||||
import netaddr
|
||||
from ansible.module_utils import six
|
||||
|
||||
|
||||
@@ -265,7 +280,8 @@ class DNSZoneModule(IPAAnsibleModule):
|
||||
if any(invalid_ips):
|
||||
self.fail_json(msg=error_msg % invalid_ips)
|
||||
|
||||
def is_valid_nsec3param_rec(self, nsec3param_rec): # pylint: disable=R0201
|
||||
@staticmethod
|
||||
def is_valid_nsec3param_rec(nsec3param_rec):
|
||||
try:
|
||||
part1, part2, part3, part4 = nsec3param_rec.split(" ")
|
||||
except ValueError:
|
||||
@@ -487,8 +503,8 @@ class DNSZoneModule(IPAAnsibleModule):
|
||||
|
||||
def get_argument_spec():
|
||||
forwarder_spec = dict(
|
||||
ip_address=dict(type=str, required=True),
|
||||
port=dict(type=int, required=False, default=None),
|
||||
ip_address=dict(type="str", required=True),
|
||||
port=dict(type="int", required=False, default=None),
|
||||
)
|
||||
|
||||
return dict(
|
||||
@@ -500,11 +516,13 @@ def get_argument_spec():
|
||||
ipaadmin_principal=dict(type="str", default="admin"),
|
||||
ipaadmin_password=dict(type="str", required=False, no_log=True),
|
||||
name=dict(
|
||||
type="list", default=None, required=False, aliases=["zone_name"]
|
||||
type="list", elements="str", default=None, required=False,
|
||||
aliases=["zone_name"]
|
||||
),
|
||||
name_from_ip=dict(type="str", default=None, required=False),
|
||||
forwarders=dict(
|
||||
type="list",
|
||||
elements="dict",
|
||||
default=None,
|
||||
required=False,
|
||||
options=dict(**forwarder_spec),
|
||||
@@ -526,8 +544,10 @@ def get_argument_spec():
|
||||
aliases=["dynamicupdate"],
|
||||
),
|
||||
dnssec=dict(type="bool", required=False, default=None),
|
||||
allow_transfer=dict(type="list", required=False, default=None),
|
||||
allow_query=dict(type="list", required=False, default=None),
|
||||
allow_transfer=dict(type="list", elements="str", required=False,
|
||||
default=None),
|
||||
allow_query=dict(type="list", elements="str", required=False,
|
||||
default=None),
|
||||
refresh=dict(type="int", required=False, default=None),
|
||||
retry=dict(type="int", required=False, default=None),
|
||||
expire=dict(type="int", required=False, default=None),
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2019 Red Hat
|
||||
# Copyright (C) 2019-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,20 +32,104 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The group name
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["cn"]
|
||||
groups:
|
||||
description: The list of group dicts (internally gid).
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
name:
|
||||
description: The group (internally gid).
|
||||
type: str
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
description:
|
||||
description: The group description
|
||||
type: str
|
||||
required: false
|
||||
gid:
|
||||
description: The GID
|
||||
type: int
|
||||
required: false
|
||||
aliases: ["gidnumber"]
|
||||
nonposix:
|
||||
description: Create as a non-POSIX group
|
||||
required: false
|
||||
type: bool
|
||||
external:
|
||||
description: Allow adding external non-IPA members from trusted domains
|
||||
required: false
|
||||
type: bool
|
||||
posix:
|
||||
description:
|
||||
Create a non-POSIX group or change a non-POSIX to a posix group.
|
||||
required: false
|
||||
type: bool
|
||||
nomembers:
|
||||
description: Suppress processing of membership attributes
|
||||
required: false
|
||||
type: bool
|
||||
user:
|
||||
description: List of user names assigned to this group.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
group:
|
||||
description: List of group names assigned to this group.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
service:
|
||||
description:
|
||||
- List of service names assigned to this group.
|
||||
- Only usable with IPA versions 4.7 and up.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
membermanager_user:
|
||||
description:
|
||||
- List of member manager users assigned to this group.
|
||||
- Only usable with IPA versions 4.8.4 and up.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
membermanager_group:
|
||||
description:
|
||||
- List of member manager groups assigned to this group.
|
||||
- Only usable with IPA versions 4.8.4 and up.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
externalmember:
|
||||
description:
|
||||
- List of members of a trusted domain in DOM\\name or name@domain form.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaexternalmember", "external_member"]
|
||||
idoverrideuser:
|
||||
description:
|
||||
- User ID overrides to add
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
description:
|
||||
description: The group description
|
||||
type: str
|
||||
required: false
|
||||
gid:
|
||||
description: The GID
|
||||
type: int
|
||||
required: false
|
||||
aliases: ["gidnumber"]
|
||||
nonposix:
|
||||
@@ -69,49 +153,58 @@ options:
|
||||
description: List of user names assigned to this group.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
group:
|
||||
description: List of group names assigned to this group.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
service:
|
||||
description:
|
||||
- List of service names assigned to this group.
|
||||
- Only usable with IPA versions 4.7 and up.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
membermanager_user:
|
||||
description:
|
||||
- List of member manager users assigned to this group.
|
||||
- Only usable with IPA versions 4.8.4 and up.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
membermanager_group:
|
||||
description:
|
||||
- List of member manager groups assigned to this group.
|
||||
- Only usable with IPA versions 4.8.4 and up.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
externalmember:
|
||||
description:
|
||||
- List of members of a trusted domain in DOM\\name or name@domain form.
|
||||
required: false
|
||||
type: list
|
||||
ailases: ["ipaexternalmember", "external_member"]
|
||||
elements: str
|
||||
aliases: ["ipaexternalmember", "external_member"]
|
||||
idoverrideuser:
|
||||
description:
|
||||
- User ID overrides to add
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
action:
|
||||
description: Work on group or member level
|
||||
type: str
|
||||
default: group
|
||||
choices: ["member", "group"]
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent"]
|
||||
author:
|
||||
- Thomas Woerner
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -131,6 +224,14 @@ EXAMPLES = """
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: appops
|
||||
|
||||
# Create multiple groups ops, sysops
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: ops
|
||||
gidnumber: 1234
|
||||
- name: sysops
|
||||
|
||||
# Add user member pinky to group sysops
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -147,7 +248,7 @@ EXAMPLES = """
|
||||
user:
|
||||
- brain
|
||||
|
||||
# Add group members sysops and appops to group sysops
|
||||
# Add group members sysops and appops to group ops
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: ops
|
||||
@@ -155,6 +256,17 @@ EXAMPLES = """
|
||||
- sysops
|
||||
- appops
|
||||
|
||||
# Add user and group members to groups sysops and appops
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: sysops
|
||||
user:
|
||||
- user1
|
||||
- name: appops
|
||||
group:
|
||||
- group2
|
||||
|
||||
# Create a non-POSIX group
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -176,7 +288,16 @@ EXAMPLES = """
|
||||
- WINIPA\\Web Users
|
||||
- WINIPA\\Developers
|
||||
|
||||
# Remove goups sysops, appops, ops and nongroup
|
||||
# Create multiple non-POSIX and external groups
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
groups:
|
||||
- name: nongroup
|
||||
nonposix: true
|
||||
- name: extgroup
|
||||
external: true
|
||||
|
||||
# Remove groups sysops, appops, ops and nongroup
|
||||
- ipagroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: sysops,appops,ops, nongroup
|
||||
@@ -190,6 +311,20 @@ 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, api_check_param
|
||||
from ansible.module_utils import six
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
# Ensuring (adding) several groups with mixed types external, nonposix
|
||||
# and posix require to have a fix in IPA:
|
||||
# FreeIPA issue: https://pagure.io/freeipa/issue/9349
|
||||
# FreeIPA fix: https://github.com/freeipa/freeipa/pull/6741
|
||||
try:
|
||||
from ipaserver.plugins import baseldap
|
||||
except ImportError:
|
||||
FIX_6741_DEEPCOPY_OBJECTCLASSES = False
|
||||
else:
|
||||
FIX_6741_DEEPCOPY_OBJECTCLASSES = \
|
||||
"deepcopy" in baseldap.LDAPObject.__json__.__code__.co_names
|
||||
|
||||
|
||||
def find_group(module, name):
|
||||
@@ -244,6 +379,22 @@ def gen_member_args(user, group, service, externalmember, idoverrideuser):
|
||||
return _args
|
||||
|
||||
|
||||
def check_parameters(module, state, action):
|
||||
invalid = []
|
||||
if state == "present":
|
||||
if action == "member":
|
||||
invalid = ["description", "gid", "posix", "nonposix", "external",
|
||||
"nomembers"]
|
||||
|
||||
else:
|
||||
invalid = ["description", "gid", "posix", "nonposix", "external",
|
||||
"nomembers"]
|
||||
if action == "group":
|
||||
invalid.extend(["user", "group", "service", "externalmember"])
|
||||
|
||||
module.params_fail_used_invalid(invalid, state, action)
|
||||
|
||||
|
||||
def is_external_group(res_find):
|
||||
"""Verify if the result group is an external group."""
|
||||
return res_find and 'ipaexternalgroup' in res_find['objectclass']
|
||||
@@ -272,39 +423,63 @@ def check_objectclass_args(module, res_find, posix, external):
|
||||
|
||||
|
||||
def main():
|
||||
group_spec = dict(
|
||||
# present
|
||||
description=dict(type="str", default=None),
|
||||
gid=dict(type="int", aliases=["gidnumber"], default=None),
|
||||
nonposix=dict(required=False, type='bool', default=None),
|
||||
external=dict(required=False, type='bool', default=None),
|
||||
posix=dict(required=False, type='bool', default=None),
|
||||
nomembers=dict(required=False, type='bool', default=None),
|
||||
user=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
group=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
service=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
idoverrideuser=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
membermanager_user=dict(required=False, type='list',
|
||||
elements="str", default=None),
|
||||
membermanager_group=dict(required=False, type='list',
|
||||
elements="str", default=None),
|
||||
externalmember=dict(required=False, type='list', elements="str",
|
||||
default=None,
|
||||
aliases=[
|
||||
"ipaexternalmember",
|
||||
"external_member"
|
||||
])
|
||||
)
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"], default=None,
|
||||
required=True),
|
||||
# present
|
||||
description=dict(type="str", default=None),
|
||||
gid=dict(type="int", aliases=["gidnumber"], default=None),
|
||||
nonposix=dict(required=False, type='bool', default=None),
|
||||
external=dict(required=False, type='bool', default=None),
|
||||
posix=dict(required=False, type='bool', default=None),
|
||||
nomembers=dict(required=False, type='bool', default=None),
|
||||
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),
|
||||
externalmember=dict(required=False, type='list', default=None,
|
||||
aliases=[
|
||||
"ipaexternalmember",
|
||||
"external_member"
|
||||
]),
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
default=None, required=False),
|
||||
groups=dict(type="list",
|
||||
default=None,
|
||||
options=dict(
|
||||
# Here name is a simple string
|
||||
name=dict(type="str", required=True,
|
||||
aliases=["cn"]),
|
||||
# Add group specific parameters
|
||||
**group_spec
|
||||
),
|
||||
elements='dict',
|
||||
required=False),
|
||||
# general
|
||||
action=dict(type="str", default="group",
|
||||
choices=["member", "group"]),
|
||||
# state
|
||||
state=dict(type="str", default="present",
|
||||
choices=["present", "absent"]),
|
||||
|
||||
# Add group specific parameters for simple use case
|
||||
**group_spec
|
||||
),
|
||||
# It does not make sense to set posix, nonposix or external at the
|
||||
# same time
|
||||
mutually_exclusive=[['posix', 'nonposix', 'external']],
|
||||
mutually_exclusive=[['posix', 'nonposix', 'external'],
|
||||
["name", "groups"]],
|
||||
required_one_of=[["name", "groups"]],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
@@ -314,6 +489,7 @@ def main():
|
||||
|
||||
# general
|
||||
names = ansible_module.params_get("name")
|
||||
groups = ansible_module.params_get("groups")
|
||||
|
||||
# present
|
||||
description = ansible_module.params_get("description")
|
||||
@@ -335,31 +511,50 @@ def main():
|
||||
state = ansible_module.params_get("state")
|
||||
|
||||
# Check parameters
|
||||
invalid = []
|
||||
|
||||
if (names is None or len(names) < 1) and \
|
||||
(groups is None or len(groups) < 1):
|
||||
ansible_module.fail_json(msg="At least one name or groups is required")
|
||||
|
||||
if state == "present":
|
||||
if len(names) != 1:
|
||||
if names is not None and len(names) != 1:
|
||||
ansible_module.fail_json(
|
||||
msg="Only one group can be added at a time.")
|
||||
if action == "member":
|
||||
invalid = ["description", "gid", "posix", "nonposix", "external",
|
||||
"nomembers"]
|
||||
msg="Only one group can be added at a time using 'name'.")
|
||||
|
||||
if state == "absent":
|
||||
if len(names) < 1:
|
||||
ansible_module.fail_json(
|
||||
msg="No name given.")
|
||||
invalid = ["description", "gid", "posix", "nonposix", "external",
|
||||
"nomembers"]
|
||||
if action == "group":
|
||||
invalid.extend(["user", "group", "service", "externalmember"])
|
||||
|
||||
ansible_module.params_fail_used_invalid(invalid, state, action)
|
||||
check_parameters(ansible_module, state, action)
|
||||
|
||||
if external is False:
|
||||
ansible_module.fail_json(
|
||||
msg="group can not be non-external")
|
||||
|
||||
# Ensuring (adding) several groups with mixed types external, nonposix
|
||||
# and posix require to have a fix in IPA:
|
||||
#
|
||||
# FreeIPA issue: https://pagure.io/freeipa/issue/9349
|
||||
# FreeIPA fix: https://github.com/freeipa/freeipa/pull/6741
|
||||
#
|
||||
# The simple solution is to switch to client context for ensuring
|
||||
# several groups simply if the user was not explicitly asking for
|
||||
# the server context no matter if mixed types are used.
|
||||
context = None
|
||||
if state == "present" and groups is not None and len(groups) > 1 \
|
||||
and not FIX_6741_DEEPCOPY_OBJECTCLASSES:
|
||||
_context = ansible_module.params_get("ipaapi_context")
|
||||
if _context is None:
|
||||
context = "client"
|
||||
ansible_module.debug(
|
||||
"Switching to client context due to an unfixed issue in "
|
||||
"your IPA version: https://pagure.io/freeipa/issue/9349")
|
||||
elif _context == "server":
|
||||
ansible_module.fail_json(
|
||||
msg="Ensuring several groups with server context is not "
|
||||
"supported by your IPA version: "
|
||||
"https://pagure.io/freeipa/issue/9349")
|
||||
|
||||
# Use groups if names is None
|
||||
if groups is not None:
|
||||
names = groups
|
||||
|
||||
# Init
|
||||
|
||||
changed = False
|
||||
@@ -370,7 +565,7 @@ def main():
|
||||
posix = not nonposix
|
||||
|
||||
# Connect to IPA API
|
||||
with ansible_module.ipa_connect():
|
||||
with ansible_module.ipa_connect(context=context):
|
||||
|
||||
has_add_member_service = ansible_module.ipa_command_param_exists(
|
||||
"group_add_member", "service")
|
||||
@@ -396,8 +591,57 @@ def main():
|
||||
"supported by your IPA version")
|
||||
|
||||
commands = []
|
||||
group_set = set()
|
||||
|
||||
for group_name in names:
|
||||
if isinstance(group_name, dict):
|
||||
name = group_name.get("name")
|
||||
if name in group_set:
|
||||
ansible_module.fail_json(
|
||||
msg="group '%s' is used more than once" % name)
|
||||
group_set.add(name)
|
||||
# present
|
||||
description = group_name.get("description")
|
||||
gid = group_name.get("gid")
|
||||
nonposix = group_name.get("nonposix")
|
||||
external = group_name.get("external")
|
||||
idoverrideuser = group_name.get("idoverrideuser")
|
||||
posix = group_name.get("posix")
|
||||
# Check mutually exclusive condition for multiple groups
|
||||
# creation. It's not possible to check it with
|
||||
# `mutually_exclusive` argument in `IPAAnsibleModule` class
|
||||
# because it accepts only (list[str] or list[list[str]]). Here
|
||||
# we need to loop over all groups and fail on mutually
|
||||
# exclusive ones.
|
||||
if all((posix, nonposix)) or\
|
||||
all((posix, external)) or\
|
||||
all((nonposix, external)):
|
||||
ansible_module.fail_json(
|
||||
msg="parameters are mutually exclusive for group "
|
||||
"`{0}`: posix|nonposix|external".format(name))
|
||||
# Duplicating the condition for multiple group creation
|
||||
if external is False:
|
||||
ansible_module.fail_json(
|
||||
msg="group can not be non-external")
|
||||
# If nonposix is used, set posix as not nonposix
|
||||
if nonposix is not None:
|
||||
posix = not nonposix
|
||||
user = group_name.get("user")
|
||||
group = group_name.get("group")
|
||||
service = group_name.get("service")
|
||||
membermanager_user = group_name.get("membermanager_user")
|
||||
membermanager_group = group_name.get("membermanager_group")
|
||||
externalmember = group_name.get("externalmember")
|
||||
nomembers = group_name.get("nomembers")
|
||||
|
||||
check_parameters(ansible_module, state, action)
|
||||
|
||||
elif isinstance(group_name, (str, unicode)):
|
||||
name = group_name
|
||||
else:
|
||||
ansible_module.fail_json(msg="Group '%s' is not valid" %
|
||||
repr(group_name))
|
||||
|
||||
for name in names:
|
||||
# Make sure group exists
|
||||
res_find = find_group(ansible_module, name)
|
||||
|
||||
@@ -574,10 +818,12 @@ def main():
|
||||
del_member_args["service"] = service_del
|
||||
|
||||
if is_external_group(res_find):
|
||||
add_member_args["ipaexternalmember"] = \
|
||||
externalmember_add
|
||||
del_member_args["ipaexternalmember"] = \
|
||||
externalmember_del
|
||||
if len(externalmember_add) > 0:
|
||||
add_member_args["ipaexternalmember"] = \
|
||||
externalmember_add
|
||||
if len(externalmember_del) > 0:
|
||||
del_member_args["ipaexternalmember"] = \
|
||||
externalmember_del
|
||||
elif externalmember or external:
|
||||
ansible_module.fail_json(
|
||||
msg="Cannot add external members to a "
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2019 Red Hat
|
||||
# Copyright (C) 2019-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,30 +32,36 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The hbacrule name
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
description:
|
||||
description: The hbacrule description
|
||||
type: str
|
||||
required: false
|
||||
usercategory:
|
||||
description: User category the rule applies to
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["usercat"]
|
||||
choices: ["all", ""]
|
||||
hostcategory:
|
||||
description: Host category the rule applies to
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["hostcat"]
|
||||
choices: ["all", ""]
|
||||
servicecategory:
|
||||
description: Service category the rule applies to
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["servicecat"]
|
||||
choices: ["all", ""]
|
||||
@@ -67,36 +73,44 @@ options:
|
||||
description: List of host names assigned to this hbacrule.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
hostgroup:
|
||||
description: List of host groups assigned to this hbacrule.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
hbacsvc:
|
||||
description: List of HBAC service names assigned to this hbacrule.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
hbacsvcgroup:
|
||||
description: List of HBAC service names assigned to this hbacrule.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
user:
|
||||
description: List of user names assigned to this hbacrule.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
group:
|
||||
description: List of user groups assigned to this hbacrule.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
action:
|
||||
description: Work on hbacrule or member level
|
||||
type: str
|
||||
default: hbacrule
|
||||
choices: ["member", "hbacrule"]
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent", "enabled", "disabled"]
|
||||
author:
|
||||
- Thomas Woerner
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -198,7 +212,7 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"], default=None,
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
required=True),
|
||||
# present
|
||||
description=dict(type="str", default=None),
|
||||
@@ -209,12 +223,18 @@ def main():
|
||||
servicecategory=dict(type="str", default=None,
|
||||
aliases=["servicecat"], choices=["all", ""]),
|
||||
nomembers=dict(required=False, type='bool', default=None),
|
||||
host=dict(required=False, type='list', default=None),
|
||||
hostgroup=dict(required=False, type='list', default=None),
|
||||
hbacsvc=dict(required=False, type='list', default=None),
|
||||
hbacsvcgroup=dict(required=False, type='list', default=None),
|
||||
user=dict(required=False, type='list', default=None),
|
||||
group=dict(required=False, type='list', default=None),
|
||||
host=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
hostgroup=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
hbacsvc=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
hbacsvcgroup=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
user=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
group=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
action=dict(type="str", default="hbacrule",
|
||||
choices=["member", "hbacrule"]),
|
||||
# state
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2019 Red Hat
|
||||
# Copyright (C) 2019-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,24 +32,28 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The group name
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["cn", "service"]
|
||||
description:
|
||||
description: The HBAC Service description
|
||||
type: str
|
||||
required: false
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent"]
|
||||
author:
|
||||
- Thomas Woerner
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -102,7 +106,7 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn", "service"], default=None,
|
||||
name=dict(type="list", elements="str", aliases=["cn", "service"],
|
||||
required=True),
|
||||
# present
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2019 Red Hat
|
||||
# Copyright (C) 2019-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -33,36 +33,42 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The hbacsvcgroup name
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
description:
|
||||
description: The hbacsvcgroup description
|
||||
type: str
|
||||
required: false
|
||||
hbacsvc:
|
||||
description: List of hbacsvc names assigned to this hbacsvcgroup.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
nomembers:
|
||||
description: Suppress processing of membership attributes
|
||||
required: false
|
||||
type: bool
|
||||
action:
|
||||
description: Work on hbacsvcgroup or member level
|
||||
type: str
|
||||
default: hbacsvcgroup
|
||||
choices: ["member", "hbacsvcgroup"]
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent"]
|
||||
author:
|
||||
- Thomas Woerner
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -159,12 +165,13 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"], default=None,
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
required=True),
|
||||
# present
|
||||
description=dict(type="str", default=None),
|
||||
nomembers=dict(required=False, type='bool', default=None),
|
||||
hbacsvc=dict(required=False, type='list', default=None),
|
||||
hbacsvc=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
action=dict(type="str", default="hbacsvcgroup",
|
||||
choices=["member", "hbacsvcgroup"]),
|
||||
# state
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2019 Red Hat
|
||||
# Copyright (C) 2019-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,124 +32,159 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The full qualified domain name.
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["fqdn"]
|
||||
required: true
|
||||
|
||||
hosts:
|
||||
description: The list of user host dicts
|
||||
required: false
|
||||
options:
|
||||
hosts:
|
||||
description: The list of host dicts
|
||||
required: false
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
name:
|
||||
description: The host (internally uid).
|
||||
type: str
|
||||
aliases: ["fqdn"]
|
||||
required: true
|
||||
description:
|
||||
description: The host description
|
||||
type: str
|
||||
required: false
|
||||
locality:
|
||||
description: Host locality (e.g. "Baltimore, MD")
|
||||
type: str
|
||||
required: false
|
||||
location:
|
||||
description: Host location (e.g. "Lab 2")
|
||||
description: Host physical location hist (e.g. "Lab 2")
|
||||
type: str
|
||||
aliases: ["ns_host_location"]
|
||||
required: false
|
||||
platform:
|
||||
description: Host hardware platform (e.g. "Lenovo T61")
|
||||
type: str
|
||||
aliases: ["ns_hardware_platform"]
|
||||
required: false
|
||||
os:
|
||||
description: Host operating system and version (e.g. "Fedora 9")
|
||||
type: str
|
||||
aliases: ["ns_os_version"]
|
||||
required: false
|
||||
password:
|
||||
description: Password used in bulk enrollment
|
||||
type: str
|
||||
aliases: ["user_password", "userpassword"]
|
||||
required: false
|
||||
random:
|
||||
description:
|
||||
Initiate the generation of a random password to be used in bulk
|
||||
enrollment
|
||||
type: bool
|
||||
aliases: ["random_password"]
|
||||
required: false
|
||||
certificate:
|
||||
description: List of base-64 encoded host certificates
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["usercertificate"]
|
||||
required: false
|
||||
managedby_host:
|
||||
description: List of hosts that can manage this host
|
||||
type: list
|
||||
aliases: ["principalname", "krbprincipalname"]
|
||||
elements: str
|
||||
required: false
|
||||
principal:
|
||||
description: List of principal aliases for this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["principalname", "krbprincipalname"]
|
||||
required: false
|
||||
allow_create_keytab_user:
|
||||
description: Users allowed to create a keytab of this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_write_keys_user"]
|
||||
required: false
|
||||
allow_create_keytab_group:
|
||||
description: Groups allowed to create a keytab of this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_write_keys_group"]
|
||||
required: false
|
||||
allow_create_keytab_host:
|
||||
description: Hosts allowed to create a keytab of this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_write_keys_host"]
|
||||
required: false
|
||||
allow_create_keytab_hostgroup:
|
||||
description: Hostgroups allowed to create a keytab of this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_write_keys_hostgroup"]
|
||||
required: false
|
||||
allow_retrieve_keytab_user:
|
||||
description: Users allowed to retrieve a keytab of this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_read_keys_user"]
|
||||
required: false
|
||||
allow_retrieve_keytab_group:
|
||||
description: Groups allowed to retrieve a keytab of this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_read_keys_group"]
|
||||
required: false
|
||||
allow_retrieve_keytab_host:
|
||||
description: Hosts allowed to retrieve a keytab of this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_read_keys_host"]
|
||||
required: false
|
||||
allow_retrieve_keytab_hostgroup:
|
||||
description: Hostgroups allowed to retrieve a keytab of this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_read_keys_hostgroup"]
|
||||
required: false
|
||||
mac_address:
|
||||
description: List of hardware MAC addresses.
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["macaddress"]
|
||||
required: false
|
||||
sshpubkey:
|
||||
description: List of SSH public keys
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipasshpubkey"]
|
||||
required: false
|
||||
userclass:
|
||||
description:
|
||||
Host category (semantics placed on this attribute are for local
|
||||
interpretation)
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["class"]
|
||||
required: false
|
||||
auth_ind:
|
||||
description:
|
||||
Defines a whitelist for Authentication Indicators. Use 'otp' to allow
|
||||
OTP-based 2FA authentications. Use 'radius' to allow RADIUS-based 2FA
|
||||
authentications. Other values may be used for custom configurations.
|
||||
Use empty string to reset auth_ind to the initial value.
|
||||
Defines an allow list for Authentication Indicators. Use 'otp'
|
||||
to allow OTP-based 2FA authentications. Use 'radius' to allow
|
||||
RADIUS-based 2FA authentications. Other values may be used
|
||||
for custom configurations. Use empty string to reset auth_ind
|
||||
to the initial value.
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["krbprincipalauthind"]
|
||||
choices: ["radius", "otp", "pkinit", "hardened", ""]
|
||||
choices: ["radius", "otp", "pkinit", "hardened", "idp", ""]
|
||||
required: false
|
||||
requires_pre_auth:
|
||||
description: Pre-authentication is required for the service
|
||||
@@ -169,15 +204,18 @@ options:
|
||||
required: false
|
||||
force:
|
||||
description: Force host name even if not in DNS
|
||||
type: bool
|
||||
required: false
|
||||
reverse:
|
||||
description: Reverse DNS detection
|
||||
default: true
|
||||
type: bool
|
||||
required: false
|
||||
ip_address:
|
||||
description:
|
||||
The host IP address list (IPv4 and IPv6). No IP address conflict
|
||||
check will be done.
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaddress"]
|
||||
required: false
|
||||
update_dns:
|
||||
@@ -185,107 +223,140 @@ options:
|
||||
Controls the update of the DNS SSHFP records for existing hosts and
|
||||
the removal of all DNS entries if a host gets removed with state
|
||||
absent.
|
||||
type: bool
|
||||
aliases: ["updatedns"]
|
||||
required: false
|
||||
description:
|
||||
description: The host description
|
||||
type: str
|
||||
required: false
|
||||
locality:
|
||||
description: Host locality (e.g. "Baltimore, MD")
|
||||
type: str
|
||||
required: false
|
||||
location:
|
||||
description: Host location (e.g. "Lab 2")
|
||||
type: str
|
||||
aliases: ["ns_host_location"]
|
||||
required: false
|
||||
platform:
|
||||
description: Host hardware platform (e.g. "Lenovo T61")
|
||||
type: str
|
||||
aliases: ["ns_hardware_platform"]
|
||||
required: false
|
||||
os:
|
||||
description: Host operating system and version (e.g. "Fedora 9")
|
||||
type: str
|
||||
aliases: ["ns_os_version"]
|
||||
required: false
|
||||
password:
|
||||
description: Password used in bulk enrollment
|
||||
type: str
|
||||
aliases: ["user_password", "userpassword"]
|
||||
required: false
|
||||
random:
|
||||
description:
|
||||
Initiate the generation of a random password to be used in bulk
|
||||
enrollment
|
||||
type: bool
|
||||
aliases: ["random_password"]
|
||||
required: false
|
||||
certificate:
|
||||
description: List of base-64 encoded host certificates
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["usercertificate"]
|
||||
required: false
|
||||
managedby_host:
|
||||
description: List of hosts that can manage this host
|
||||
type: list
|
||||
aliases: ["principalname", "krbprincipalname"]
|
||||
elements: str
|
||||
required: false
|
||||
principal:
|
||||
description: List of principal aliases for this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["principalname", "krbprincipalname"]
|
||||
required: false
|
||||
allow_create_keytab_user:
|
||||
description: Users allowed to create a keytab of this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_write_keys_user"]
|
||||
required: false
|
||||
allow_create_keytab_group:
|
||||
description: Groups allowed to create a keytab of this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_write_keys_group"]
|
||||
required: false
|
||||
allow_create_keytab_host:
|
||||
description: Hosts allowed to create a keytab of this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_write_keys_host"]
|
||||
required: false
|
||||
allow_create_keytab_hostgroup:
|
||||
description: Hostgroups allowed to create a keytab of this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_write_keys_hostgroup"]
|
||||
required: false
|
||||
allow_retrieve_keytab_user:
|
||||
description: Users allowed to retrieve a keytab of this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_read_keys_user"]
|
||||
required: false
|
||||
allow_retrieve_keytab_group:
|
||||
description: Groups allowed to retrieve a keytab of this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_read_keys_group"]
|
||||
required: false
|
||||
allow_retrieve_keytab_host:
|
||||
description: Hosts allowed to retrieve a keytab of this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_read_keys_host"]
|
||||
required: false
|
||||
allow_retrieve_keytab_hostgroup:
|
||||
description: Hostgroups allowed to retrieve a keytab of this host
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_read_keys_hostgroup"]
|
||||
required: false
|
||||
mac_address:
|
||||
description: List of hardware MAC addresses.
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["macaddress"]
|
||||
required: false
|
||||
sshpubkey:
|
||||
description: List of SSH public keys
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipasshpubkey"]
|
||||
required: false
|
||||
userclass:
|
||||
description:
|
||||
Host category (semantics placed on this attribute are for local
|
||||
interpretation)
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["class"]
|
||||
required: false
|
||||
auth_ind:
|
||||
description:
|
||||
Defines a whitelist for Authentication Indicators. Use 'otp' to allow
|
||||
OTP-based 2FA authentications. Use 'radius' to allow RADIUS-based 2FA
|
||||
authentications. Other values may be used for custom configurations.
|
||||
Use empty string to reset auth_ind to the initial value.
|
||||
Defines an allow list for Authentication Indicators. Use 'otp'
|
||||
to allow OTP-based 2FA authentications. Use 'radius' to allow
|
||||
RADIUS-based 2FA authentications. Other values may be used
|
||||
for custom configurations. Use empty string to reset auth_ind
|
||||
to the initial value.
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["krbprincipalauthind"]
|
||||
choices: ["radius", "otp", "pkinit", "hardened", ""]
|
||||
choices: ["radius", "otp", "pkinit", "hardened", "idp", ""]
|
||||
required: false
|
||||
requires_pre_auth:
|
||||
description: Pre-authentication is required for the service
|
||||
@@ -298,21 +369,25 @@ options:
|
||||
aliases: ["ipakrbokasdelegate"]
|
||||
required: false
|
||||
ok_to_auth_as_delegate:
|
||||
description: The service is allowed to authenticate on behalf of a client
|
||||
description:
|
||||
The service is allowed to authenticate on behalf of a client
|
||||
type: bool
|
||||
aliases: ["ipakrboktoauthasdelegate"]
|
||||
required: false
|
||||
force:
|
||||
description: Force host name even if not in DNS
|
||||
type: bool
|
||||
required: false
|
||||
reverse:
|
||||
description: Reverse DNS detection
|
||||
default: true
|
||||
type: bool
|
||||
required: false
|
||||
ip_address:
|
||||
description:
|
||||
The host IP address list (IPv4 and IPv6). No IP address conflict
|
||||
check will be done.
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaddress"]
|
||||
required: false
|
||||
update_dns:
|
||||
@@ -320,23 +395,27 @@ options:
|
||||
Controls the update of the DNS SSHFP records for existing hosts and
|
||||
the removal of all DNS entries if a host gets removed with state
|
||||
absent.
|
||||
type: bool
|
||||
aliases: ["updatedns"]
|
||||
required: false
|
||||
update_password:
|
||||
description:
|
||||
Set password for a host in present state only on creation or always
|
||||
default: 'always'
|
||||
type: str
|
||||
choices: ["always", "on_create"]
|
||||
action:
|
||||
description: Work on host or member level
|
||||
type: str
|
||||
default: "host"
|
||||
choices: ["member", "host"]
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent",
|
||||
"disabled"]
|
||||
author:
|
||||
- Thomas Woerner
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -362,6 +441,15 @@ EXAMPLES = """
|
||||
description: Example host
|
||||
force: yes
|
||||
|
||||
# Ensure multiple hosts are present with random passwords
|
||||
- ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
hosts:
|
||||
- name: host01.example.com
|
||||
random: yes
|
||||
- name: host02.example.com
|
||||
random: yes
|
||||
|
||||
# Initiate generation of a random password for the host
|
||||
- ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -370,6 +458,18 @@ EXAMPLES = """
|
||||
ip_address: 192.168.0.123
|
||||
random: yes
|
||||
|
||||
# Ensure multiple hosts are present with principals
|
||||
- ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
hosts:
|
||||
- name: host01.example.com
|
||||
principal:
|
||||
- host/testhost01.example.com
|
||||
- name: host02.example.com
|
||||
principal:
|
||||
- host/myhost01.example.com
|
||||
action: member
|
||||
|
||||
# Ensure host is disabled
|
||||
- ipahost:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
@@ -387,19 +487,23 @@ EXAMPLES = """
|
||||
RETURN = """
|
||||
host:
|
||||
description: Host dict with random password
|
||||
returned: If random is yes and user did not exist or update_password is yes
|
||||
returned: If random is yes and host did not exist or update_password is yes
|
||||
type: dict
|
||||
options:
|
||||
contains:
|
||||
randompassword:
|
||||
description: The generated random password
|
||||
returned: If only one user is handled by the module
|
||||
type: str
|
||||
returned: |
|
||||
If only one host is handled by the module without using hosts parameter
|
||||
name:
|
||||
description: The user name of the user that got a new random password
|
||||
returned: If several users are handled by the module
|
||||
description: The host name of the host that got a new random password
|
||||
returned: |
|
||||
If several hosts are handled by the module with the hosts parameter
|
||||
type: dict
|
||||
options:
|
||||
contains:
|
||||
randompassword:
|
||||
description: The generated random password
|
||||
type: str
|
||||
returned: always
|
||||
"""
|
||||
|
||||
@@ -563,12 +667,21 @@ def check_parameters( # pylint: disable=unused-argument
|
||||
module.params_fail_used_invalid(invalid, state, action)
|
||||
|
||||
|
||||
def check_authind(module, auth_ind):
|
||||
_invalid = module.ipa_command_invalid_param_choices(
|
||||
"host_add", "krbprincipalauthind", auth_ind)
|
||||
if _invalid:
|
||||
module.fail_json(
|
||||
msg="The use of krbprincipalauthind '%s' is not supported "
|
||||
"by your IPA version" % "','".join(_invalid))
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def result_handler(module, result, command, name, args, errors, exit_args,
|
||||
one_name):
|
||||
single_host):
|
||||
if "random" in args and command in ["host_add", "host_mod"] \
|
||||
and "randompassword" in result["result"]:
|
||||
if one_name:
|
||||
if single_host:
|
||||
exit_args["randompassword"] = \
|
||||
result["result"]["randompassword"]
|
||||
else:
|
||||
@@ -590,7 +703,7 @@ def result_handler(module, result, command, name, args, errors, exit_args,
|
||||
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def exception_handler(module, ex, errors, exit_args, one_name):
|
||||
def exception_handler(module, ex, errors, exit_args, single_host):
|
||||
msg = str(ex)
|
||||
if "already contains" in msg \
|
||||
or "does not contain" in msg:
|
||||
@@ -626,53 +739,54 @@ def main():
|
||||
default=None, no_log=True),
|
||||
random=dict(type="bool", aliases=["random_password"],
|
||||
default=None),
|
||||
certificate=dict(type="list", aliases=["usercertificate"],
|
||||
default=None),
|
||||
managedby_host=dict(type="list",
|
||||
default=None),
|
||||
principal=dict(type="list", aliases=["krbprincipalname"],
|
||||
certificate=dict(type="list", elements="str",
|
||||
aliases=["usercertificate"], default=None),
|
||||
managedby_host=dict(type="list", elements="str", default=None),
|
||||
principal=dict(type="list", elements="str",
|
||||
aliases=["principalname", "krbprincipalname"],
|
||||
default=None),
|
||||
allow_create_keytab_user=dict(
|
||||
type="list",
|
||||
type="list", elements="str",
|
||||
aliases=["ipaallowedtoperform_write_keys_user"],
|
||||
default=None),
|
||||
default=None, no_log=False),
|
||||
allow_create_keytab_group=dict(
|
||||
type="list",
|
||||
type="list", elements="str",
|
||||
aliases=["ipaallowedtoperform_write_keys_group"],
|
||||
default=None),
|
||||
default=None, no_log=False),
|
||||
allow_create_keytab_host=dict(
|
||||
type="list",
|
||||
type="list", elements="str",
|
||||
aliases=["ipaallowedtoperform_write_keys_host"],
|
||||
default=None),
|
||||
default=None, no_log=False),
|
||||
allow_create_keytab_hostgroup=dict(
|
||||
type="list",
|
||||
type="list", elements="str",
|
||||
aliases=["ipaallowedtoperform_write_keys_hostgroup"],
|
||||
default=None),
|
||||
default=None, no_log=False),
|
||||
allow_retrieve_keytab_user=dict(
|
||||
type="list",
|
||||
aliases=["ipaallowedtoperform_write_keys_user"],
|
||||
default=None),
|
||||
type="list", elements="str",
|
||||
aliases=["ipaallowedtoperform_read_keys_user"],
|
||||
default=None, no_log=False),
|
||||
allow_retrieve_keytab_group=dict(
|
||||
type="list",
|
||||
aliases=["ipaallowedtoperform_write_keys_group"],
|
||||
default=None),
|
||||
type="list", elements="str",
|
||||
aliases=["ipaallowedtoperform_read_keys_group"],
|
||||
default=None, no_log=False),
|
||||
allow_retrieve_keytab_host=dict(
|
||||
type="list",
|
||||
aliases=["ipaallowedtoperform_write_keys_host"],
|
||||
default=None),
|
||||
type="list", elements="str",
|
||||
aliases=["ipaallowedtoperform_read_keys_host"],
|
||||
default=None, no_log=False),
|
||||
allow_retrieve_keytab_hostgroup=dict(
|
||||
type="list",
|
||||
aliases=["ipaallowedtoperform_write_keys_hostgroup"],
|
||||
default=None),
|
||||
mac_address=dict(type="list", aliases=["macaddress"],
|
||||
type="list", elements="str",
|
||||
aliases=["ipaallowedtoperform_read_keys_hostgroup"],
|
||||
default=None, no_log=False),
|
||||
mac_address=dict(type="list", elements="str", aliases=["macaddress"],
|
||||
default=None),
|
||||
sshpubkey=dict(type="str", aliases=["ipasshpubkey"],
|
||||
sshpubkey=dict(type="list", elements="str", aliases=["ipasshpubkey"],
|
||||
default=None),
|
||||
userclass=dict(type="list", aliases=["class"],
|
||||
userclass=dict(type="list", elements="str", aliases=["class"],
|
||||
default=None),
|
||||
auth_ind=dict(type='list', aliases=["krbprincipalauthind"],
|
||||
default=None,
|
||||
choices=['radius', 'otp', 'pkinit', 'hardened', '']),
|
||||
auth_ind=dict(type='list', elements="str",
|
||||
aliases=["krbprincipalauthind"], default=None,
|
||||
choices=["radius", "otp", "pkinit", "hardened", "idp",
|
||||
""]),
|
||||
requires_pre_auth=dict(type="bool", aliases=["ipakrbrequirespreauth"],
|
||||
default=None),
|
||||
ok_as_delegate=dict(type="bool", aliases=["ipakrbokasdelegate"],
|
||||
@@ -682,7 +796,7 @@ def main():
|
||||
default=None),
|
||||
force=dict(type='bool', default=None),
|
||||
reverse=dict(type='bool', default=None),
|
||||
ip_address=dict(type="list", aliases=["ipaddress"],
|
||||
ip_address=dict(type="list", elements="str", aliases=["ipaddress"],
|
||||
default=None),
|
||||
update_dns=dict(type="bool", aliases=["updatedns"],
|
||||
default=None),
|
||||
@@ -695,8 +809,8 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["fqdn"], default=None,
|
||||
required=False),
|
||||
name=dict(type="list", elements="str", aliases=["fqdn"],
|
||||
default=None, required=False),
|
||||
|
||||
hosts=dict(type="list", default=None,
|
||||
options=dict(
|
||||
@@ -762,7 +876,8 @@ def main():
|
||||
allow_retrieve_keytab_hostgroup = ansible_module.params_get(
|
||||
"allow_retrieve_keytab_hostgroup")
|
||||
mac_address = ansible_module.params_get("mac_address")
|
||||
sshpubkey = ansible_module.params_get("sshpubkey")
|
||||
sshpubkey = ansible_module.params_get("sshpubkey",
|
||||
allow_empty_string=True)
|
||||
userclass = ansible_module.params_get("userclass")
|
||||
auth_ind = ansible_module.params_get("auth_ind", allow_empty_string=True)
|
||||
requires_pre_auth = ansible_module.params_get("requires_pre_auth")
|
||||
@@ -814,6 +929,8 @@ def main():
|
||||
|
||||
# Check version specific settings
|
||||
|
||||
check_authind(ansible_module, auth_ind)
|
||||
|
||||
server_realm = ansible_module.ipa_get_realm()
|
||||
|
||||
commands = []
|
||||
@@ -856,6 +973,7 @@ def main():
|
||||
sshpubkey = host.get("sshpubkey")
|
||||
userclass = host.get("userclass")
|
||||
auth_ind = host.get("auth_ind")
|
||||
check_authind(ansible_module, auth_ind)
|
||||
requires_pre_auth = host.get("requires_pre_auth")
|
||||
ok_as_delegate = host.get("ok_as_delegate")
|
||||
ok_to_auth_as_delegate = host.get("ok_to_auth_as_delegate")
|
||||
@@ -1386,7 +1504,7 @@ def main():
|
||||
|
||||
changed = ansible_module.execute_ipa_commands(
|
||||
commands, result_handler, exception_handler,
|
||||
exit_args=exit_args, one_name=len(names) == 1)
|
||||
exit_args=exit_args, single_host=hosts is None)
|
||||
|
||||
# Done
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2019 Red Hat
|
||||
# Copyright (C) 2019-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -33,17 +33,20 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The hostgroup name
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
description:
|
||||
description: The hostgroup description
|
||||
type: str
|
||||
required: false
|
||||
nomembers:
|
||||
description: Suppress processing of membership attributes
|
||||
@@ -53,38 +56,45 @@ options:
|
||||
description: List of host names assigned to this hostgroup.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
hostgroup:
|
||||
description: List of hostgroup names assigned to this hostgroup.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
membermanager_user:
|
||||
description:
|
||||
- List of member manager users assigned to this hostgroup.
|
||||
- Only usable with IPA versions 4.8.4 and up.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
membermanager_group:
|
||||
description:
|
||||
- List of member manager groups assigned to this hostgroup.
|
||||
- Only usable with IPA versions 4.8.4 and up.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
rename:
|
||||
description:
|
||||
- Rename hostgroup to the given name.
|
||||
- Only usable with IPA versions 4.8.7 and up.
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["new_name"]
|
||||
action:
|
||||
description: Work on hostgroup or member level
|
||||
type: str
|
||||
default: hostgroup
|
||||
choices: ["member", "hostgroup"]
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent", "renamed"]
|
||||
author:
|
||||
- Thomas Woerner
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -185,16 +195,19 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"], default=None,
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
required=True),
|
||||
# present
|
||||
description=dict(type="str", default=None),
|
||||
nomembers=dict(required=False, type='bool', default=None),
|
||||
host=dict(required=False, type='list', default=None),
|
||||
hostgroup=dict(required=False, type='list', default=None),
|
||||
membermanager_user=dict(required=False, type='list', default=None),
|
||||
host=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
hostgroup=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
membermanager_user=dict(required=False, type='list',
|
||||
elements="str", default=None),
|
||||
membermanager_group=dict(required=False, type='list',
|
||||
default=None),
|
||||
elements="str", default=None),
|
||||
rename=dict(required=False, type='str', default=None,
|
||||
aliases=["new_name"]),
|
||||
action=dict(type="str", default="hostgroup",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
# Authors:
|
||||
# Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
@@ -32,7 +33,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipaidrange
|
||||
short description: Manage FreeIPA idrange
|
||||
short_description: Manage FreeIPA idrange
|
||||
description: Manage FreeIPA idrange
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
@@ -40,6 +41,8 @@ extends_documentation_fragment:
|
||||
options:
|
||||
name:
|
||||
description: The list of idrange name strings.
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
base_id:
|
||||
@@ -64,33 +67,37 @@ options:
|
||||
aliases: ["ipasecondarybaserid"]
|
||||
idrange_type:
|
||||
description: ID range type.
|
||||
type: string
|
||||
type: str
|
||||
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
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["ipanttrusteddomainsid"]
|
||||
dom_name:
|
||||
description: |
|
||||
Domain name of the trusted domain. Can only be used when
|
||||
`ipaapi_context: server`.
|
||||
type: string
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["ipanttrusteddomainname"]
|
||||
auto_private_groups:
|
||||
description: Auto creation of private groups.
|
||||
type: string
|
||||
type: str
|
||||
required: false
|
||||
choices: ["true", "false", "hybrid"]
|
||||
aliases: ["ipaautoprivategroups"]
|
||||
state:
|
||||
description: The state to ensure.
|
||||
type: str
|
||||
choices: ["present", "absent"]
|
||||
default: present
|
||||
required: true
|
||||
required: false
|
||||
author:
|
||||
- Rafael Guterres Jeffman (@rjeffman)
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -184,8 +191,8 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"],
|
||||
default=None, required=True),
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
required=True),
|
||||
# present
|
||||
base_id=dict(required=False, type='int',
|
||||
aliases=["ipabaseid"], default=None),
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2020 Red Hat
|
||||
# Copyright (C) 2020-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,23 +32,29 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The list of location name strings.
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["idnsname"]
|
||||
description:
|
||||
description: The IPA location string
|
||||
type: str
|
||||
required: false
|
||||
state:
|
||||
description: The state to ensure.
|
||||
type: str
|
||||
choices: ["present", "absent"]
|
||||
default: present
|
||||
required: true
|
||||
required: false
|
||||
author:
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -94,8 +100,8 @@ def gen_args(description):
|
||||
def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
name=dict(type="list", aliases=["idnsname"],
|
||||
default=None, required=True),
|
||||
name=dict(type="list", elements="str", aliases=["idnsname"],
|
||||
required=True),
|
||||
# present
|
||||
description=dict(required=False, type='str', default=None),
|
||||
# state
|
||||
|
||||
436
plugins/modules/ipanetgroup.py
Normal file
436
plugins/modules/ipanetgroup.py
Normal file
@@ -0,0 +1,436 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Authors:
|
||||
# Denis Karpelevich <dkarpele@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: ipanetgroup
|
||||
short_description: NIS entities can be stored in netgroups.
|
||||
description: |
|
||||
A netgroup is a group used for permission checking.
|
||||
It can contain both user and host values.
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
- ipamodule_base_docs.delete_continue
|
||||
options:
|
||||
name:
|
||||
description: The list of netgroup name strings.
|
||||
required: true
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["cn"]
|
||||
description:
|
||||
description: Netgroup description
|
||||
required: false
|
||||
type: str
|
||||
aliases: ["desc"]
|
||||
nisdomain:
|
||||
description: NIS domain name
|
||||
required: false
|
||||
type: str
|
||||
aliases: ["nisdomainname"]
|
||||
nomembers:
|
||||
description: Suppress processing of membership attributes
|
||||
required: false
|
||||
type: bool
|
||||
user:
|
||||
description: List of user names assigned to this netgroup.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["users"]
|
||||
group:
|
||||
description: List of group names assigned to this netgroup.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["groups"]
|
||||
host:
|
||||
description: List of host names assigned to this netgroup.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["hosts"]
|
||||
hostgroup:
|
||||
description: List of host group names assigned to this netgroup.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["hostgroups"]
|
||||
netgroup:
|
||||
description: List of netgroup names assigned to this netgroup.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["netgroups"]
|
||||
action:
|
||||
description: Work on netgroup or member level
|
||||
required: false
|
||||
type: str
|
||||
default: netgroup
|
||||
choices: ["member", "netgroup"]
|
||||
state:
|
||||
description: The state to ensure.
|
||||
type: str
|
||||
choices: ["present", "absent"]
|
||||
default: present
|
||||
author:
|
||||
- Denis Karpelevich (@dkarpele)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
- name: Ensure netgroup my_netgroup1 is present
|
||||
ipanetgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my_netgroup1
|
||||
description: My netgroup 1
|
||||
|
||||
- name: Ensure netgroup my_netgroup1 is absent
|
||||
ipanetgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: my_netgroup1
|
||||
state: absent
|
||||
|
||||
- name: Ensure netgroup is present with user "user1"
|
||||
ipanetgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestNetgroup1
|
||||
user: user1
|
||||
action: member
|
||||
|
||||
- name: Ensure netgroup user, "user1", is absent
|
||||
ipanetgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestNetgroup1
|
||||
user: "user1"
|
||||
action: member
|
||||
state: absent
|
||||
|
||||
- name: Ensure netgroup is present with members
|
||||
ipanetgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: TestNetgroup1
|
||||
user: user1,user2
|
||||
group: group1
|
||||
host: host1
|
||||
hostgroup: ipaservers
|
||||
netgroup: admins
|
||||
action: member
|
||||
|
||||
- name: Ensure 2 netgroups TestNetgroup1, admins are absent
|
||||
ipanetgroup:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name:
|
||||
- TestNetgroup1
|
||||
- admins
|
||||
state: absent
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
"""
|
||||
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, \
|
||||
gen_add_list, gen_intersection_list, ensure_fqdn
|
||||
|
||||
|
||||
def find_netgroup(module, name):
|
||||
"""Find if a netgroup with the given name already exist."""
|
||||
_args = {
|
||||
"all": True,
|
||||
"cn": name,
|
||||
}
|
||||
|
||||
# `netgroup_find` is used here instead of `netgroup_show` to workaround
|
||||
# FreeIPA bug https://pagure.io/freeipa/issue/9284.
|
||||
# `ipa netgroup-show hostgroup` shows hostgroup - it's a bug.
|
||||
# `ipa netgroup-find hostgroup` doesn't show hostgroup - it's correct.
|
||||
_result = module.ipa_command("netgroup_find", name, _args)
|
||||
|
||||
if len(_result["result"]) > 1:
|
||||
module.fail_json(
|
||||
msg="There is more than one netgroup '%s'" % name)
|
||||
elif len(_result["result"]) == 1:
|
||||
return _result["result"][0]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def gen_args(description, nisdomain, nomembers):
|
||||
_args = {}
|
||||
if description is not None:
|
||||
_args["description"] = description
|
||||
if nisdomain is not None:
|
||||
_args["nisdomainname"] = nisdomain
|
||||
if nomembers is not None:
|
||||
_args["nomembers"] = nomembers
|
||||
|
||||
return _args
|
||||
|
||||
|
||||
def gen_member_args(user, group, host, hostgroup, netgroup):
|
||||
_args = {}
|
||||
if user is not None:
|
||||
_args["memberuser_user"] = user
|
||||
if group is not None:
|
||||
_args["memberuser_group"] = group
|
||||
if host is not None:
|
||||
_args["memberhost_host"] = host
|
||||
if hostgroup is not None:
|
||||
_args["memberhost_hostgroup"] = hostgroup
|
||||
if netgroup is not None:
|
||||
_args["member_netgroup"] = netgroup
|
||||
|
||||
return _args
|
||||
|
||||
|
||||
def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
required=True),
|
||||
# present
|
||||
description=dict(required=False, type='str',
|
||||
aliases=["desc"], default=None),
|
||||
nisdomain=dict(required=False, type='str',
|
||||
aliases=["nisdomainname"], default=None),
|
||||
nomembers=dict(required=False, type='bool', default=None),
|
||||
user=dict(required=False, type='list', elements="str",
|
||||
aliases=["users"], default=None),
|
||||
group=dict(required=False, type='list', elements="str",
|
||||
aliases=["groups"], default=None),
|
||||
host=dict(required=False, type='list', elements="str",
|
||||
aliases=["hosts"], default=None),
|
||||
hostgroup=dict(required=False, type='list', elements="str",
|
||||
aliases=["hostgroups"], default=None),
|
||||
netgroup=dict(required=False, type='list', elements="str",
|
||||
aliases=["netgroups"], default=None),
|
||||
action=dict(required=False, type="str", default="netgroup",
|
||||
choices=["member", "netgroup"]),
|
||||
# state
|
||||
state=dict(type="str", default="present",
|
||||
choices=["present", "absent"]),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
ipa_module_options=["delete_continue"],
|
||||
)
|
||||
|
||||
ansible_module._ansible_debug = True
|
||||
|
||||
# Get parameters
|
||||
|
||||
# general
|
||||
names = ansible_module.params_get("name")
|
||||
|
||||
# present
|
||||
description = ansible_module.params_get("description")
|
||||
nisdomain = ansible_module.params_get("nisdomain")
|
||||
nomembers = ansible_module.params_get("nomembers")
|
||||
user = ansible_module.params_get_lowercase("user")
|
||||
group = ansible_module.params_get_lowercase("group")
|
||||
host = ansible_module.params_get_lowercase("host")
|
||||
hostgroup = ansible_module.params_get_lowercase("hostgroup")
|
||||
netgroup = ansible_module.params_get_lowercase("netgroup")
|
||||
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 netgroup can be added at a time.")
|
||||
if action == "member":
|
||||
invalid = ["description", "nisdomain", "nomembers"]
|
||||
|
||||
if state == "absent":
|
||||
if len(names) < 1:
|
||||
ansible_module.fail_json(msg="No name given.")
|
||||
if len(names) != 1 and action == "member":
|
||||
ansible_module.fail_json(msg="Members can be removed only from one"
|
||||
" netgroup at a time.")
|
||||
invalid = ["description", "nisdomain", "nomembers"]
|
||||
if action == "netgroup":
|
||||
invalid.extend(["user", "group", "host", "hostgroup", "netgroup"])
|
||||
|
||||
ansible_module.params_fail_used_invalid(invalid, state)
|
||||
|
||||
# Init
|
||||
|
||||
exit_args = {}
|
||||
|
||||
# Connect to IPA API
|
||||
with ansible_module.ipa_connect():
|
||||
# Ensure fqdn host names, use default domain for simple names
|
||||
if host is not None:
|
||||
default_domain = ansible_module.ipa_get_domain()
|
||||
host = [ensure_fqdn(_host, default_domain).lower()
|
||||
for _host in host]
|
||||
|
||||
commands = []
|
||||
for name in names:
|
||||
# Make sure netgroup exists
|
||||
res_find = find_netgroup(ansible_module, name)
|
||||
|
||||
user_add, user_del = [], []
|
||||
group_add, group_del = [], []
|
||||
host_add, host_del = [], []
|
||||
hostgroup_add, hostgroup_del = [], []
|
||||
netgroup_add, netgroup_del = [], []
|
||||
|
||||
# Create command
|
||||
if state == "present":
|
||||
# Generate args
|
||||
args = gen_args(description, nisdomain, nomembers)
|
||||
|
||||
if action == "netgroup":
|
||||
# Found the netgroup
|
||||
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):
|
||||
commands.append([name, "netgroup_mod", args])
|
||||
else:
|
||||
commands.append([name, "netgroup_add", args])
|
||||
res_find = {}
|
||||
|
||||
member_args = gen_member_args(
|
||||
user, group, host, hostgroup, netgroup
|
||||
)
|
||||
if not compare_args_ipa(ansible_module, member_args,
|
||||
res_find):
|
||||
# Generate addition and removal lists
|
||||
user_add, user_del = gen_add_del_lists(
|
||||
user, res_find.get("memberuser_user"))
|
||||
|
||||
group_add, group_del = gen_add_del_lists(
|
||||
group, res_find.get("memberuser_group"))
|
||||
|
||||
host_add, host_del = gen_add_del_lists(
|
||||
host, res_find.get("memberhost_host"))
|
||||
|
||||
hostgroup_add, hostgroup_del = gen_add_del_lists(
|
||||
hostgroup, res_find.get("memberhost_hostgroup"))
|
||||
|
||||
netgroup_add, netgroup_del = gen_add_del_lists(
|
||||
netgroup, res_find.get("member_netgroup"))
|
||||
|
||||
elif action == "member":
|
||||
if res_find is None:
|
||||
ansible_module.fail_json(msg="No netgroup '%s'" % name)
|
||||
|
||||
# Reduce add lists for memberuser_user, memberuser_group,
|
||||
# member_service and member_external to new entries
|
||||
# only that are not in res_find.
|
||||
user_add = gen_add_list(
|
||||
user, res_find.get("memberuser_user"))
|
||||
group_add = gen_add_list(
|
||||
group, res_find.get("memberuser_group"))
|
||||
host_add = gen_add_list(
|
||||
host, res_find.get("memberhost_host"))
|
||||
hostgroup_add = gen_add_list(
|
||||
hostgroup, res_find.get("memberhost_hostgroup"))
|
||||
netgroup_add = gen_add_list(
|
||||
netgroup, res_find.get("member_netgroup"))
|
||||
|
||||
elif state == "absent":
|
||||
if action == "netgroup":
|
||||
if res_find is not None:
|
||||
commands.append([name, "netgroup_del", {}])
|
||||
|
||||
elif action == "member":
|
||||
if res_find is None:
|
||||
ansible_module.fail_json(msg="No netgroup '%s'" % name)
|
||||
user_del = gen_intersection_list(
|
||||
user, res_find.get("memberuser_user"))
|
||||
group_del = gen_intersection_list(
|
||||
group, res_find.get("memberuser_group"))
|
||||
host_del = gen_intersection_list(
|
||||
host, res_find.get("memberhost_host"))
|
||||
hostgroup_del = gen_intersection_list(
|
||||
hostgroup, res_find.get("memberhost_hostgroup"))
|
||||
netgroup_del = gen_intersection_list(
|
||||
netgroup, res_find.get("member_netgroup"))
|
||||
|
||||
else:
|
||||
ansible_module.fail_json(msg="Unknown state '%s'" % state)
|
||||
|
||||
# manage members
|
||||
# setup member args for add/remove members.
|
||||
add_member_args = {
|
||||
"user": user_add,
|
||||
"group": group_add,
|
||||
"host": host_add,
|
||||
"hostgroup": hostgroup_add,
|
||||
"netgroup": netgroup_add
|
||||
}
|
||||
|
||||
del_member_args = {
|
||||
"user": user_del,
|
||||
"group": group_del,
|
||||
"host": host_del,
|
||||
"hostgroup": hostgroup_del,
|
||||
"netgroup": netgroup_del
|
||||
}
|
||||
|
||||
# Add members
|
||||
add_members = any([user_add, group_add, host_add,
|
||||
hostgroup_add, netgroup_add])
|
||||
if add_members:
|
||||
commands.append(
|
||||
[name, "netgroup_add_member", add_member_args]
|
||||
)
|
||||
# Remove members
|
||||
remove_members = any([user_del, group_del, host_del,
|
||||
hostgroup_del, netgroup_del])
|
||||
if remove_members:
|
||||
commands.append(
|
||||
[name, "netgroup_remove_member", del_member_args]
|
||||
)
|
||||
# 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()
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
# Authors:
|
||||
# Seth Kress <kresss@gmail.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2020 Red Hat
|
||||
# Copyright (C) 2020-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,13 +33,15 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The permission name string.
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
right:
|
||||
@@ -46,52 +49,64 @@ options:
|
||||
required: false
|
||||
choices: ["read", "search", "compare", "write", "add", "delete", "all"]
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipapermright"]
|
||||
attrs:
|
||||
description: All attributes to which the permission applies
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
bindtype:
|
||||
description: Bind rule type
|
||||
required: false
|
||||
choices: ["permission", "all", "anonymous"]
|
||||
type: str
|
||||
choices: ["permission", "all", "anonymous", "self"]
|
||||
aliases: ["ipapermbindruletype"]
|
||||
subtree:
|
||||
description: Subtree to apply permissions to
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["ipapermlocation"]
|
||||
filter:
|
||||
extra_target_filter:
|
||||
description: Extra target filter
|
||||
required: false
|
||||
type: list
|
||||
aliases: ["extratargetfilter"]
|
||||
elements: str
|
||||
aliases: ["filter", "extratargetfilter"]
|
||||
rawfilter:
|
||||
description: All target filters
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipapermtargetfilter"]
|
||||
target:
|
||||
description: Optional DN to apply the permission to
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["ipapermtarget"]
|
||||
targetto:
|
||||
description: Optional DN subtree where an entry can be moved to
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["ipapermtargetto"]
|
||||
targetfrom:
|
||||
description: Optional DN subtree from where an entry can be moved
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["ipapermtargetfrom"]
|
||||
memberof:
|
||||
description: Target members of a group (sets memberOf targetfilter)
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
targetgroup:
|
||||
description: User group to apply permissions to (sets target)
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["targetgroup"]
|
||||
object_type:
|
||||
description: Type of IPA object (sets subtree and objectClass targetfilter)
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["type"]
|
||||
no_members:
|
||||
@@ -100,18 +115,24 @@ options:
|
||||
type: bool
|
||||
rename:
|
||||
description: Rename the permission object
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["new_name"]
|
||||
action:
|
||||
description: Work on permission or member privilege level.
|
||||
type: str
|
||||
choices: ["permission", "member"]
|
||||
default: permission
|
||||
required: false
|
||||
state:
|
||||
description: The state to ensure.
|
||||
type: str
|
||||
choices: ["present", "absent", "renamed"]
|
||||
default: present
|
||||
required: true
|
||||
required: false
|
||||
author:
|
||||
- Seth Kress (@kresss)
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -203,24 +224,26 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"],
|
||||
default=None, required=True),
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
required=True),
|
||||
# present
|
||||
right=dict(type="list", aliases=["ipapermright"], default=None,
|
||||
required=False,
|
||||
right=dict(type="list", elements="str", aliases=["ipapermright"],
|
||||
default=None, required=False,
|
||||
choices=["read", "search", "compare", "write", "add",
|
||||
"delete", "all"]),
|
||||
attrs=dict(type="list", default=None, required=False),
|
||||
attrs=dict(type="list", elements="str", default=None,
|
||||
required=False),
|
||||
# Note: bindtype has a default of permission for Adds.
|
||||
bindtype=dict(type="str", aliases=["ipapermbindruletype"],
|
||||
default=None, require=False, choices=["permission",
|
||||
default=None, required=False, choices=["permission",
|
||||
"all", "anonymous", "self"]),
|
||||
subtree=dict(type="str", aliases=["ipapermlocation"], default=None,
|
||||
required=False),
|
||||
extra_target_filter=dict(type="list", aliases=["filter",
|
||||
"extratargetfilter"], default=None,
|
||||
required=False),
|
||||
rawfilter=dict(type="list", aliases=["ipapermtargetfilter"],
|
||||
extra_target_filter=dict(type="list", elements="str",
|
||||
aliases=["filter", "extratargetfilter"],
|
||||
default=None, required=False),
|
||||
rawfilter=dict(type="list", elements="str",
|
||||
aliases=["ipapermtargetfilter"],
|
||||
default=None, required=False),
|
||||
target=dict(type="str", aliases=["ipapermtarget"], default=None,
|
||||
required=False),
|
||||
@@ -228,11 +251,12 @@ def main():
|
||||
default=None, required=False),
|
||||
targetfrom=dict(type="str", aliases=["ipapermtargetfrom"],
|
||||
default=None, required=False),
|
||||
memberof=dict(type="list", default=None, required=False),
|
||||
memberof=dict(type="list", elements="str", default=None,
|
||||
required=False),
|
||||
targetgroup=dict(type="str", default=None, required=False),
|
||||
object_type=dict(type="str", aliases=["type"], default=None,
|
||||
required=False),
|
||||
no_members=dict(type=bool, default=None, require=False),
|
||||
no_members=dict(type="bool", default=None, required=False),
|
||||
rename=dict(type="str", default=None, required=False,
|
||||
aliases=["new_name"]),
|
||||
action=dict(type="str", default="permission",
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
# Authors:
|
||||
# Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2020 Red Hat
|
||||
# Copyright (C) 2020-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -35,35 +36,46 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The list of privilege name strings.
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
description:
|
||||
description: Privilege description
|
||||
type: str
|
||||
required: false
|
||||
rename:
|
||||
description: Rename the privilege object.
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["new_name"]
|
||||
permission:
|
||||
description: Permissions to be added to the privilege.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
action:
|
||||
description: Work on privilege or member level.
|
||||
type: str
|
||||
choices: ["privilege", "member"]
|
||||
default: privilege
|
||||
required: false
|
||||
state:
|
||||
description: The state to ensure.
|
||||
type: str
|
||||
choices: ["present", "absent", "renamed"]
|
||||
default: present
|
||||
required: true
|
||||
required: false
|
||||
author:
|
||||
- Rafael Guterres Jeffman (@rjeffman)
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -134,13 +146,14 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"],
|
||||
default=None, required=True),
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
required=True),
|
||||
# present
|
||||
description=dict(required=False, type='str', default=None),
|
||||
rename=dict(required=False, type='str', default=None,
|
||||
aliases=["new_name"], ),
|
||||
permission=dict(required=False, type='list', default=None),
|
||||
permission=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
action=dict(type="str", default="privilege",
|
||||
choices=["member", "privilege"]),
|
||||
# state
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
# Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2019 Red Hat
|
||||
# Copyright (C) 2019-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,70 +33,107 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipapwpolicy
|
||||
short description: Manage FreeIPA pwpolicies
|
||||
short_description: Manage FreeIPA pwpolicies
|
||||
description: Manage FreeIPA pwpolicies
|
||||
extends_documentation_fragment:
|
||||
- ipamodule_base_docs
|
||||
options:
|
||||
ipaadmin_principal:
|
||||
description: The admin principal
|
||||
default: admin
|
||||
ipaadmin_password:
|
||||
description: The admin password
|
||||
required: false
|
||||
name:
|
||||
description: The group name
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["cn"]
|
||||
maxlife:
|
||||
description: Maximum password lifetime (in days)
|
||||
type: int
|
||||
description: Maximum password lifetime (in days). (int or "")
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["krbmaxpwdlife"]
|
||||
minlife:
|
||||
description: Minimum password lifetime (in hours)
|
||||
type: int
|
||||
description: Minimum password lifetime (in hours). (int or "")
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["krbminpwdlife"]
|
||||
history:
|
||||
description: Password history size
|
||||
type: int
|
||||
description: Password history size. (int or "")
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["krbpwdhistorylength"]
|
||||
minclasses:
|
||||
description: Minimum number of character classes
|
||||
type: int
|
||||
description: Minimum number of character classes. (int or "")
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["krbpwdmindiffchars"]
|
||||
minlength:
|
||||
description: Minimum length of password
|
||||
type: int
|
||||
description: Minimum length of password. (int or "")
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["krbpwdminlength"]
|
||||
priority:
|
||||
description: Priority of the policy (higher number means lower priority)
|
||||
type: int
|
||||
description: >
|
||||
Priority of the policy (higher number means lower priority). (int or "")
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["cospriority"]
|
||||
maxfail:
|
||||
description: Consecutive failures before lockout
|
||||
type: int
|
||||
description: Consecutive failures before lockout. (int or "")
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["krbpwdmaxfailure"]
|
||||
failinterval:
|
||||
description: Period after which failure count will be reset (seconds)
|
||||
type: int
|
||||
description: >
|
||||
Period after which failure count will be reset (seconds). (int or "")
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["krbpwdfailurecountinterval"]
|
||||
lockouttime:
|
||||
description: Period for which lockout is enforced (seconds)
|
||||
type: int
|
||||
description: Period for which lockout is enforced (seconds). (int or "")
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["krbpwdlockoutduration"]
|
||||
maxrepeat:
|
||||
description: >
|
||||
Maximum number of same consecutive characters.
|
||||
Requires IPA 4.9+. (int or "")
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["ipapwdmaxrepeat"]
|
||||
maxsequence:
|
||||
description: >
|
||||
The maximum length of monotonic character sequences (abcd).
|
||||
Requires IPA 4.9+. (int or "")
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["ipapwdmaxsequence"]
|
||||
dictcheck:
|
||||
description: >
|
||||
Check if the password is a dictionary word.
|
||||
Requires IPA 4.9+. (bool or "")
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["ipapwdictcheck"]
|
||||
usercheck:
|
||||
description: >
|
||||
Check if the password contains the username.
|
||||
Requires IPA 4.9+. (bool or "")
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["ipapwdusercheck"]
|
||||
gracelimit:
|
||||
description: >
|
||||
Number of LDAP authentications allowed after expiration.
|
||||
Requires IPA 4.10.1+. (int or "")
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["passwordgracelimit"]
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent"]
|
||||
author:
|
||||
- Thomas Woerner
|
||||
- Thomas Woerner (@t-woerner)
|
||||
- Rafael Guterres Jeffman (@rjeffman)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -115,7 +153,7 @@ RETURN = """
|
||||
"""
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa
|
||||
IPAAnsibleModule, compare_args_ipa, boolean
|
||||
|
||||
|
||||
def find_pwpolicy(module, name):
|
||||
@@ -135,8 +173,10 @@ def find_pwpolicy(module, name):
|
||||
return None
|
||||
|
||||
|
||||
def gen_args(maxlife, minlife, history, minclasses, minlength, priority,
|
||||
maxfail, failinterval, lockouttime):
|
||||
def gen_args(module,
|
||||
maxlife, minlife, history, minclasses, minlength, priority,
|
||||
maxfail, failinterval, lockouttime, maxrepeat, maxsequence,
|
||||
dictcheck, usercheck, gracelimit):
|
||||
_args = {}
|
||||
if maxlife is not None:
|
||||
_args["krbmaxpwdlife"] = maxlife
|
||||
@@ -156,34 +196,89 @@ def gen_args(maxlife, minlife, history, minclasses, minlength, priority,
|
||||
_args["krbpwdfailurecountinterval"] = failinterval
|
||||
if lockouttime is not None:
|
||||
_args["krbpwdlockoutduration"] = lockouttime
|
||||
if maxrepeat is not None:
|
||||
_args["ipapwdmaxrepeat"] = maxrepeat
|
||||
if maxsequence is not None:
|
||||
_args["ipapwdmaxsequence"] = maxsequence
|
||||
if dictcheck is not None:
|
||||
if module.ipa_check_version("<", "4.9.10"):
|
||||
# Allowed values: "TRUE", "FALSE", ""
|
||||
_args["ipapwddictcheck"] = "TRUE" if dictcheck is True else \
|
||||
"FALSE" if dictcheck is False else dictcheck
|
||||
else:
|
||||
_args["ipapwddictcheck"] = dictcheck
|
||||
if usercheck is not None:
|
||||
if module.ipa_check_version("<", "4.9.10"):
|
||||
# Allowed values: "TRUE", "FALSE", ""
|
||||
_args["ipapwdusercheck"] = "TRUE" if usercheck is True else \
|
||||
"FALSE" if usercheck is False else usercheck
|
||||
else:
|
||||
_args["ipapwdusercheck"] = usercheck
|
||||
if gracelimit is not None:
|
||||
_args["passwordgracelimit"] = gracelimit
|
||||
|
||||
return _args
|
||||
|
||||
|
||||
def check_supported_params(
|
||||
module, maxrepeat, maxsequence, dictcheck, usercheck, gracelimit
|
||||
):
|
||||
# All password checking parameters were added by the same commit,
|
||||
# so we only need to test one of them.
|
||||
has_password_check = module.ipa_command_param_exists(
|
||||
"pwpolicy_add", "ipapwdmaxrepeat")
|
||||
# check if gracelimit is supported
|
||||
has_gracelimit = module.ipa_command_param_exists(
|
||||
"pwpolicy_add", "passwordgracelimit")
|
||||
|
||||
# If needed, report unsupported password checking paramteres
|
||||
if (
|
||||
not has_password_check
|
||||
and any([maxrepeat, maxsequence, dictcheck, usercheck])
|
||||
):
|
||||
module.fail_json(
|
||||
msg="Your IPA version does not support arguments: "
|
||||
"maxrepeat, maxsequence, dictcheck, usercheck.")
|
||||
|
||||
if not has_gracelimit and gracelimit is not None:
|
||||
module.fail_json(
|
||||
msg="Your IPA version does not support 'gracelimit'.")
|
||||
|
||||
|
||||
def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"], default=None,
|
||||
required=False),
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
default=None, required=False),
|
||||
# present
|
||||
|
||||
maxlife=dict(type="int", aliases=["krbmaxpwdlife"], default=None),
|
||||
minlife=dict(type="int", aliases=["krbminpwdlife"], default=None),
|
||||
history=dict(type="int", aliases=["krbpwdhistorylength"],
|
||||
maxlife=dict(type="str", aliases=["krbmaxpwdlife"], default=None),
|
||||
minlife=dict(type="str", aliases=["krbminpwdlife"], default=None),
|
||||
history=dict(type="str", aliases=["krbpwdhistorylength"],
|
||||
default=None),
|
||||
minclasses=dict(type="int", aliases=["krbpwdmindiffchars"],
|
||||
minclasses=dict(type="str", aliases=["krbpwdmindiffchars"],
|
||||
default=None),
|
||||
minlength=dict(type="int", aliases=["krbpwdminlength"],
|
||||
minlength=dict(type="str", aliases=["krbpwdminlength"],
|
||||
default=None),
|
||||
priority=dict(type="int", aliases=["cospriority"], default=None),
|
||||
maxfail=dict(type="int", aliases=["krbpwdmaxfailure"],
|
||||
priority=dict(type="str", aliases=["cospriority"], default=None),
|
||||
maxfail=dict(type="str", aliases=["krbpwdmaxfailure"],
|
||||
default=None),
|
||||
failinterval=dict(type="int",
|
||||
failinterval=dict(type="str",
|
||||
aliases=["krbpwdfailurecountinterval"],
|
||||
default=None),
|
||||
lockouttime=dict(type="int", aliases=["krbpwdlockoutduration"],
|
||||
lockouttime=dict(type="str", aliases=["krbpwdlockoutduration"],
|
||||
default=None),
|
||||
maxrepeat=dict(type="str", aliases=["ipapwdmaxrepeat"],
|
||||
default=None),
|
||||
maxsequence=dict(type="str", aliases=["ipapwdmaxsequence"],
|
||||
default=None),
|
||||
dictcheck=dict(type="str", aliases=["ipapwdictcheck"],
|
||||
default=None),
|
||||
usercheck=dict(type="str", aliases=["ipapwdusercheck"],
|
||||
default=None),
|
||||
gracelimit=dict(type="str", aliases=["passwordgracelimit"],
|
||||
default=None),
|
||||
# state
|
||||
state=dict(type="str", default="present",
|
||||
choices=["present", "absent"]),
|
||||
@@ -208,6 +303,11 @@ def main():
|
||||
maxfail = ansible_module.params_get("maxfail")
|
||||
failinterval = ansible_module.params_get("failinterval")
|
||||
lockouttime = ansible_module.params_get("lockouttime")
|
||||
maxrepeat = ansible_module.params_get("maxrepeat")
|
||||
maxsequence = ansible_module.params_get("maxsequence")
|
||||
dictcheck = ansible_module.params_get("dictcheck")
|
||||
usercheck = ansible_module.params_get("usercheck")
|
||||
gracelimit = ansible_module.params_get("gracelimit")
|
||||
|
||||
# state
|
||||
state = ansible_module.params_get("state")
|
||||
@@ -231,10 +331,52 @@ def main():
|
||||
msg="'global_policy' can not be made absent.")
|
||||
invalid = ["maxlife", "minlife", "history", "minclasses",
|
||||
"minlength", "priority", "maxfail", "failinterval",
|
||||
"lockouttime"]
|
||||
"lockouttime", "maxrepeat", "maxsequence", "dictcheck",
|
||||
"usercheck", "gracelimit"]
|
||||
|
||||
ansible_module.params_fail_used_invalid(invalid, state)
|
||||
|
||||
# Ensure parameter values are valid and have proper type.
|
||||
def int_or_empty_param(value, param):
|
||||
if value is not None and value != "":
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
ansible_module.fail_json(
|
||||
msg="Invalid value '%s' for argument '%s'" % (value, param)
|
||||
)
|
||||
return value
|
||||
|
||||
maxlife = int_or_empty_param(maxlife, "maxlife")
|
||||
minlife = int_or_empty_param(minlife, "minlife")
|
||||
history = int_or_empty_param(history, "history")
|
||||
minclasses = int_or_empty_param(minclasses, "minclasses")
|
||||
minlength = int_or_empty_param(minlength, "minlength")
|
||||
priority = int_or_empty_param(priority, "priority")
|
||||
maxfail = int_or_empty_param(maxfail, "maxfail")
|
||||
failinterval = int_or_empty_param(failinterval, "failinterval")
|
||||
lockouttime = int_or_empty_param(lockouttime, "lockouttime")
|
||||
maxrepeat = int_or_empty_param(maxrepeat, "maxrepeat")
|
||||
maxsequence = int_or_empty_param(maxsequence, "maxsequence")
|
||||
gracelimit = int_or_empty_param(gracelimit, "gracelimit")
|
||||
|
||||
def bool_or_empty_param(value, param): # pylint: disable=R1710
|
||||
if value is None or value == "":
|
||||
return value
|
||||
try:
|
||||
return boolean(value)
|
||||
except TypeError as terr:
|
||||
ansible_module.fail_json(msg="Param '%s': %s" % (param, str(terr)))
|
||||
|
||||
dictcheck = bool_or_empty_param(dictcheck, "dictcheck")
|
||||
usercheck = bool_or_empty_param(usercheck, "usercheck")
|
||||
|
||||
# Ensure gracelimit has proper limit.
|
||||
if gracelimit:
|
||||
if gracelimit < -1:
|
||||
ansible_module.fail_json(
|
||||
msg="'gracelimit' must be no less than -1")
|
||||
|
||||
# Init
|
||||
|
||||
changed = False
|
||||
@@ -242,6 +384,11 @@ def main():
|
||||
|
||||
with ansible_module.ipa_connect():
|
||||
|
||||
check_supported_params(
|
||||
ansible_module, maxrepeat, maxsequence, dictcheck, usercheck,
|
||||
gracelimit
|
||||
)
|
||||
|
||||
commands = []
|
||||
|
||||
for name in names:
|
||||
@@ -251,9 +398,11 @@ def main():
|
||||
# Create command
|
||||
if state == "present":
|
||||
# Generate args
|
||||
args = gen_args(maxlife, minlife, history, minclasses,
|
||||
args = gen_args(ansible_module,
|
||||
maxlife, minlife, history, minclasses,
|
||||
minlength, priority, maxfail, failinterval,
|
||||
lockouttime)
|
||||
lockouttime, maxrepeat, maxsequence, dictcheck,
|
||||
usercheck, gracelimit)
|
||||
|
||||
# Found the pwpolicy
|
||||
if res_find is not None:
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
|
||||
# Authors:
|
||||
# Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2020 Red Hat
|
||||
# Copyright (C) 2020-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -34,47 +35,71 @@ 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
|
||||
options:
|
||||
role:
|
||||
name:
|
||||
description: The list of role name strings.
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
description:
|
||||
description: A description for the role.
|
||||
type: str
|
||||
required: false
|
||||
rename:
|
||||
description: Rename the role object.
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["new_name"]
|
||||
privilege:
|
||||
description: List of privileges
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
user:
|
||||
description: List of users.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
group:
|
||||
description: List of groups.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
host:
|
||||
description: List of hosts.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
hostgroup:
|
||||
description: List of hostgroups.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
service:
|
||||
description: List of services.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
action:
|
||||
description: Work on role or member level.
|
||||
type: str
|
||||
choices: ["role", "member"]
|
||||
default: role
|
||||
required: false
|
||||
state:
|
||||
description: The state to ensure.
|
||||
type: str
|
||||
choices: ["present", "absent", "renamed"]
|
||||
default: present
|
||||
required: true
|
||||
required: false
|
||||
author:
|
||||
- Rafael Guterres Jeffman (@rjeffman)
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -394,19 +419,25 @@ def create_module():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# generalgroups
|
||||
name=dict(type="list", aliases=["cn"], default=None,
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
required=True),
|
||||
# present
|
||||
description=dict(required=False, type="str", default=None),
|
||||
rename=dict(required=False, type="str", default=None,
|
||||
aliases=["new_name"]),
|
||||
# members
|
||||
privilege=dict(required=False, type='list', default=None),
|
||||
user=dict(required=False, type='list', default=None),
|
||||
group=dict(required=False, type='list', default=None),
|
||||
host=dict(required=False, type='list', default=None),
|
||||
hostgroup=dict(required=False, type='list', default=None),
|
||||
service=dict(required=False, type='list', default=None),
|
||||
privilege=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
user=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
group=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
host=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
hostgroup=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
service=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
|
||||
# state
|
||||
action=dict(type="str", default="role",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2020 Red Hat
|
||||
# Copyright (C) 2020-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,33 +32,43 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The list of selfservice name strings.
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["aciname"]
|
||||
permission:
|
||||
description: Permissions to grant (read, write). Default is write.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["permissions"]
|
||||
attribute:
|
||||
description: Attribute list to which the selfservice applies
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["attrs"]
|
||||
action:
|
||||
description: Work on selfservice or member level.
|
||||
type: str
|
||||
choices: ["selfservice", "member"]
|
||||
default: selfservice
|
||||
required: false
|
||||
state:
|
||||
description: The state to ensure.
|
||||
type: str
|
||||
choices: ["present", "absent"]
|
||||
default: present
|
||||
required: true
|
||||
required: false
|
||||
author:
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -130,13 +140,13 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["aciname"], default=None,
|
||||
name=dict(type="list", elements="str", aliases=["aciname"],
|
||||
required=True),
|
||||
# present
|
||||
permission=dict(required=False, type='list',
|
||||
permission=dict(required=False, type='list', elements="str",
|
||||
aliases=["permissions"], default=None),
|
||||
attribute=dict(required=False, type='list', aliases=["attrs"],
|
||||
default=None),
|
||||
attribute=dict(required=False, type='list', elements="str",
|
||||
aliases=["attrs"], default=None),
|
||||
action=dict(type="str", default="selfservice",
|
||||
choices=["member", "selfservice"]),
|
||||
# state
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2021 Red Hat
|
||||
# Copyright (C) 2021-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,73 +32,79 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The list of server name strings.
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
location:
|
||||
description: |
|
||||
The server location string.
|
||||
"" for location reset.
|
||||
Only in state: present.
|
||||
The server DNS location.
|
||||
Only available with 'state: present'.
|
||||
Use "" for location reset.
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["ipalocation_location"]
|
||||
service_weight:
|
||||
description: |
|
||||
Weight for server services
|
||||
Values 0 to 65535, -1 for weight reset.
|
||||
Only in state: present.
|
||||
Only available with 'state: present'.
|
||||
required: false
|
||||
type: int
|
||||
aliases: ["ipaserviceweight"]
|
||||
hidden:
|
||||
description: |
|
||||
Set hidden state of a server.
|
||||
Only in state: present.
|
||||
Only available with 'state: present'.
|
||||
required: false
|
||||
type: bool
|
||||
no_members:
|
||||
description: |
|
||||
Suppress processing of membership attributes
|
||||
Only in state: present.
|
||||
Only available with 'state: present'.
|
||||
required: false
|
||||
type: bool
|
||||
delete_continue:
|
||||
description: |
|
||||
Continuous mode: Don't stop on errors.
|
||||
Only in state: absent.
|
||||
Only available with 'state: absent'.
|
||||
required: false
|
||||
type: bool
|
||||
aliases: ["continue"]
|
||||
ignore_last_of_role:
|
||||
description: |
|
||||
Skip a check whether the last CA master or DNS server is removed.
|
||||
Only in state: absent.
|
||||
Only available with 'state: absent'.
|
||||
required: false
|
||||
type: bool
|
||||
ignore_topology_disconnect:
|
||||
description: |
|
||||
Ignore topology connectivity problems after removal.
|
||||
Only in state: absent.
|
||||
Only available with 'state: absent'.
|
||||
required: false
|
||||
type: bool
|
||||
force:
|
||||
description: |
|
||||
Force server removal even if it does not exist.
|
||||
Will always result in changed.
|
||||
Only in state: absent.
|
||||
Only available with 'state: absent'.
|
||||
required: false
|
||||
type: bool
|
||||
state:
|
||||
description: The state to ensure.
|
||||
type: str
|
||||
choices: ["present", "absent"]
|
||||
default: present
|
||||
required: true
|
||||
required: false
|
||||
author:
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -244,8 +250,8 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"],
|
||||
default=None, required=True),
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
required=True),
|
||||
# present
|
||||
location=dict(required=False, type='str',
|
||||
aliases=["ipalocation_location"], default=None),
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Authors:
|
||||
# Denis Karpelevich <dkarpele@redhat.com>
|
||||
# Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2019 Red Hat
|
||||
# Copyright (C) 2019-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -33,30 +35,157 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The service to manage
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["service"]
|
||||
services:
|
||||
description: The list of service dicts.
|
||||
type: list
|
||||
elements: dict
|
||||
suboptions:
|
||||
name:
|
||||
description: The service to manage
|
||||
type: str
|
||||
required: true
|
||||
aliases: ["service"]
|
||||
certificate:
|
||||
description: Base-64 encoded service certificate.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["usercertificate"]
|
||||
pac_type:
|
||||
description: Supported PAC type.
|
||||
required: false
|
||||
choices: ["MS-PAC", "PAD", "NONE", ""]
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["pac_type", "ipakrbauthzdata"]
|
||||
auth_ind:
|
||||
description: Defines an allow list for Authentication Indicators.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
choices: ["otp", "radius", "pkinit", "hardened", "idp", ""]
|
||||
aliases: ["krbprincipalauthind"]
|
||||
skip_host_check:
|
||||
description: Skip checking if host object exists.
|
||||
required: False
|
||||
type: bool
|
||||
force:
|
||||
description: Force principal name even if host is not in DNS.
|
||||
required: False
|
||||
type: bool
|
||||
requires_pre_auth:
|
||||
description: Pre-authentication is required for the service.
|
||||
required: false
|
||||
type: bool
|
||||
aliases: ["ipakrbrequirespreauth"]
|
||||
ok_as_delegate:
|
||||
description: Client credentials may be delegated to the service.
|
||||
required: false
|
||||
type: bool
|
||||
aliases: ["ipakrbokasdelegate"]
|
||||
ok_to_auth_as_delegate:
|
||||
description: Allow service to authenticate on behalf of a client.
|
||||
required: false
|
||||
type: bool
|
||||
aliases: ["ipakrboktoauthasdelegate"]
|
||||
principal:
|
||||
description: List of principal aliases for the service.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["krbprincipalname"]
|
||||
smb:
|
||||
description: Add a SMB service.
|
||||
required: false
|
||||
type: bool
|
||||
netbiosname:
|
||||
description: NETBIOS name for the SMB service.
|
||||
required: false
|
||||
type: str
|
||||
host:
|
||||
description: Host that can manage the service.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["managedby_host"]
|
||||
allow_create_keytab_user:
|
||||
description: Users allowed to create a keytab of this host.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_write_keys_user"]
|
||||
allow_create_keytab_group:
|
||||
description: Groups allowed to create a keytab of this host.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_write_keys_group"]
|
||||
allow_create_keytab_host:
|
||||
description: Hosts allowed to create a keytab of this host.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_write_keys_host"]
|
||||
allow_create_keytab_hostgroup:
|
||||
description: Host group allowed to create a keytab of this host.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_write_keys_hostgroup"]
|
||||
allow_retrieve_keytab_user:
|
||||
description: User allowed to retrieve a keytab of this host.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_read_keys_user"]
|
||||
allow_retrieve_keytab_group:
|
||||
description: Groups allowed to retrieve a keytab of this host.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_read_keys_group"]
|
||||
allow_retrieve_keytab_host:
|
||||
description: Hosts allowed to retrieve a keytab of this host.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_read_keys_host"]
|
||||
allow_retrieve_keytab_hostgroup:
|
||||
description: Host groups allowed to retrieve a keytab of this host.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_read_keys_hostgroup"]
|
||||
certificate:
|
||||
description: Base-64 encoded service certificate.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["usercertificate"]
|
||||
pac_type:
|
||||
description: Supported PAC type.
|
||||
required: false
|
||||
choices: ["MS-PAC", "PAD", "NONE", ""]
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["pac_type", "ipakrbauthzdata"]
|
||||
auth_ind:
|
||||
description: Defines a whitelist for Authentication Indicators.
|
||||
description: Defines an allow list for Authentication Indicators.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
choices: ["otp", "radius", "pkinit", "hardened", ""]
|
||||
choices: ["otp", "radius", "pkinit", "hardened", "idp", ""]
|
||||
aliases: ["krbprincipalauthind"]
|
||||
skip_host_check:
|
||||
description: Skip checking if host object exists.
|
||||
@@ -70,24 +199,22 @@ options:
|
||||
description: Pre-authentication is required for the service.
|
||||
required: false
|
||||
type: bool
|
||||
default: False
|
||||
aliases: ["ipakrbrequirespreauth"]
|
||||
ok_as_delegate:
|
||||
description: Client credentials may be delegated to the service.
|
||||
required: false
|
||||
type: bool
|
||||
default: False
|
||||
aliases: ["ipakrbokasdelegate"]
|
||||
ok_to_auth_as_delegate:
|
||||
description: Allow service to authenticate on behalf of a client.
|
||||
required: false
|
||||
type: bool
|
||||
default: False
|
||||
aliases: ["ipakrboktoauthasdelegate"]
|
||||
principal:
|
||||
description: List of principal aliases for the service.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["krbprincipalname"]
|
||||
smb:
|
||||
description: Add a SMB service.
|
||||
@@ -101,63 +228,75 @@ options:
|
||||
description: Host that can manage the service.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["managedby_host"]
|
||||
allow_create_keytab_user:
|
||||
description: Users allowed to create a keytab of this host.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_write_keys_user"]
|
||||
allow_create_keytab_group:
|
||||
description: Groups allowed to create a keytab of this host.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_write_keys_group"]
|
||||
allow_create_keytab_host:
|
||||
description: Hosts allowed to create a keytab of this host.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_write_keys_host"]
|
||||
allow_create_keytab_hostgroup:
|
||||
description: Host group allowed to create a keytab of this host.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_write_keys_hostgroup"]
|
||||
allow_retrieve_keytab_user:
|
||||
description: User allowed to retrieve a keytab of this host.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_read_keys_user"]
|
||||
allow_retrieve_keytab_group:
|
||||
description: Groups allowed to retrieve a keytab of this host.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_read_keys_group"]
|
||||
allow_retrieve_keytab_host:
|
||||
description: Hosts allowed to retrieve a keytab of this host.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_read_keys_host"]
|
||||
allow_retrieve_keytab_hostgroup:
|
||||
description: Host groups allowed to retrieve a keytab of this host.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["ipaallowedtoperform_read_keys_hostgroup"]
|
||||
continue:
|
||||
delete_continue:
|
||||
description:
|
||||
Continuous mode. Don't stop on errors. Valid only if `state` is `absent`.
|
||||
required: false
|
||||
default: True
|
||||
type: bool
|
||||
aliases: ["continue"]
|
||||
action:
|
||||
description: Work on service or member level
|
||||
type: str
|
||||
default: service
|
||||
choices: ["member", "service"]
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent", "disabled"]
|
||||
author:
|
||||
- Rafael Jeffman
|
||||
- Rafael Guterres Jeffman (@rjeffman)
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -222,6 +361,15 @@ EXAMPLES = """
|
||||
- host1.example.com
|
||||
- host2.example.com
|
||||
action: member
|
||||
|
||||
# Ensure multiple services are present.
|
||||
- ipaservice:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
services:
|
||||
- name: HTTP/www.example.com
|
||||
host:
|
||||
- host1.example.com
|
||||
- name: HTTP/www.service.com
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
@@ -231,6 +379,9 @@ from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, encode_certificate, \
|
||||
gen_add_del_lists, gen_add_list, gen_intersection_list, ipalib_errors, \
|
||||
api_get_realm, to_text
|
||||
from ansible.module_utils import six
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
|
||||
|
||||
def find_service(module, name):
|
||||
@@ -304,8 +455,9 @@ def check_parameters(module, state, action, names):
|
||||
'allow_retrieve_keytab_hostgroup']
|
||||
|
||||
if state == 'present':
|
||||
if len(names) != 1:
|
||||
module.fail_json(msg="Only one service can be added at a time.")
|
||||
if names is not None and len(names) != 1:
|
||||
module.fail_json(msg="Only one service can be added at a time "
|
||||
"using 'name'.")
|
||||
|
||||
if action == 'service':
|
||||
invalid = ['delete_continue']
|
||||
@@ -321,9 +473,6 @@ def check_parameters(module, state, action, names):
|
||||
invalid.append('delete_continue')
|
||||
|
||||
elif state == 'absent':
|
||||
if len(names) < 1:
|
||||
module.fail_json(msg="No name given.")
|
||||
|
||||
if action == "service":
|
||||
invalid.extend(invalid_not_member)
|
||||
else:
|
||||
@@ -342,65 +491,96 @@ def check_parameters(module, state, action, names):
|
||||
module.params_fail_used_invalid(invalid, state, action)
|
||||
|
||||
|
||||
def check_authind(module, auth_ind):
|
||||
_invalid = module.ipa_command_invalid_param_choices(
|
||||
"service_add", "krbprincipalauthind", auth_ind)
|
||||
if _invalid:
|
||||
module.fail_json(
|
||||
msg="The use of krbprincipalauthind '%s' is not supported "
|
||||
"by your IPA version" % "','".join(_invalid))
|
||||
|
||||
|
||||
def init_ansible_module():
|
||||
service_spec = dict(
|
||||
# service attributesstr
|
||||
certificate=dict(type="list", elements="str",
|
||||
aliases=['usercertificate'],
|
||||
default=None, required=False),
|
||||
principal=dict(type="list", elements="str",
|
||||
aliases=["krbprincipalname"], default=None),
|
||||
smb=dict(type="bool", required=False),
|
||||
netbiosname=dict(type="str", required=False),
|
||||
pac_type=dict(type="list", elements="str",
|
||||
aliases=["ipakrbauthzdata"],
|
||||
choices=["MS-PAC", "PAD", "NONE", ""]),
|
||||
auth_ind=dict(type="list", elements="str",
|
||||
aliases=["krbprincipalauthind"],
|
||||
choices=["otp", "radius", "pkinit", "hardened", "idp",
|
||||
""]),
|
||||
skip_host_check=dict(type="bool"),
|
||||
force=dict(type="bool"),
|
||||
requires_pre_auth=dict(
|
||||
type="bool", aliases=["ipakrbrequirespreauth"]),
|
||||
ok_as_delegate=dict(type="bool", aliases=["ipakrbokasdelegate"]),
|
||||
ok_to_auth_as_delegate=dict(type="bool",
|
||||
aliases=["ipakrboktoauthasdelegate"]),
|
||||
host=dict(type="list", elements="str", aliases=["managedby_host"],
|
||||
required=False),
|
||||
allow_create_keytab_user=dict(
|
||||
type="list", elements="str", required=False, no_log=False,
|
||||
aliases=['ipaallowedtoperform_write_keys_user']),
|
||||
allow_retrieve_keytab_user=dict(
|
||||
type="list", elements="str", required=False, no_log=False,
|
||||
aliases=['ipaallowedtoperform_read_keys_user']),
|
||||
allow_create_keytab_group=dict(
|
||||
type="list", elements="str", required=False, no_log=False,
|
||||
aliases=['ipaallowedtoperform_write_keys_group']),
|
||||
allow_retrieve_keytab_group=dict(
|
||||
type="list", elements="str", required=False, no_log=False,
|
||||
aliases=['ipaallowedtoperform_read_keys_group']),
|
||||
allow_create_keytab_host=dict(
|
||||
type="list", elements="str", required=False, no_log=False,
|
||||
aliases=['ipaallowedtoperform_write_keys_host']),
|
||||
allow_retrieve_keytab_host=dict(
|
||||
type="list", elements="str", required=False, no_log=False,
|
||||
aliases=['ipaallowedtoperform_read_keys_host']),
|
||||
allow_create_keytab_hostgroup=dict(
|
||||
type="list", elements="str", required=False, no_log=False,
|
||||
aliases=['ipaallowedtoperform_write_keys_hostgroup']),
|
||||
allow_retrieve_keytab_hostgroup=dict(
|
||||
type="list", elements="str", required=False, no_log=False,
|
||||
aliases=['ipaallowedtoperform_read_keys_hostgroup']),
|
||||
delete_continue=dict(type="bool", required=False,
|
||||
aliases=['continue']),
|
||||
)
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["service"], default=None,
|
||||
required=True),
|
||||
# service attributesstr
|
||||
certificate=dict(type="list", aliases=['usercertificate'],
|
||||
default=None, required=False),
|
||||
principal=dict(type="list", aliases=["krbprincipalname"],
|
||||
default=None),
|
||||
smb=dict(type="bool", required=False),
|
||||
netbiosname=dict(type="str", required=False),
|
||||
pac_type=dict(type="list", aliases=["ipakrbauthzdata"],
|
||||
choices=["MS-PAC", "PAD", "NONE", ""]),
|
||||
auth_ind=dict(type="list",
|
||||
aliases=["krbprincipalauthind"],
|
||||
choices=["otp", "radius", "pkinit", "hardened", ""]),
|
||||
skip_host_check=dict(type="bool"),
|
||||
force=dict(type="bool"),
|
||||
requires_pre_auth=dict(
|
||||
type="bool", aliases=["ipakrbrequirespreauth"]),
|
||||
ok_as_delegate=dict(type="bool", aliases=["ipakrbokasdelegate"]),
|
||||
ok_to_auth_as_delegate=dict(type="bool",
|
||||
aliases=["ipakrboktoauthasdelegate"]),
|
||||
host=dict(type="list", aliases=["managedby_host"], required=False),
|
||||
allow_create_keytab_user=dict(
|
||||
type="list", required=False,
|
||||
aliases=['ipaallowedtoperform_write_keys_user']),
|
||||
allow_retrieve_keytab_user=dict(
|
||||
type="list", required=False,
|
||||
aliases=['ipaallowedtoperform_read_keys_user']),
|
||||
allow_create_keytab_group=dict(
|
||||
type="list", required=False,
|
||||
aliases=['ipaallowedtoperform_write_keys_group']),
|
||||
allow_retrieve_keytab_group=dict(
|
||||
type="list", required=False,
|
||||
aliases=['ipaallowedtoperform_read_keys_group']),
|
||||
allow_create_keytab_host=dict(
|
||||
type="list", required=False,
|
||||
aliases=['ipaallowedtoperform_write_keys_host']),
|
||||
allow_retrieve_keytab_host=dict(
|
||||
type="list", required=False,
|
||||
aliases=['ipaallowedtoperform_read_keys_host']),
|
||||
allow_create_keytab_hostgroup=dict(
|
||||
type="list", required=False,
|
||||
aliases=['ipaallowedtoperform_write_keys_hostgroup']),
|
||||
allow_retrieve_keytab_hostgroup=dict(
|
||||
type="list", required=False,
|
||||
aliases=['ipaallowedtoperform_read_keys_hostgroup']),
|
||||
delete_continue=dict(type="bool", required=False,
|
||||
aliases=['continue']),
|
||||
name=dict(type="list", elements="str", aliases=["service"],
|
||||
default=None, required=False),
|
||||
services=dict(type="list",
|
||||
default=None,
|
||||
options=dict(
|
||||
# Here name is a simple string
|
||||
name=dict(type="str", required=True,
|
||||
aliases=["service"]),
|
||||
# Add service specific parameters
|
||||
**service_spec
|
||||
),
|
||||
elements='dict',
|
||||
required=False),
|
||||
# action
|
||||
action=dict(type="str", default="service",
|
||||
choices=["member", "service"]),
|
||||
# state
|
||||
state=dict(type="str", default="present",
|
||||
choices=["present", "absent", "disabled"]),
|
||||
|
||||
# Add service specific parameters for simple use case
|
||||
**service_spec
|
||||
),
|
||||
mutually_exclusive=[["name", "services"]],
|
||||
required_one_of=[["name", "services"]],
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
@@ -416,10 +596,17 @@ def main():
|
||||
|
||||
# general
|
||||
names = ansible_module.params_get("name")
|
||||
services = ansible_module.params_get("services")
|
||||
|
||||
# service attributes
|
||||
principal = ansible_module.params_get("principal")
|
||||
certificate = ansible_module.params_get("certificate")
|
||||
# Any leading or trailing whitespace is removed while adding the
|
||||
# certificate with serive_add_cert. To be able to compare the results
|
||||
# from service_show with the given certificates we have to remove the
|
||||
# white space also.
|
||||
if certificate is not None:
|
||||
certificate = [cert.strip() for cert in certificate]
|
||||
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")
|
||||
@@ -442,8 +629,16 @@ def main():
|
||||
state = ansible_module.params_get("state")
|
||||
|
||||
# check parameters
|
||||
if (names is None or len(names) < 1) and \
|
||||
(services is None or len(services) < 1):
|
||||
ansible_module.fail_json(msg="At least one name or services is "
|
||||
"required")
|
||||
check_parameters(ansible_module, state, action, names)
|
||||
|
||||
# Use services if names is None
|
||||
if services is not None:
|
||||
names = services
|
||||
|
||||
# Init
|
||||
|
||||
changed = False
|
||||
@@ -457,11 +652,50 @@ def main():
|
||||
if skip_host_check and not has_skip_host_check:
|
||||
ansible_module.fail_json(
|
||||
msg="Skipping host check is not supported by your IPA version")
|
||||
check_authind(ansible_module, auth_ind)
|
||||
|
||||
commands = []
|
||||
keytab_members = ["user", "group", "host", "hostgroup"]
|
||||
service_set = set()
|
||||
|
||||
for name in names:
|
||||
for service in names:
|
||||
if isinstance(service, dict):
|
||||
name = service.get("name")
|
||||
if name in service_set:
|
||||
ansible_module.fail_json(
|
||||
msg="service '%s' is used more than once" % name)
|
||||
service_set.add(name)
|
||||
principal = service.get("principal")
|
||||
certificate = service.get("certificate")
|
||||
# Any leading or trailing whitespace is removed while adding
|
||||
# the certificate with serive_add_cert. To be able to compare
|
||||
# the results from service_show with the given certificates
|
||||
# we have to remove the white space also.
|
||||
if certificate is not None:
|
||||
certificate = [cert.strip() for cert in certificate]
|
||||
pac_type = service.get("pac_type")
|
||||
auth_ind = service.get("auth_ind")
|
||||
check_authind(ansible_module, auth_ind)
|
||||
skip_host_check = service.get("skip_host_check")
|
||||
if skip_host_check and not has_skip_host_check:
|
||||
ansible_module.fail_json(
|
||||
msg="Skipping host check is not supported by your IPA "
|
||||
"version")
|
||||
force = service.get("force")
|
||||
requires_pre_auth = service.get("requires_pre_auth")
|
||||
ok_as_delegate = service.get("ok_as_delegate")
|
||||
ok_to_auth_as_delegate = service.get("ok_to_auth_as_delegate")
|
||||
smb = service.get("smb")
|
||||
netbiosname = service.get("netbiosname")
|
||||
host = service.get("host")
|
||||
|
||||
delete_continue = service.get("delete_continue")
|
||||
|
||||
elif isinstance(service, (str, unicode)):
|
||||
name = service
|
||||
else:
|
||||
ansible_module.fail_json(msg="Service '%s' is not valid" %
|
||||
repr(service))
|
||||
res_find = find_service(ansible_module, name)
|
||||
res_principals = []
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipaservicedelegationrule
|
||||
short description: Manage FreeIPA servicedelegationrule
|
||||
short_description: Manage FreeIPA servicedelegationrule
|
||||
description: |
|
||||
Manage FreeIPA servicedelegationrule and servicedelegationrule members
|
||||
extends_documentation_fragment:
|
||||
@@ -40,6 +40,8 @@ extends_documentation_fragment:
|
||||
options:
|
||||
name:
|
||||
description: The list of servicedelegationrule name strings.
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
principal:
|
||||
@@ -49,22 +51,30 @@ options:
|
||||
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.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
target:
|
||||
description: |
|
||||
The list of service delegation targets.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
aliases: ["servicedelegationtarget"]
|
||||
action:
|
||||
description: Work on servicedelegationrule or member level.
|
||||
type: str
|
||||
choices: ["servicedelegationrule", "member"]
|
||||
default: servicedelegationrule
|
||||
required: false
|
||||
state:
|
||||
description: The state to ensure.
|
||||
type: str
|
||||
choices: ["present", "absent"]
|
||||
default: present
|
||||
required: true
|
||||
required: false
|
||||
author:
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -161,11 +171,12 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"], default=None,
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
required=True),
|
||||
# present
|
||||
principal=dict(required=False, type='list', default=None),
|
||||
target=dict(required=False, type='list',
|
||||
principal=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
target=dict(required=False, type='list', elements="str",
|
||||
aliases=["servicedelegationtarget"], default=None),
|
||||
|
||||
action=dict(type="str", default="servicedelegationrule",
|
||||
|
||||
@@ -32,7 +32,7 @@ ANSIBLE_METADATA = {
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ipaservicedelegationtarget
|
||||
short description: Manage FreeIPA servicedelegationtarget
|
||||
short_description: Manage FreeIPA servicedelegationtarget
|
||||
description: |
|
||||
Manage FreeIPA servicedelegationtarget and servicedelegationtarget members
|
||||
extends_documentation_fragment:
|
||||
@@ -40,6 +40,8 @@ extends_documentation_fragment:
|
||||
options:
|
||||
name:
|
||||
description: The list of servicedelegationtarget name strings.
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
principal:
|
||||
@@ -49,17 +51,23 @@ options:
|
||||
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.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
action:
|
||||
description: Work on servicedelegationtarget or member level.
|
||||
type: str
|
||||
choices: ["servicedelegationtarget", "member"]
|
||||
default: servicedelegationtarget
|
||||
required: false
|
||||
state:
|
||||
description: The state to ensure.
|
||||
type: str
|
||||
choices: ["present", "absent"]
|
||||
default: present
|
||||
required: true
|
||||
required: false
|
||||
author:
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -121,10 +129,11 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"], default=None,
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
required=True),
|
||||
# present
|
||||
principal=dict(required=False, type='list', default=None),
|
||||
principal=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
|
||||
action=dict(type="str", default="servicedelegationtarget",
|
||||
choices=["member", "servicedelegationtarget"]),
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
# Authors:
|
||||
# Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2019 Red Hat
|
||||
# Copyright (C) 2019-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -33,24 +34,29 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The sudo command
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["sudocmd"]
|
||||
description:
|
||||
description: The command description
|
||||
type: str
|
||||
required: false
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent"]
|
||||
author:
|
||||
- Rafael Jeffman
|
||||
- Rafael Guterres Jeffman (@rjeffman)
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -103,7 +109,7 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["sudocmd"], default=None,
|
||||
name=dict(type="list", elements="str", aliases=["sudocmd"],
|
||||
required=True),
|
||||
# present
|
||||
description=dict(type="str", default=None),
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
# Authors:
|
||||
# Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2019 Red Hat
|
||||
# Copyright (C) 2019-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -33,17 +34,20 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The sudocmodgroup name
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
description:
|
||||
description: The sudocmdgroup description
|
||||
type: str
|
||||
required: false
|
||||
nomembers:
|
||||
description: Suppress processing of membership attributes
|
||||
@@ -53,16 +57,20 @@ options:
|
||||
description: List of sudocmds assigned to this sudocmdgroup.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
action:
|
||||
description: Work on sudocmdgroup or member level
|
||||
default: hostgroup
|
||||
type: str
|
||||
default: sudocmdgroup
|
||||
choices: ["member", "sudocmdgroup"]
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent"]
|
||||
author:
|
||||
- Rafael Guterres Jeffman
|
||||
- Rafael Guterres Jeffman (@rjeffman)
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -140,12 +148,13 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"], default=None,
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
required=True),
|
||||
# present
|
||||
description=dict(type="str", default=None),
|
||||
nomembers=dict(required=False, type='bool', default=None),
|
||||
sudocmd=dict(required=False, type='list', default=None),
|
||||
sudocmd=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
action=dict(type="str", default="sudocmdgroup",
|
||||
choices=["member", "sudocmdgroup"]),
|
||||
# state
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
# Authors:
|
||||
# Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2019 Red Hat
|
||||
# Copyright (C) 2019-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,36 +33,46 @@ 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
|
||||
options:
|
||||
name:
|
||||
description: The sudorule name
|
||||
type: list
|
||||
elements: str
|
||||
required: true
|
||||
aliases: ["cn"]
|
||||
description:
|
||||
description: The sudorule description
|
||||
type: str
|
||||
required: false
|
||||
user:
|
||||
description: List of users assigned to the sudo rule.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
usercategory:
|
||||
description: User category the sudo rule applies to
|
||||
type: str
|
||||
required: false
|
||||
choices: ["all", ""]
|
||||
aliases: ["usercat"]
|
||||
group:
|
||||
description: List of user groups assigned to the sudo rule.
|
||||
type: list
|
||||
elements: str
|
||||
required: false
|
||||
runasgroupcategory:
|
||||
description: RunAs Group category applied to the sudo rule.
|
||||
type: str
|
||||
required: false
|
||||
choices: ["all", ""]
|
||||
aliases: ["runasgroupcat"]
|
||||
runasusercategory:
|
||||
description: RunAs User category applied to the sudorule.
|
||||
type: str
|
||||
required: false
|
||||
choices: ["all", ""]
|
||||
aliases: ["runasusercat"]
|
||||
@@ -73,12 +84,15 @@ options:
|
||||
description: List of host names assigned to this sudorule.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
hostgroup:
|
||||
description: List of host groups assigned to this sudorule.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
hostcategory:
|
||||
description: Host category the sudo rule applies to.
|
||||
type: str
|
||||
required: false
|
||||
choices: ["all", ""]
|
||||
aliases: ["hostcat"]
|
||||
@@ -86,20 +100,25 @@ options:
|
||||
description: List of allowed sudocmds assigned to this sudorule.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
allow_sudocmdgroup:
|
||||
description: List of allowed sudocmd groups assigned to this sudorule.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
deny_sudocmd:
|
||||
description: List of denied sudocmds assigned to this sudorule.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
deny_sudocmdgroup:
|
||||
description: List of denied sudocmd groups assigned to this sudorule.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
cmdcategory:
|
||||
description: Command category the sudo rule applies to
|
||||
type: str
|
||||
required: false
|
||||
choices: ["all", ""]
|
||||
aliases: ["cmdcat"]
|
||||
@@ -107,29 +126,41 @@ options:
|
||||
description: Order to apply this rule.
|
||||
required: false
|
||||
type: int
|
||||
aliases: ["sudoorder"]
|
||||
sudooption:
|
||||
description: List of sudo options.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
aliases: ["options"]
|
||||
runasuser:
|
||||
description: List of users for Sudo to execute as.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
runasgroup:
|
||||
description: List of groups for Sudo to execute as.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
hostmask:
|
||||
description: Host masks of allowed hosts.
|
||||
required: false
|
||||
type: list
|
||||
elements: str
|
||||
action:
|
||||
description: Work on sudorule or member level
|
||||
type: str
|
||||
default: sudorule
|
||||
choices: ["member", "sudorule"]
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent", "enabled", "disabled"]
|
||||
author:
|
||||
- Rafael Jeffman
|
||||
- Rafael Guterres Jeffman (@rjeffman)
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -162,19 +193,28 @@ 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 applies for hosts with hostmasks
|
||||
- ipasudorule:
|
||||
ipaadmin_password: SomeADMINpassword
|
||||
name: testrule1
|
||||
hostmask:
|
||||
- 192.168.122.1/24
|
||||
- 192.168.120.1/24
|
||||
action: member
|
||||
|
||||
# Ensure Sudo Rule tesrule1 is absent
|
||||
- ipasudorule:
|
||||
@@ -188,7 +228,7 @@ RETURN = """
|
||||
|
||||
from ansible.module_utils.ansible_freeipa_module import \
|
||||
IPAAnsibleModule, compare_args_ipa, gen_add_del_lists, gen_add_list, \
|
||||
gen_intersection_list, api_get_domain, ensure_fqdn
|
||||
gen_intersection_list, api_get_domain, ensure_fqdn, netaddr, to_text
|
||||
|
||||
|
||||
def find_sudorule(module, name):
|
||||
@@ -236,7 +276,7 @@ def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
# general
|
||||
name=dict(type="list", aliases=["cn"], default=None,
|
||||
name=dict(type="list", elements="str", aliases=["cn"],
|
||||
required=True),
|
||||
# present
|
||||
description=dict(required=False, type="str", default=None),
|
||||
@@ -245,14 +285,24 @@ def main():
|
||||
hostcategory=dict(required=False, type="str", default=None,
|
||||
choices=["all", ""], aliases=['hostcat']),
|
||||
nomembers=dict(required=False, type='bool', default=None),
|
||||
host=dict(required=False, type='list', default=None),
|
||||
hostgroup=dict(required=False, type='list', default=None),
|
||||
user=dict(required=False, type='list', default=None),
|
||||
group=dict(required=False, type='list', default=None),
|
||||
allow_sudocmd=dict(required=False, type="list", default=None),
|
||||
deny_sudocmd=dict(required=False, type="list", default=None),
|
||||
allow_sudocmdgroup=dict(required=False, type="list", default=None),
|
||||
deny_sudocmdgroup=dict(required=False, type="list", default=None),
|
||||
host=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
hostgroup=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
hostmask=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
user=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
group=dict(required=False, type='list', elements="str",
|
||||
default=None),
|
||||
allow_sudocmd=dict(required=False, type="list", elements="str",
|
||||
default=None),
|
||||
deny_sudocmd=dict(required=False, type="list", elements="str",
|
||||
default=None),
|
||||
allow_sudocmdgroup=dict(required=False, type="list",
|
||||
elements="str", default=None),
|
||||
deny_sudocmdgroup=dict(required=False, type="list", elements="str",
|
||||
default=None),
|
||||
cmdcategory=dict(required=False, type="str", default=None,
|
||||
choices=["all", ""], aliases=['cmdcat']),
|
||||
runasusercategory=dict(required=False, type="str", default=None,
|
||||
@@ -261,11 +311,13 @@ def main():
|
||||
runasgroupcategory=dict(required=False, type="str", default=None,
|
||||
choices=["all", ""],
|
||||
aliases=['runasgroupcat']),
|
||||
runasuser=dict(required=False, type="list", default=None),
|
||||
runasgroup=dict(required=False, type="list", default=None),
|
||||
runasuser=dict(required=False, type="list", elements="str",
|
||||
default=None),
|
||||
runasgroup=dict(required=False, type="list", elements="str",
|
||||
default=None),
|
||||
order=dict(type="int", required=False, aliases=['sudoorder']),
|
||||
sudooption=dict(required=False, type='list', default=None,
|
||||
aliases=["options"]),
|
||||
sudooption=dict(required=False, type='list', elements="str",
|
||||
default=None, aliases=["options"]),
|
||||
action=dict(type="str", default="sudorule",
|
||||
choices=["member", "sudorule"]),
|
||||
# state
|
||||
@@ -298,6 +350,7 @@ def main():
|
||||
nomembers = ansible_module.params_get("nomembers") # noqa
|
||||
host = ansible_module.params_get("host")
|
||||
hostgroup = ansible_module.params_get_lowercase("hostgroup")
|
||||
hostmask = ansible_module.params_get("hostmask")
|
||||
user = ansible_module.params_get_lowercase("user")
|
||||
group = ansible_module.params_get_lowercase("group")
|
||||
allow_sudocmd = ansible_module.params_get('allow_sudocmd')
|
||||
@@ -315,6 +368,10 @@ def main():
|
||||
# state
|
||||
state = ansible_module.params_get("state")
|
||||
|
||||
# ensure hostmasks are network cidr
|
||||
if hostmask is not None:
|
||||
hostmask = [to_text(netaddr.IPNetwork(x).cidr) for x in hostmask]
|
||||
|
||||
# Check parameters
|
||||
invalid = []
|
||||
|
||||
@@ -346,7 +403,7 @@ def main():
|
||||
"cmdcategory", "runasusercategory",
|
||||
"runasgroupcategory", "nomembers", "order"]
|
||||
if action == "sudorule":
|
||||
invalid.extend(["host", "hostgroup", "user", "group",
|
||||
invalid.extend(["host", "hostgroup", "hostmask", "user", "group",
|
||||
"runasuser", "runasgroup", "allow_sudocmd",
|
||||
"allow_sudocmdgroup", "deny_sudocmd",
|
||||
"deny_sudocmdgroup", "sudooption"])
|
||||
@@ -360,7 +417,7 @@ def main():
|
||||
"disabled")
|
||||
invalid = ["description", "usercategory", "hostcategory",
|
||||
"cmdcategory", "runasusercategory", "runasgroupcategory",
|
||||
"nomembers", "nomembers", "host", "hostgroup",
|
||||
"nomembers", "nomembers", "host", "hostgroup", "hostmask",
|
||||
"user", "group", "allow_sudocmd", "allow_sudocmdgroup",
|
||||
"deny_sudocmd", "deny_sudocmdgroup", "runasuser",
|
||||
"runasgroup", "order", "sudooption"]
|
||||
@@ -389,6 +446,7 @@ def main():
|
||||
user_add, user_del = [], []
|
||||
group_add, group_del = [], []
|
||||
hostgroup_add, hostgroup_del = [], []
|
||||
hostmask_add, hostmask_del = [], []
|
||||
allow_cmd_add, allow_cmd_del = [], []
|
||||
allow_cmdgroup_add, allow_cmdgroup_del = [], []
|
||||
deny_cmd_add, deny_cmd_del = [], []
|
||||
@@ -454,6 +512,9 @@ def main():
|
||||
hostgroup_add, hostgroup_del = gen_add_del_lists(
|
||||
hostgroup, res_find.get('memberhost_hostgroup', []))
|
||||
|
||||
hostmask_add, hostmask_del = gen_add_del_lists(
|
||||
hostmask, res_find.get('hostmask', []))
|
||||
|
||||
user_add, user_del = gen_add_del_lists(
|
||||
user, res_find.get('memberuser_user', []))
|
||||
|
||||
@@ -520,6 +581,9 @@ def main():
|
||||
if hostgroup is not None:
|
||||
hostgroup_add = gen_add_list(
|
||||
hostgroup, res_find.get("memberhost_hostgroup"))
|
||||
if hostmask is not None:
|
||||
hostmask_add = gen_add_list(
|
||||
hostmask, res_find.get("hostmask"))
|
||||
if user is not None:
|
||||
user_add = gen_add_list(
|
||||
user, res_find.get("memberuser_user"))
|
||||
@@ -592,6 +656,10 @@ def main():
|
||||
hostgroup_del = gen_intersection_list(
|
||||
hostgroup, res_find.get("memberhost_hostgroup"))
|
||||
|
||||
if hostmask is not None:
|
||||
hostmask_del = gen_intersection_list(
|
||||
hostmask, res_find.get("hostmask"))
|
||||
|
||||
if user is not None:
|
||||
user_del = gen_intersection_list(
|
||||
user, res_find.get("memberuser_user"))
|
||||
@@ -683,18 +751,19 @@ def main():
|
||||
|
||||
# Manage members.
|
||||
# Manage hosts and hostgroups
|
||||
if host_add or hostgroup_add:
|
||||
commands.append([name, "sudorule_add_host",
|
||||
{
|
||||
"host": host_add,
|
||||
"hostgroup": hostgroup_add,
|
||||
}])
|
||||
if host_del or hostgroup_del:
|
||||
commands.append([name, "sudorule_remove_host",
|
||||
{
|
||||
"host": host_del,
|
||||
"hostgroup": hostgroup_del,
|
||||
}])
|
||||
if any([host_add, hostgroup_add, hostmask_add]):
|
||||
params = {"host": host_add, "hostgroup": hostgroup_add}
|
||||
# An empty Hostmask cannot be used, or IPA API will fail.
|
||||
if hostmask_add:
|
||||
params["hostmask"] = hostmask_add
|
||||
commands.append([name, "sudorule_add_host", params])
|
||||
|
||||
if any([host_del, hostgroup_del, hostmask_del]):
|
||||
params = {"host": host_del, "hostgroup": hostgroup_del}
|
||||
# An empty Hostmask cannot be used, or IPA API will fail.
|
||||
if hostmask_del:
|
||||
params["hostmask"] = hostmask_del
|
||||
commands.append([name, "sudorule_remove_host", params])
|
||||
|
||||
# Manage users and groups
|
||||
if user_add or group_add:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2019 Red Hat
|
||||
# Copyright (C) 2019-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,36 +32,44 @@ 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
|
||||
options:
|
||||
suffix:
|
||||
description: Topology suffix
|
||||
type: str
|
||||
required: true
|
||||
choices: ["domain", "ca", "domain+ca"]
|
||||
name:
|
||||
description: Topology segment name, unique identifier.
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["cn"]
|
||||
left:
|
||||
description: Left replication node - an IPA server
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["leftnode"]
|
||||
right:
|
||||
description: Right replication node - an IPA server
|
||||
type: str
|
||||
required: false
|
||||
aliases: ["rightnode"]
|
||||
direction:
|
||||
description: The direction a segment will be reinitialized
|
||||
type: str
|
||||
required: false
|
||||
choices: ["left-to-right", "right-to-left"]
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
default: present
|
||||
choices: ["present", "absent", "enabled", "disabled", "reinitialized",
|
||||
"checked" ]
|
||||
author:
|
||||
- Thomas Woerner
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -178,7 +186,8 @@ def find_left_right_cn(module, suffix, left, right, name):
|
||||
def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
suffix=dict(choices=["domain", "ca", "domain+ca"], required=True),
|
||||
suffix=dict(type="str", choices=["domain", "ca", "domain+ca"],
|
||||
required=True),
|
||||
name=dict(type="str", aliases=["cn"], default=None),
|
||||
left=dict(type="str", aliases=["leftnode"], default=None),
|
||||
right=dict(type="str", aliases=["rightnode"], default=None),
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Authors:
|
||||
# Thomas Woerner <twoerner@redhat.com>
|
||||
#
|
||||
# Copyright (C) 2019 Red Hat
|
||||
# Copyright (C) 2019-2022 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,21 +32,23 @@ 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
|
||||
options:
|
||||
suffix:
|
||||
description: Topology suffix
|
||||
type: str
|
||||
required: true
|
||||
choices: ["domain", "ca"]
|
||||
state:
|
||||
description: State to ensure
|
||||
type: str
|
||||
default: verified
|
||||
choices: ["verified"]
|
||||
author:
|
||||
- Thomas Woerner
|
||||
- Thomas Woerner (@t-woerner)
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
@@ -65,7 +67,7 @@ from ansible.module_utils.ansible_freeipa_module import IPAAnsibleModule
|
||||
def main():
|
||||
ansible_module = IPAAnsibleModule(
|
||||
argument_spec=dict(
|
||||
suffix=dict(choices=["domain", "ca"], required=True),
|
||||
suffix=dict(type="str", choices=["domain", "ca"], required=True),
|
||||
state=dict(type="str", default="verified",
|
||||
choices=["verified"]),
|
||||
),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user