Merge "TLS support for API services"

This commit is contained in:
Zuul 2020-09-03 15:53:01 +00:00 committed by Gerrit Code Review
commit 3aae442b82
37 changed files with 549 additions and 39 deletions

View File

@ -154,6 +154,8 @@ def cmd_install(args):
install_dib='true', install_dib='true',
network_interface=args.network_interface, network_interface=args.network_interface,
enable_keystone=args.enable_keystone, enable_keystone=args.enable_keystone,
enable_tls=args.enable_tls,
generate_tls=args.enable_tls,
noauth_mode='false', noauth_mode='false',
enabled_hardware_types=args.hardware_types, enabled_hardware_types=args.hardware_types,
cleaning_disk_erase=args.cleaning_disk_erase, cleaning_disk_erase=args.cleaning_disk_erase,
@ -220,6 +222,8 @@ def parse_args():
help='the network interface to use') help='the network interface to use')
install.add_argument('--enable-keystone', action='store_true', install.add_argument('--enable-keystone', action='store_true',
help='enable keystone and use authentication') help='enable keystone and use authentication')
install.add_argument('--enable-tls', action='store_true',
help='enable self-signed TLS on API endpoints')
install.add_argument('--hardware-types', install.add_argument('--hardware-types',
# only generic types are enabled in the simple CI # only generic types are enabled in the simple CI
default='ipmi,redfish,manual-management', default='ipmi,redfish,manual-management',

View File

@ -222,6 +222,11 @@ Additionally, the following parameters can be useful:
A comma separated list of hardware types to enable. A comma separated list of hardware types to enable.
``--enable-keystone`` ``--enable-keystone``
Whether to enable authentication with Keystone_. Whether to enable authentication with Keystone_.
``--enable-tls``
Enable self-signed TLS on API endpoints.
.. warning::
If using Keystone_, see :ref:`keystone-tls` for important notes.
See the built-in documentation for more details: See the built-in documentation for more details:
@ -314,6 +319,30 @@ If you are running the installation behind a proxy, export the
environment variables ``http_proxy``, ``https_proxy`` and ``no_proxy`` environment variables ``http_proxy``, ``https_proxy`` and ``no_proxy``
so that ansible will use these proxy settings. so that ansible will use these proxy settings.
TLS support
-----------
Bifrost supports TLS for API services with two options:
* A self-signed certificate can be generated automatically. Set
``enable_tls=true`` and ``generate_tls=true``.
.. note:: This is equivalent to the ``--enable-tls`` flag of ``bifrost-cli``.
* Certificate paths can be provided via:
``tls_certificate_path``
Path to the TLS certificate (must be world-readable).
``tls_private_key_path``
Path to the private key (must not be password protected).
``tls_csr_path``
Path to the certificate signing request file.
Set ``enable_tls=true`` and do not set ``generate_tls`` to use this option.
.. warning::
If using Keystone, see :ref:`keystone-tls` for important notes.
Dependencies Dependencies
============ ============

View File

@ -30,6 +30,25 @@ See the following files for more settings that can be overridden:
* ``playbooks/roles/bifrost-ironic-install/defaults/main.yml`` * ``playbooks/roles/bifrost-ironic-install/defaults/main.yml``
* ``playbooks/roles/bifrost-keystone-install/defaults/main.yml`` * ``playbooks/roles/bifrost-keystone-install/defaults/main.yml``
.. _keystone-tls:
TLS notes
---------
There are two important limitations to keep in mind when using Keystone with
TLS:
* It's not possible to enable TLS on upgrade from Bifrost < 9.0 (Ussuri
and early Victoria). First do an upgrade to Bifrost >= 9.0, then enable TLS
in a separate step.
* Automatically updating from a TLS environment to a non-TLS one may not be
possible if using custom TLS certificates in a non-standard location
(``/etc/bifrost/bifrost.crt``). You need to manually change identity
endpoints in the catalog from ``https`` to ``http`` directly before
an update. The ``public`` endpoint **must** be updated **last** or you may
lock yourself out of keystone.
Using an existing Keystone Using an existing Keystone
-------------------------- --------------------------

View File

@ -15,3 +15,4 @@
BOOT_MODE: "{{ boot_mode | default('') }}" BOOT_MODE: "{{ boot_mode | default('') }}"
TEST_VM_NODE_DRIVER: "{{ test_driver | default('ipmi') }}" TEST_VM_NODE_DRIVER: "{{ test_driver | default('ipmi') }}"
NOAUTH_MODE: "{{ noauth_mode | default(false) | bool | lower }}" NOAUTH_MODE: "{{ noauth_mode | default(false) | bool | lower }}"
ENABLE_TLS: "{{ enable_tls | default(false) | bool | lower }}"

View File

@ -45,6 +45,10 @@ overridden in no-auth mode.
Ironic endpoint to use. If the fact is already defined, it is not overridden. Ironic endpoint to use. If the fact is already defined, it is not overridden.
`tls_certificate_path`
Path to the TLS certificate. Only set if TLS is used.
Notes Notes
----- -----

View File

@ -5,5 +5,6 @@ network_interface: "virbr0"
ans_network_interface: "{{ network_interface | replace('-', '_') }}" ans_network_interface: "{{ network_interface | replace('-', '_') }}"
internal_ip: "{{ hostvars[inventory_hostname]['ansible_' + ans_network_interface]['ipv4']['address'] }}" internal_ip: "{{ hostvars[inventory_hostname]['ansible_' + ans_network_interface]['ipv4']['address'] }}"
api_protocol: http enable_tls: false
api_protocol: "{{ 'https' if enable_tls | bool else 'http' }}"
ironic_api_url: "{{ api_protocol }}://{{ internal_ip }}:6385" ironic_api_url: "{{ api_protocol }}://{{ internal_ip }}:6385"

View File

@ -38,6 +38,14 @@
- openstack_cloud is defined - openstack_cloud is defined
no_log: yes no_log: yes
- name: "Set the TLS certificate if present"
set_fact:
tls_certificate_path: "{{ openstack_cloud.cacert }}"
when:
- tls_certificate_path is undefined
- openstack_cloud is defined
- openstack_cloud.cacert is defined
- name: "If in noauth mode and no clouds.yaml, unset authentication parameters." - name: "If in noauth mode and no clouds.yaml, unset authentication parameters."
set_fact: set_fact:
auth_type: None auth_type: None

View File

@ -23,6 +23,7 @@
cloud: "{{ cloud_name | default(omit) }}" cloud: "{{ cloud_name | default(omit) }}"
auth_type: "{{ auth_type | default(omit) }}" auth_type: "{{ auth_type | default(omit) }}"
auth: "{{ auth | default(omit) }}" auth: "{{ auth | default(omit) }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
ironic_url: "{{ ironic_url | default(omit) }}" ironic_url: "{{ ironic_url | default(omit) }}"
uuid: "{{ uuid | default() }}" uuid: "{{ uuid | default() }}"
name: "{{ name | default() }}" name: "{{ name | default() }}"

View File

@ -56,6 +56,7 @@
cloud: "{{ cloud_name | default(omit) }}" cloud: "{{ cloud_name | default(omit) }}"
auth_type: "{{ auth_type | default(omit) }}" auth_type: "{{ auth_type | default(omit) }}"
auth: "{{ auth | default(omit) }}" auth: "{{ auth | default(omit) }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
ironic_url: "{{ ironic_url | default(omit) }}" ironic_url: "{{ ironic_url | default(omit) }}"
uuid: "{{ uuid }}" uuid: "{{ uuid }}"
state: present state: present
@ -85,6 +86,7 @@
cloud: "{{ cloud_name | default(omit) }}" cloud: "{{ cloud_name | default(omit) }}"
auth_type: "{{ auth_type | default(omit) }}" auth_type: "{{ auth_type | default(omit) }}"
auth: "{{ auth | default(omit) }}" auth: "{{ auth | default(omit) }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
ironic_url: "{{ ironic_url | default(omit) }}" ironic_url: "{{ ironic_url | default(omit) }}"
uuid: "{{ uuid }}" uuid: "{{ uuid }}"
state: present state: present

View File

@ -262,7 +262,7 @@ noauth_mode: true
enable_keystone: false enable_keystone: false
# Service URLs used for communication with them. # Service URLs used for communication with them.
api_protocol: http api_protocol: "{{ 'https' if enable_tls | bool else 'http' }}"
ironic_api_url: "{{ api_protocol }}://{{ internal_ip }}:6385" ironic_api_url: "{{ api_protocol }}://{{ internal_ip }}:6385"
ironic_inspector_api_url: "{{ api_protocol }}://{{ internal_ip }}:5050" ironic_inspector_api_url: "{{ api_protocol }}://{{ internal_ip }}:5050"
keystone_api_url: "{{ api_protocol }}://{{ internal_ip }}:5000/v3" keystone_api_url: "{{ api_protocol }}://{{ internal_ip }}:5000/v3"
@ -341,3 +341,10 @@ pip_opts: "{{ lookup('env', 'PIP_OPTS') | default('') }}"
# Timeout for gathering facts. # Timeout for gathering facts.
fact_gather_timeout: "{{ lookup('config', 'DEFAULT_GATHER_TIMEOUT', on_missing='skip') | default(omit, true) }}" fact_gather_timeout: "{{ lookup('config', 'DEFAULT_GATHER_TIMEOUT', on_missing='skip') | default(omit, true) }}"
# Enable TLS support.
enable_tls: false
tls_root: /etc/bifrost
tls_certificate_path: "{{ tls_root }}/bifrost.crt"
ironic_private_key_path: /etc/ironic/ironic.pem
ironic_inspector_private_key_path: /etc/ironic-inspector/inspector.pem

View File

@ -144,6 +144,15 @@
- not noauth_mode | bool - not noauth_mode | bool
- not enable_keystone | bool - not enable_keystone | bool
- name: "Generate TLS parameters"
include_role:
name: bifrost-tls
vars:
dest_private_key_path: "{{ ironic_private_key_path }}"
dest_private_key_owner: ironic
dest_private_key_group: ironic
when: enable_tls | bool
- name: "Populate keystone for Bifrost" - name: "Populate keystone for Bifrost"
include: keystone_setup.yml include: keystone_setup.yml
when: when:

View File

@ -92,6 +92,15 @@
- not noauth_mode | bool - not noauth_mode | bool
- not enable_keystone | bool - not enable_keystone | bool
- name: "Generate TLS parameters"
include_role:
name: bifrost-tls
vars:
dest_private_key_path: "{{ ironic_inspector_private_key_path }}"
dest_private_key_owner: ironic
dest_private_key_group: ironic
when: enable_tls | bool
- name: "Populate keystone for ironic-inspector " - name: "Populate keystone for ironic-inspector "
include: keystone_setup_inspector.yml include: keystone_setup_inspector.yml
when: enable_keystone | bool when: enable_keystone | bool

View File

@ -53,6 +53,7 @@
domain_id: "default" domain_id: "default"
enabled: yes enabled: yes
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
no_log: true no_log: true
@ -66,6 +67,7 @@
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
update_password: always update_password: always
wait: yes wait: yes
ca_cert: "{{ tls_certificate_path | default(omit) }}"
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
no_log: true no_log: true
@ -76,6 +78,7 @@
project: "{{ ironic.service_catalog.project_name }}" project: "{{ ironic.service_catalog.project_name }}"
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
wait: yes wait: yes
ca_cert: "{{ tls_certificate_path | default(omit) }}"
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
no_log: true no_log: true
@ -87,6 +90,7 @@
description: OpenStack Baremetal Service description: OpenStack Baremetal Service
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
wait: yes wait: yes
ca_cert: "{{ tls_certificate_path | default(omit) }}"
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
register: baremetal_catalog_service register: baremetal_catalog_service
no_log: true no_log: true
@ -99,6 +103,7 @@
url: "{{ ironic.keystone.admin_url | default(ironic_api_url) }}" url: "{{ ironic.keystone.admin_url | default(ironic_api_url) }}"
region: "{{ keystone.bootstrap.region_name | default('RegionOne') }}" region: "{{ keystone.bootstrap.region_name | default('RegionOne') }}"
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
no_log: true no_log: true
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
@ -115,6 +120,7 @@
url: "{{ ironic.keystone.public_url | default(ironic_public_url) | default(ironic_api_url) }}" url: "{{ ironic.keystone.public_url | default(ironic_public_url) | default(ironic_api_url) }}"
region: "{{ keystone.bootstrap.region_name | default('RegionOne') }}" region: "{{ keystone.bootstrap.region_name | default('RegionOne') }}"
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
no_log: true no_log: true
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
@ -131,6 +137,7 @@
url: "{{ ironic.keystone.internal_url | default(ironic_private_url) | default(ironic_api_url) }}" url: "{{ ironic.keystone.internal_url | default(ironic_private_url) | default(ironic_api_url) }}"
region: "{{ keystone.bootstrap.region_name | default('RegionOne') }}" region: "{{ keystone.bootstrap.region_name | default('RegionOne') }}"
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
no_log: true no_log: true
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
@ -139,6 +146,7 @@
name: "baremetal_admin" name: "baremetal_admin"
state: present state: present
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
no_log: true no_log: true
@ -147,6 +155,7 @@
name: "baremetal_observer" name: "baremetal_observer"
state: present state: present
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
no_log: true no_log: true
@ -158,6 +167,7 @@
domain_id: "default" domain_id: "default"
enabled: yes enabled: yes
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
no_log: true no_log: true
@ -169,6 +179,7 @@
domain: "default" domain: "default"
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
wait: yes wait: yes
ca_cert: "{{ tls_certificate_path | default(omit) }}"
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
no_log: true no_log: true
@ -179,5 +190,6 @@
project: "baremetal" project: "baremetal"
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
wait: yes wait: yes
ca_cert: "{{ tls_certificate_path | default(omit) }}"
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
no_log: true no_log: true

View File

@ -53,6 +53,7 @@
default_project: "{{ ironic_inspector.service_catalog.project_name | default('service') }}" default_project: "{{ ironic_inspector.service_catalog.project_name | default('service') }}"
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
wait: yes wait: yes
ca_cert: "{{ tls_certificate_path | default(omit) }}"
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
no_log: true no_log: true
@ -63,6 +64,7 @@
project: "{{ ironic_inspector.service_catalog.project_name | default('service') }}" project: "{{ ironic_inspector.service_catalog.project_name | default('service') }}"
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
wait: yes wait: yes
ca_cert: "{{ tls_certificate_path | default(omit) }}"
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
no_log: true no_log: true
@ -74,6 +76,7 @@
description: OpenStack Baremetal Introspection Service description: OpenStack Baremetal Introspection Service
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
wait: yes wait: yes
ca_cert: "{{ tls_certificate_path | default(omit) }}"
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
register: introspection_catalog_service register: introspection_catalog_service
no_log: true no_log: true
@ -86,6 +89,7 @@
url: "{{ ironic_inspector.keystone.admin_url | default(ironic_inspector_api_url) }}" url: "{{ ironic_inspector.keystone.admin_url | default(ironic_inspector_api_url) }}"
region: "{{ keystone.bootstrap.region_name | default('RegionOne') }}" region: "{{ keystone.bootstrap.region_name | default('RegionOne') }}"
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
no_log: true no_log: true
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
@ -102,6 +106,7 @@
url: "{{ ironic_inspector.keystone.public_url | default(ironic_inspector_public_url) | default(ironic_inspector_api_url) }}" url: "{{ ironic_inspector.keystone.public_url | default(ironic_inspector_public_url) | default(ironic_inspector_api_url) }}"
region: "{{ keystone.bootstrap.region_name | default('RegionOne') }}" region: "{{ keystone.bootstrap.region_name | default('RegionOne') }}"
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
no_log: true no_log: true
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
@ -118,6 +123,7 @@
url: "{{ ironic_inspector.keystone.internal_url | default(ironic_inspector_private_url) | default(ironic_inspector_api_url) }}" url: "{{ ironic_inspector.keystone.internal_url | default(ironic_inspector_private_url) | default(ironic_inspector_api_url) }}"
region: "{{ keystone.bootstrap.region_name | default('RegionOne') }}" region: "{{ keystone.bootstrap.region_name | default('RegionOne') }}"
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
no_log: true no_log: true
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
@ -130,6 +136,7 @@
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
update_password: always update_password: always
wait: yes wait: yes
ca_cert: "{{ tls_certificate_path | default(omit) }}"
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
no_log: true no_log: true
@ -140,5 +147,6 @@
project: baremetal project: baremetal
auth: "{{ keystone_auth }}" auth: "{{ keystone_auth }}"
wait: yes wait: yes
ca_cert: "{{ tls_certificate_path | default(omit) }}"
environment: "{{ bifrost_venv_env }}" environment: "{{ bifrost_venv_env }}"
no_log: true no_log: true

View File

@ -44,6 +44,11 @@
- not enable_keystone | bool - not enable_keystone | bool
no_log: yes no_log: yes
- name: "Set OS_CACERT if required"
set_fact:
testing_env: "{{ testing_env | combine({'OS_CACERT': tls_certificate_path}) }}"
when: enable_tls | bool
- name: "Validate API access and at least one conductor" - name: "Validate API access and at least one conductor"
command: baremetal conductor list -f value -c Hostname command: baremetal conductor list -f value -c Hostname
environment: "{{ testing_env | combine(bifrost_venv_env) }}" environment: "{{ testing_env | combine(bifrost_venv_env) }}"
@ -77,6 +82,11 @@
- enable_inspector | bool - enable_inspector | bool
no_log: yes no_log: yes
- name: "Set OS_CACERT if required"
set_fact:
testing_env: "{{ testing_env | combine({'OS_CACERT': tls_certificate_path}) }}"
when: enable_tls | bool
- name: "Validate introspection API access" - name: "Validate introspection API access"
command: baremetal introspection list command: baremetal introspection list
environment: "{{ testing_env | combine(bifrost_venv_env) }}" environment: "{{ testing_env | combine(bifrost_venv_env) }}"

View File

@ -5,6 +5,6 @@ dhcp || reboot
goto introspect goto introspect
:introspect :introspect
kernel {{ ipa_kernel_url }} ipa-inspection-callback-url=http://{{ internal_ip }}:5050/v1/continue {% if fast_track | bool %}ipa-api-url=http://{{ internal_ip }}:6385{% endif %} systemd.journald.forward_to_console=yes BOOTIF=${mac} nofb nomodeset vga=normal console=ttyS0 {{ inspector_extra_kernel_options | default('') }} initrd={{ ipa_ramdisk_url | basename }} kernel {{ ipa_kernel_url }} ipa-inspection-callback-url={{ api_protocol }}://{{ internal_ip }}:5050/v1/continue {% if fast_track | bool %}ipa-api-url={{ api_protocol }}://{{ internal_ip }}:6385{% endif %} systemd.journald.forward_to_console=yes BOOTIF=${mac} nofb nomodeset vga=normal console=ttyS0 {{ inspector_extra_kernel_options | default('') }} ipa-insecure=1 initrd={{ ipa_ramdisk_url | basename }}
initrd {{ ipa_ramdisk_url }} initrd {{ ipa_ramdisk_url }}
boot boot

View File

@ -21,6 +21,14 @@ transport_url = rabbit://ironic:{{ironic_db_password }}@{{ message_queue_host |
transport_url = fake:// transport_url = fake://
{% endif %} {% endif %}
{% if enable_tls | bool %}
use_ssl = True
[ssl]
cert_file = {{ tls_certificate_path }}
key_file = {{ ironic_inspector_private_key_path }}
{% endif %}
[database] [database]
connection=mysql+pymysql://{{ ironic_inspector.database.username }}:{{ ironic_inspector.database.password }}@{{ ironic_inspector.database.host }}/{{ ironic_inspector.database.name }}?charset=utf8 connection=mysql+pymysql://{{ ironic_inspector.database.username }}:{{ ironic_inspector.database.password }}@{{ ironic_inspector.database.host }}/{{ ironic_inspector.database.name }}?charset=utf8
@ -50,6 +58,9 @@ endpoint_override = {{ ironic_api_url }}
username = {{ admin_username }} username = {{ admin_username }}
password = {{ admin_password }} password = {{ admin_password }}
{% endif %} {% endif %}
{% if enable_tls | bool %}
cafile = {{ tls_certificate_path }}
{% endif %}
{% if enable_keystone is defined and enable_keystone | bool == true %} {% if enable_keystone is defined and enable_keystone | bool == true %}
[keystone_authtoken] [keystone_authtoken]
@ -60,7 +71,9 @@ password = {{ ironic_inspector.service_catalog.password }}
user_domain_id = default user_domain_id = default
project_name = service project_name = service
project_domain_id = default project_domain_id = default
{% if enable_tls | bool %}
cafile = {{ tls_certificate_path }}
{% endif %}
{% endif %} {% endif %}
[processing] [processing]

View File

@ -40,6 +40,15 @@ http_basic_auth_user_file = /etc/ironic/htpasswd
log_dir = {{ ironic_log_dir }} log_dir = {{ ironic_log_dir }}
{% endif %} {% endif %}
{% if enable_tls | bool %}
[api]
enable_ssl_api = True
[ssl]
cert_file = {{ tls_certificate_path }}
key_file = {{ ironic_private_key_path }}
{% endif %}
[agent] [agent]
{% if ironic_store_ramdisk_logs | bool %} {% if ironic_store_ramdisk_logs | bool %}
deploy_logs_collect = always deploy_logs_collect = always
@ -50,9 +59,9 @@ deploy_logs_local_path = {{ ironic_agent_deploy_logs_local_path }}
[pxe] [pxe]
{% if testing | bool %} {% if testing | bool %}
pxe_append_params = console=ttyS0 pxe_append_params = console=ttyS0 ipa-insecure=1
{% else %} {% else %}
pxe_append_params = systemd.journald.forward_to_console=yes {{ extra_kernel_options | default('') }} pxe_append_params = systemd.journald.forward_to_console=yes ipa-insecure=1 {{ extra_kernel_options | default('') }}
{% endif %} {% endif %}
pxe_config_template = $pybasedir/drivers/modules/ipxe_config.template pxe_config_template = $pybasedir/drivers/modules/ipxe_config.template
tftp_server = {{ internal_ip }} tftp_server = {{ internal_ip }}
@ -108,7 +117,7 @@ use_web_server_for_images = true
{% if enable_inspector | bool == true %} {% if enable_inspector | bool == true %}
[inspector] [inspector]
power_off = {{ power_off_after_inspection }} power_off = {{ power_off_after_inspection }}
extra_kernel_params = {{ inspector_extra_kernel_options | default('') }} extra_kernel_params = ipa-insecure=1 {{ inspector_extra_kernel_options | default('') }}
{% if enable_keystone | bool %} {% if enable_keystone | bool %}
auth_type = password auth_type = password
auth_url = {{ ironic.service_catalog.auth_url }} auth_url = {{ ironic.service_catalog.auth_url }}
@ -118,16 +127,20 @@ user_domain_id = default
project_name = {{ ironic.service_catalog.project_name }} project_name = {{ ironic.service_catalog.project_name }}
project_domain_id = default project_domain_id = default
region_name = {{ keystone.bootstrap.region_name | default('RegionOne')}} region_name = {{ keystone.bootstrap.region_name | default('RegionOne')}}
callback_endpoint_override = http://{{ internal_ip }}:5050 # NOTE(dtantsur): this has to be on internal IP even if public IPs are used
callback_endpoint_override = {{ api_protocol }}://{{ internal_ip }}:5050
{% elif noauth_mode | bool %} {% elif noauth_mode | bool %}
auth_type=none auth_type=none
endpoint_override = http://{{ internal_ip }}:5050 endpoint_override = {{ ironic_inspector_api_url }}
{% else %} {% else %}
auth_type = http_basic auth_type = http_basic
endpoint_override = http://{{ internal_ip }}:5050 endpoint_override = {{ ironic_inspector_api_url }}
username = {{ admin_username }} username = {{ admin_username }}
password = {{ admin_password }} password = {{ admin_password }}
{% endif %} {% endif %}
{% if enable_tls | bool %}
cafile = {{ tls_certificate_path }}
{% endif %}
{% endif %} {% endif %}
{% if enable_keystone is defined and enable_keystone | bool == true %} {% if enable_keystone is defined and enable_keystone | bool == true %}
@ -139,6 +152,9 @@ password = {{ ironic.service_catalog.password }}
user_domain_id = default user_domain_id = default
project_name = {{ ironic.service_catalog.project_name }} project_name = {{ ironic.service_catalog.project_name }}
project_domain_id = default project_domain_id = default
{% if enable_tls | bool %}
cafile = {{ tls_certificate_path }}
{% endif %}
{% endif %} {% endif %}
[service_catalog] [service_catalog]
@ -158,9 +174,14 @@ auth_type = http_basic
username = {{ admin_username }} username = {{ admin_username }}
password = {{ admin_password }} password = {{ admin_password }}
{% endif %} {% endif %}
endpoint_override = http://{{ internal_ip }}:6385 # NOTE(dtantsur): this has to be on internal IP even if public IPs are used
endpoint_override = {{ api_protocol }}://{{ internal_ip }}:6385
[json_rpc] [json_rpc]
{% if enable_tls | bool %}
use_ssl = True
cafile = {{ tls_certificate_path }}
{% endif %}
{% if enable_keystone | bool %} {% if enable_keystone | bool %}
auth_strategy = keystone auth_strategy = keystone
auth_url = {{ ironic.service_catalog.auth_url }} auth_url = {{ ironic.service_catalog.auth_url }}

View File

@ -4,8 +4,10 @@ network_interface: "virbr0"
ans_network_interface: "{{ network_interface | replace('-', '_') }}" ans_network_interface: "{{ network_interface | replace('-', '_') }}"
internal_ip: "{{ hostvars[inventory_hostname]['ansible_' + ans_network_interface]['ipv4']['address'] }}" internal_ip: "{{ hostvars[inventory_hostname]['ansible_' + ans_network_interface]['ipv4']['address'] }}"
enable_tls: false
# Service URLs used for communication with them. # Service URLs used for communication with them.
api_protocol: http api_protocol: "{{ 'https' if enable_tls | bool else 'http' }}"
ironic_api_url: "{{ api_protocol }}://{{ internal_ip }}:6385" ironic_api_url: "{{ api_protocol }}://{{ internal_ip }}:6385"
ironic_inspector_api_url: "{{ api_protocol }}://{{ internal_ip }}:5050" ironic_inspector_api_url: "{{ api_protocol }}://{{ internal_ip }}:5050"

View File

@ -31,6 +31,11 @@
- "{{ config_region_name is defined }}" - "{{ config_region_name is defined }}"
- "{{ config_auth_url is defined }}" - "{{ config_auth_url is defined }}"
- name: "Generate TLS parameters"
include_role:
name: bifrost-tls
when: enable_tls | bool
- name: "Ensure the ~/.config exists" - name: "Ensure the ~/.config exists"
file: file:
name: "~{{ user | default('root') }}/.config" name: "~{{ user | default('root') }}/.config"

View File

@ -13,16 +13,25 @@ clouds:
project_domain_id: "{{ cloud.1.config_project_domain_id | default('default') }}" project_domain_id: "{{ cloud.1.config_project_domain_id | default('default') }}"
user_domain_id: "{{ cloud.1.config_user_domain_id | default('default') }}" user_domain_id: "{{ cloud.1.config_user_domain_id | default('default') }}"
identity_api_version: "3" identity_api_version: "3"
{% if enable_tls | bool %}
cacert: "{{ tls_certificate_path }}"
{% endif %}
{% endfor %} {% endfor %}
{% elif noauth_mode | default(true) | bool %} {% elif noauth_mode | default(true) | bool %}
bifrost: bifrost:
auth_type: "none" auth_type: "none"
baremetal_endpoint_override: {{ ironic_api_url }} baremetal_endpoint_override: {{ ironic_api_url }}
baremetal_introspection_endpoint_override: {{ ironic_inspector_api_url }} baremetal_introspection_endpoint_override: {{ ironic_inspector_api_url }}
{% if enable_tls | bool %}
cacert: "{{ tls_certificate_path }}"
{% endif %}
# Deprecated # Deprecated
bifrost-inspector: bifrost-inspector:
auth_type: "none" auth_type: "none"
endpoint: {{ ironic_inspector_api_url }} endpoint: {{ ironic_inspector_api_url }}
{% if enable_tls | bool %}
cacert: "{{ tls_certificate_path }}"
{% endif %}
{% else %} {% else %}
bifrost: bifrost:
auth_type: "http_basic" auth_type: "http_basic"
@ -31,6 +40,9 @@ clouds:
password: "{{ default_password }}" password: "{{ default_password }}"
endpoint: {{ ironic_api_url }} endpoint: {{ ironic_api_url }}
baremetal_introspection_endpoint_override: {{ ironic_inspector_api_url }} baremetal_introspection_endpoint_override: {{ ironic_inspector_api_url }}
{% if enable_tls | bool %}
cacert: "{{ tls_certificate_path }}"
{% endif %}
bifrost-admin: bifrost-admin:
auth_type: "http_basic" auth_type: "http_basic"
auth: auth:
@ -38,4 +50,7 @@ clouds:
password: "{{ admin_password }}" password: "{{ admin_password }}"
endpoint: {{ ironic_api_url }} endpoint: {{ ironic_api_url }}
baremetal_introspection_endpoint_override: {{ ironic_inspector_api_url }} baremetal_introspection_endpoint_override: {{ ironic_inspector_api_url }}
{% if enable_tls | bool %}
cacert: "{{ tls_certificate_path }}"
{% endif %}
{% endif %} {% endif %}

View File

@ -36,3 +36,7 @@ case "${1:-bifrost}" in
*) echo -e "\nERROR unsupported or unspecified profile: $1\nMust be one of bifrost, bifrost-admin";; *) echo -e "\nERROR unsupported or unspecified profile: $1\nMust be one of bifrost, bifrost-admin";;
esac esac
{% endif %} {% endif %}
{% if enable_tls | bool %}
export OS_CACERT="{{ tls_certificate_path }}"
{% endif %}

