Skip to content

Commit 8102ea0

Browse files
committed
- Adding support for UEFI
- Adding support for custom %post sections - Adding support for adding users - Adding support to enable FIPS in the custom ISO
1 parent 7539910 commit 8102ea0

File tree

13 files changed

+687
-67
lines changed

13 files changed

+687
-67
lines changed

README.md

Lines changed: 219 additions & 43 deletions
Large diffs are not rendered by default.

defaults/main.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ _def_pxelinux_cfg_path: 'isolinux/isolinux.cfg'
5454
# relative path within the temporary_work_dir_source_files_path to the grub.conf file
5555
_def_grub_cfg_path: 'isolinux/grub.conf'
5656

57+
# relative path within temporary_work_dir_source_files_path to the UEFI grub.conf file
58+
_def_grub_cfg_path_uefi: 'EFI/BOOT/grub.cfg'
59+
5760
# whether to clean up the downloaded ISO
5861
_def_cleanup_iso: false
5962

@@ -84,5 +87,22 @@ _def_implant_md5: true
8487
# package name that provides the implantisomd5 command
8588
_def_implantisomd5_package_name: 'isomd5sum'
8689

90+
# relative path within the temporary_work_dir_source_files_path to the UEFI image file
91+
_def_uefi_image_path: 'images/efiboot.img'
92+
8793
# whether to quiet asserts
8894
_def_quiet_assert: true
95+
96+
# whether to enable FIPS mode for the ISO
97+
_def_enable_fips: false
98+
99+
# post sections to insert into the kickstart file
100+
_def_post_sections:
101+
- name: 'User creation'
102+
template: 'post__users.j2'
103+
104+
- name: 'FIPS'
105+
template: 'post__fips.j2'
106+
107+
- name: 'Autorelabel'
108+
template: 'post__autorelabel.j2'

tasks/assert.yml

Lines changed: 151 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
- lookup('ansible.builtin.vars', item) is defined
88
- lookup('ansible.builtin.vars', item) | bool | string == lookup('ansible.builtin.vars', item) | string
99
- lookup('ansible.builtin.vars', item) is boolean
10-
- lookup('ansible.builtin.vars', item) | type_debug == 'bool'
1110
success_msg: "Variable '{{ item }}' defined properly - value: '{{ lookup('ansible.builtin.vars', item) }}'"
1211
fail_msg: "Variable '{{ item }}' failed to validate"
1312
quiet: '{{ _quiet_assert }}'
@@ -18,6 +17,7 @@
1817
- '_cleanup_work_dir'
1918
- '_force_recreate_custom_iso'
2019
- '_implant_md5'
20+
- '_enable_fips'
2121
loop_control:
2222
label: 'variable: {{ item }}'
2323

