Skip to content

Commit e2bc693

Browse files
committed
Inject Ironic CA Cert in IPA
Signed-off-by: Nicolas Belouin <nicolas.belouin@suse.com>
1 parent a058212 commit e2bc693

File tree

8 files changed

+73
-4
lines changed

8 files changed

+73
-4
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,20 @@ media HTTP server configuration:
125125
- `IRONIC_VMEDIA_TLS_ENFORCE_SERVER_CIPHER_ORDER` - Setting this variable to
126126
`true` will make the server enforce its cipher list ordering for TLS version
127127
up to 1.2, defaults to `false`
128+
- `IRONIC_INSECURE` - Setting this variable to `true` will add the `ipa-insecure=1`
129+
flag to the kernel command line, disabling TLS certificate verification by the
130+
IPA image.
128131

129132
The following mountpoints can be passed in to customize run-time
130133
functionality:
131134

132135
- `/certs/ca/bmc` - The storage path of BMC CA certificates. If the path exists
133136
and verify_ca field in driver_info is True or None, the certificates in this
134137
path will be used.
138+
- `/certs/ca/ipa` - The storage path of IPA CA certificates. If the path exists
139+
and `IRONIC_INSECURE` variable is not set to `true`, the certificates in this
140+
path will be used by the Ironic Python Agent. The Ironic CA bundle will be
141+
added to the trusted CA automatically.
135142

136143
MariaDB configuration:
137144

ironic-config/inspector.ipxe.j2

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ echo In inspector.ipxe
55
imgfree
66
# NOTE(dtantsur): keep inspection kernel params in [mdns]params in
77
# ironic-inspector-image and configuration in configure-ironic.sh
8-
kernel --timeout 60000 {{ env.IRONIC_HTTP_URL }}/images/ironic-python-agent.kernel ipa-insecure=1 ipa-inspection-collectors={{ env.IRONIC_IPA_COLLECTORS }} systemd.journald.forward_to_console=yes BOOTIF=${mac} ipa-debug=1 ipa-enable-vlan-interfaces={{ env.IRONIC_ENABLE_VLAN_INTERFACES }} ipa-inspection-dhcp-all-interfaces=1 ipa-collect-lldp=1 {{ env.INSPECTOR_EXTRA_ARGS }} initrd=ironic-python-agent.initramfs {% if env.IRONIC_RAMDISK_SSH_KEY %}sshkey="{{ env.IRONIC_RAMDISK_SSH_KEY|trim }}"{% endif %} {{ env.IRONIC_KERNEL_PARAMS|trim }} || goto retry_boot
8+
kernel --timeout 60000 {{ env.IRONIC_HTTP_URL }}/images/ironic-python-agent.kernel {% if env.IRONIC_INSECURE %}ipa-insecure=1{% endif %} ipa-inspection-collectors={{ env.IRONIC_IPA_COLLECTORS }} systemd.journald.forward_to_console=yes BOOTIF=${mac} ipa-debug=1 ipa-enable-vlan-interfaces={{ env.IRONIC_ENABLE_VLAN_INTERFACES }} ipa-inspection-dhcp-all-interfaces=1 ipa-collect-lldp=1 {{ env.INSPECTOR_EXTRA_ARGS }} initrd=ironic-python-agent.initramfs initrd=ipa-cacert-bundle {% if env.IRONIC_RAMDISK_SSH_KEY %}sshkey="{{ env.IRONIC_RAMDISK_SSH_KEY|trim }}"{% endif %} {{ env.IRONIC_KERNEL_PARAMS|trim }} || goto retry_boot
99
initrd --timeout 60000 {{ env.IRONIC_HTTP_URL }}/images/ironic-python-agent.initramfs || goto retry_boot
10+
initrd --timeout 60000 {{ env.IRONIC_HTTP_URL }}/ipa-cacert-bundle || goto retry_boot
1011
boot

ironic-config/ipxe_config.template

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ imgfree
2222
kernel {% if pxe_options.ipxe_timeout > 0 %}--timeout {{ pxe_options.ipxe_timeout }} {% endif %}{{ aki_path_https }} selinux=0 troubleshoot=0 text {{ pxe_options.pxe_append_params|default("", true) }} BOOTIF=${mac} initrd={{ pxe_options.initrd_filename|default("deploy_ramdisk", true) }} || goto retry
2323