View File

@ -35,7 +35,7 @@ network_interface: "virbr0"
ans_network_interface: "{{ network_interface | replace('-', '_') }}" ans_network_interface: "{{ network_interface | replace('-', '_') }}"
internal_ip: "{{ hostvars[inventory_hostname]['ansible_' + ans_network_interface]['ipv4']['address'] }}" internal_ip: "{{ hostvars[inventory_hostname]['ansible_' + ans_network_interface]['ipv4']['address'] }}"
api_protocol: http api_protocol: "{{ 'https' if enable_tls | bool else 'http' }}"
keystone_api_url: "{{ api_protocol }}://{{ internal_ip }}:5000/v3" keystone_api_url: "{{ api_protocol }}://{{ internal_ip }}:5000/v3"
# Defaults required by this role that are normally inherited via # Defaults required by this role that are normally inherited via
@ -85,3 +85,9 @@ keystone:
host: localhost host: localhost
pip_opts: "{{ lookup('env', 'PIP_OPTS') | default('') }}" pip_opts: "{{ lookup('env', 'PIP_OPTS') | default('') }}"
# Enable TLS support.
enable_tls: false
tls_root: /etc/bifrost
tls_certificate_path: "{{ tls_root }}/bifrost.crt"
nginx_private_key_path: /etc/nginx/keystone.pem

