From e0901510d7c4b71c1c55fad62ba9c690276d9a19 Mon Sep 17 00:00:00 2001 From: Corey Bryant Date: Thu, 11 Mar 2021 11:58:02 -0500 Subject: [PATCH] Add TLS OpenStack API endpoints A new config.tls.generate-cert option is added that defaults to true. When true, a self-signed certificate will be generated and OpenStack API endpoints will be configured to use TLS with that self-signed certificate. The following config options are added: snap get microstack config.tls.generate-cert snap get microstack config.tls.cacert-path snap get microstack config.tls.cert-path snap get microstack config.tls.key-path Users can provide their own certificate by setting generate-cert to false and storing their own certificates/key at the paths specified by cacert-path, cert-path, and key-path. 'snap set' can also be used to change the cert/key file names. An important detail for clustering is that additional compute nodes will need manual configuration of cacert-path, cert-path, and key-path. The same certificates/key can can be copied from the controller node to the compute node. Other notable changes: * The existing generate_selfsigned() function is modified to change the subject alternative name to be made up of the hostname and optionally an IP. The controller hostname and IP are used when generating the certificate for self-signed TLS endpoints. The hostname is now used instead of 'microstack.run' when generating the clustering certificate. * This change also aligns logging for nginx and corresponding sites and moves all nginx sites to {snap_common}/etc/nginx/sites-enabled. Depends-On: https://review.opendev.org/c/x/microstack/+/772900 Change-Id: Iceea3127822404a3275fcf8a221cbedc4b52c217 --- DEMO.md | 6 +-- snap-overlay/bin/set-default-config.py | 10 +++- snap-overlay/snap-openstack.yaml | 25 ++++++--- snap-overlay/templates/05_snap_tweaks.j2 | 9 +++- snap-overlay/templates/cinder-nginx.conf.j2 | 6 ++- .../templates/cinder.keystone.conf.j2 | 5 +- snap-overlay/templates/glance-nginx.conf.j2 | 16 ++++++ snap-overlay/templates/glance-snap.conf.j2 | 1 + .../templates/glance.conf.d.keystone.conf.j2 | 5 +- snap-overlay/templates/horizon-nginx.conf.j2 | 13 ++--- snap-overlay/templates/keystone-nginx.conf.j2 | 10 ++-- snap-overlay/templates/microstack.json.j2 | 4 +- snap-overlay/templates/microstack.rc.j2 | 5 +- snap-overlay/templates/neutron-nginx.conf.j2 | 16 ++++++ snap-overlay/templates/neutron-snap.conf.j2 | 1 + .../templates/neutron.keystone.conf.j2 | 5 +- snap-overlay/templates/neutron.nova.conf.j2 | 3 +- .../templates/neutron.placement.conf.j2 | 3 +- snap-overlay/templates/nginx.conf.j2 | 6 +-- snap-overlay/templates/nova-nginx.conf.j2 | 14 +++-- snap-overlay/templates/nova-snap.conf.j2 | 2 + .../templates/nova.conf.d.cinder.conf.j2 | 5 ++ .../templates/nova.conf.d.glance.conf.j2 | 1 + .../templates/nova.conf.d.keystone.conf.j2 | 5 +- .../templates/nova.conf.d.neutron.conf.j2 | 5 +- .../templates/nova.conf.d.placement.conf.j2 | 5 +- .../templates/placement-nginx.conf.j2 | 10 ++-- .../placement.conf.d.keystone.conf.j2 | 5 +- snap/hooks/post-refresh | 2 +- tests/basic-test.sh | 2 +- tests/configure-the-things.sh | 6 +-- tests/framework.py | 3 +- tests/test_cluster.py | 8 +++ tools/cluster/cluster/add_compute.py | 9 +++- tools/cluster/cluster/daemon.py | 9 +++- tools/init/init/main.py | 1 + tools/init/init/questions/__init__.py | 52 +++++++++++++++---- tools/init/init/{cluster_tls.py => tls.py} | 29 +++++++---- 38 files changed, 240 insertions(+), 82 deletions(-) create mode 100644 snap-overlay/templates/glance-nginx.conf.j2 create mode 100644 snap-overlay/templates/neutron-nginx.conf.j2 create mode 100644 snap-overlay/templates/nova.conf.d.cinder.conf.j2 rename tools/init/init/{cluster_tls.py => tls.py} (79%) diff --git a/DEMO.md b/DEMO.md index b2a2179..7af950b 100644 --- a/DEMO.md +++ b/DEMO.md @@ -158,11 +158,11 @@ Answer the questions as follows: - + - +
cloud type: openstack
endpoint: http://10.20.20.1:5000/v3
endpoint: https://10.20.20.1:5000/v3
cert path: none
auth type: userpass
region: microstack
region endpoint: http://10.20.20.1:5000/v3
region endpoint: https://10.20.20.1:5000/v3
add another region?: N
@@ -182,7 +182,7 @@ images in your microstack cloud. Here's how to set that up. ``` mkdir simplestreams -juju metadata generate-image -d ~/simplestreams -i $IMAGE -s bionic -r microstack -u http://10.20.20.1:5000/v3 +juju metadata generate-image -d ~/simplestreams -i $IMAGE -s bionic -r microstack -u https://10.20.20.1:5000/v3 ``` (If you don't still have an `IMAGE` variable in your env, you can find diff --git a/snap-overlay/bin/set-default-config.py b/snap-overlay/bin/set-default-config.py index 8623560..4ef59b7 100755 --- a/snap-overlay/bin/set-default-config.py +++ b/snap-overlay/bin/set-default-config.py @@ -35,7 +35,7 @@ def _get_default_config(): 'config.network.ext-cidr': '10.20.20.1/24', 'config.network.security-rules': True, 'config.network.dashboard-allowed-hosts': '*', - 'config.network.ports.dashboard': 80, + 'config.network.ports.dashboard': 443, 'config.network.ports.mysql': 3306, 'config.network.ports.rabbit': 5672, 'config.network.external-bridge-name': 'br-ex', @@ -74,6 +74,14 @@ def _get_default_config(): 'config.nova.cpu-mode': 'host-model', # Do not override cpu-models by default. 'config.nova.cpu-models': '', + + 'config.tls.generate-cert': True, + 'config.tls.cacert-path': + f'{snap_common}/etc/ssl/certs/cacert.pem', + 'config.tls.cert-path': + f'{snap_common}/etc/ssl/certs/cacert.pem', + 'config.tls.key-path': + f'{snap_common}/etc/ssl/private/key.pem', } diff --git a/snap-overlay/snap-openstack.yaml b/snap-overlay/snap-openstack.yaml index aed5901..c748f98 100644 --- a/snap-overlay/snap-openstack.yaml +++ b/snap-overlay/snap-openstack.yaml @@ -8,7 +8,6 @@ setup: - "{snap_common}/etc/neutron/policy.d" - "{snap_common}/etc/neutron/rootwrap.d" - "{snap_common}/etc/nginx/sites-enabled" - - "{snap_common}/etc/nginx/snap/sites-enabled" - "{snap_common}/etc/glance/glance.conf.d" - "{snap_common}/etc/placement/placement.conf.d" - "{snap_common}/etc/horizon/horizon.conf.d" @@ -22,6 +21,8 @@ setup: - "{snap_common}/etc/cluster/tls" - "{snap_common}/etc/cluster/uwsgi/snap" - "{snap_common}/etc/rabbitmq" + - "{snap_common}/etc/ssl/certs" + - "{snap_common}/etc/ssl/private" - "{snap_common}/fernet-keys" - "{snap_common}/lib" - "{snap_common}/lib/images" @@ -33,24 +34,25 @@ setup: - "{snap_common}/etc/iscsi" - "{snap_common}/etc/target" templates: - cluster-nginx.conf.j2: "{snap_common}/etc/nginx/snap/sites-enabled/cluster.conf" - keystone-nginx.conf.j2: "{snap_common}/etc/nginx/snap/sites-enabled/keystone.conf" + cluster-nginx.conf.j2: "{snap_common}/etc/nginx/sites-enabled/cluster.conf" + keystone-nginx.conf.j2: "{snap_common}/etc/nginx/sites-enabled/keystone.conf" keystone-snap.conf.j2: "{snap_common}/etc/keystone/keystone.conf.d/keystone-snap.conf" neutron-snap.conf.j2: "{snap_common}/etc/neutron/neutron.conf.d/neutron-snap.conf" nginx.conf.j2: "{snap_common}/etc/nginx/snap/nginx.conf" nova-snap.conf.j2: "{snap_common}/etc/nova/nova.conf.d/nova-snap.conf" - nova-nginx.conf.j2: "{snap_common}/etc/nginx/snap/sites-enabled/nova.conf" + nova-nginx.conf.j2: "{snap_common}/etc/nginx/sites-enabled/nova.conf" glance-snap.conf.j2: "{snap_common}/etc/glance/glance.conf.d/glance-snap.conf" - placement-nginx.conf.j2: "{snap_common}/etc/nginx/snap/sites-enabled/placement.conf" + glance-nginx.conf.j2: "{snap_common}/etc/nginx/sites-enabled/glance.conf" + placement-nginx.conf.j2: "{snap_common}/etc/nginx/sites-enabled/placement.conf" placement-snap.conf.j2: "{snap_common}/etc/placement/placement.conf.d/placement-snap.conf" - cinder-nginx.conf.j2: "{snap_common}/etc/nginx/snap/sites-enabled/cinder.conf" + cinder-nginx.conf.j2: "{snap_common}/etc/nginx/sites-enabled/cinder.conf" cinder-snap.conf.j2: "{snap_common}/etc/cinder/cinder.conf.d/cinder-snap.conf" cinder.database.conf.j2: "{snap_common}/etc/cinder/cinder.conf.d/database.conf" cinder.rabbitmq.conf.j2: "{snap_common}/etc/cinder/cinder.conf.d/rabbitmq.conf" cinder.keystone.conf.j2: "{snap_common}/etc/cinder/cinder.conf.d/keystone.conf" cinder-rootwrap.conf.j2: "{snap_common}/etc/cinder/rootwrap.conf" horizon-snap.conf.j2: "{snap_common}/etc/horizon/horizon.conf.d/horizon-snap.conf" - horizon-nginx.conf.j2: "{snap_common}/etc/nginx/snap/sites-enabled/horizon.conf" + horizon-nginx.conf.j2: "{snap_common}/etc/nginx/sites-enabled/horizon.conf" 05_snap_tweaks.j2: "{snap_common}/etc/horizon/local_settings.d/_05_snap_tweaks.py" libvirtd.conf.j2: "{snap_common}/etc/libvirt/libvirtd.conf" qemu.conf.j2: "{snap_common}/etc/libvirt/qemu.conf" @@ -62,10 +64,12 @@ setup: nova.conf.d.keystone.conf.j2: "{snap_common}/etc/nova/nova.conf.d/keystone.conf" nova.conf.d.database.conf.j2: "{snap_common}/etc/nova/nova.conf.d/database.conf" nova.conf.d.rabbitmq.conf.j2: "{snap_common}/etc/nova/nova.conf.d/rabbitmq.conf" + nova.conf.d.cinder.conf.j2: "{snap_common}/etc/nova/nova.conf.d/cinder.conf" nova.conf.d.glance.conf.j2: "{snap_common}/etc/nova/nova.conf.d/glance.conf" nova.conf.d.neutron.conf.j2: "{snap_common}/etc/nova/nova.conf.d/neutron.conf" nova.conf.d.placement.conf.j2: "{snap_common}/etc/nova/nova.conf.d/placement.conf" nova.conf.d.console.conf.j2: "{snap_common}/etc/nova/nova.conf.d/console.conf" + nova-nginx.conf.j2: "{snap_common}/etc/nginx/sites-enabled/nova.conf" keystone.database.conf.j2: "{snap_common}/etc/keystone/keystone.conf.d/database.conf" glance.database.conf.j2: "{snap_common}/etc/glance/glance.conf.d/database.conf" placement.conf.d.database.conf.j2: "{snap_common}/etc/placement/placement.conf.d/database.conf" @@ -75,6 +79,7 @@ setup: neutron.database.conf.j2: "{snap_common}/etc/neutron/neutron.conf.d/database.conf" neutron.conf.d.rabbitmq.conf.j2: "{snap_common}/etc/neutron/neutron.conf.d/rabbitmq.conf" neutron_ovn_metadata_agent.ini.j2: "{snap_common}/etc/neutron/neutron_ovn_metadata_agent.ini" + neutron-nginx.conf.j2: "{snap_common}/etc/nginx/sites-enabled/neutron.conf" rabbitmq.conf.j2: "{snap_common}/etc/rabbitmq/rabbitmq.config" iscsid.conf.j2: "{snap_common}/etc/iscsi/iscsid.conf" lvm.conf.j2: "{snap_common}/etc/lvm/lvm.conf" @@ -84,6 +89,9 @@ setup: nrpe.cfg.j2: "{snap_common}/etc/nrpe/nrpe-microstack.cfg" filebeat.yaml.j2: "{snap_common}/etc/filebeat/filebeat-microstack.yaml" chmod: + "{snap_common}/etc/ssl": 0755 + "{snap_common}/etc/ssl/certs": 0755 + "{snap_common}/etc/ssl/private": 0700 "{snap_common}/instances": 0755 "{snap_common}/etc/microstack.rc": 0644 "{snap_common}/etc/microstack.json": 0644 @@ -123,6 +131,9 @@ setup: virt_type: 'config.nova.virt-type' cpu_mode: 'config.nova.cpu-mode' cpu_models: 'config.nova.cpu-models' + tls_cacert_path: 'config.tls.cacert-path' + tls_cert_path: 'config.tls.cert-path' + tls_key_path: 'config.tls.key-path' entry_points: keystone-manage: binary: "{snap}/bin/keystone-manage" diff --git a/snap-overlay/templates/05_snap_tweaks.j2 b/snap-overlay/templates/05_snap_tweaks.j2 index 6a2149b..ad9545c 100644 --- a/snap-overlay/templates/05_snap_tweaks.j2 +++ b/snap-overlay/templates/05_snap_tweaks.j2 @@ -23,7 +23,7 @@ AVAILABLE_THEMES = [ # Point us at keystone. OPENSTACK_HOST = "10.20.20.1" -OPENSTACK_KEYSTONE_URL = "http://%s:5000/v3" % OPENSTACK_HOST +OPENSTACK_KEYSTONE_URL = "https://%s:5000/v3" % OPENSTACK_HOST OPENSTACK_KEYSTONE_DEFAULT_ROLE = "_member_" # Turn off external access for now. (This should be turned on once we @@ -40,4 +40,9 @@ CACHES = { } SESSION_ENGINE='django.contrib.sessions.backends.cache' - +# SSL config +CSRF_COOKIE_SECURE = True +SESSION_COOKIE_SECURE = True +# TODO(coreycb): Remove OPENSTACK_SSL_NO_VERIFY +OPENSTACK_SSL_NO_VERIFY = True +OPENSTACK_SSL_CACERT = "{{ tls_cacert_path }}" diff --git a/snap-overlay/templates/cinder-nginx.conf.j2 b/snap-overlay/templates/cinder-nginx.conf.j2 index 47e6c7f..5134741 100644 --- a/snap-overlay/templates/cinder-nginx.conf.j2 +++ b/snap-overlay/templates/cinder-nginx.conf.j2 @@ -1,5 +1,9 @@ server { - listen 8776; + listen 8776 ssl; + ssl_certificate {{ tls_cert_path }}; + ssl_certificate_key {{ tls_key_path }}; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; access_log {{ snap_common }}/log/nginx-access.log; error_log {{ snap_common }}/log/nginx-error.log; location / { diff --git a/snap-overlay/templates/cinder.keystone.conf.j2 b/snap-overlay/templates/cinder.keystone.conf.j2 index e4144f5..5c56735 100644 --- a/snap-overlay/templates/cinder.keystone.conf.j2 +++ b/snap-overlay/templates/cinder.keystone.conf.j2 @@ -2,8 +2,8 @@ auth_strategy = keystone [keystone_authtoken] -auth_uri = http://{{ control_ip }}:5000 -auth_url = http://{{ control_ip }}:5000 +auth_uri = https://{{ control_ip }}:5000/v3 +auth_url = https://{{ control_ip }}:5000/v3 memcached_servers = {{ compute_ip }}:11211 auth_type = password project_domain_name = default @@ -11,3 +11,4 @@ user_domain_name = default project_name = service username = cinder password = {{ cinder_password }} +cafile = {{ tls_cacert_path }} diff --git a/snap-overlay/templates/glance-nginx.conf.j2 b/snap-overlay/templates/glance-nginx.conf.j2 new file mode 100644 index 0000000..d238762 --- /dev/null +++ b/snap-overlay/templates/glance-nginx.conf.j2 @@ -0,0 +1,16 @@ +server { + listen 9292 ssl; + ssl_certificate {{ tls_cert_path }}; + ssl_certificate_key {{ tls_key_path }}; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + access_log {{ snap_common }}/log/nginx-access.log; + error_log {{ snap_common }}/log/nginx-error.log; + client_max_body_size 0; + location / { + proxy_set_header X-Forwarded-Host $host:$server_port; + proxy_set_header X-Forwarded-Server $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://127.0.0.1:9282; + } +} diff --git a/snap-overlay/templates/glance-snap.conf.j2 b/snap-overlay/templates/glance-snap.conf.j2 index 8a5e94d..2c7ea1e 100644 --- a/snap-overlay/templates/glance-snap.conf.j2 +++ b/snap-overlay/templates/glance-snap.conf.j2 @@ -3,6 +3,7 @@ state_path = {{ snap_common }}/lib # Log to systemd journal use_journal = True +bind_port = 9282 [oslo_concurrency] # Oslo Concurrency lock path diff --git a/snap-overlay/templates/glance.conf.d.keystone.conf.j2 b/snap-overlay/templates/glance.conf.d.keystone.conf.j2 index 9857898..f593dff 100644 --- a/snap-overlay/templates/glance.conf.d.keystone.conf.j2 +++ b/snap-overlay/templates/glance.conf.d.keystone.conf.j2 @@ -1,6 +1,6 @@ [keystone_authtoken] -auth_uri = http://{{ control_ip }}:5000 -auth_url = http://{{ control_ip }}:5000 +auth_uri = https://{{ control_ip }}:5000/v3 +auth_url = https://{{ control_ip }}:5000/v3 memcached_servers = {{ compute_ip }}:11211 auth_type = password project_domain_name = default @@ -8,6 +8,7 @@ user_domain_name = default project_name = service username = glance password = {{ glance_password }} +cafile = {{ tls_cacert_path }} [paste_deploy] flavor = keystone diff --git a/snap-overlay/templates/horizon-nginx.conf.j2 b/snap-overlay/templates/horizon-nginx.conf.j2 index 394e4e9..3f9b36d 100644 --- a/snap-overlay/templates/horizon-nginx.conf.j2 +++ b/snap-overlay/templates/horizon-nginx.conf.j2 @@ -1,10 +1,11 @@ -# If the OpenStack service has an API that runs behind uwsgi+nginx, you'll need -# to define this template. Be sure to update "listen" with the port number and -# also update "api-name" for the socket. server { - listen {{ dashboard_port }}; - error_log syslog:server=unix:/dev/log; - access_log syslog:server=unix:/dev/log; + listen {{ dashboard_port }} ssl; + ssl_certificate {{ tls_cert_path }}; + ssl_certificate_key {{ tls_key_path }}; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + access_log {{ snap_common }}/log/nginx-access.log; + error_log {{ snap_common }}/log/nginx-error.log; location / { include {{ snap }}/usr/conf/uwsgi_params; uwsgi_param SCRIPT_NAME ''; diff --git a/snap-overlay/templates/keystone-nginx.conf.j2 b/snap-overlay/templates/keystone-nginx.conf.j2 index 413e923..62f6e1a 100644 --- a/snap-overlay/templates/keystone-nginx.conf.j2 +++ b/snap-overlay/templates/keystone-nginx.conf.j2 @@ -1,7 +1,11 @@ server { - listen 5000; - error_log syslog:server=unix:/dev/log; - access_log syslog:server=unix:/dev/log; + listen 5000 ssl; + ssl_certificate {{ tls_cert_path }}; + ssl_certificate_key {{ tls_key_path }}; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + access_log {{ snap_common }}/log/nginx-access.log; + error_log {{ snap_common }}/log/nginx-error.log; location / { include {{ snap }}/usr/conf/uwsgi_params; uwsgi_param SCRIPT_NAME ''; diff --git a/snap-overlay/templates/microstack.json.j2 b/snap-overlay/templates/microstack.json.j2 index 587d62d..75ad760 100644 --- a/snap-overlay/templates/microstack.json.j2 +++ b/snap-overlay/templates/microstack.json.j2 @@ -13,11 +13,11 @@ "version": 3 } }, - "auth_url": "http://{{ control_ip }}:5000", + "auth_url": "https://{{ control_ip }}:5000/v3", "endpoint_type": null, "https_cacert": "", "https_cert": "", - "https_insecure": false, + "https_insecure": true, "https_key": "", "profiler_conn_str": null, "profiler_hmac_key": null, diff --git a/snap-overlay/templates/microstack.rc.j2 b/snap-overlay/templates/microstack.rc.j2 index 1545f2e..f1e9df8 100644 --- a/snap-overlay/templates/microstack.rc.j2 +++ b/snap-overlay/templates/microstack.rc.j2 @@ -3,7 +3,8 @@ export OS_USER_DOMAIN_NAME=default export OS_PROJECT_NAME=admin export OS_USERNAME=admin export OS_PASSWORD={{ keystone_password }} -export OS_AUTH_URL=http://{{ control_ip }}:5000 +export OS_AUTH_PROTOCOL=https +export OS_AUTH_URL=https://{{ control_ip }}:5000/v3 export OS_IDENTITY_API_VERSION=3 export OS_IMAGE_API_VERSION=2 - +export OS_CACERT={{ tls_cacert_path }} diff --git a/snap-overlay/templates/neutron-nginx.conf.j2 b/snap-overlay/templates/neutron-nginx.conf.j2 new file mode 100644 index 0000000..27cd4f8 --- /dev/null +++ b/snap-overlay/templates/neutron-nginx.conf.j2 @@ -0,0 +1,16 @@ +server { + listen 9696 ssl; + ssl_certificate {{ tls_cert_path }}; + ssl_certificate_key {{ tls_key_path }}; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + access_log {{ snap_common }}/log/nginx-access.log; + error_log {{ snap_common }}/log/nginx-error.log; + client_max_body_size 0; + location / { + proxy_set_header X-Forwarded-Host $host:$server_port; + proxy_set_header X-Forwarded-Server $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://127.0.0.1:9686; + } +} diff --git a/snap-overlay/templates/neutron-snap.conf.j2 b/snap-overlay/templates/neutron-snap.conf.j2 index 2d089db..803b74e 100644 --- a/snap-overlay/templates/neutron-snap.conf.j2 +++ b/snap-overlay/templates/neutron-snap.conf.j2 @@ -3,6 +3,7 @@ state_path = {{ snap_common }}/lib # Log to systemd journal use_journal = True +bind_port = 9686 {% if dns_domain %} dns_domain = {{ dns_domain }} diff --git a/snap-overlay/templates/neutron.keystone.conf.j2 b/snap-overlay/templates/neutron.keystone.conf.j2 index fef46ab..5ae9e96 100644 --- a/snap-overlay/templates/neutron.keystone.conf.j2 +++ b/snap-overlay/templates/neutron.keystone.conf.j2 @@ -2,8 +2,8 @@ auth_strategy = keystone [keystone_authtoken] -auth_uri = http://{{ control_ip }}:5000 -auth_url = http://{{ control_ip }}:5000 +auth_uri = https://{{ control_ip }}:5000/v3 +auth_url = https://{{ control_ip }}:5000/v3 memcached_servers = {{ compute_ip }}:11211 auth_type = password project_domain_name = default @@ -11,3 +11,4 @@ user_domain_name = default project_name = service username = neutron password = {{ neutron_password }} +cafile = {{ tls_cacert_path }} diff --git a/snap-overlay/templates/neutron.nova.conf.j2 b/snap-overlay/templates/neutron.nova.conf.j2 index 5cba31a..02d5ac5 100644 --- a/snap-overlay/templates/neutron.nova.conf.j2 +++ b/snap-overlay/templates/neutron.nova.conf.j2 @@ -3,7 +3,7 @@ notify_nova_on_port_status_changes = True notify_nova_on_port_data_changes = True [nova] -auth_url = http://{{ control_ip }}:5000 +auth_url = https://{{ control_ip }}:5000/v3 auth_type = password project_domain_name = default user_domain_name = default @@ -11,3 +11,4 @@ region_name = {{ region_name }} project_name = service username = nova password = {{ nova_password }} +cafile = {{ tls_cacert_path }} diff --git a/snap-overlay/templates/neutron.placement.conf.j2 b/snap-overlay/templates/neutron.placement.conf.j2 index e1dff73..741355b 100644 --- a/snap-overlay/templates/neutron.placement.conf.j2 +++ b/snap-overlay/templates/neutron.placement.conf.j2 @@ -1,5 +1,5 @@ [placement] -auth_url = http://{{ control_ip }}:5000 +auth_url = https://{{ control_ip }}:5000/v3 auth_type = password project_domain_name = default user_domain_name = default @@ -7,3 +7,4 @@ region_name = {{ region_name }} project_name = service username = placement password = {{ placement_password }} +cafile = {{ tls_cacert_path }} diff --git a/snap-overlay/templates/nginx.conf.j2 b/snap-overlay/templates/nginx.conf.j2 index a62b8c5..1d49054 100644 --- a/snap-overlay/templates/nginx.conf.j2 +++ b/snap-overlay/templates/nginx.conf.j2 @@ -24,8 +24,8 @@ http { # Logging Settings ## - error_log syslog:server=unix:/dev/log; - access_log syslog:server=unix:/dev/log; + error_log {{ snap_common }}/log/nginx-error.log; + access_log {{ snap_common }}/log/nginx-access.log; ## # Gzip Settings @@ -35,5 +35,5 @@ http { gzip_disable "msie6"; include {{ snap_common }}/etc/nginx/conf.d/*.conf; - include {{ snap_common }}/etc/nginx/snap/sites-enabled/*; + include {{ snap_common }}/etc/nginx/sites-enabled/*; } diff --git a/snap-overlay/templates/nova-nginx.conf.j2 b/snap-overlay/templates/nova-nginx.conf.j2 index 91c43a6..e21ac45 100644 --- a/snap-overlay/templates/nova-nginx.conf.j2 +++ b/snap-overlay/templates/nova-nginx.conf.j2 @@ -1,10 +1,16 @@ server { - listen 8778; + listen 8774 ssl; + ssl_certificate {{ tls_cert_path }}; + ssl_certificate_key {{ tls_key_path }}; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; access_log {{ snap_common }}/log/nginx-access.log; error_log {{ snap_common }}/log/nginx-error.log; + client_max_body_size 0; location / { - include {{ snap }}/usr/conf/uwsgi_params; - uwsgi_param SCRIPT_NAME ''; - uwsgi_pass unix://{{ snap_common }}/run/placement-api.sock; + proxy_set_header X-Forwarded-Host $host:$server_port; + proxy_set_header X-Forwarded-Server $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://127.0.0.1:8764; } } diff --git a/snap-overlay/templates/nova-snap.conf.j2 b/snap-overlay/templates/nova-snap.conf.j2 index fc43232..860a98c 100644 --- a/snap-overlay/templates/nova-snap.conf.j2 +++ b/snap-overlay/templates/nova-snap.conf.j2 @@ -7,6 +7,8 @@ state_path = {{ snap_common }}/lib # Log to systemd journal use_journal = True +osapi_compute_listen_port = 8764 + # Set a hostname to be an FQDN to avoid issues with port binding for # which a hostname of a Nova node must match a hostname of an OVN chassis. host = {{ node_fqdn }} diff --git a/snap-overlay/templates/nova.conf.d.cinder.conf.j2 b/snap-overlay/templates/nova.conf.d.cinder.conf.j2 new file mode 100644 index 0000000..77bd1c1 --- /dev/null +++ b/snap-overlay/templates/nova.conf.d.cinder.conf.j2 @@ -0,0 +1,5 @@ +[cinder] +service_type = volume +service_name = cinder +region_name = {{ region_name }} +cafile = {{ tls_cacert_path }} diff --git a/snap-overlay/templates/nova.conf.d.glance.conf.j2 b/snap-overlay/templates/nova.conf.d.glance.conf.j2 index 973442d..99abdaa 100644 --- a/snap-overlay/templates/nova.conf.d.glance.conf.j2 +++ b/snap-overlay/templates/nova.conf.d.glance.conf.j2 @@ -2,3 +2,4 @@ service_type = image service_name = glance region_name = {{ region_name }} +cafile = {{ tls_cacert_path }} diff --git a/snap-overlay/templates/nova.conf.d.keystone.conf.j2 b/snap-overlay/templates/nova.conf.d.keystone.conf.j2 index c259341..93ab25d 100644 --- a/snap-overlay/templates/nova.conf.d.keystone.conf.j2 +++ b/snap-overlay/templates/nova.conf.d.keystone.conf.j2 @@ -1,6 +1,6 @@ [keystone_authtoken] -auth_uri = http://{{ control_ip }}:5000 -auth_url = http://{{ control_ip }}:5000 +auth_uri = https://{{ control_ip }}:5000/v3 +auth_url = https://{{ control_ip }}:5000/v3 memcached_servers = {{ compute_ip }}:11211 auth_type = password project_domain_name = default @@ -8,6 +8,7 @@ user_domain_name = default project_name = service username = nova password = {{ nova_password }} +cafile = {{ tls_cacert_path }} [paste_deploy] flavor = keystone diff --git a/snap-overlay/templates/nova.conf.d.neutron.conf.j2 b/snap-overlay/templates/nova.conf.d.neutron.conf.j2 index 1a717cb..41c65f4 100644 --- a/snap-overlay/templates/nova.conf.d.neutron.conf.j2 +++ b/snap-overlay/templates/nova.conf.d.neutron.conf.j2 @@ -1,6 +1,6 @@ [neutron] -url = http://{{ control_ip }}:9696 -auth_url = http://{{ control_ip }}:5000 +url = https://{{ control_ip }}:9696 +auth_url = https://{{ control_ip }}:5000/v3 memcached_servers = {{ compute_ip }}:11211 auth_type = password project_domain_name = default @@ -11,3 +11,4 @@ username = neutron password = {{ neutron_password }} service_metadata_proxy = True metadata_proxy_shared_secret = {{ ovn_metadata_proxy_shared_secret }} +cafile = {{ tls_cacert_path }} diff --git a/snap-overlay/templates/nova.conf.d.placement.conf.j2 b/snap-overlay/templates/nova.conf.d.placement.conf.j2 index 065d21c..b749277 100644 --- a/snap-overlay/templates/nova.conf.d.placement.conf.j2 +++ b/snap-overlay/templates/nova.conf.d.placement.conf.j2 @@ -1,6 +1,6 @@ [placement] -auth_uri = http://{{ control_ip }}:5000 -auth_url = http://{{ control_ip }}:5000 +auth_uri = https://{{ control_ip }}:5000/v3 +auth_url = https://{{ control_ip }}:5000/v3 memcached_servers = {{ compute_ip }}:11211 auth_type = password project_domain_name = default @@ -9,3 +9,4 @@ project_name = service username = nova password = {{ nova_password }} region_name = {{ region_name }} +cafile = {{ tls_cacert_path }} diff --git a/snap-overlay/templates/placement-nginx.conf.j2 b/snap-overlay/templates/placement-nginx.conf.j2 index c60dc9d..d84daaa 100644 --- a/snap-overlay/templates/placement-nginx.conf.j2 +++ b/snap-overlay/templates/placement-nginx.conf.j2 @@ -1,7 +1,11 @@ server { - listen 8778; - error_log syslog:server=unix:/dev/log; - access_log syslog:server=unix:/dev/log; + listen 8778 ssl; + ssl_certificate {{ tls_cert_path }}; + ssl_certificate_key {{ tls_key_path }}; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + access_log {{ snap_common }}/log/nginx-access.log; + error_log {{ snap_common }}/log/nginx-error.log; location / { include {{ snap }}/usr/conf/uwsgi_params; uwsgi_param SCRIPT_NAME ''; diff --git a/snap-overlay/templates/placement.conf.d.keystone.conf.j2 b/snap-overlay/templates/placement.conf.d.keystone.conf.j2 index ed05bee..dfd1438 100644 --- a/snap-overlay/templates/placement.conf.d.keystone.conf.j2 +++ b/snap-overlay/templates/placement.conf.d.keystone.conf.j2 @@ -1,6 +1,6 @@ [keystone_authtoken] -auth_uri = http://{{ control_ip }}:5000 -auth_url = http://{{ control_ip }}:5000 +auth_uri = https://{{ control_ip }}:5000/v3 +auth_url = https://{{ control_ip }}:5000/v3 memcached_servers = {{ compute_ip }}:11211 auth_type = password project_domain_name = default @@ -8,6 +8,7 @@ user_domain_name = default project_name = service username = placement password = {{ placement_password }} +cafile = {{ tls_cacert_path }} [paste_deploy] flavor = keystone diff --git a/snap/hooks/post-refresh b/snap/hooks/post-refresh index 327a9bd..ff75d4a 100755 --- a/snap/hooks/post-refresh +++ b/snap/hooks/post-refresh @@ -22,7 +22,7 @@ fi # Add default ports for mysql, rabbit and dashboard services. # [2019-11-21] build 171 (beta) -> master if [ -z "$(snapctl get config.network.ports.dashboard)" ]; then - snapctl set config.network.ports.dashboard=80 + snapctl set config.network.ports.dashboard=443 fi if [ -z "$(snapctl get config.network.ports.mysql)" ]; then diff --git a/tests/basic-test.sh b/tests/basic-test.sh index d4099f5..19a9971 100755 --- a/tests/basic-test.sh +++ b/tests/basic-test.sh @@ -190,7 +190,7 @@ echo "++++++++++++++++++++++++++++++++++++++++++++++++++" export HORIZON_IP if [[ $PREFIX == *"multipass"* ]]; then - echo "Opening $HORIZON_IP:80 up to the outside world." + echo "Opening $HORIZON_IP:443 up to the outside world." cat< /tmp/_10_hosts.py # Allow all hosts to connect to this machine ALLOWED_HOSTS = ['*',] diff --git a/tests/configure-the-things.sh b/tests/configure-the-things.sh index 7ffe635..36dc616 100644 --- a/tests/configure-the-things.sh +++ b/tests/configure-the-things.sh @@ -26,9 +26,9 @@ sudo systemctl restart snap.microstack.* microstack.openstack user show admin || { sudo microstack.keystone-manage bootstrap \ --bootstrap-password $OS_PASSWORD \ - --bootstrap-admin-url http://10.20.20.1:5000/v3/ \ - --bootstrap-internal-url http://10.20.20.1:5000/v3/ \ - --bootstrap-public-url http://10.20.20.1:5000/v3/ \ + --bootstrap-admin-url https://10.20.20.1:5000/v3/ \ + --bootstrap-internal-url https://10.20.20.1:5000/v3/ \ + --bootstrap-public-url https://10.20.20.1:5000/v3/ \ --bootstrap-region-id microstack } diff --git a/tests/framework.py b/tests/framework.py index 2fdbe07..2c2fcfe 100644 --- a/tests/framework.py +++ b/tests/framework.py @@ -115,6 +115,7 @@ class TestHost: '/var/snap/microstack/common/etc/microstack.json', '/tmp/snap.microstack-test/tmp/microstack.json']) self.check_call(['microstack-test.rally', 'db', 'recreate']) + # TODO(coreycb): Update microstack.json.j2 to enable TLS self.check_call([ 'microstack-test.rally', 'deployment', 'create', '--filename', '/tmp/microstack.json', @@ -425,7 +426,7 @@ class Framework(unittest.TestCase): 'microstack', 'config.credentials.keystone-password' ]).decode('utf-8') - self.driver.get(f'http://{control_ip}:{dashboard_port}/') + self.driver.get(f'https://{control_ip}:{dashboard_port}/') # Login to horizon! self.driver.find_element(By.ID, "id_username").click() self.driver.find_element(By.ID, "id_username").send_keys("admin") diff --git a/tests/test_cluster.py b/tests/test_cluster.py index 26c1561..d9e6b8b 100755 --- a/tests/test_cluster.py +++ b/tests/test_cluster.py @@ -85,6 +85,14 @@ class TestCluster(Framework): compute_host.install_microstack(path='microstack_ussuri_amd64.snap', snap_try=self.snap_try) + for conf in ['cacert-path', 'cert-path', 'key-path']: + path = compute_host.check_output([ + 'sudo', 'snap', + 'get', 'microstack', + 'config.tls.{}'.format(conf), + ]).decode('utf-8') + compute_host.copy_to(path, os.path.dirname(path)) + # TODO add the following to args for init compute_host.check_call([ 'sudo', 'snap', 'set', 'microstack', diff --git a/tools/cluster/cluster/add_compute.py b/tools/cluster/cluster/add_compute.py index e88e09c..f4b9e21 100644 --- a/tools/cluster/cluster/add_compute.py +++ b/tools/cluster/cluster/add_compute.py @@ -29,14 +29,19 @@ def _create_credential(): domain_name = 'default' # TODO: add support for TLS-terminated Keystone once this is supported. auth = v3.password.Password( - auth_url="http://localhost:5000/v3", + auth_url="https://localhost:5000/v3", username='nova', password=config_get('config.credentials.nova-password'), user_domain_name=domain_name, project_domain_name=domain_name, project_name=project_name ) - sess = session.Session(auth=auth) + sess = session.Session( + auth=auth, + # TODO(coreycb): Enable TLS here + # verify=config_get('config.tls.cacert-path'), + verify=False, + ) keystone_client = client.Client(session=sess) # Only allow this credential to list the Keystone catalog. After it diff --git a/tools/cluster/cluster/daemon.py b/tools/cluster/cluster/daemon.py index b462f6c..f9fe597 100644 --- a/tools/cluster/cluster/daemon.py +++ b/tools/cluster/cluster/daemon.py @@ -211,7 +211,7 @@ def join(): return MissingAuthDataInRequest() # TODO: handle https here when TLS termination support is added. - keystone_base_url = 'http://localhost:5000/v3' + keystone_base_url = 'https://localhost:5000/v3' # In an unlikely event of failing to construct an auth object # treat it as if invalid data got passed in terms of responding @@ -231,7 +231,12 @@ def join(): try: # Use the auth object with the app credential to create a session # which the Keystone client will use. - sess = session.Session(auth=auth) + sess = session.Session( + auth=auth, + # TODO(coreycb): Enable TLS here + # verify=config_get('config.tls.cacert-path'), + verify=False, + ) except Exception: logger.exception('An exception has occurred while trying to build' ' a Session object with auth data' diff --git a/tools/init/init/main.py b/tools/init/init/main.py index fa175b9..7f929ba 100644 --- a/tools/init/init/main.py +++ b/tools/init/init/main.py @@ -182,6 +182,7 @@ def init() -> None: # The following are not yet implemented: # questions.VmSwappiness(), # questions.FileHandleLimits(), + questions.TlsCertificate(), questions.DashboardAccess(), questions.RabbitMq(), questions.DatabaseSetup(), diff --git a/tools/init/init/questions/__init__.py b/tools/init/init/questions/__init__.py index 7b2555d..c4e7eb0 100644 --- a/tools/init/init/questions/__init__.py +++ b/tools/init/init/questions/__init__.py @@ -26,12 +26,13 @@ limitations under the License. import json from time import sleep from os import path +from pathlib import Path from init import shell from init.shell import (check, call, check_output, sql, nc_wait, log_wait, restart, download, disable, enable) from init.config import Env, log -from init import cluster_tls +from init import tls from init.questions.question import Question from init.questions import clustering, network, uninstall # noqa F401 @@ -102,7 +103,13 @@ class Clustering(Question): 'config.services.hypervisor': 'true', }) # Generate a self-signed certificate for the clustering service. - cluster_tls.generate_selfsigned() + cert_path, key_path = ( + Path(shell.config_get('config.cluster.tls-cert-path')), + Path(shell.config_get('config.cluster.tls-key-path')), + ) + tls.generate_selfsigned( + cert_path, key_path, + fingerprint_config='config.cluster.fingerprint') # Write templates check('snap-openstack', 'setup') @@ -288,6 +295,30 @@ class DashboardAccess(ConfigQuestion): hosts=answer)) +class TlsCertificate(Question): + + _type = 'boolean' + _question = 'Do you wish to generate a self-signed certificate for TLS?' + config_key = 'config.tls.generate-cert' + + def yes(self, answer: str) -> None: + role = shell.config_get('config.cluster.role') + + if role == 'control': + log.info('Generating TLS Certificate and Key') + cert_path, key_path = ( + Path(shell.config_get('config.tls.cert-path')), + Path(shell.config_get('config.tls.key-path')), + ) + tls.generate_selfsigned(cert_path, key_path, ip=_env['control_ip']) + restart('nginx') + + def no(self, answer: str): + log.info('TLS certificate details must be provided. ' + 'See config.tls settings.') + restart('nginx') + + class RabbitMq(Question): """Wait for Rabbit to start, then setup permissions.""" @@ -362,7 +393,7 @@ class DatabaseSetup(Question): if call('openstack', 'user', 'show', 'admin'): return - bootstrap_url = 'http://{control_ip}:5000/v3/'.format(**_env) + bootstrap_url = 'https://{control_ip}:5000/v3/'.format(**_env) check('snap-openstack', 'launch', 'keystone-manage', 'bootstrap', '--bootstrap-password', _env['keystone_password'], @@ -401,7 +432,7 @@ class DatabaseSetup(Question): log.info('Creating service project ...') if not call('openstack', 'project', 'show', 'service'): check('openstack', 'project', 'create', '--domain', - 'default', '--description', 'Service Project', + 'default', '--description', '"Service Project"', 'service') log.info('Keystone configured!') @@ -536,7 +567,7 @@ class PlacementSetup(Question): for endpoint in ['public', 'internal', 'admin']: call('openstack', 'endpoint', 'create', '--region', 'microstack', 'placement', endpoint, - 'http://{control_ip}:8778'.format(**_env)) + 'https://{control_ip}:8778'.format(**_env)) log.info('Running Placement DB migrations...') check('snap-openstack', 'launch', 'placement-manage', 'db', 'sync') @@ -612,6 +643,7 @@ class NovaControlPlane(Question): enable('nova-api') restart('nova-compute') + restart('nginx') for service in [ 'nova-api-metadata', @@ -630,7 +662,7 @@ class NovaControlPlane(Question): for endpoint in ['public', 'internal', 'admin']: call('openstack', 'endpoint', 'create', '--region', 'microstack', 'compute', endpoint, - 'http://{control_ip}:8774/v2.1'.format(**_env)) + 'https://{control_ip}:8774/v2.1'.format(**_env)) log.info('Creating default flavors...') @@ -682,7 +714,7 @@ class CinderSetup(Question): check( 'openstack', 'endpoint', 'create', '--region', 'microstack', f'volume{api_version}', endpoint, - f'http://{control_ip}:8776/{api_version}/' + f'https://{control_ip}:8776/{api_version}/' '$(project_id)s' ) log.info('Running Cinder DB migrations...') @@ -754,12 +786,13 @@ class NeutronControlPlane(Question): for endpoint in ['public', 'internal', 'admin']: call('openstack', 'endpoint', 'create', '--region', 'microstack', 'network', endpoint, - 'http://{control_ip}:9696'.format(**_env)) + 'https://{control_ip}:9696'.format(**_env)) check('snap-openstack', 'launch', 'neutron-db-manage', 'upgrade', 'head') enable('neutron-api') enable('neutron-ovn-metadata-agent') + restart('nginx') nc_wait(_env['control_ip'], '9696') @@ -864,10 +897,11 @@ class GlanceSetup(Question): for endpoint in ['internal', 'admin', 'public']: check('openstack', 'endpoint', 'create', '--region', 'microstack', 'image', endpoint, - 'http://{compute_ip}:9292'.format(**_env)) + 'https://{compute_ip}:9292'.format(**_env)) check('snap-openstack', 'launch', 'glance-manage', 'db_sync') enable('glance-api') + restart('nginx') nc_wait(_env['compute_ip'], '9292') diff --git a/tools/init/init/cluster_tls.py b/tools/init/init/tls.py similarity index 79% rename from tools/init/init/cluster_tls.py rename to tools/init/init/tls.py index 95e4c98..39f6bd5 100644 --- a/tools/init/init/cluster_tls.py +++ b/tools/init/init/tls.py @@ -1,9 +1,12 @@ #!/usr/bin/env python3 -from pathlib import Path + +from init.shell import check from datetime import datetime from dateutil.relativedelta import relativedelta +import ipaddress +import socket from cryptography.hazmat.primitives import hashes from cryptography.hazmat.backends import default_backend @@ -15,7 +18,7 @@ from cryptography.x509.oid import NameOID from init import shell -def generate_selfsigned(): +def generate_selfsigned(cert_path, key_path, ip=None, fingerprint_config=None): """Generate a self-signed certificate with associated keys. The certificate will have a fake CNAME and subjAltName since @@ -28,26 +31,29 @@ def generate_selfsigned(): via a secure channel. https://owasp.org/www-community/controls/Certificate_and_Public_Key_Pinning """ - cert_path, key_path = ( - Path(shell.config_get('config.cluster.tls-cert-path')), - Path(shell.config_get('config.cluster.tls-key-path')), - ) # Do not generate a new certificate and key if there is already an existing # pair. TODO: improve this check and allow renewal. if cert_path.exists() and key_path.exists(): return - dummy_cn = 'microstack.run' key = rsa.generate_private_key( public_exponent=65537, key_size=2048, backend=default_backend(), ) + cn = socket.gethostname() common_name = x509.Name([ - x509.NameAttribute(NameOID.COMMON_NAME, dummy_cn) + x509.NameAttribute(NameOID.COMMON_NAME, cn) ]) - san = x509.SubjectAlternativeName([x509.DNSName(dummy_cn)]) + if ip: + san = x509.SubjectAlternativeName( + [x509.DNSName(cn), x509.IPAddress(ipaddress.ip_address(ip))] + ) + else: + san = x509.SubjectAlternativeName([x509.DNSName(cn)]) + basic_contraints = x509.BasicConstraints(ca=True, path_length=0) + now = datetime.utcnow() cert = ( x509.CertificateBuilder() @@ -63,7 +69,8 @@ def generate_selfsigned(): ) cert_fprint = cert.fingerprint(hashes.SHA256()).hex() - shell.config_set(**{'config.cluster.fingerprint': cert_fprint}) + if fingerprint_config: + shell.config_set(**{fingerprint_config: cert_fprint}) serialized_cert = cert.public_bytes(encoding=serialization.Encoding.PEM) serialized_key = key.private_bytes( @@ -73,3 +80,5 @@ def generate_selfsigned(): ) cert_path.write_bytes(serialized_cert) key_path.write_bytes(serialized_key) + check('chmod', '644', str(cert_path)) + check('chmod', '600', str(key_path))