2424
initrd {% if pxe_options.ipxe_timeout > 0 %}--timeout {{ pxe_options.ipxe_timeout }} {% endif %}{{ ari_path_https }} || goto retry
25+
# Load ipa-cacert-bundle, path is relative to the ipxe script that will be located in /shared/html/{node_id}/
26+
initrd {% if pxe_options.ipxe_timeout > 0 %}--timeout {{ pxe_options.ipxe_timeout }} {% endif %} ../ipa-cacert-bundle || goto retry
2527
boot
2628

2729
:retry
@@ -41,6 +43,7 @@ poweroff
4143
imgfree
4244
kernel {% if pxe_options.ipxe_timeout > 0 %}--timeout {{ pxe_options.ipxe_timeout }} {% endif %}{{ aki_path_https }} text {{ pxe_options.pxe_append_params|default("", true) }} inst.ks={{ pxe_options.ks_cfg_url }} {% if pxe_options.repo_url %}inst.repo={{ pxe_options.repo_url }}{% else %}inst.stage2={{ pxe_options.stage2_url }}{% endif %} initrd=ramdisk || goto boot_anaconda
4345
initrd {% if pxe_options.ipxe_timeout > 0 %}--timeout {{ pxe_options.ipxe_timeout }} {% endif %}{{ ari_path_https }} || goto boot_anaconda
46+
initrd {% if pxe_options.ipxe_timeout > 0 %}--timeout {{ pxe_options.ipxe_timeout }} {% endif %} ../ipa-cacert-bundle || goto boot_anaconda
4447
boot
4548

4649
:boot_ramdisk
@@ -50,6 +53,7 @@ sanboot {{ pxe_options.boot_iso_url }}
5053
{%- else %}
5154
kernel {% if pxe_options.ipxe_timeout > 0 %}--timeout {{ pxe_options.ipxe_timeout }} {% endif %}{{ aki_path_https }} root=/dev/ram0 text {{ pxe_options.pxe_append_params|default("", true) }} {{ pxe_options.ramdisk_opts|default('', true) }} initrd=ramdisk || goto boot_ramdisk
5255
initrd {% if pxe_options.ipxe_timeout > 0 %}--timeout {{ pxe_options.ipxe_timeout }} {% endif %}{{ ari_path_https }} || goto boot_ramdisk
56+
initrd {% if pxe_options.ipxe_timeout > 0 %}--timeout {{ pxe_options.ipxe_timeout }} {% endif %} ../ipa-cacert-bundle || goto boot_ramdisk
5357
boot
5458
{%- endif %}
5559

ironic-config/ironic.conf.j2

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ deploy_logs_local_path = /shared/log/ironic/deploy
5454
# See https://bugzilla.redhat.com/show_bug.cgi?id=1822763
5555
max_command_attempts = 30
5656
certificates_path = {{ env.IRONIC_GEN_CERT_DIR }}
57+
api_ca_file = {{ env.IPA_CACERT_FILE }}
5758

5859
[api]
5960
{% if env.IRONIC_REVERSE_PROXY_SETUP == "true" %}
@@ -227,7 +228,7 @@ images_path = /shared/html/tmp
227228
instance_master_path = /shared/html/master_images
228229
tftp_master_path = /shared/tftpboot/master_images
229230
tftp_root = /shared/tftpboot
230-
kernel_append_params = nofb nomodeset vga=normal ipa-insecure=1 {% if env.ENABLE_FIPS_IPA %}fips={{ env.ENABLE_FIPS_IPA|trim }}{% endif %} {% if env.IRONIC_RAMDISK_SSH_KEY %}sshkey="{{ env.IRONIC_RAMDISK_SSH_KEY|trim }}"{% endif %} {{ env.IRONIC_KERNEL_PARAMS|trim }} systemd.journald.forward_to_console=yes
231+
kernel_append_params = nofb nomodeset vga=normal initrd=ipa-cacert-bundle {% if env.IRONIC_INSECURE %}ipa-insecure=1{% endif %} {% if env.ENABLE_FIPS_IPA %}fips={{ env.ENABLE_FIPS_IPA|trim }}{% endif %} {% if env.IRONIC_RAMDISK_SSH_KEY %}sshkey="{{ env.IRONIC_RAMDISK_SSH_KEY|trim }}"{% endif %} {{ env.IRONIC_KERNEL_PARAMS|trim }} systemd.journald.forward_to_console=yes
231232
# This makes networking boot templates generated even for nodes using local
232233
# boot (the default), ensuring that they boot correctly even if they start
233234
# netbooting for some reason (e.g. with the noop management interface).
@@ -240,14 +241,14 @@ ipxe_config_template = /templates/ipxe_config.template
240241