View File

@ -77,6 +77,15 @@
login_password: "{{ mysql_password | default(None) }}" login_password: "{{ mysql_password | default(None) }}"
when: keystone.database.host == 'localhost' when: keystone.database.host == 'localhost'
- name: "Generate TLS parameters"
include_role:
name: bifrost-tls
vars:
dest_private_key_path: "{{ nginx_private_key_path }}"
dest_private_key_owner: "{{ nginx_user }}"
dest_private_key_group: "{{ nginx_user }}"
when: enable_tls | bool
- name: "Create an keystone service group" - name: "Create an keystone service group"
group: group:
name: "keystone" name: "keystone"

View File

@ -45,34 +45,15 @@
- enable_keystone | bool - enable_keystone | bool
- not skip_bootstrap | bool - not skip_bootstrap | bool
- name: "Upgrade existing installation"
include: upgrade.yml
when:
- enable_keystone | bool
- not skip_bootstrap | bool
- not skip_start | bool
- name: "Start Keystone services" - name: "Start Keystone services"
include: start.yml include: start.yml
when: when:
- enable_keystone | bool - enable_keystone | bool
- not skip_start | bool - not skip_start | bool
- name: "Change the bootstrap password from the static value on upgrade"
os_user:
name: "{{ keystone.bootstrap.username }}"
password: "{{ keystone.bootstrap.password }}"
update_password: always
state: present
domain: "default"
default_project: "{{ keystone.bootstrap.project_name }}"
auth:
auth_url: "{{ ironic.service_catalog.auth_url | default('http://127.0.0.1:5000/') }}"
username: "{{ keystone.bootstrap.username }}"
password: "ChangeThisPa55w0rd"
project_name: "{{ keystone.bootstrap.project_name | default('admin') }}"
project_domain_id: "default"
user_domain_id: "default"
wait: yes
environment: "{{ bifrost_venv_env }}"
no_log: true
ignore_errors: true
when:
- enable_keystone | bool
- not skip_bootstrap | bool
- test_created_keystone_db is undefined or not test_created_keystone_db.changed | bool
- keystone.bootstrap.enabled | bool
- keystone.database.host == 'localhost'

