diff --git a/ansible/roles/ironic/defaults/main.yml b/ansible/roles/ironic/defaults/main.yml index 2305157d6883eb42c7df4d5cf4fad1e552329b04..b4c0d2c1f79b5447fa98b8f181e9432d4fa0649e 100644 --- a/ansible/roles/ironic/defaults/main.yml +++ b/ansible/roles/ironic/defaults/main.yml @@ -16,12 +16,14 @@ ironic_services: external: false port: "{{ ironic_api_port }}" listen_port: "{{ ironic_api_listen_port }}" + tls_backend: "{{ ironic_enable_tls_backend }}" ironic_api_external: enabled: "{{ enable_ironic }}" mode: "http" external: true port: "{{ ironic_api_port }}" listen_port: "{{ ironic_api_listen_port }}" + tls_backend: "{{ ironic_enable_tls_backend }}" ironic-conductor: container_name: ironic_conductor group: ironic-conductor @@ -253,3 +255,8 @@ ironic_ks_users: user: "{{ ironic_inspector_keystone_user }}" password: "{{ ironic_inspector_keystone_password }}" role: "admin" + +#################### +# TLS +#################### +ironic_enable_tls_backend: "{{ kolla_enable_tls_backend }}" diff --git a/ansible/roles/ironic/handlers/main.yml b/ansible/roles/ironic/handlers/main.yml index 458d648e1bc31bfd57b28259455e11e3b4713721..a1b701506ec08176757e758c602639affb6d32e8 100644 --- a/ansible/roles/ironic/handlers/main.yml +++ b/ansible/roles/ironic/handlers/main.yml @@ -40,6 +40,7 @@ module_name: uri module_args: url: "{{ ironic_internal_endpoint }}" + validate_certs: false register: result until: result is success retries: 12 diff --git a/ansible/roles/ironic/tasks/config.yml b/ansible/roles/ironic/tasks/config.yml index 26111f48f5fe519849554440535b97ccf86d692c..45410533b5697557abcc28d1494e785376f364f1 100644 --- a/ansible/roles/ironic/tasks/config.yml +++ b/ansible/roles/ironic/tasks/config.yml @@ -33,7 +33,7 @@ - include_tasks: copy-certs.yml when: - - kolla_copy_ca_into_containers | bool + - kolla_copy_ca_into_containers | bool or ironic_enable_tls_backend | bool - name: Copying over config.json files for services template: @@ -244,5 +244,17 @@ notify: - "Restart {{ item.key }} container" +- name: Copying over ironic-api-wsgi.conf + template: + src: "ironic-api-wsgi.conf.j2" + dest: "{{ node_config_directory }}/ironic-api/ironic-api-wsgi.conf" + mode: "0660" + become: true + when: + - inventory_hostname in groups["ironic-api"] + - ironic_services["ironic-api"].enabled | bool + notify: + - "Restart ironic-api container" + - import_tasks: check-containers.yml when: kolla_action != "config" diff --git a/ansible/roles/ironic/templates/ironic-api-wsgi.conf.j2 b/ansible/roles/ironic/templates/ironic-api-wsgi.conf.j2 new file mode 100644 index 0000000000000000000000000000000000000000..c83138f274e4dd0f2018bd8485cdc472a057cf7f --- /dev/null +++ b/ansible/roles/ironic/templates/ironic-api-wsgi.conf.j2 @@ -0,0 +1,50 @@ +{% set ironic_log_dir = '/var/log/kolla/ironic' %} +{% set wsgi_directory = '/usr/bin' if ironic_install_type == 'binary' else '/var/lib/kolla/venv/bin' %} +{% if ironic_enable_tls_backend | bool %} +{% if kolla_base_distro in ['centos'] %} +LoadModule ssl_module /usr/lib64/httpd/modules/mod_ssl.so +{% else %} +LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so +{% endif %} +{% endif %} +Listen {{ api_interface_address | put_address_in_context('url') }}:{{ ironic_api_listen_port }} + +ServerSignature Off +ServerTokens Prod +TraceEnable off +KeepAliveTimeout {{ kolla_httpd_keep_alive }} + +<Directory "{{ wsgi_directory }}"> + <FilesMatch "^ironic-api-wsgi$"> + Options None + Require all granted + </FilesMatch> +</Directory> + +ErrorLog "{{ ironic_log_dir }}/apache-error.log" +<IfModule log_config_module> +CustomLog "{{ ironic_log_dir }}/apache-access.log" common +</IfModule> + +{% if ironic_logging_debug | bool %} +LogLevel info +{% endif %} + +<VirtualHost *:{{ ironic_api_listen_port }}> + WSGIDaemonProcess ironic-api processes={{ openstack_service_workers }} threads=1 user=ironic group=ironic display-name=%{GROUP} + WSGIProcessGroup ironic-api + WSGIScriptAlias / {{ wsgi_directory }}/ironic-api-wsgi + WSGIApplicationGroup %{GLOBAL} + WSGIPassAuthorization On + <IfVersion >= 2.4> + ErrorLogFormat "%{cu}t %M" + </IfVersion> + ErrorLog "{{ ironic_log_dir }}/ironic-api-error.log" + LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b %D \"%{Referer}i\" \"%{User-Agent}i\"" logformat + CustomLog "{{ ironic_log_dir }}/ironic-api-access.log" logformat +{% if ironic_enable_tls_backend | bool %} + SSLEngine on + SSLCertificateFile /etc/ironic/certs/ironic-cert.pem + SSLCertificateKeyFile /etc/ironic/certs/ironic-key.pem +{% endif %} +</VirtualHost> diff --git a/ansible/roles/ironic/templates/ironic-api.json.j2 b/ansible/roles/ironic/templates/ironic-api.json.j2 index 075b0d04eef355eb7f1db2a28ec2466d835fb7a3..a03a6a6719f2f63223ca74ddac74f2ff79dfba00 100644 --- a/ansible/roles/ironic/templates/ironic-api.json.j2 +++ b/ansible/roles/ironic/templates/ironic-api.json.j2 @@ -1,17 +1,37 @@ +{% set apache_binary = 'apache2' if kolla_base_distro in ['ubuntu', 'debian'] else 'httpd' %} +{% set apache_conf_dir = 'apache2/conf-enabled' if kolla_base_distro in ['ubuntu', 'debian'] else 'httpd/conf.d' %} { - "command": "ironic-api", + "command": "/usr/sbin/{{ apache_binary }} -DFOREGROUND", "config_files": [ { "source": "{{ container_config_directory }}/ironic.conf", "dest": "/etc/ironic/ironic.conf", "owner": "ironic", "perm": "0600" + }, + { + "source": "{{ container_config_directory }}/ironic-api-wsgi.conf", + "dest": "/etc/{{ apache_conf_dir }}/ironic-api-wsgi.conf", + "owner": "ironic", + "perm": "0600" }{% if ironic_policy_file is defined %}, { "source": "{{ container_config_directory }}/{{ ironic_policy_file }}", "dest": "/etc/ironic/{{ ironic_policy_file }}", "owner": "ironic", "perm": "0600" + }{% endif %}{% if ironic_enable_tls_backend | bool %}, + { + "source": "{{ container_config_directory }}/ironic-cert.pem", + "dest": "/etc/ironic/certs/ironic-cert.pem", + "owner": "ironic", + "perm": "0600" + }, + { + "source": "{{ container_config_directory }}/ironic-key.pem", + "dest": "/etc/ironic/certs/ironic-key.pem", + "owner": "ironic", + "perm": "0600" }{% endif %} ], "permissions": [ diff --git a/ansible/roles/ironic/templates/ironic.conf.j2 b/ansible/roles/ironic/templates/ironic.conf.j2 index 7e79cd278974a8d9c1dfaeec8db428570044be61..666adc59343201ddd2805e1b65ab67a39f505da5 100644 --- a/ansible/roles/ironic/templates/ironic.conf.j2 +++ b/ansible/roles/ironic/templates/ironic.conf.j2 @@ -35,13 +35,6 @@ driver = noop policy_file = {{ ironic_policy_file }} {% endif %} -{% if service_name == 'ironic-api' %} -[api] -host_ip = {{ api_interface_address }} -port = {{ ironic_api_listen_port }} -api_workers = {{ openstack_service_workers }} -{% endif %} - {% if service_name == 'ironic-conductor' %} [conductor] automated_clean=false diff --git a/releasenotes/notes/encrypt-additional-services-backend-haproxy-29467a9771e99917.yaml b/releasenotes/notes/encrypt-additional-services-backend-haproxy-29467a9771e99917.yaml new file mode 100644 index 0000000000000000000000000000000000000000..76e8326172d1230b02e04f585135e5ed84622753 --- /dev/null +++ b/releasenotes/notes/encrypt-additional-services-backend-haproxy-29467a9771e99917.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + Adds configuration options to enable backend TLS encryption from HAProxy + to the Nova and Ironic services. When used in conjunction with enabling TLS + for service API endpoints, network communcation will be encrypted end to + end, from client through HAProxy to the backend service. diff --git a/tests/run.yml b/tests/run.yml index dc4eb1665c5c1123f616be2b27f54d4cf5c923da..c8df10e73ab8ade2a53cdddfbcbe90647bd65742 100644 --- a/tests/run.yml +++ b/tests/run.yml @@ -421,6 +421,8 @@ cmd: test-ironic.sh executable: /bin/bash chdir: "{{ kolla_ansible_src_dir }}" + environment: + TLS_ENABLED: "{{ tls_enabled }}" when: scenario == "ironic" - name: Run test-magnum.sh script diff --git a/tests/test-ironic.sh b/tests/test-ironic.sh index 6cc3ede3f37203b66b59f9839f7f1c97d195a3ac..9e7876f2a1b052412d580780a6a608e9d19a5bac 100755 --- a/tests/test-ironic.sh +++ b/tests/test-ironic.sh @@ -35,7 +35,13 @@ function wait_for_placement_resources { for i in $(seq 1 120); do # Fetch provider UUIDs from Placement local providers - providers=$(curl -sH "X-Auth-Token: $token" $endpoint/resource_providers \ + args=( + -sH "X-Auth-Token: $token" + ) + if [[ "$TLS_ENABLED" = "True" ]]; then + args+=(--cacert $OS_CACERT) + fi + providers=$(curl "${args[@]}" $endpoint/resource_providers \ | ./jq -r '.resource_providers[].uuid') local p @@ -46,7 +52,7 @@ function wait_for_placement_resources { # A resource class inventory record looks something like # {"max_unit": 1, "min_unit": 1, "step_size": 1, "reserved": 0, "total": 1, "allocation_ratio": 1} # Subtract reserved from total (defaulting both to 0) - amount=$(curl -sH "X-Auth-Token: $token" $endpoint/resource_providers/$p/inventories \ + amount=$(curl "${args[@]}" $endpoint/resource_providers/$p/inventories \ | ./jq ".inventories.CUSTOM_$resource_class as \$cls | (\$cls.total // 0) - (\$cls.reserved // 0)") if [ $amount -gt 0 ]; then