241242
[redfish]
242243
use_swift = false
243-
kernel_append_params = nofb nomodeset vga=normal ipa-insecure=1 {% if env.ENABLE_FIPS_IPA %}fips={{ env.ENABLE_FIPS_IPA|trim }}{% endif %} {% if env.IRONIC_RAMDISK_SSH_KEY %}sshkey="{{ env.IRONIC_RAMDISK_SSH_KEY|trim }}"{% endif %} {{ env.IRONIC_KERNEL_PARAMS|trim }} systemd.journald.forward_to_console=yes
244+
kernel_append_params = nofb nomodeset vga=normal {% if env.IRONIC_INSECURE %}ipa-insecure=1{% endif %} {% if env.ENABLE_FIPS_IPA %}fips={{ env.ENABLE_FIPS_IPA|trim }}{% endif %} {% if env.IRONIC_RAMDISK_SSH_KEY %}sshkey="{{ env.IRONIC_RAMDISK_SSH_KEY|trim }}"{% endif %} {{ env.IRONIC_KERNEL_PARAMS|trim }} systemd.journald.forward_to_console=yes
244245
{% if env.BMC_TLS_ENABLED == "true" %}
245246
# idrac uses the same options as the redfish driver
246247
verify_ca = {{ env.BMC_CACERT_FILE }}
247248
{% endif %}
248249

249250
[irmc]
250-
kernel_append_params = nofb nomodeset vga=normal ipa-insecure=1 {% if env.ENABLE_FIPS_IPA %}fips={{ env.ENABLE_FIPS_IPA|trim }}{% endif %} {% if env.IRONIC_RAMDISK_SSH_KEY %}sshkey="{{ env.IRONIC_RAMDISK_SSH_KEY|trim }}"{% endif %} {{ env.IRONIC_KERNEL_PARAMS|trim }} systemd.journald.forward_to_console=yes
251+
kernel_append_params = nofb nomodeset vga=normal {% if env.IRONIC_INSECURE %}ipa-insecure=1{% endif %} {% if env.ENABLE_FIPS_IPA %}fips={{ env.ENABLE_FIPS_IPA|trim }}{% endif %} {% if env.IRONIC_RAMDISK_SSH_KEY %}sshkey="{{ env.IRONIC_RAMDISK_SSH_KEY|trim }}"{% endif %} {{ env.IRONIC_KERNEL_PARAMS|trim }} systemd.journald.forward_to_console=yes
251252
{% if env.BMC_TLS_ENABLED == "true" %}
252253
verify_ca = {{ env.BMC_CACERT_FILE }}
253254
{% endif %}

main-packages-list.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
cpio
12
dnsmasq
23
dosfstools
34
httpd

scripts/rundnsmasq

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ if [[ "${DNS_IP:-}" == "provisioning" ]]; then
2020
fi
2121

2222
mkdir -p /shared/tftpboot
23+
mkdir -p /shared/html
2324

2425
# Copy files to shared mount
2526
if [[ -r "${IPXE_CUSTOM_FIRMWARE_DIR}" ]]; then
@@ -30,6 +31,12 @@ else
3031
cp /tftpboot/undionly.kpxe /tftpboot/snponly.efi /shared/tftpboot
3132
fi
3233

34+
generate_cacert_bundle_initrd /shared/tftpboot/ipa-cacert-bundle
35+
generate_cacert_bundle_initrd /shared/html/ipa-cacert-bundle
36+
37+
# this will get dnsmasq killed on certificate update triggering a pod restart
38+
configure_restart_on_certificate_update "true" dnsmasq "${IPA_CACERTS_PATH}/*"
39+
3340
# Template and write dnsmasq.conf
3441
# we template via /tmp as sed otherwise creates temp files in /etc directory
3542
# where we can't write