View File

@ -0,0 +1,121 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
---
# TODO(dtantsur): can be removed in W
- name: "Change the bootstrap password from the static value on upgrade"
openstack.cloud.identity_user:
name: "{{ keystone.bootstrap.username }}"
password: "{{ keystone.bootstrap.password }}"
update_password: always
state: present
domain: "default"
default_project: "{{ keystone.bootstrap.project_name }}"
auth:
auth_url: "{{ ironic.service_catalog.auth_url | default('http://127.0.0.1:5000/') }}"
username: "{{ keystone.bootstrap.username }}"
password: "ChangeThisPa55w0rd"
project_name: "{{ keystone.bootstrap.project_name | default('admin') }}"
project_domain_id: "default"
user_domain_id: "default"
wait: yes
ca_cert: "{{ tls_certificate_path | default(omit) }}"
environment: "{{ bifrost_venv_env }}"
no_log: true
ignore_errors: true
when:
- test_created_keystone_db is undefined or not test_created_keystone_db.changed | bool
- keystone.bootstrap.enabled | bool
- keystone.database.host == 'localhost'
# NOTE(dtantsur): these tasks are required for update from HTTP to HTTPS
- name: "Configure keystone auth with http"
set_fact:
keystone_auth:
auth_url: "{{ ironic.service_catalog.auth_url | default(keystone_api_url) | replace('https:', 'http:') }}"
username: "{{ keystone.bootstrap.username }}"
password: "{{ keystone.bootstrap.password }}"
project_name: "{{ keystone.bootstrap.project_name | default('admin') }}"
project_domain_id: "default"
user_domain_id: "default"
no_log: true
when: api_protocol == 'https'
- name: "Configure keystone auth with https"
set_fact:
keystone_auth:
auth_url: "{{ ironic.service_catalog.auth_url | default(keystone_api_url) | replace('http:', 'https:') }}"
username: "{{ keystone.bootstrap.username }}"
password: "{{ keystone.bootstrap.password }}"
project_name: "{{ keystone.bootstrap.project_name | default('admin') }}"
project_domain_id: "default"
user_domain_id: "default"
# NOTE(dtantsur): we cannot use tls_certificate_path as it won't be present
# on an upgrade to non-TLS.
keystone_ca_cert: /etc/bifrost/bifrost.crt
no_log: true
when: api_protocol == 'http'
- name: "Ensure keystone service record for keystone"
openstack.cloud.catalog_service:
state: present
name: "keystone"
service_type: "identity"
auth: "{{ keystone_auth }}"
wait: yes
ca_cert: "{{ keystone_ca_cert | default(omit) }}"
environment: "{{ bifrost_venv_env }}"
register: identity_catalog_service
ignore_errors: true
no_log: true
- name: "Update identity internal endpoint"
openstack.cloud.endpoint:
state: present
service: "{{ identity_catalog_service.id }}"
endpoint_interface: internal
url: "{{ keystone.bootstrap.internal_url | default(keystone_private_url) | default(keystone_api_url) }}"
region: "{{ keystone.bootstrap.region_name | default('RegionOne') }}"
auth: "{{ keystone_auth }}"
ca_cert: "{{ keystone_ca_cert | default(omit) }}"
ignore_errors: true
no_log: true
when: identity_catalog_service.id is defined
- name: "Update identity admin endpoint"
openstack.cloud.endpoint:
state: present
service: "{{ identity_catalog_service.id }}"
endpoint_interface: admin
url: "{{ keystone.bootstrap.admin_url | default(keystone_api_url) }}"
region: "{{ keystone.bootstrap.region_name | default('RegionOne') }}"
auth: "{{ keystone_auth }}"
ca_cert: "{{ keystone_ca_cert | default(omit) }}"
ignore_errors: true
no_log: true
when: identity_catalog_service.id is defined
# NOTE(dtantsur): the public endpoint MUST go last, otherwise the other
# endpoints will fail to update.
- name: "Update identity public endpoint"
openstack.cloud.endpoint:
state: present
service: "{{ identity_catalog_service.id }}"
endpoint_interface: public
url: "{{ keystone.bootstrap.public_url | default(keystone_public_url) | default(keystone_api_url) }}"
region: "{{ keystone.bootstrap.region_name | default('RegionOne') }}"
auth: "{{ keystone_auth }}"
ca_cert: "{{ keystone_ca_cert | default(omit) }}"
ignore_errors: true
no_log: true
when: identity_catalog_service.id is defined