@@ -114,3 +114,153 @@
114114
fail_msg: "Variable '_api_token' failed to validate"
115115
quiet: '{{ _quiet_assert }}'
116116
no_log: true
117+
118+
- name: 'Ensure optional variables, are defined properly, if set (list)'
119+
ansible.builtin.assert:
120+
that:
121+
- lookup('ansible.builtin.vars', __var) is defined
122+
- lookup('ansible.builtin.vars', __var) | list | string == lookup('ansible.builtin.vars', __var) | string
123+
- lookup('ansible.builtin.vars', __var) is sequence
124+
success_msg: "Variable '{{ __var }}' defined properly"
125+
fail_msg: "Variable '{{ __var }}' failed to validate"
126+
quiet: '{{ _quiet_assert }}'
127+
no_log: true
128+
when: >
129+
lookup('ansible.builtin.vars', __var, default='') != '' and
130+
lookup('ansible.builtin.vars', __var, default='') | length > 0
131+
loop:
132+
- '_users'
133+
- '_post_sections'
134+
register: '__tmp_list_variables'
135+
loop_control:
136+
loop_var: '__var'
137+
label: 'variable: {{ __var }}'
138+
139+
- name: 'Ensure post_sections are defined properly'
140+
ansible.builtin.assert:
141+
that:
142+
- _section.name is defined
143+
- _section.name is string
144+
- _section.name != None
145+
- _section.name != ''
146+
147+
- _section.template is defined
148+
- _section.template is string
149+
- _section.template != None
150+
- _section.template != ''
151+
152+
# load the template to see if it exists
153+
- lookup('template', _section.template) | length > 0
154+
155+
loop: '{{ _post_sections }}'
156+
loop_control:
157+
loop_var: '_section'
158+
when: >
159+
_post_sections is defined
160+
and _post_sections | length > 0
161+
162+
- name: 'Ensure _users is defined properly'
163+
ansible.builtin.assert:
164+
that:
165+
# _user.name
166+
- _user.name is defined
167+
- _user.name is string
168+
- _user.name != None
169+
- _user.name != ''
170+
171+
# _user.gecos
172+
- (_user.gecos is defined) | ternary(_user.gecos | default(None) is string, true)
173+
- (_user.gecos is defined) | ternary(_user.gecos | default(None) != None, true)
174+
- (_user.gecos is defined) | ternary(_user.gecos | default(None) != '', true)
175+
176+
# _user.shell
177+
- (_user.shell is defined) | ternary(_user.shell | default(None) is string, true)
178+
- (_user.shell is defined) | ternary(_user.shell | default(None) != None, true)
179+
- (_user.shell is defined) | ternary(_user.shell | default(None) != '', true)
180+
181+
# _user.home
182+
- (_user.home is defined) | ternary(_user.home | default(None) is string, true)
183+
- (_user.home is defined) | ternary(_user.home | default(None) != None, true)
184+
- (_user.home is defined) | ternary(_user.home | default(None) != '', true)
185+
186+
# _user.password
187+
- (_user.password is defined) | ternary(_user.password | default(None) is string, true)
188+
- (_user.password is defined) | ternary(_user.password | default(None) != None, true)
189+
- (_user.password is defined) | ternary(_user.password | default(None) != '', true)
190+
191+
# _user.gid
192+
- (_user.gid is defined) | ternary(_user.gid | default(None) | int | string == _user.gid | default(None) | string, true)
193+
- (_user.gid is defined) | ternary(_user.gid | default(None) is number, true)
194+
- (_user.gid is defined) | ternary(_user.gid | default(None) is integer, true)
195+
- (_user.gid is defined) | ternary(_user.gid | default(None) >= 1, true)
196+
197+
# _user.uid
198+
- (_user.uid is defined) | ternary(_user.uid | default(None) | int | string == _user.uid | default(None) | string, true)
199+
- (_user.uid is defined) | ternary(_user.uid | default(None) is number, true)
200+
- (_user.uid is defined) | ternary(_user.uid | default(None) is integer, true)
201+
- (_user.uid is defined) | ternary(_user.uid | default(None) >= 1, true)
202+
203+
# _user.create_user_group
204+
- (_user.create_user_group is defined) | ternary(_user.create_user_group | default(None) | bool | string == _user.create_user_group | default(None) | string, true)
205+
- (_user.create_user_group is defined) | ternary(_user.create_user_group | default(None) is boolean, true)
206+
207+
# _user.lock
208+
- (_user.lock is defined) | ternary(_user.lock | default(None) | bool | string == _user.lock | default(None) | string, true)
209+
- (_user.lock is defined) | ternary(_user.lock | default(None) is boolean, true)
210+
211+
# _user.privileged
212+
- (_user.privileged is defined) | ternary(_user.privileged | default(None) | bool | string == _user.privileged | default(None) | string, true)
213+
- (_user.privileged is defined) | ternary(_user.privileged | default(None) is boolean, true)
214+
215+
# _user.groups
216+
- (_user.groups is defined) | ternary(_user.groups | default([]) | list | string == _user.groups | default(None) | string, true)
217+
- (_user.groups is defined) | ternary(_user.groups | default([]) is sequence, true)
218+
219+
# _user.authorized_keys
220+
- (_user.authorized_keys is defined) | ternary(_user.authorized_keys | default([]) | list | string == _user.authorized_keys | default(None) | string, true)
221+
- (_user.authorized_keys is defined) | ternary(_user.authorized_keys | default([]) is sequence, true)
222+
success_msg: 'Users are defined correctly'
223+
fail_msg: 'One or more users failed to validated correctly'
224+
no_log: true
225+
loop: '{{ _users }}'
226+
loop_control:
227+
loop_var: '_user'
228+
when: >
229+
_users is defined
230+
and _users | length > 0
231+
232+
- name: 'Ensure _users does not specify conflicting options'
233+
ansible.builtin.assert:
234+
that:
235+
- _user.home is defined
236+
- _user.home is string
237+
- _user.home != ''
238+
- _user.home != None
239+
success_msg: 'No conflicting options specified'
240+
fail_msg: 'A user needs a home directory when authorized keys are specified'
241+
no_log: true
242+
loop: '{{ _users }}'
243+
loop_control:
244+
loop_var: '_user'
245+
when: >
246+
_user.authorized_keys is defined
247+
and _user.authorized_keys | length > 0
248+
249+
- name: 'Skip block if no variables defined beforehand'
250+
when: >
251+
__tmp_list_variables.results is defined and
252+
__tmp_list_variables.results | map(attribute='skipped', default=[]) | select() | length > 0
253+
block:
254+
255+
- name: 'Show variables that have been skipped to check, due to being undefined'
256+
ansible.builtin.debug:
257+
msg: 'Variable name: {{ __var }}'
258+
loop:
259+
- "{{ __tmp_list_variables['results'] | default([]) }}"
260+
loop_control:
261+
loop_var: '__var'
262+
label: '{{ __var }}'
263+
264+
- name: 'Ensure above variables are not important to you, as they are not going to be used!'
265+
ansible.builtin.pause:
266+
seconds: 5