scripts/runironic

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,14 @@ if [[ "${BMC_TLS_ENABLED}" == "true" ]]; then
2424
"${BMC_CACERTS_PATH}" &
2525
fi
2626

27+
if ls "${IPA_CACERTS_PATH}"/* > /dev/null 2>&1; then
28+
# Ignore error if IRONIC_CACERT_FILE doesn't exist as it will still work as intended
29+
# shellcheck disable=SC2034
30+
watchmedo shell-command \
31+
--patterns="*" \
32+
--ignore-directories \
33+
--command='cat "${IPA_CACERTS_PATH}"/* "${IRONIC_CACERT_FILE}" 2>/dev/null > "${IPA_CACERT_FILE}"' \
34+
"${IPA_CACERTS_PATH}" &
35+
fi
36+
2737
exec /usr/bin/ironic --config-dir "${IRONIC_CONF_DIR}"

scripts/tls-common.sh

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ export IRONIC_SSL_PROTOCOL=${IRONIC_SSL_PROTOCOL:-"-ALL +TLSv1.2 +TLSv1.3"}
55
export IPXE_SSL_PROTOCOL=${IPXE_SSL_PROTOCOL:-"-ALL +TLSv1.2 +TLSv1.3"}
66
export IRONIC_VMEDIA_SSL_PROTOCOL=${IRONIC_VMEDIA_SSL_PROTOCOL:-"ALL"}
77

8+
export DEFAULT_CACERT_BUNDLE=${DEFAULT_CACERT_BUNDLE:-"/etc/ssl/cert.pem"}
9+
810
# Node image storage is using the same cert and port as the API
911
export IRONIC_CERT_FILE=/certs/ironic/tls.crt
1012
export IRONIC_KEY_FILE=/certs/ironic/tls.key
@@ -23,6 +25,8 @@ export MARIADB_CACERT_FILE=/certs/ca/mariadb/tls.crt
2325
export BMC_CACERTS_PATH=/certs/ca/bmc
2426
export BMC_CACERT_FILE=/conf/bmc-tls.pem
2527
export IRONIC_CACERT_FILE=/certs/ca/ironic/tls.crt
28+
export IPA_CACERT_FILE=/conf/ipa-tls.pem
29+
export IPA_CACERTS_PATH=/certs/ca/ipa
2630

2731
export IPXE_TLS_PORT="${IPXE_TLS_PORT:-8084}"
2832

@@ -129,3 +133,37 @@ if ls "${BMC_CACERTS_PATH}"/* > /dev/null 2>&1; then
129133
else
130134
export BMC_TLS_ENABLED="false"
131135
fi
136+
137+
if ls "${IPA_CACERTS_PATH}"/* > /dev/null 2>&1; then
138+
cat "${IPA_CACERTS_PATH}"/* > "${IPA_CACERT_FILE}"
139+
else
140+
if [ -f "${DEFAULT_CACERT_BUNDLE}" ]; then
141+
copy_atomic "${DEFAULT_CACERT_BUNDLE}" "${IPA_CACERT_FILE}"
142+
fi
143+
fi
144+
145+
if [ -f "${IRONIC_CACERT_FILE}" ]; then
146+
cat "${IRONIC_CACERT_FILE}" >> "${IPA_CACERT_FILE}"
147+
fi
148+
149+
generate_cacert_bundle_initrd()
150+
(
151+
local output_path="$1"
152+
local temp_dir
153+
154+
temp_dir="$(mktemp -d)"
155+
156+
cd "${temp_dir}" || return
157+
158+
mkdir -p etc/ironic-python-agent.d etc/ironic-python-agent
159+
cp "${IPA_CACERT_FILE}" etc/ironic-python-agent/ironic.crt
160+
cat > etc/ironic-python-agent.d/ironic-tls.conf <<EOF
161+
[DEFAULT]
162+
cafile = /etc/ironic-python-agent/ironic.crt
163+
EOF
164+
165+
find . | cpio -o -H newc --reproducible >> "${output_path}"
166+
167+
# Remove temp directory
168+
cd && rm -rf "${temp_dir}"
169+
)

0 commit comments

Comments
 (0)