View File

@ -1,6 +1,12 @@
# {{ ansible_managed }} # {{ ansible_managed }}
server { server {
{% if enable_tls | bool %}
listen 5000 ssl;
ssl_certificate {{ tls_certificate_path }};
ssl_certificate_key {{ nginx_private_key_path }};
{% else %}
listen 5000; listen 5000;
{% endif %}
access_log /var/log/nginx/keystone/access.log; access_log /var/log/nginx/keystone/access.log;
error_log /var/log/nginx/keystone/error.log; error_log /var/log/nginx/keystone/error.log;
location / { location / {
@ -10,7 +16,13 @@ server {
} }
} }
server { server {
{% if enable_tls | bool %}
listen 35357 ssl;
ssl_certificate {{ tls_certificate_path }};
ssl_certificate_key {{ nginx_private_key_path }};
{% else %}
listen 35357; listen 35357;
{% endif %}
access_log /var/log/nginx/keystone/access.log; access_log /var/log/nginx/keystone/access.log;
error_log /var/log/nginx/keystone/error.log; error_log /var/log/nginx/keystone/error.log;
location / { location / {

View File

@ -0,0 +1,86 @@
bifrost-tls
===========
This role generates TLS certificates for Bifrost and copies the private key to
a predefined location.
Requirements
------------
This role requires:
- Ansible 2.9
Role Variables
--------------
generate_tls: Whether the generate new certificates or use existing ones.
If the latter, this role only handles copying the private key,
all files have to exist. Defaults to `false` to avoid overwriting
operator's files.
network_interface: Network interface services are listening on.
tls_common_name: The common name of the certificate. Defaults to the host's
full domain name (FQDN).
tls_hosts: A list of valid IP addresses for the generated certificate. Defaults
to `public_ip` (if set), `private_ip` (if set), `internal_ip` and
127.0.0.1. The host `localhost` is always added.
tls_host_names: A list of valid host names for the generated certificate.
Defaults to the host's FQDN + `localhost`.
tls_certificate_path: Path to the TLS certificate. Can be generated.
tls_private_key_path: Path to the private key. Can be generated.
tls_csr_path: Path to the signing request. Can be generated.
tls_force_regenerate: Boolean, whether to regenerate existing certificates.
Defaults to `false`.
dest_private_key_path: Destination to copy the private key to. Defaults to
undefined (not copying).
dest_private_key_owner: Owner of the destination private key. Defaults to root.
dest_private_key_group: Group of the destination private key. Defaults to root.
Dependencies
------------
None at this time.
Example Playbook
----------------
- hosts: localhost
connection: local
name: "Generate TLS parameters"
become: yes
gather_facts: yes
roles:
- role: bifrost-tls
generate_tls: true
tls_common_name: example.com
License
-------
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Author Information
------------------
Ironic Developers

View File

@ -0,0 +1,34 @@
---
generate_tls: false
# NOTE(dtantsur): we don't want to make our generated certificates accepted
# system-wide, hence storing them here.
tls_root: /etc/bifrost
tls_certificate_path: "{{ tls_root }}/bifrost.crt"
tls_private_key_path: "{{ tls_root }}/bifrost.pem"
tls_csr_path: "{{ tls_root }}/bifrost.csr"
# Force re-generating of certificates.
tls_force_regenerate: false
# Copy the resulting key to:
#dest_private_key_path:
dest_private_key_owner: root
dest_private_key_group: root
# Don't change this unless you really know what you're doing.
dest_private_key_mode: 0600
network_interface: "virbr0"
ans_network_interface: "{{ network_interface | replace('-', '_') }}"
internal_interface: "{{ hostvars[inventory_hostname]['ansible_' + ans_network_interface]['ipv4'] }}"
internal_ip: "{{ internal_interface['address'] }}"
# Common name for the certificate.
tls_common_name: "{{ ansible_fqdn }}"
tls_hosts: >-
{{ [internal_ip, '127.0.0.1']
+ ([public_ip] if public_ip is defined else [])
+ ([private_ip] if private_ip is defined else []) }}
tls_host_names:
- localhost
- "{{ ansible_fqdn }}"

View File

@ -0,0 +1,54 @@
---
- name: "Ensure the certificate root directory"
file:
path: "{{ tls_root }}"
state: directory
owner: root
group: root
mode: 0755
when: generate_tls | bool
- name: "Generate private key"
openssl_privatekey:
path: "{{ tls_private_key_path }}"
force: "{{ tls_force_regenerate | bool }}"
owner: root
group: root
mode: 0600
when: generate_tls | bool
- name: "Generate certificate signing request"
openssl_csr:
path: "{{ tls_csr_path }}"
privatekey_path: "{{ tls_private_key_path }}"
force: "{{ tls_force_regenerate | bool }}"
owner: root
group: root
mode: 0600
common_name: "{{ tls_common_name }}"
subject_alt_name: >-
{{ (tls_hosts | map('regex_replace', '^', 'IP:') | list)
+ (tls_host_names | map('regex_replace', '^', 'DNS:') | list) }}
when: generate_tls | bool
- name: "Generate self-signed TLS certificates"
openssl_certificate:
provider: selfsigned
path: "{{ tls_certificate_path }}"
privatekey_path: "{{ tls_private_key_path }}"
csr_path: "{{ tls_csr_path }}"
force: "{{ tls_force_regenerate | bool }}"
owner: root
group: root
mode: 0644
when: generate_tls | bool
- name: "Copy the key to the destination"
copy:
src: "{{ tls_private_key_path }}"
dest: "{{ dest_private_key_path }}"
remote_src: yes
owner: "{{ dest_private_key_owner }}"
group: "{{ dest_private_key_group }}"
mode: "{{ dest_private_key_mode }}"
when: dest_private_key_path is defined

View File

@ -20,6 +20,7 @@
cloud: "{{ cloud_name | default(omit) }}" cloud: "{{ cloud_name | default(omit) }}"
auth_type: "{{ auth_type | default(omit) }}" auth_type: "{{ auth_type | default(omit) }}"
auth: "{{ auth | default(omit) }}" auth: "{{ auth | default(omit) }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
ironic_url: "{{ ironic_url | default(omit) }}" ironic_url: "{{ ironic_url | default(omit) }}"
uuid: "{{ uuid | default() }}" uuid: "{{ uuid | default() }}"
name: "{{ name | default() }}" name: "{{ name | default() }}"

View File

@ -20,6 +20,7 @@
cloud: "{{ cloud_name | default(omit) }}" cloud: "{{ cloud_name | default(omit) }}"
auth_type: "{{ auth_type | default(omit) }}" auth_type: "{{ auth_type | default(omit) }}"
auth: "{{ auth | default(omit) }}" auth: "{{ auth | default(omit) }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
ironic_url: "{{ ironic_url | default(omit) }}" ironic_url: "{{ ironic_url | default(omit) }}"
driver: "" driver: ""
uuid: "{{ uuid | default() }}" uuid: "{{ uuid | default() }}"

View File

@ -24,6 +24,7 @@
cloud: "{{ cloud_name | default(omit) }}" cloud: "{{ cloud_name | default(omit) }}"
auth_type: "{{ auth_type | default(omit) }}" auth_type: "{{ auth_type | default(omit) }}"
auth: "{{ auth | default(omit) }}" auth: "{{ auth | default(omit) }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
ironic_url: "{{ ironic_url | default(omit) }}" ironic_url: "{{ ironic_url | default(omit) }}"
driver: "{{ driver }}" driver: "{{ driver }}"
uuid: "{{ uuid | default() }}" uuid: "{{ uuid | default() }}"

View File

@ -49,6 +49,7 @@
cloud: "{{ cloud_name | default(omit) }}" cloud: "{{ cloud_name | default(omit) }}"
auth_type: "{{ auth_type | default(omit) }}" auth_type: "{{ auth_type | default(omit) }}"
auth: "{{ auth | default(omit) }}" auth: "{{ auth | default(omit) }}"
ca_cert: "{{ tls_certificate_path | default(omit) }}"
ironic_url: "{{ ironic_url | default(omit) }}" ironic_url: "{{ ironic_url | default(omit) }}"
uuid: "{{ uuid | default('') }}" uuid: "{{ uuid | default('') }}"
name: "{{ name | default('') }}" name: "{{ name | default('') }}"

View File

@ -0,0 +1,14 @@
---
features:
- |
Supports TLS configuration by setting ``enable_tls=true`` and, optionally,
``generate_tls=true``. The corresponding ``bifrost-cli`` argument is
``--enable-tls`` (auto-generated certificates only).
issues:
- |
When using Keystone for authentication, it may not be possible to disable
TLS after enabling it if the certificate is in a non-standard location.
- |
Due to upgrade limitations, it may not be possible to enable TLS on
upgrading from a previous version. Do an upgrade first, then enable TLS
in a separate installation step.

View File

@ -13,6 +13,7 @@ ENABLE_KEYSTONE="${ENABLE_KEYSTONE:-false}"
ZUUL_BRANCH=${ZUUL_BRANCH:-} ZUUL_BRANCH=${ZUUL_BRANCH:-}
CLI_TEST=${CLI_TEST:-false} CLI_TEST=${CLI_TEST:-false}
BOOT_MODE=${BOOT_MODE:-} BOOT_MODE=${BOOT_MODE:-}
ENABLE_TLS=${ENABLE_TLS:-false}
# Set defaults for ansible command-line options to drive the different # Set defaults for ansible command-line options to drive the different
# tests. # tests.
@ -178,6 +179,8 @@ ${ANSIBLE} -vvvv \
-e enable_keystone=${ENABLE_KEYSTONE} \ -e enable_keystone=${ENABLE_KEYSTONE} \
-e wait_for_node_deploy=${WAIT_FOR_DEPLOY} \ -e wait_for_node_deploy=${WAIT_FOR_DEPLOY} \
-e not_enrolled_data_file=${BAREMETAL_DATA_FILE}.rest \ -e not_enrolled_data_file=${BAREMETAL_DATA_FILE}.rest \
-e enable_tls=${ENABLE_TLS} \
-e generate_tls=${ENABLE_TLS} \
-e skip_install=${CLI_TEST} \ -e skip_install=${CLI_TEST} \
-e skip_package_install=${CLI_TEST} \ -e skip_package_install=${CLI_TEST} \
-e skip_bootstrap=${CLI_TEST} \ -e skip_bootstrap=${CLI_TEST} \

View File

@ -83,6 +83,7 @@
- openstack/keystone - openstack/keystone
vars: vars:
enable_keystone: true enable_keystone: true
enable_tls: true
test_driver: redfish test_driver: redfish
- job: - job:
@ -109,6 +110,7 @@
- openstack/keystone - openstack/keystone
vars: vars:
enable_keystone: true enable_keystone: true
enable_tls: true
test_driver: redfish test_driver: redfish
- job: - job: