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
This commit is contained in:
parent
1f87b3e360
commit
ee011bfef1
6
DEMO.md
6
DEMO.md
|
@ -158,11 +158,11 @@ Answer the questions as follows:
|
|||
|
||||
<table>
|
||||
<tr><td>cloud type:</td> <td><code>openstack</code></td></tr>
|
||||
<tr><td>endpoint:</td> <td><code>http://10.20.20.1:5000/v3</code></td></tr>
|
||||
<tr><td>endpoint:</td> <td><code>https://10.20.20.1:5000/v3</code></td></tr>
|
||||
<tr><td>cert path:</td> <td><code>none</code></td></tr>
|
||||
<tr><td>auth type:</td> <td><code>userpass</code></td></tr>
|
||||
<tr><td>region:</td> <td><code>microstack</code></td></tr>
|
||||
<tr><td>region endpoint:</td> <td><code>http://10.20.20.1:5000/v3</code></td></tr>
|
||||
<tr><td>region endpoint:</td> <td><code>https://10.20.20.1:5000/v3</code></td></tr>
|
||||
<tr><td>add another region?:</td> <td><code>N</code></td></tr>
|
||||
</table>
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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',
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
@ -83,6 +88,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
|
||||
|
@ -122,6 +130,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"
|
||||
|
|
|
@ -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 }}"
|
||||
|
|
|
@ -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 / {
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 '';
|
||||
|
|
|
@ -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 '';
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 }}
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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/*;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
[cinder]
|
||||
service_type = volume
|
||||
service_name = cinder
|
||||
region_name = {{ region_name }}
|
||||
cafile = {{ tls_cacert_path }}
|
|
@ -2,3 +2,4 @@
|
|||
service_type = image
|
||||
service_name = glance
|
||||
region_name = {{ region_name }}
|
||||
cafile = {{ tls_cacert_path }}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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 }}
|
||||
|
|
|
@ -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 '';
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<<EOF > /tmp/_10_hosts.py
|
||||
# Allow all hosts to connect to this machine
|
||||
ALLOWED_HOSTS = ['*',]
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -103,6 +103,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',
|
||||
|
@ -413,7 +414,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")
|
||||
|
|
|
@ -76,6 +76,14 @@ class TestCluster(Framework):
|
|||
|
||||
compute_host.install_microstack(path='microstack_ussuri_amd64.snap')
|
||||
|
||||
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',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -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))
|
Loading…
Reference in New Issue