tasks/build_user_statement.yml

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
- name: 'Set fact: Start building the user statement for user {{ _user.name }}'
3+
ansible.builtin.set_fact:
4+
_user_statement: "{{ 'user --name=' ~ _user.name }}"
5+
6+
- name: 'Set fact: Insert gecos into the user statement for user {{ _user.name }}'
7+
ansible.builtin.set_fact:
8+
_user_statement: "{{ _user_statement ~ ' --gecos=\"' ~ _user.gecos ~ '\"' }}"
9+
when: >
10+
_user.gecos is defined
11+
and _user.gecos != ''
12+
and _user.gecos != None
13+
14+
- name: 'Set fact: Insert uid into the user statement for user {{ _user.name }}'
15+
ansible.builtin.set_fact:
16+
_user_statement: "{{ _user_statement ~ ' --uid=' ~ _user.uid }}"
17+
when: >
18+
_user.uid is defined
19+
and _user.uid | string != ''
20+
21+
- name: 'Set fact: Insert gid into the user statement for user {{ _user.name }}'
22+
ansible.builtin.set_fact:
23+
_user_statement: "{{ _user_statement ~ ' --gid=' ~ _user.gid }}"
24+
when: >
25+
_user.gid is defined
26+
and _user.gid | string != ''
27+
28+
- name: 'Set fact: Insert groups into the user statement for user {{ _user.name }}'
29+
ansible.builtin.set_fact:
30+
_user_statement: "{{ _user_statement ~ ' --groups=' ~ _user.groups | join(',') }}"
31+
when: >
32+
_user.groups is defined
33+
and _user.groups | string != ''
34+
35+
- name: 'Set fact: Insert homedir into the user statement for user {{ _user.name }}'
36+
ansible.builtin.set_fact:
37+
_user_statement: "{{ _user_statement ~ ' --homedir=' ~ _user.home }}"
38+
when: >
39+
_user.home is defined
40+
and _user.home | string != ''
41+
42+
- name: 'Set fact: Insert shell into the user statement for user {{ _user.name }}'
43+
ansible.builtin.set_fact:
44+
_user_statement: "{{ _user_statement ~ ' --shell=' ~ _user.shell }}"
45+
when: >
46+
_user.shell is defined
47+
and _user.shell | string != ''
48+
49+
- name: 'Set fact: Insert lock into the user statement for user {{ _user.name }}'
50+
ansible.builtin.set_fact:
51+
_user_statement: "{{ _user_statement ~ ' --lock' }}"
52+
when: >
53+
_user.lock is defined
54+
and _user.lock
55+
56+
- name: 'Set fact: Insert password into the user statement for user {{ _user.name }}'
57+
ansible.builtin.set_fact:
58+
_user_statement: >
59+
{{
60+
_user_statement ~ ' --iscrypted --password=' ~
61+
_user.password | string | ansible.builtin.password_hash(hashtype='sha512')
62+
}}
63+
no_log: true
64+
when: >
65+
_user.gid is defined
66+
and _user.gid | string != ''
67+
68+
- name: 'Insert user creation statement into the provided kickstart for user {{ _user.name }}'
69+
ansible.builtin.lineinfile:
70+
path: '{{ __work_dir_kickstart_path }}'
71+
regex: '^user\s--name={{ _user.name }}.+$'
72+
line: '{{ _user_statement }}'
73+
no_log: true
74+
become: true

