Add TLS OpenStack API endpoints
This patch provides TLS endpoints secured by a self-signed certificate. Another patch will provide support for trusted CA-signed certificates. 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-self-signed 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 self-signed certificate by setting generate-self-signed 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. If using clustering, the certificates/key will be copied from the control node to the compute nodes. The config for cacert-path, cert-path, and key-path will be set to the same values as on the control 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. Change-Id: Iceea3127822404a3275fcf8a221cbedc4b52c217
This commit is contained in:
parent
abf8af66ef
commit
064aae8458
6
DEMO.md
6
DEMO.md
@ -158,11 +158,11 @@ Answer the questions as follows:
|
|||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr><td>cloud type:</td> <td><code>openstack</code></td></tr>
|
<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>cert path:</td> <td><code>none</code></td></tr>
|
||||||
<tr><td>auth type:</td> <td><code>userpass</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:</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>
|
<tr><td>add another region?:</td> <td><code>N</code></td></tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@ -182,7 +182,7 @@ images in your microstack cloud. Here's how to set that up.
|
|||||||
|
|
||||||
```
|
```
|
||||||
mkdir simplestreams
|
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
|
(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.ext-cidr': '10.20.20.1/24',
|
||||||
'config.network.security-rules': True,
|
'config.network.security-rules': True,
|
||||||
'config.network.dashboard-allowed-hosts': '*',
|
'config.network.dashboard-allowed-hosts': '*',
|
||||||
'config.network.ports.dashboard': 80,
|
'config.network.ports.dashboard': 443,
|
||||||
'config.network.ports.mysql': 3306,
|
'config.network.ports.mysql': 3306,
|
||||||
'config.network.ports.rabbit': 5672,
|
'config.network.ports.rabbit': 5672,
|
||||||
'config.network.external-bridge-name': 'br-ex',
|
'config.network.external-bridge-name': 'br-ex',
|
||||||
@ -75,6 +75,14 @@ def _get_default_config():
|
|||||||
'config.nova.cpu-mode': 'host-model',
|
'config.nova.cpu-mode': 'host-model',
|
||||||
# Do not override cpu-models by default.
|
# Do not override cpu-models by default.
|
||||||
'config.nova.cpu-models': '',
|
'config.nova.cpu-models': '',
|
||||||
|
|
||||||
|
'config.tls.generate-self-signed': True,
|
||||||
|
'config.tls.cacert-path':
|
||||||
|
f'{snap_common}/etc/ssl/certs/cacert.pem',
|
||||||
|
'config.tls.cert-path':
|
||||||
|
f'{snap_common}/etc/ssl/certs/cert.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/policy.d"
|
||||||
- "{snap_common}/etc/neutron/rootwrap.d"
|
- "{snap_common}/etc/neutron/rootwrap.d"
|
||||||
- "{snap_common}/etc/nginx/sites-enabled"
|
- "{snap_common}/etc/nginx/sites-enabled"
|
||||||
- "{snap_common}/etc/nginx/snap/sites-enabled"
|
|
||||||
- "{snap_common}/etc/glance/glance.conf.d"
|
- "{snap_common}/etc/glance/glance.conf.d"
|
||||||
- "{snap_common}/etc/placement/placement.conf.d"
|
- "{snap_common}/etc/placement/placement.conf.d"
|
||||||
- "{snap_common}/etc/horizon/horizon.conf.d"
|
- "{snap_common}/etc/horizon/horizon.conf.d"
|
||||||
@ -22,6 +21,8 @@ setup:
|
|||||||
- "{snap_common}/etc/cluster/tls"
|
- "{snap_common}/etc/cluster/tls"
|
||||||
- "{snap_common}/etc/cluster/uwsgi/snap"
|
- "{snap_common}/etc/cluster/uwsgi/snap"
|
||||||
- "{snap_common}/etc/rabbitmq"
|
- "{snap_common}/etc/rabbitmq"
|
||||||
|
- "{snap_common}/etc/ssl/certs"
|
||||||
|
- "{snap_common}/etc/ssl/private"
|
||||||
- "{snap_common}/fernet-keys"
|
- "{snap_common}/fernet-keys"
|
||||||
- "{snap_common}/lib"
|
- "{snap_common}/lib"
|
||||||
- "{snap_common}/lib/images"
|
- "{snap_common}/lib/images"
|
||||||
@ -33,24 +34,25 @@ setup:
|
|||||||
- "{snap_common}/etc/iscsi"
|
- "{snap_common}/etc/iscsi"
|
||||||
- "{snap_common}/etc/target"
|
- "{snap_common}/etc/target"
|
||||||
templates:
|
templates:
|
||||||
cluster-nginx.conf.j2: "{snap_common}/etc/nginx/snap/sites-enabled/cluster.conf"
|
cluster-nginx.conf.j2: "{snap_common}/etc/nginx/sites-enabled/cluster.conf"
|
||||||
keystone-nginx.conf.j2: "{snap_common}/etc/nginx/snap/sites-enabled/keystone.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"
|
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"
|
neutron-snap.conf.j2: "{snap_common}/etc/neutron/neutron.conf.d/neutron-snap.conf"
|
||||||
nginx.conf.j2: "{snap_common}/etc/nginx/snap/nginx.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-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"
|
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"
|
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-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.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.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.keystone.conf.j2: "{snap_common}/etc/cinder/cinder.conf.d/keystone.conf"
|
||||||
cinder-rootwrap.conf.j2: "{snap_common}/etc/cinder/rootwrap.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-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"
|
05_snap_tweaks.j2: "{snap_common}/etc/horizon/local_settings.d/_05_snap_tweaks.py"
|
||||||
libvirtd.conf.j2: "{snap_common}/etc/libvirt/libvirtd.conf"
|
libvirtd.conf.j2: "{snap_common}/etc/libvirt/libvirtd.conf"
|
||||||
qemu.conf.j2: "{snap_common}/etc/libvirt/qemu.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.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.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.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.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.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.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.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"
|
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"
|
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"
|
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.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.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_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"
|
rabbitmq.conf.j2: "{snap_common}/etc/rabbitmq/rabbitmq.config"
|
||||||
iscsid.conf.j2: "{snap_common}/etc/iscsi/iscsid.conf"
|
iscsid.conf.j2: "{snap_common}/etc/iscsi/iscsid.conf"
|
||||||
lvm.conf.j2: "{snap_common}/etc/lvm/lvm.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"
|
nrpe.cfg.j2: "{snap_common}/etc/nrpe/nrpe-microstack.cfg"
|
||||||
filebeat.yaml.j2: "{snap_common}/etc/filebeat/filebeat-microstack.yaml"
|
filebeat.yaml.j2: "{snap_common}/etc/filebeat/filebeat-microstack.yaml"
|
||||||
chmod:
|
chmod:
|
||||||
|
"{snap_common}/etc/ssl": 0755
|
||||||
|
"{snap_common}/etc/ssl/certs": 0755
|
||||||
|
"{snap_common}/etc/ssl/private": 0700
|
||||||
"{snap_common}/instances": 0755
|
"{snap_common}/instances": 0755
|
||||||
"{snap_common}/etc/microstack.rc": 0644
|
"{snap_common}/etc/microstack.rc": 0644
|
||||||
"{snap_common}/etc/microstack.json": 0644
|
"{snap_common}/etc/microstack.json": 0644
|
||||||
@ -124,6 +132,10 @@ setup:
|
|||||||
virt_type: 'config.nova.virt-type'
|
virt_type: 'config.nova.virt-type'
|
||||||
cpu_mode: 'config.nova.cpu-mode'
|
cpu_mode: 'config.nova.cpu-mode'
|
||||||
cpu_models: 'config.nova.cpu-models'
|
cpu_models: 'config.nova.cpu-models'
|
||||||
|
tls_generate_self_signed: 'config.tls.generate-self-signed'
|
||||||
|
tls_cacert_path: 'config.tls.cacert-path'
|
||||||
|
tls_cert_path: 'config.tls.cert-path'
|
||||||
|
tls_key_path: 'config.tls.key-path'
|
||||||
entry_points:
|
entry_points:
|
||||||
keystone-manage:
|
keystone-manage:
|
||||||
binary: "{snap}/bin/keystone-manage"
|
binary: "{snap}/bin/keystone-manage"
|
||||||
|
@ -23,7 +23,7 @@ AVAILABLE_THEMES = [
|
|||||||
|
|
||||||
# Point us at keystone.
|
# Point us at keystone.
|
||||||
OPENSTACK_HOST = "10.20.20.1"
|
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_"
|
OPENSTACK_KEYSTONE_DEFAULT_ROLE = "_member_"
|
||||||
|
|
||||||
# Turn off external access for now. (This should be turned on once we
|
# Turn off external access for now. (This should be turned on once we
|
||||||
@ -40,4 +40,13 @@ CACHES = {
|
|||||||
}
|
}
|
||||||
SESSION_ENGINE='django.contrib.sessions.backends.cache'
|
SESSION_ENGINE='django.contrib.sessions.backends.cache'
|
||||||
|
|
||||||
|
# SSL config
|
||||||
|
CSRF_COOKIE_SECURE = True
|
||||||
|
SESSION_COOKIE_SECURE = True
|
||||||
|
{% if tls_generate_self_signed|lower == "false" %}
|
||||||
|
# TODO(coreycb): Can we verify cert if self-signed certs
|
||||||
|
# include a ca-cert and cert?
|
||||||
|
OPENSTACK_SSL_CACERT = "{{ tls_cacert_path }}"
|
||||||
|
{% else %}
|
||||||
|
OPENSTACK_SSL_NO_VERIFY = True
|
||||||
|
{% endif %}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
server {
|
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;
|
access_log {{ snap_common }}/log/nginx-access.log;
|
||||||
error_log {{ snap_common }}/log/nginx-error.log;
|
error_log {{ snap_common }}/log/nginx-error.log;
|
||||||
location / {
|
location / {
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
auth_strategy = keystone
|
auth_strategy = keystone
|
||||||
|
|
||||||
[keystone_authtoken]
|
[keystone_authtoken]
|
||||||
auth_uri = http://{{ control_ip }}:5000
|
auth_uri = https://{{ control_ip }}:5000/v3
|
||||||
auth_url = http://{{ control_ip }}:5000
|
auth_url = https://{{ control_ip }}:5000/v3
|
||||||
memcached_servers = {{ compute_ip }}:11211
|
memcached_servers = {{ compute_ip }}:11211
|
||||||
auth_type = password
|
auth_type = password
|
||||||
project_domain_name = default
|
project_domain_name = default
|
||||||
@ -11,3 +11,4 @@ user_domain_name = default
|
|||||||
project_name = service
|
project_name = service
|
||||||
username = cinder
|
username = cinder
|
||||||
password = {{ cinder_password }}
|
password = {{ cinder_password }}
|
||||||
|
cafile = {{ tls_cacert_path }}
|
||||||
|
18
snap-overlay/templates/glance-nginx.conf.j2
Normal file
18
snap-overlay/templates/glance-nginx.conf.j2
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
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;
|
||||||
|
# Disabled for glance image uploads. The maximum size will be
|
||||||
|
# determined by glance settings.
|
||||||
|
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
|
state_path = {{ snap_common }}/lib
|
||||||
# Log to systemd journal
|
# Log to systemd journal
|
||||||
use_journal = True
|
use_journal = True
|
||||||
|
bind_port = 9282
|
||||||
|
|
||||||
log_file = {{ snap_common }}/log/glance.log
|
log_file = {{ snap_common }}/log/glance.log
|
||||||
debug = {{ logging_debug }}
|
debug = {{ logging_debug }}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[keystone_authtoken]
|
[keystone_authtoken]
|
||||||
auth_uri = http://{{ control_ip }}:5000
|
auth_uri = https://{{ control_ip }}:5000/v3
|
||||||
auth_url = http://{{ control_ip }}:5000
|
auth_url = https://{{ control_ip }}:5000/v3
|
||||||
memcached_servers = {{ compute_ip }}:11211
|
memcached_servers = {{ compute_ip }}:11211
|
||||||
auth_type = password
|
auth_type = password
|
||||||
project_domain_name = default
|
project_domain_name = default
|
||||||
@ -8,6 +8,7 @@ user_domain_name = default
|
|||||||
project_name = service
|
project_name = service
|
||||||
username = glance
|
username = glance
|
||||||
password = {{ glance_password }}
|
password = {{ glance_password }}
|
||||||
|
cafile = {{ tls_cacert_path }}
|
||||||
|
|
||||||
[paste_deploy]
|
[paste_deploy]
|
||||||
flavor = keystone
|
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 {
|
server {
|
||||||
listen {{ dashboard_port }};
|
listen {{ dashboard_port }} ssl;
|
||||||
error_log syslog:server=unix:/dev/log;
|
ssl_certificate {{ tls_cert_path }};
|
||||||
access_log syslog:server=unix:/dev/log;
|
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 / {
|
location / {
|
||||||
include {{ snap }}/usr/conf/uwsgi_params;
|
include {{ snap }}/usr/conf/uwsgi_params;
|
||||||
uwsgi_param SCRIPT_NAME '';
|
uwsgi_param SCRIPT_NAME '';
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
server {
|
server {
|
||||||
listen 5000;
|
listen 5000 ssl;
|
||||||
error_log syslog:server=unix:/dev/log;
|
ssl_certificate {{ tls_cert_path }};
|
||||||
access_log syslog:server=unix:/dev/log;
|
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 / {
|
location / {
|
||||||
include {{ snap }}/usr/conf/uwsgi_params;
|
include {{ snap }}/usr/conf/uwsgi_params;
|
||||||
uwsgi_param SCRIPT_NAME '';
|
uwsgi_param SCRIPT_NAME '';
|
||||||
|
@ -13,12 +13,19 @@
|
|||||||
"version": 3
|
"version": 3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"auth_url": "http://{{ control_ip }}:5000",
|
"auth_url": "https://{{ control_ip }}:5000/v3",
|
||||||
"endpoint_type": null,
|
"endpoint_type": null,
|
||||||
|
{% if tls_generate_self_signed|lower == "false" %}
|
||||||
|
"https_cacert": "{{ tls_cacert_path }}",
|
||||||
|
"https_cert": "{{ tls_cert_path }}",
|
||||||
|
"https_key": "{{ tls_key_path }}",
|
||||||
|
"https_insecure": false,
|
||||||
|
{% else %}
|
||||||
"https_cacert": "",
|
"https_cacert": "",
|
||||||
"https_cert": "",
|
"https_cert": "",
|
||||||
"https_insecure": false,
|
|
||||||
"https_key": "",
|
"https_key": "",
|
||||||
|
"https_insecure": true,
|
||||||
|
{% endif %}
|
||||||
"profiler_conn_str": null,
|
"profiler_conn_str": null,
|
||||||
"profiler_hmac_key": null,
|
"profiler_hmac_key": null,
|
||||||
"region_name": ""
|
"region_name": ""
|
||||||
|
@ -3,7 +3,8 @@ export OS_USER_DOMAIN_NAME=default
|
|||||||
export OS_PROJECT_NAME=admin
|
export OS_PROJECT_NAME=admin
|
||||||
export OS_USERNAME=admin
|
export OS_USERNAME=admin
|
||||||
export OS_PASSWORD={{ keystone_password }}
|
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_IDENTITY_API_VERSION=3
|
||||||
export OS_IMAGE_API_VERSION=2
|
export OS_IMAGE_API_VERSION=2
|
||||||
|
export OS_CACERT={{ tls_cacert_path }}
|
||||||
|
15
snap-overlay/templates/neutron-nginx.conf.j2
Normal file
15
snap-overlay/templates/neutron-nginx.conf.j2
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
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;
|
||||||
|
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
|
state_path = {{ snap_common }}/lib
|
||||||
# Log to systemd journal
|
# Log to systemd journal
|
||||||
use_journal = True
|
use_journal = True
|
||||||
|
bind_port = 9686
|
||||||
|
|
||||||
log_file = {{ snap_common }}/log/neutron.log
|
log_file = {{ snap_common }}/log/neutron.log
|
||||||
debug = {{ logging_debug }}
|
debug = {{ logging_debug }}
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
auth_strategy = keystone
|
auth_strategy = keystone
|
||||||
|
|
||||||
[keystone_authtoken]
|
[keystone_authtoken]
|
||||||
auth_uri = http://{{ control_ip }}:5000
|
auth_uri = https://{{ control_ip }}:5000/v3
|
||||||
auth_url = http://{{ control_ip }}:5000
|
auth_url = https://{{ control_ip }}:5000/v3
|
||||||
memcached_servers = {{ compute_ip }}:11211
|
memcached_servers = {{ compute_ip }}:11211
|
||||||
auth_type = password
|
auth_type = password
|
||||||
project_domain_name = default
|
project_domain_name = default
|
||||||
@ -11,3 +11,4 @@ user_domain_name = default
|
|||||||
project_name = service
|
project_name = service
|
||||||
username = neutron
|
username = neutron
|
||||||
password = {{ neutron_password }}
|
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
|
notify_nova_on_port_data_changes = True
|
||||||
|
|
||||||
[nova]
|
[nova]
|
||||||
auth_url = http://{{ control_ip }}:5000
|
auth_url = https://{{ control_ip }}:5000/v3
|
||||||
auth_type = password
|
auth_type = password
|
||||||
project_domain_name = default
|
project_domain_name = default
|
||||||
user_domain_name = default
|
user_domain_name = default
|
||||||
@ -11,3 +11,4 @@ region_name = {{ region_name }}
|
|||||||
project_name = service
|
project_name = service
|
||||||
username = nova
|
username = nova
|
||||||
password = {{ nova_password }}
|
password = {{ nova_password }}
|
||||||
|
cafile = {{ tls_cacert_path }}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[placement]
|
[placement]
|
||||||
auth_url = http://{{ control_ip }}:5000
|
auth_url = https://{{ control_ip }}:5000/v3
|
||||||
auth_type = password
|
auth_type = password
|
||||||
project_domain_name = default
|
project_domain_name = default
|
||||||
user_domain_name = default
|
user_domain_name = default
|
||||||
@ -7,3 +7,4 @@ region_name = {{ region_name }}
|
|||||||
project_name = service
|
project_name = service
|
||||||
username = placement
|
username = placement
|
||||||
password = {{ placement_password }}
|
password = {{ placement_password }}
|
||||||
|
cafile = {{ tls_cacert_path }}
|
||||||
|
@ -45,5 +45,5 @@ http {
|
|||||||
gzip_disable "msie6";
|
gzip_disable "msie6";
|
||||||
|
|
||||||
include {{ snap_common }}/etc/nginx/conf.d/*.conf;
|
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,15 @@
|
|||||||
server {
|
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;
|
access_log {{ snap_common }}/log/nginx-access.log;
|
||||||
error_log {{ snap_common }}/log/nginx-error.log;
|
error_log {{ snap_common }}/log/nginx-error.log;
|
||||||
location / {
|
location / {
|
||||||
include {{ snap }}/usr/conf/uwsgi_params;
|
proxy_set_header X-Forwarded-Host $host:$server_port;
|
||||||
uwsgi_param SCRIPT_NAME '';
|
proxy_set_header X-Forwarded-Server $host;
|
||||||
uwsgi_pass unix://{{ snap_common }}/run/placement-api.sock;
|
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
|
# Log to systemd journal
|
||||||
use_journal = True
|
use_journal = True
|
||||||
|
|
||||||
|
osapi_compute_listen_port = 8764
|
||||||
|
|
||||||
# Set a hostname to be an FQDN to avoid issues with port binding for
|
# 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.
|
# which a hostname of a Nova node must match a hostname of an OVN chassis.
|
||||||
host = {{ node_fqdn }}
|
host = {{ node_fqdn }}
|
||||||
|
5
snap-overlay/templates/nova.conf.d.cinder.conf.j2
Normal file
5
snap-overlay/templates/nova.conf.d.cinder.conf.j2
Normal file
@ -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_type = image
|
||||||
service_name = glance
|
service_name = glance
|
||||||
region_name = {{ region_name }}
|
region_name = {{ region_name }}
|
||||||
|
cafile = {{ tls_cacert_path }}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[keystone_authtoken]
|
[keystone_authtoken]
|
||||||
auth_uri = http://{{ control_ip }}:5000
|
auth_uri = https://{{ control_ip }}:5000/v3
|
||||||
auth_url = http://{{ control_ip }}:5000
|
auth_url = https://{{ control_ip }}:5000/v3
|
||||||
memcached_servers = {{ compute_ip }}:11211
|
memcached_servers = {{ compute_ip }}:11211
|
||||||
auth_type = password
|
auth_type = password
|
||||||
project_domain_name = default
|
project_domain_name = default
|
||||||
@ -8,6 +8,7 @@ user_domain_name = default
|
|||||||
project_name = service
|
project_name = service
|
||||||
username = nova
|
username = nova
|
||||||
password = {{ nova_password }}
|
password = {{ nova_password }}
|
||||||
|
cafile = {{ tls_cacert_path }}
|
||||||
|
|
||||||
[paste_deploy]
|
[paste_deploy]
|
||||||
flavor = keystone
|
flavor = keystone
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[neutron]
|
[neutron]
|
||||||
url = http://{{ control_ip }}:9696
|
url = https://{{ control_ip }}:9696
|
||||||
auth_url = http://{{ control_ip }}:5000
|
auth_url = https://{{ control_ip }}:5000/v3
|
||||||
memcached_servers = {{ compute_ip }}:11211
|
memcached_servers = {{ compute_ip }}:11211
|
||||||
auth_type = password
|
auth_type = password
|
||||||
project_domain_name = default
|
project_domain_name = default
|
||||||
@ -11,3 +11,4 @@ username = neutron
|
|||||||
password = {{ neutron_password }}
|
password = {{ neutron_password }}
|
||||||
service_metadata_proxy = True
|
service_metadata_proxy = True
|
||||||
metadata_proxy_shared_secret = {{ ovn_metadata_proxy_shared_secret }}
|
metadata_proxy_shared_secret = {{ ovn_metadata_proxy_shared_secret }}
|
||||||
|
cafile = {{ tls_cacert_path }}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[placement]
|
[placement]
|
||||||
auth_uri = http://{{ control_ip }}:5000
|
auth_uri = https://{{ control_ip }}:5000/v3
|
||||||
auth_url = http://{{ control_ip }}:5000
|
auth_url = https://{{ control_ip }}:5000/v3
|
||||||
memcached_servers = {{ compute_ip }}:11211
|
memcached_servers = {{ compute_ip }}:11211
|
||||||
auth_type = password
|
auth_type = password
|
||||||
project_domain_name = default
|
project_domain_name = default
|
||||||
@ -9,3 +9,4 @@ project_name = service
|
|||||||
username = nova
|
username = nova
|
||||||
password = {{ nova_password }}
|
password = {{ nova_password }}
|
||||||
region_name = {{ region_name }}
|
region_name = {{ region_name }}
|
||||||
|
cafile = {{ tls_cacert_path }}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
server {
|
server {
|
||||||
listen 8778;
|
listen 8778 ssl;
|
||||||
error_log syslog:server=unix:/dev/log;
|
ssl_certificate {{ tls_cert_path }};
|
||||||
access_log syslog:server=unix:/dev/log;
|
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 / {
|
location / {
|
||||||
include {{ snap }}/usr/conf/uwsgi_params;
|
include {{ snap }}/usr/conf/uwsgi_params;
|
||||||
uwsgi_param SCRIPT_NAME '';
|
uwsgi_param SCRIPT_NAME '';
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[keystone_authtoken]
|
[keystone_authtoken]
|
||||||
auth_uri = http://{{ control_ip }}:5000
|
auth_uri = https://{{ control_ip }}:5000/v3
|
||||||
auth_url = http://{{ control_ip }}:5000
|
auth_url = https://{{ control_ip }}:5000/v3
|
||||||
memcached_servers = {{ compute_ip }}:11211
|
memcached_servers = {{ compute_ip }}:11211
|
||||||
auth_type = password
|
auth_type = password
|
||||||
project_domain_name = default
|
project_domain_name = default
|
||||||
@ -8,6 +8,7 @@ user_domain_name = default
|
|||||||
project_name = service
|
project_name = service
|
||||||
username = placement
|
username = placement
|
||||||
password = {{ placement_password }}
|
password = {{ placement_password }}
|
||||||
|
cafile = {{ tls_cacert_path }}
|
||||||
|
|
||||||
[paste_deploy]
|
[paste_deploy]
|
||||||
flavor = keystone
|
flavor = keystone
|
||||||
|
@ -22,7 +22,7 @@ fi
|
|||||||
# Add default ports for mysql, rabbit and dashboard services.
|
# Add default ports for mysql, rabbit and dashboard services.
|
||||||
# [2019-11-21] build 171 (beta) -> master
|
# [2019-11-21] build 171 (beta) -> master
|
||||||
if [ -z "$(snapctl get config.network.ports.dashboard)" ]; then
|
if [ -z "$(snapctl get config.network.ports.dashboard)" ]; then
|
||||||
snapctl set config.network.ports.dashboard=80
|
snapctl set config.network.ports.dashboard=443
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$(snapctl get config.network.ports.mysql)" ]; then
|
if [ -z "$(snapctl get config.network.ports.mysql)" ]; then
|
||||||
|
@ -190,7 +190,7 @@ echo "++++++++++++++++++++++++++++++++++++++++++++++++++"
|
|||||||
|
|
||||||
export HORIZON_IP
|
export HORIZON_IP
|
||||||
if [[ $PREFIX == *"multipass"* ]]; then
|
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
|
cat<<EOF > /tmp/_10_hosts.py
|
||||||
# Allow all hosts to connect to this machine
|
# Allow all hosts to connect to this machine
|
||||||
ALLOWED_HOSTS = ['*',]
|
ALLOWED_HOSTS = ['*',]
|
||||||
|
@ -26,9 +26,9 @@ sudo systemctl restart snap.microstack.*
|
|||||||
microstack.openstack user show admin || {
|
microstack.openstack user show admin || {
|
||||||
sudo microstack.keystone-manage bootstrap \
|
sudo microstack.keystone-manage bootstrap \
|
||||||
--bootstrap-password $OS_PASSWORD \
|
--bootstrap-password $OS_PASSWORD \
|
||||||
--bootstrap-admin-url http://10.20.20.1:5000/v3/ \
|
--bootstrap-admin-url https://10.20.20.1:5000/v3/ \
|
||||||
--bootstrap-internal-url http://10.20.20.1:5000/v3/ \
|
--bootstrap-internal-url https://10.20.20.1:5000/v3/ \
|
||||||
--bootstrap-public-url http://10.20.20.1:5000/v3/ \
|
--bootstrap-public-url https://10.20.20.1:5000/v3/ \
|
||||||
--bootstrap-region-id microstack
|
--bootstrap-region-id microstack
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,7 +434,7 @@ class Framework(unittest.TestCase):
|
|||||||
'microstack',
|
'microstack',
|
||||||
'config.credentials.keystone-password'
|
'config.credentials.keystone-password'
|
||||||
]).decode('utf-8')
|
]).decode('utf-8')
|
||||||
self.driver.get(f'http://{control_ip}:{dashboard_port}/')
|
self.driver.get(f'https://{control_ip}:{dashboard_port}/')
|
||||||
# Login to horizon!
|
# Login to horizon!
|
||||||
self.driver.find_element(By.ID, "id_username").click()
|
self.driver.find_element(By.ID, "id_username").click()
|
||||||
self.driver.find_element(By.ID, "id_username").send_keys("admin")
|
self.driver.find_element(By.ID, "id_username").send_keys("admin")
|
||||||
|
@ -27,16 +27,26 @@ VALIDITY_PERIOD = relativedelta(minutes=20)
|
|||||||
def _create_credential():
|
def _create_credential():
|
||||||
project_name = 'service'
|
project_name = 'service'
|
||||||
domain_name = 'default'
|
domain_name = 'default'
|
||||||
# TODO: add support for TLS-terminated Keystone once this is supported.
|
|
||||||
auth = v3.password.Password(
|
auth = v3.password.Password(
|
||||||
auth_url="http://localhost:5000/v3",
|
auth_url="https://localhost:5000/v3",
|
||||||
username='nova',
|
username='nova',
|
||||||
password=config_get('config.credentials.nova-password'),
|
password=config_get('config.credentials.nova-password'),
|
||||||
user_domain_name=domain_name,
|
user_domain_name=domain_name,
|
||||||
project_domain_name=domain_name,
|
project_domain_name=domain_name,
|
||||||
project_name=project_name
|
project_name=project_name
|
||||||
)
|
)
|
||||||
sess = session.Session(auth=auth)
|
if config_get('config.tls.generate-self-signed'):
|
||||||
|
# TODO(coreycb): Can we verify cert if self-signed certs
|
||||||
|
# include a ca-cert and cert?
|
||||||
|
sess = session.Session(
|
||||||
|
auth=auth,
|
||||||
|
verify=False,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
sess = session.Session(
|
||||||
|
auth=auth,
|
||||||
|
verify=config_get('config.tls.cacert-path'),
|
||||||
|
)
|
||||||
keystone_client = client.Client(session=sess)
|
keystone_client = client.Client(session=sess)
|
||||||
|
|
||||||
# Only allow this credential to list the Keystone catalog. After it
|
# Only allow this credential to list the Keystone catalog. After it
|
||||||
|
@ -98,6 +98,19 @@ def join():
|
|||||||
control_ip = response_dict['config']['network']['control-ip']
|
control_ip = response_dict['config']['network']['control-ip']
|
||||||
shell.config_set(**{'config.network.control-ip': control_ip})
|
shell.config_set(**{'config.network.control-ip': control_ip})
|
||||||
|
|
||||||
|
# Write controller's TLS certificate data to compute node
|
||||||
|
tls_path_map = {
|
||||||
|
'cacert-path': 'tls_cacert',
|
||||||
|
'cert-path': 'tls_cert',
|
||||||
|
'key-path': 'tls_key',
|
||||||
|
}
|
||||||
|
for tls_config, tls_file in tls_path_map.items():
|
||||||
|
tls_path = response_dict['config']['tls'][tls_config]
|
||||||
|
shell.config_set(**{'config.tls.{}'.format(tls_config): tls_path})
|
||||||
|
with open(tls_path, "w") as f:
|
||||||
|
f.write(response_dict[tls_file])
|
||||||
|
shell.config_set(**{'config.tls.generate-self-signed': False})
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
join()
|
join()
|
||||||
|
@ -10,6 +10,7 @@ from werkzeug.exceptions import BadRequest
|
|||||||
|
|
||||||
|
|
||||||
from cluster.shell import check_output
|
from cluster.shell import check_output
|
||||||
|
from cluster.shell import config_get
|
||||||
|
|
||||||
from keystoneauth1.identity import v3
|
from keystoneauth1.identity import v3
|
||||||
from keystoneauth1 import session
|
from keystoneauth1 import session
|
||||||
@ -153,8 +154,20 @@ def handle_unexpected_error(error):
|
|||||||
def join_info():
|
def join_info():
|
||||||
"""Generate the configuration information to return to a client."""
|
"""Generate the configuration information to return to a client."""
|
||||||
# TODO: be selective about what we return. For now, we just get everything.
|
# TODO: be selective about what we return. For now, we just get everything.
|
||||||
|
info = {}
|
||||||
config = json.loads(check_output('snapctl', 'get', 'config'))
|
config = json.loads(check_output('snapctl', 'get', 'config'))
|
||||||
info = {'config': config}
|
info['config'] = config
|
||||||
|
|
||||||
|
# Add the controller's TLS certificate data
|
||||||
|
tls_path_map = {
|
||||||
|
'cacert-path': 'tls_cacert',
|
||||||
|
'cert-path': 'tls_cert',
|
||||||
|
'key-path': 'tls_key',
|
||||||
|
}
|
||||||
|
for tls_config, tls_file in tls_path_map.items():
|
||||||
|
with open(config_get('config.tls.{}'.format(tls_config)), "r") as f:
|
||||||
|
info[tls_file] = f.read()
|
||||||
|
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
@ -210,8 +223,7 @@ def join():
|
|||||||
' authentication data in the request.')
|
' authentication data in the request.')
|
||||||
return MissingAuthDataInRequest()
|
return MissingAuthDataInRequest()
|
||||||
|
|
||||||
# TODO: handle https here when TLS termination support is added.
|
keystone_base_url = 'https://localhost:5000/v3'
|
||||||
keystone_base_url = 'http://localhost:5000/v3'
|
|
||||||
|
|
||||||
# In an unlikely event of failing to construct an auth object
|
# In an unlikely event of failing to construct an auth object
|
||||||
# treat it as if invalid data got passed in terms of responding
|
# treat it as if invalid data got passed in terms of responding
|
||||||
@ -231,7 +243,18 @@ def join():
|
|||||||
try:
|
try:
|
||||||
# Use the auth object with the app credential to create a session
|
# Use the auth object with the app credential to create a session
|
||||||
# which the Keystone client will use.
|
# which the Keystone client will use.
|
||||||
sess = session.Session(auth=auth)
|
if config_get('config.tls.generate-self-signed'):
|
||||||
|
# TODO(coreycb): Can we verify cert if self-signed certs
|
||||||
|
# include a ca-cert and cert?
|
||||||
|
sess = session.Session(
|
||||||
|
auth=auth,
|
||||||
|
verify=False,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
sess = session.Session(
|
||||||
|
auth=auth,
|
||||||
|
verify=config_get('config.tls.cacert-path'),
|
||||||
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception('An exception has occurred while trying to build'
|
logger.exception('An exception has occurred while trying to build'
|
||||||
' a Session object with auth data'
|
' a Session object with auth data'
|
||||||
|
@ -182,6 +182,7 @@ def init() -> None:
|
|||||||
# The following are not yet implemented:
|
# The following are not yet implemented:
|
||||||
# questions.VmSwappiness(),
|
# questions.VmSwappiness(),
|
||||||
# questions.FileHandleLimits(),
|
# questions.FileHandleLimits(),
|
||||||
|
questions.TlsCertificates(),
|
||||||
questions.DashboardAccess(),
|
questions.DashboardAccess(),
|
||||||
questions.RabbitMq(),
|
questions.RabbitMq(),
|
||||||
questions.DatabaseSetup(),
|
questions.DatabaseSetup(),
|
||||||
|
@ -26,14 +26,16 @@ limitations under the License.
|
|||||||
import json
|
import json
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from os import path
|
from os import path
|
||||||
|
from pathlib import Path
|
||||||
|
from shutil import copyfile
|
||||||
|
|
||||||
from init import shell
|
from init import shell
|
||||||
from init.shell import (check, call, check_output, sql, nc_wait, log_wait,
|
from init.shell import (check, call, check_output, sql, nc_wait, log_wait,
|
||||||
restart, download, disable, enable)
|
restart, download, disable, enable)
|
||||||
from init.config import Env, log
|
from init.config import Env, log
|
||||||
from init import cluster_tls
|
from init import tls
|
||||||
from init.questions.question import Question
|
from init.questions.question import Question
|
||||||
from init.questions import clustering, network, uninstall # noqa F401
|
from init.questions import clustering, network, tls, uninstall # noqa F401
|
||||||
|
|
||||||
|
|
||||||
_env = Env().get_env()
|
_env = Env().get_env()
|
||||||
@ -102,7 +104,13 @@ class Clustering(Question):
|
|||||||
'config.services.hypervisor': 'true',
|
'config.services.hypervisor': 'true',
|
||||||
})
|
})
|
||||||
# Generate a self-signed certificate for the clustering service.
|
# 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_self_signed(
|
||||||
|
cert_path, key_path,
|
||||||
|
fingerprint_config='config.cluster.fingerprint')
|
||||||
|
|
||||||
# Write templates
|
# Write templates
|
||||||
check('snap-openstack', 'setup')
|
check('snap-openstack', 'setup')
|
||||||
@ -288,6 +296,37 @@ class DashboardAccess(ConfigQuestion):
|
|||||||
hosts=answer))
|
hosts=answer))
|
||||||
|
|
||||||
|
|
||||||
|
class TlsCertificates(Question):
|
||||||
|
|
||||||
|
_type = 'boolean'
|
||||||
|
_question = 'Do you wish to generate a self-signed certificate for TLS?'
|
||||||
|
config_key = 'config.tls.generate-self-signed'
|
||||||
|
|
||||||
|
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_self_signed(cert_path, key_path,
|
||||||
|
ip=_env['control_ip'])
|
||||||
|
copyfile(Path(shell.config_get('config.tls.cert-path')),
|
||||||
|
Path(shell.config_get('config.tls.cacert-path')))
|
||||||
|
restart('nginx')
|
||||||
|
|
||||||
|
elif role == 'compute':
|
||||||
|
log.warning('TLS certificate generation can only be performed on '
|
||||||
|
'control node')
|
||||||
|
|
||||||
|
def no(self, answer: str):
|
||||||
|
log.info('TLS certificates must be provided: config.tls.cacert-path, '
|
||||||
|
'config.tls.cert-path, and config.tls.key-path.')
|
||||||
|
restart('nginx')
|
||||||
|
|
||||||
|
|
||||||
class RabbitMq(Question):
|
class RabbitMq(Question):
|
||||||
"""Wait for Rabbit to start, then setup permissions."""
|
"""Wait for Rabbit to start, then setup permissions."""
|
||||||
|
|
||||||
@ -362,7 +401,7 @@ class DatabaseSetup(Question):
|
|||||||
if call('openstack', 'user', 'show', 'admin'):
|
if call('openstack', 'user', 'show', 'admin'):
|
||||||
return
|
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',
|
check('snap-openstack', 'launch', 'keystone-manage', 'bootstrap',
|
||||||
'--bootstrap-password', _env['keystone_password'],
|
'--bootstrap-password', _env['keystone_password'],
|
||||||
@ -401,7 +440,7 @@ class DatabaseSetup(Question):
|
|||||||
log.info('Creating service project ...')
|
log.info('Creating service project ...')
|
||||||
if not call('openstack', 'project', 'show', 'service'):
|
if not call('openstack', 'project', 'show', 'service'):
|
||||||
check('openstack', 'project', 'create', '--domain',
|
check('openstack', 'project', 'create', '--domain',
|
||||||
'default', '--description', 'Service Project',
|
'default', '--description', '"Service Project"',
|
||||||
'service')
|
'service')
|
||||||
|
|
||||||
log.info('Keystone configured!')
|
log.info('Keystone configured!')
|
||||||
@ -536,7 +575,7 @@ class PlacementSetup(Question):
|
|||||||
for endpoint in ['public', 'internal', 'admin']:
|
for endpoint in ['public', 'internal', 'admin']:
|
||||||
call('openstack', 'endpoint', 'create', '--region',
|
call('openstack', 'endpoint', 'create', '--region',
|
||||||
'microstack', 'placement', endpoint,
|
'microstack', 'placement', endpoint,
|
||||||
'http://{control_ip}:8778'.format(**_env))
|
'https://{control_ip}:8778'.format(**_env))
|
||||||
|
|
||||||
log.info('Running Placement DB migrations...')
|
log.info('Running Placement DB migrations...')
|
||||||
check('snap-openstack', 'launch', 'placement-manage', 'db', 'sync')
|
check('snap-openstack', 'launch', 'placement-manage', 'db', 'sync')
|
||||||
@ -612,6 +651,7 @@ class NovaControlPlane(Question):
|
|||||||
|
|
||||||
enable('nova-api')
|
enable('nova-api')
|
||||||
restart('nova-compute')
|
restart('nova-compute')
|
||||||
|
restart('nginx')
|
||||||
|
|
||||||
for service in [
|
for service in [
|
||||||
'nova-api-metadata',
|
'nova-api-metadata',
|
||||||
@ -630,7 +670,7 @@ class NovaControlPlane(Question):
|
|||||||
for endpoint in ['public', 'internal', 'admin']:
|
for endpoint in ['public', 'internal', 'admin']:
|
||||||
call('openstack', 'endpoint', 'create', '--region',
|
call('openstack', 'endpoint', 'create', '--region',
|
||||||
'microstack', 'compute', endpoint,
|
'microstack', 'compute', endpoint,
|
||||||
'http://{control_ip}:8774/v2.1'.format(**_env))
|
'https://{control_ip}:8774/v2.1'.format(**_env))
|
||||||
|
|
||||||
log.info('Creating default flavors...')
|
log.info('Creating default flavors...')
|
||||||
|
|
||||||
@ -682,7 +722,7 @@ class CinderSetup(Question):
|
|||||||
check(
|
check(
|
||||||
'openstack', 'endpoint', 'create', '--region',
|
'openstack', 'endpoint', 'create', '--region',
|
||||||
'microstack', f'volume{api_version}', endpoint,
|
'microstack', f'volume{api_version}', endpoint,
|
||||||
f'http://{control_ip}:8776/{api_version}/'
|
f'https://{control_ip}:8776/{api_version}/'
|
||||||
'$(project_id)s'
|
'$(project_id)s'
|
||||||
)
|
)
|
||||||
log.info('Running Cinder DB migrations...')
|
log.info('Running Cinder DB migrations...')
|
||||||
@ -754,12 +794,13 @@ class NeutronControlPlane(Question):
|
|||||||
for endpoint in ['public', 'internal', 'admin']:
|
for endpoint in ['public', 'internal', 'admin']:
|
||||||
call('openstack', 'endpoint', 'create', '--region',
|
call('openstack', 'endpoint', 'create', '--region',
|
||||||
'microstack', 'network', endpoint,
|
'microstack', 'network', endpoint,
|
||||||
'http://{control_ip}:9696'.format(**_env))
|
'https://{control_ip}:9696'.format(**_env))
|
||||||
|
|
||||||
check('snap-openstack', 'launch', 'neutron-db-manage', 'upgrade',
|
check('snap-openstack', 'launch', 'neutron-db-manage', 'upgrade',
|
||||||
'head')
|
'head')
|
||||||
enable('neutron-api')
|
enable('neutron-api')
|
||||||
enable('neutron-ovn-metadata-agent')
|
enable('neutron-ovn-metadata-agent')
|
||||||
|
restart('nginx')
|
||||||
|
|
||||||
nc_wait(_env['control_ip'], '9696')
|
nc_wait(_env['control_ip'], '9696')
|
||||||
|
|
||||||
@ -864,10 +905,11 @@ class GlanceSetup(Question):
|
|||||||
for endpoint in ['internal', 'admin', 'public']:
|
for endpoint in ['internal', 'admin', 'public']:
|
||||||
check('openstack', 'endpoint', 'create', '--region',
|
check('openstack', 'endpoint', 'create', '--region',
|
||||||
'microstack', 'image', endpoint,
|
'microstack', 'image', endpoint,
|
||||||
'http://{compute_ip}:9292'.format(**_env))
|
'https://{compute_ip}:9292'.format(**_env))
|
||||||
|
|
||||||
check('snap-openstack', 'launch', 'glance-manage', 'db_sync')
|
check('snap-openstack', 'launch', 'glance-manage', 'db_sync')
|
||||||
enable('glance-api')
|
enable('glance-api')
|
||||||
|
restart('nginx')
|
||||||
|
|
||||||
nc_wait(_env['compute_ip'], '9292')
|
nc_wait(_env['compute_ip'], '9292')
|
||||||
|
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
|
from init.shell import check
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
|
import ipaddress
|
||||||
|
import socket
|
||||||
|
|
||||||
from cryptography.hazmat.primitives import hashes
|
from cryptography.hazmat.primitives import hashes
|
||||||
from cryptography.hazmat.backends import default_backend
|
from cryptography.hazmat.backends import default_backend
|
||||||
@ -15,7 +18,8 @@ from cryptography.x509.oid import NameOID
|
|||||||
from init import shell
|
from init import shell
|
||||||
|
|
||||||
|
|
||||||
def generate_selfsigned():
|
def generate_self_signed(cert_path, key_path, ip=None,
|
||||||
|
fingerprint_config=None):
|
||||||
"""Generate a self-signed certificate with associated keys.
|
"""Generate a self-signed certificate with associated keys.
|
||||||
|
|
||||||
The certificate will have a fake CNAME and subjAltName since
|
The certificate will have a fake CNAME and subjAltName since
|
||||||
@ -28,26 +32,29 @@ def generate_selfsigned():
|
|||||||
via a secure channel.
|
via a secure channel.
|
||||||
https://owasp.org/www-community/controls/Certificate_and_Public_Key_Pinning
|
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
|
# Do not generate a new certificate and key if there is already an existing
|
||||||
# pair. TODO: improve this check and allow renewal.
|
# pair. TODO: improve this check and allow renewal.
|
||||||
if cert_path.exists() and key_path.exists():
|
if cert_path.exists() and key_path.exists():
|
||||||
return
|
return
|
||||||
|
|
||||||
dummy_cn = 'microstack.run'
|
|
||||||
key = rsa.generate_private_key(
|
key = rsa.generate_private_key(
|
||||||
public_exponent=65537,
|
public_exponent=65537,
|
||||||
key_size=2048,
|
key_size=2048,
|
||||||
backend=default_backend(),
|
backend=default_backend(),
|
||||||
)
|
)
|
||||||
|
cn = socket.gethostname()
|
||||||
common_name = x509.Name([
|
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)
|
basic_contraints = x509.BasicConstraints(ca=True, path_length=0)
|
||||||
|
|
||||||
now = datetime.utcnow()
|
now = datetime.utcnow()
|
||||||
cert = (
|
cert = (
|
||||||
x509.CertificateBuilder()
|
x509.CertificateBuilder()
|
||||||
@ -63,7 +70,8 @@ def generate_selfsigned():
|
|||||||
)
|
)
|
||||||
|
|
||||||
cert_fprint = cert.fingerprint(hashes.SHA256()).hex()
|
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_cert = cert.public_bytes(encoding=serialization.Encoding.PEM)
|
||||||
serialized_key = key.private_bytes(
|
serialized_key = key.private_bytes(
|
||||||
@ -73,3 +81,5 @@ def generate_selfsigned():
|
|||||||
)
|
)
|
||||||
cert_path.write_bytes(serialized_cert)
|
cert_path.write_bytes(serialized_cert)
|
||||||
key_path.write_bytes(serialized_key)
|
key_path.write_bytes(serialized_key)
|
||||||
|
check('chmod', '644', str(cert_path))
|
||||||
|
check('chmod', '600', str(key_path))
|
@ -207,7 +207,7 @@ Access it with `ssh -i {key_path} {username}@{ip}`\
|
|||||||
gate = check_output('snapctl', 'get', 'config.network.ext-gateway')
|
gate = check_output('snapctl', 'get', 'config.network.ext-gateway')
|
||||||
port = check_output('snapctl', 'get', 'config.network.ports.dashboard')
|
port = check_output('snapctl', 'get', 'config.network.ports.dashboard')
|
||||||
|
|
||||||
print('You can also visit the OpenStack dashboard at http://{}:{}'.format(
|
print('You can also visit the OpenStack dashboard at https://{}:{}'.format(
|
||||||
gate, port))
|
gate, port))
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user