tasks/create_iso.yml

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
- name: 'Ensure xorriso is present'
33
ansible.builtin.package:
4-
name: '{{ _xorriso_package_name }}'
4+
name: '{{ _xorriso_package_name }},syslinux'
55
state: 'present'
66
become: true
77

@@ -29,6 +29,9 @@
2929
ansible.builtin.set_fact:
3030
__iso_label: '{{ __t_label.stdout }}'
3131

32+
# Note: Adding '-no-emul-boot' *twice* is necessary to avoid the following issue:
33+
# https://unix.stackexchange.com/questions/491043/boot-grub-efi-img-invalid-image-size
34+
# Command has been built according to https://access.redhat.com/solutions/60959
3235
- name: 'Create the ISO with the included kickstart at: {{ __dest_iso_path }}'
3336
ansible.builtin.command:
3437
argv:
@@ -37,27 +40,35 @@
3740
- '{{ __dest_iso_path }}'
3841
- '-b'
3942
- '{{ _isolinux_bin_path }}'
40-
- '-c'
41-
- '{{ _boot_cat_path }}'
4243
- '-J'
4344
- '-R'
4445
- '-l'
45-
- '-v'
46+
- '-c'
47+
- '{{ _boot_cat_path }}'
4648
- '-no-emul-boot'
4749
- '-boot-load-size'
4850
- '4'
4951
- '-boot-info-table'
5052
- '-eltorito-alt-boot'
53+
- '-e'
54+
- '{{ _uefi_image_path }}'
55+
- '-no-emul-boot'
5156
- '-graft-points'
5257
- '-joliet-long'
5358
- '-V'
5459
- '{{ __iso_label }}'
55-
- '-volid'
56-
- '{{ __iso_label }}'
5760
- '{{ __src_files_path }}'
5861
creates: '{{ __dest_iso_path }}'
5962
become: true
6063

64+
- name: 'Ensure ISO is bootable via BIOS and UEFI' # noqa: no-changed-when
65+
ansible.builtin.command:
66+
argv:
67+
- 'isohybrid'
68+
- '--uefi'
69+
- '{{ __dest_iso_path }}'
70+
become: true
71+
6172
- name: 'Block: Handle implanting of MD5 into ISO'
6273
become: true
6374
when: >

tasks/download_iso.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,4 @@
6666
mode: '{{ _iso_mode }}'
6767
checksum: 'sha256:{{ _checksum }}'
6868
timeout: '{{ _download_timeout }}'
69+
become: true

tasks/fips.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
- name: 'Update kernel parameters to enable FIPS compliant cryptography (MD5 implanting requested)'
3+
ansible.builtin.lineinfile:
4+
path: '{{ _cfg_path }}'
5+
regexp: '^(.+)(hd:LABEL[A-z0-9_=-]+)(\sinst\.ks=\2:/ks\.cfg)?(\srd.live.check\squiet)(\sfips=1)?$'
6+
line: '\1\2 inst.ks=\2:/ks.cfg\4 fips=1'
7+
backrefs: true
8+
become: true
9+
loop:
10+
- '{{ __src_files_path }}/{{ _pxelinux_cfg_path }}' # BIOS
11+
- '{{ __src_files_path }}/{{ _grub_cfg_path_uefi }}' # UEFI
12+
loop_control:
13+
loop_var: '_cfg_path'
14+
when: >
15+
_implant_md5 is defined
16+
and _implant_md5
17+
18+
- name: 'BIOS/UEFI: Update kernel parameters to enable FIPS compliant cryptography'
19+
ansible.builtin.lineinfile:
20+
path: '{{ _cfg_path }}'
21+
regexp: '^(.+)(hd:LABEL[A-z0-9_=-]+)(\sinst\.ks=\2:/ks\.cfg)?(\squiet)(\sfips=1)?$'
22+
line: '\1\2 inst.ks=\2:/ks.cfg\4 fips=1'
23+
backrefs: true
24+
become: true
25+
loop:
26+
- '{{ __src_files_path }}/{{ _pxelinux_cfg_path }}' # BIOS
27+
- '{{ __src_files_path }}/{{ _grub_cfg_path_uefi }}' # UEFI
28+
loop_control:
29+
loop_var: '_cfg_path'

0 commit comments

Comments
 (0)