From 3a497cd0d3ebd8db3c7446805a15d73c1b239bb0 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Thu, 4 Apr 2024 12:49:28 +0200 Subject: [PATCH 01/51] Add first part of the secure connections standard Signed-off-by: Markus Hentsch --- Standards/scs-0114-v1-secure-connections.md | 81 +++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 Standards/scs-0114-v1-secure-connections.md diff --git a/Standards/scs-0114-v1-secure-connections.md b/Standards/scs-0114-v1-secure-connections.md new file mode 100644 index 000000000..3bda6178b --- /dev/null +++ b/Standards/scs-0114-v1-secure-connections.md @@ -0,0 +1,81 @@ +--- +title: Secure Connections +type: Standard # | Decision Record | Procedural +status: Draft +track: IaaS # | IaaS | Ops | KaaS | IAM +--- + + + +## Introduction + +A lot of internal and external connectivity is established to and within a cloud infrastructure. +Due to the nature of the IaaS approach, many communication channels may occasionally or even primarily carry potentially sensitive data of customers. +To protect this data from both tampering and unintended disclosure, communication channels need to be properly secured. + +For this reason, [SCS](https://scs.community) standardizes the use of common protection mechanisms for communication channels in OpenStack infrastructures. + +## Motivation + +As mentioned above, a lot of communication channels in an OpenStack infrastructure carry data that is potentially sensitive. +For example this includes authentication data of customers and internal OpenStack configuration data such as encryption keys among others. +OpenStack does not generically mandate or preconfigure the use of specific protection mechanisms by itself and instead only makes recommendations about best practices in its offical [Security Guide](https://docs.openstack.org/security-guide/). + +To address the potential lack of implementation of such mechanisms by a CSP and to establish a reliable foundation for communication data protection in SCS clouds, SCS formulates this standard for securing communication channels in the infrastructure, so that a customer can rely on adequate security mechanisms being in use. + +## Design Considerations + +There are many communication channels in OpenStack with different characteristics, location and eligible means of protection. +Not all channels are equally easy to secure and some protection mechanisms might put unbearable burdens on a CSP. +Hence, careful assessment is required to determine for which SCS will either mandate or recommend the use of a protection mechanism. + +For this distinction to be made, communication channels must be categorized and classified accordingly. + +### Communication Channels + +The following overview will classify the main communication channels. + +| # | Classification | Details | Example solution | +|---|---|---|---| +| 1 | Database backend traffic | Replication and sync between database instances | SSL/TLS | +| 2 | Database frontend traffic | Communication between OpenStack services and databases | SSL/TLS | +| 3 | Message queue traffic | Message queue communication between OpenStack components as provided by oslo.messaging | SSL/TLS | +| 4 | Internal API communication | HTTP traffic to services registered as internal endpoints in the Keystone service catalog | SSL/TLS | +| 5 | External API communication | HTTP traffic to services registered as external endpoints in the Keystone service catalog | SSL/TLS | +| 6 | Nova VM migration traffic | Nova VM migration data transfer traffic between compute nodes | QEMU-native TLS | +| 7 | Neutron network traffic | Traffic within Neutron SDN networks exchanged between internal systems as well as the outside | IPsec | + +### Options considered + +#### _Option 1_ + +Option 1 description + +#### _Option 2_ + +Option 2 description + +## Open questions + +RECOMMENDED + +## Decision + +Decision + +## Related Documents + +- [OpenStack Security Guide](https://docs.openstack.org/security-guide/) + - [OpenStack Security Guide: Secure communication](https://docs.openstack.org/security-guide/secure-communication.html) + - [OpenStack Security Guide: Database transport security](https://docs.openstack.org/security-guide/databases/database-transport-security.html) + - [OpenStack Security Guide: Messaging transport security](https://docs.openstack.org/security-guide/messaging/security.html#messaging-transport-security) +- [Nova Documentation: Secure live migration with QEMU-native TLS](https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html) + +## Conformance Tests + +Conformance Tests, OPTIONAL From 0821bd69cc82fe0709435aec8b1f9ade91115fce Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Thu, 4 Apr 2024 15:03:41 +0200 Subject: [PATCH 02/51] Add notes about the classifications Signed-off-by: Markus Hentsch --- Standards/scs-0114-v1-secure-connections.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/Standards/scs-0114-v1-secure-connections.md b/Standards/scs-0114-v1-secure-connections.md index 3bda6178b..82a885446 100644 --- a/Standards/scs-0114-v1-secure-connections.md +++ b/Standards/scs-0114-v1-secure-connections.md @@ -45,10 +45,23 @@ The following overview will classify the main communication channels. | 1 | Database backend traffic | Replication and sync between database instances | SSL/TLS | | 2 | Database frontend traffic | Communication between OpenStack services and databases | SSL/TLS | | 3 | Message queue traffic | Message queue communication between OpenStack components as provided by oslo.messaging | SSL/TLS | -| 4 | Internal API communication | HTTP traffic to services registered as internal endpoints in the Keystone service catalog | SSL/TLS | -| 5 | External API communication | HTTP traffic to services registered as external endpoints in the Keystone service catalog | SSL/TLS | +| 4 | External API communication | HTTP traffic to services registered as external endpoints in the Keystone service catalog | SSL/TLS | +| 5 | Internal API communication | HTTP traffic to services registered as internal endpoints in the Keystone service catalog | SSL/TLS | | 6 | Nova VM migration traffic | Nova VM migration data transfer traffic between compute nodes | QEMU-native TLS | -| 7 | Neutron network traffic | Traffic within Neutron SDN networks exchanged between internal systems as well as the outside | IPsec | +| 7 | External Neutron network traffic | VM-related traffic between the network/controller nodes and external networks (e.g. internet) established through routed provider networks and floating IPs | VPN | +| 8 | Internal Neutron network traffic | Traffic within Neutron SDN networks exchanged between internal systems such as network/controller and compute nodes | IPsec | + + +Notes about the classification categories and implications: + +1. Most database clustering solutions (e.g. MariaDB Galera) offer TLS-based encryption of their backend channels. This needs no additional configuration in OpenStack and is a configuration solely concerning the database cluster. +2. The database frontend interface is the primary connection target for the OpenStack services. OpenStack supports using TLS for database connections. +3. For the message queue, AMQP-based solutions such as RabbitMQ and QPid do offer TLS natively which is also supported by OpenStack. ZeroMQ does not and requires IPsec or CIPSO instead. +4. External API endpoints can be protected easily by using a TLS proxy. They can then be registered with their HTTPS endpoint in the Keystone service catalog. The certificates of external APIs usually need to be signed by a well-known CA in order to be accepted by arbitrary external clients. +5. Internal API endpoints can use the same TLS proxy mechanisms as the internal ones. Optionally, the TLS certificate provider and PKI can differ to the internal ones. It is often sufficient for the CA of internal TLS endpoints to be accepted within the infrastructure and doesn't need to be a common public CA. +6. For protecting the data transferred between compute nodes during live-migration of VMs, [Nova offers support for QEMU-native TLS](https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html). As an alternative, SSH is also a channel that Nova can be configured to use between hosts for this but requires passwordless SSH keys with root access to all other compute nodes which in turn requires further hardening. +7. Neutron's external network traffic leaves the IaaS infrastructure. This part is twofold: connections initiated by the VMs themselves (egress) and connections reaching VMs from the outside (ingress). The CSP cannot influence the egress connections but can offer VPNaaS for the ingress direction. +8. Neutron's internal network traffic one of the hardest aspects to address. Due to the highly dynamic nature of SDN, connection endpoints and relations are constantly changing. There is no holistic approach currently offered or recommended by OpenStack itself. IPsec could be established between all involved nodes but requires sophisticated and reliable key management. A per-tenant/per-customer encryption is very hard to establish this way. ### Options considered From 291b3da30d9a071fc9d5419958a5130c70e3bef9 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Thu, 4 Apr 2024 16:57:05 +0200 Subject: [PATCH 03/51] Add considered options and open questions Signed-off-by: Markus Hentsch --- Standards/scs-0114-v1-secure-connections.md | 40 +++++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/Standards/scs-0114-v1-secure-connections.md b/Standards/scs-0114-v1-secure-connections.md index 82a885446..4396d9d26 100644 --- a/Standards/scs-0114-v1-secure-connections.md +++ b/Standards/scs-0114-v1-secure-connections.md @@ -65,21 +65,45 @@ Notes about the classification categories and implications: ### Options considered -#### _Option 1_ +#### Option 1: fully mandate securing all channels without differentiation -Option 1 description +This option would reach the highest security standard and establish protection on all identified communication channels simultaneously. +However, this would burden CSPs greatly due to the difficulty of addressing some of the channels and properly maintaining the solution. +Also there is a risk of making this incompatible with existing infrastructures due to some of their specifics being mutually exclusive to the more intricate protection mechanisms such as cross-node IPsec configurations. +As a third aspect, not all mechanisms might fulfill the CSPs requirements regarding performance and stability and SCS cannot in good faith force CSPs to use technologies not suited to their infrastructures. -#### _Option 2_ +This seems like a bad option from many perspectives. +It also allows very little flexibility and might even make SCS conformance unappealing to CSPs due to the immense effort required to reach it. -Option 2 description +#### Option 2: only make recommendations + +This option would limit SCS to only recommend mechanisms in this standard like presented in the OpenStack Security Guide. +Although this can increase awareness about the best practices recommended by OpenStack and maybe encourage CSPs to abide by them, it would actually contribute very little to the security baseline of SCS infrastructures as a whole since everything would stay optional. + +This option would be very easy to standardize and get consensus on due to its lightweight and optional nature. +However, the actual added value for SCS is questionable at best. + +#### Option 3: mix recommendations and obligations + +This option forms a middle ground between options 1 and 2. +For this, the standard needs to carefully assess each communication channel, mechanisms for protecting it and the effort required to do so as well as the implications. +Then, only for mechanisms that are known to be reliable, are feasible to implement and for which the benefits clearly outweigh the integration effort required, should this standard enforce their implementation in a permissive way. +For any remaining mechanisms SCS should only make recommendations and refer to known best practices where applicable. + +This option would still offer improvements over arbitrary OpenStack clouds by establishing a baseline that goes beyond mere recommendations while still taking into account that not all communication channels are equally easy to secure and allowing necessary flexibility for the CSP. ## Open questions -RECOMMENDED +### Verifying standard conformance for internal mechanisms + +Most of the mentioned communication channels to be secured are part of the internal IaaS infrastructure of an SCS cloud. +When an internal protection mechanism is implemented by the CSP it cannot be verified from outside of the infrastructure without administrative access to the infrastructure. + +Thus, the SCS community is unable to fully assess a CSPs conformance to this standard without a dedicated audit of the infrastructure. ## Decision -Decision + ## Related Documents @@ -91,4 +115,6 @@ Decision ## Conformance Tests -Conformance Tests, OPTIONAL +Conformance tests are limited to communication channels exposed to users, such as the public API interfaces. + + From 2810fbf962758c86933db4d9fe33bb9c04809cce Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Thu, 4 Apr 2024 17:04:43 +0200 Subject: [PATCH 04/51] Fix linter problems Signed-off-by: Markus Hentsch --- Standards/scs-0114-v1-secure-connections.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Standards/scs-0114-v1-secure-connections.md b/Standards/scs-0114-v1-secure-connections.md index 4396d9d26..ffd48eec2 100644 --- a/Standards/scs-0114-v1-secure-connections.md +++ b/Standards/scs-0114-v1-secure-connections.md @@ -18,7 +18,7 @@ A lot of internal and external connectivity is established to and within a cloud Due to the nature of the IaaS approach, many communication channels may occasionally or even primarily carry potentially sensitive data of customers. To protect this data from both tampering and unintended disclosure, communication channels need to be properly secured. -For this reason, [SCS](https://scs.community) standardizes the use of common protection mechanisms for communication channels in OpenStack infrastructures. +For this reason, [SCS](https://scs.community) standardizes the use of common protection mechanisms for communication channels in OpenStack infrastructures. ## Motivation @@ -51,7 +51,6 @@ The following overview will classify the main communication channels. | 7 | External Neutron network traffic | VM-related traffic between the network/controller nodes and external networks (e.g. internet) established through routed provider networks and floating IPs | VPN | | 8 | Internal Neutron network traffic | Traffic within Neutron SDN networks exchanged between internal systems such as network/controller and compute nodes | IPsec | - Notes about the classification categories and implications: 1. Most database clustering solutions (e.g. MariaDB Galera) offer TLS-based encryption of their backend channels. This needs no additional configuration in OpenStack and is a configuration solely concerning the database cluster. @@ -108,9 +107,9 @@ Thus, the SCS community is unable to fully assess a CSPs conformance to this sta ## Related Documents - [OpenStack Security Guide](https://docs.openstack.org/security-guide/) - - [OpenStack Security Guide: Secure communication](https://docs.openstack.org/security-guide/secure-communication.html) - - [OpenStack Security Guide: Database transport security](https://docs.openstack.org/security-guide/databases/database-transport-security.html) - - [OpenStack Security Guide: Messaging transport security](https://docs.openstack.org/security-guide/messaging/security.html#messaging-transport-security) + - [OpenStack Security Guide: Secure communication](https://docs.openstack.org/security-guide/secure-communication.html) + - [OpenStack Security Guide: Database transport security](https://docs.openstack.org/security-guide/databases/database-transport-security.html) + - [OpenStack Security Guide: Messaging transport security](https://docs.openstack.org/security-guide/messaging/security.html#messaging-transport-security) - [Nova Documentation: Secure live migration with QEMU-native TLS](https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html) ## Conformance Tests From efce5f89f535029d38f79426dbca25767ce408a0 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Thu, 4 Apr 2024 18:38:19 +0200 Subject: [PATCH 05/51] Add TLS standardization Signed-off-by: Markus Hentsch --- Standards/scs-0114-v1-secure-connections.md | 39 ++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/Standards/scs-0114-v1-secure-connections.md b/Standards/scs-0114-v1-secure-connections.md index ffd48eec2..b0aa91322 100644 --- a/Standards/scs-0114-v1-secure-connections.md +++ b/Standards/scs-0114-v1-secure-connections.md @@ -102,7 +102,43 @@ Thus, the SCS community is unable to fully assess a CSPs conformance to this sta ## Decision - +### Transport Layer Security (TLS) + +All server-side TLS configurations integrated into the infrastructure as covered by this standard MUST adhere to the folllowing rules: + +- The following deprecated TLS versions MUST NOT be used: + - v1.0 + - v1.1 +- The following cipher suites MUST NOT be used: + - any RC4 cipher + - any DES cipher + - any cipher with less than 128-bit encryption + - any cipher in CBC mode +- Cipher suites with Perfect Forward Secrecy (using ephemeral keys with the 'E' suffix, e.g. DHE, ECDHE) SHOULD be used instead of their static key counterpart (e.g. DH, ECDH) + +### API Interfaces + + + +### Database Connections + + + +### Message Queue Connections + + + +### Live Migration Connections + + + +### External VM Connections + + + +### Internal Neutron Connections + + ## Related Documents @@ -111,6 +147,7 @@ Thus, the SCS community is unable to fully assess a CSPs conformance to this sta - [OpenStack Security Guide: Database transport security](https://docs.openstack.org/security-guide/databases/database-transport-security.html) - [OpenStack Security Guide: Messaging transport security](https://docs.openstack.org/security-guide/messaging/security.html#messaging-transport-security) - [Nova Documentation: Secure live migration with QEMU-native TLS](https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html) +- [Guide to TLS Standards Compliance](https://www.ssl.com/guide/tls-standards-compliance/) ## Conformance Tests From 82bbe94ddb28fe637d3e94742fd34d450e8ee589 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Fri, 5 Apr 2024 11:16:43 +0200 Subject: [PATCH 06/51] Add database and message queue channel security, extend TLS cipher rules Signed-off-by: Markus Hentsch --- Standards/scs-0114-v1-secure-connections.md | 28 +++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/Standards/scs-0114-v1-secure-connections.md b/Standards/scs-0114-v1-secure-connections.md index b0aa91322..11311fbed 100644 --- a/Standards/scs-0114-v1-secure-connections.md +++ b/Standards/scs-0114-v1-secure-connections.md @@ -102,6 +102,9 @@ Thus, the SCS community is unable to fully assess a CSPs conformance to this sta ## Decision +This standard will mandate or recommend appropriate measures for securing the communication channels based on existing standards and recommendations. +It will reference documents like the [OpenStack Security Guide](https://docs.openstack.org/security-guide/) where applicable. + ### Transport Layer Security (TLS) All server-side TLS configurations integrated into the infrastructure as covered by this standard MUST adhere to the folllowing rules: @@ -110,23 +113,34 @@ All server-side TLS configurations integrated into the infrastructure as covered - v1.0 - v1.1 - The following cipher suites MUST NOT be used: - - any RC4 cipher - - any DES cipher - - any cipher with less than 128-bit encryption - - any cipher in CBC mode + - any RC4 cipher suite + - any DES cipher suite + - any cipher suite involving MD5 hash algorithms + - any cipher suite with less than 128-bit encryption + - any cipher suite in CBC mode - Cipher suites with Perfect Forward Secrecy (using ephemeral keys with the 'E' suffix, e.g. DHE, ECDHE) SHOULD be used instead of their static key counterpart (e.g. DH, ECDH) ### API Interfaces - +- Internal API endpoints of all OpenStack services MUST use TLS. Their endpoint as registered in the Keystone service catalog MUST be an HTTPS address. +- External API endpoints of all OpenStack services MUST use TLS. Their endpoint as registered in the Keystone service catalog MUST be an HTTPS address. + +You MAY refer to [TLS proxies and HTTP services](https://docs.openstack.org/security-guide/secure-communication/tls-proxies-and-http-services.html) and [Secure reference architectures](https://docs.openstack.org/security-guide/secure-communication/secure-reference-architectures.html) of the OpenStack Security Guide for best practices and recommendations. ### Database Connections - +- The database servers used by the OpenStack services MUST be configured for TLS transport. +- All OpenStack services MUST have TLS configured for the database connection via the `ssl_ca` directive. See [OpenStack service database configuration](https://docs.openstack.org/security-guide/databases/database-access-control.html#openstack-service-database-configuration). +- Database user accounts for the OpenStack services SHOULD be configured to require TLS connections via the `REQUIRE SSL` SQL directive. See [Require user accounts to require SSL transport](https://docs.openstack.org/security-guide/databases/database-access-control.html#require-user-accounts-to-require-ssl-transport). +- Security MAY be further enhanced by configuring the OpenStack services to use X.509 client certificates for database authentication. See [Authentication with X.509 certificates](https://docs.openstack.org/security-guide/databases/database-access-control.html#authentication-with-x-509-certificates). ### Message Queue Connections - +- If using RabbitMQ or Qpid as the message queue service, the SSL functionality of the message broker MUST be enabled and used by the OpenStack services. See [Messaging transport security](https://docs.openstack.org/security-guide/messaging/security.html#messaging-transport-security). + - If using RabbitMQ, the OpenStack services' oslo.messaging configuration for RabbitMQ MUST use the `kombu_ssl_*` options accordingly to enable SSL. + - If using Qpid, the OpenStack services' oslo.messaging configuration for Qpid MUST set the `qpid_protocol` option to `ssl` to enable SSL. +- If using Apache Kafka, the server listener MUST be configured to accept SSL connections. See [Apache Kafka Listener Configuration](https://kafka.apache.org/documentation/#listener_configuration). + - The OpenStack services' oslo.messaging configuration for Kafka MUST specify `security_protocol` as either `SSL` or `SASL_SSL` and the related options appropriately. See [Kafka Driver Options](https://docs.openstack.org/oslo.messaging/latest/admin/kafka.html#driver-options). ### Live Migration Connections From 297e56298e3e509f5ed0f35b93e19cfe54e6ebad Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Fri, 5 Apr 2024 13:47:56 +0200 Subject: [PATCH 07/51] Add remaining decision sections Signed-off-by: Markus Hentsch --- Standards/scs-0114-v1-secure-connections.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Standards/scs-0114-v1-secure-connections.md b/Standards/scs-0114-v1-secure-connections.md index 11311fbed..bcec550ec 100644 --- a/Standards/scs-0114-v1-secure-connections.md +++ b/Standards/scs-0114-v1-secure-connections.md @@ -142,17 +142,19 @@ You MAY refer to [TLS proxies and HTTP services](https://docs.openstack.org/secu - If using Apache Kafka, the server listener MUST be configured to accept SSL connections. See [Apache Kafka Listener Configuration](https://kafka.apache.org/documentation/#listener_configuration). - The OpenStack services' oslo.messaging configuration for Kafka MUST specify `security_protocol` as either `SSL` or `SASL_SSL` and the related options appropriately. See [Kafka Driver Options](https://docs.openstack.org/oslo.messaging/latest/admin/kafka.html#driver-options). -### Live Migration Connections +### Hypervisor and Live Migration Connections + +- If using libvirt on compute nodes, the libvirt port (as per `listen_addr`) MUST NOT be exposed to the network in an unauthenticated and unprotected fashion. It SHOULD be bound to `127.0.0.1`. +- If QEMU and libvirt are used as the hypervisor interface in Nova, QEMU-native TLS SHOULD be used. See [Secure live migration with QEMU-native TLS](https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html). - ### External VM Connections - +- As an OPTIONAL measure to assist customers in protecting external connections to their OpenStack networks and VMs, the Neutron VPNaaS service MAY be integrated into the infrastructure and the Neutron VPNaaS API extension offered to users. See the [Neutron VPNaaS documentation](https://docs.openstack.org/neutron-vpnaas/latest/). ### Internal Neutron Connections - +- As an OPTIONAL measure to protect Neutron SDN traffic between physical nodes within the infrastructure, IPsec tunnels MAY be established between nodes involved in Neutron networks, such as compute and network controller nodes, at the network interfaces configured in Neutron. ## Related Documents From 1f1afe3f18a1505ab61b7bb381cb250211f4a469 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Fri, 5 Apr 2024 17:28:56 +0200 Subject: [PATCH 08/51] Add testing script for secure connection standard (WIP) Signed-off-by: Markus Hentsch --- Tests/iaas/secure-connections/tls-checker.py | 89 ++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 Tests/iaas/secure-connections/tls-checker.py diff --git a/Tests/iaas/secure-connections/tls-checker.py b/Tests/iaas/secure-connections/tls-checker.py new file mode 100644 index 000000000..276b7afed --- /dev/null +++ b/Tests/iaas/secure-connections/tls-checker.py @@ -0,0 +1,89 @@ +import openstack + +import socket +import ssl + + +def connect(cloud_name: str) -> openstack.connection.Connection: + """Create a connection to an OpenStack cloud + + :param string cloud_name: + The name of the configuration to load from clouds.yaml. + + :returns: openstack.connnection.Connection + """ + + return openstack.connect( + cloud=cloud_name, + ) + + +def enumerate_endpoints(conn: openstack.connection.Connection) \ + -> dict[str, dict[str, str]]: + """Enumerate all endpoints of the service catalog returned by the + current connection categorized by interface type and service. + + Resulting structure: + { + : { + : + } + } + + where is public, internal or admin. + """ + + ret = {} + + for svc in conn.service_catalog: + svc_name = svc['name'] + for endpoint in svc.get('endpoints'): + enp_type = endpoint['interface'] + enp_url = endpoint['url'] + subdict = ret.setdefault(enp_type, {}) + subdict[svc_name] = enp_url + + return ret + + +conn = connect("devstack") +endpoints_catalog = enumerate_endpoints(conn) +assert "public" in endpoints_catalog, ( + "ERR: No public endpoints returned in the service catalog" +) +endpoints = endpoints_catalog["public"] + +for service in endpoints: + + url = endpoints[service] + assert url.startswith("https://"), ( + f"ERR: Public endpoint URL of '{service}' " + f"does not start with 'https://'" + ) + url = url.replace("https://", '') + url = url.replace("http://", '') # DELETEME, unreachable + if ':' in url: + host, appendix = url.split(':', 1) + port = int(appendix.split('/', 1)[0]) + else: + host, _ = url.split('/', 1) + port = 443 + print(host, port) + + context = ssl.create_default_context() + + try: + with socket.create_connection((host, port)) as sock: + with context.wrap_socket(sock, server_hostname=host) as ssl_socket: + ssl_version = ssl_socket.version() + assert ssl_version not in ["TLSv1.0", "TLSv1.1"], ( + "ERR: Service endpoint for '{service}' uses invalid TLS " + "version '{ssl_version}'" + ) + + # TODO: catch all possible SSL exceptions + except ssl.SSLEOFError as e: + raise Exception( + f"ERR: Service '{service}' violated SSL protocol, " + f"{str(e)}" + ) From b1c6f2bb2971e4b5d04abd8dedb257120dad529a Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Mon, 8 Apr 2024 16:44:38 +0200 Subject: [PATCH 09/51] Turn avoiding CBC mode into a recommendation. https://crypto.stackexchange.com/a/95660 Signed-off-by: Markus Hentsch --- Standards/scs-0114-v1-secure-connections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Standards/scs-0114-v1-secure-connections.md b/Standards/scs-0114-v1-secure-connections.md index bcec550ec..4e56ef29f 100644 --- a/Standards/scs-0114-v1-secure-connections.md +++ b/Standards/scs-0114-v1-secure-connections.md @@ -117,7 +117,7 @@ All server-side TLS configurations integrated into the infrastructure as covered - any DES cipher suite - any cipher suite involving MD5 hash algorithms - any cipher suite with less than 128-bit encryption - - any cipher suite in CBC mode +- Cipher suites utilizing CBC mode SHOULD NOT be used - Cipher suites with Perfect Forward Secrecy (using ephemeral keys with the 'E' suffix, e.g. DHE, ECDHE) SHOULD be used instead of their static key counterpart (e.g. DH, ECDH) ### API Interfaces From cb1242d889e7274a78b40b58ef17b40f465932c8 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Mon, 8 Apr 2024 16:51:30 +0200 Subject: [PATCH 10/51] Refactor the TLS test script to use SSLyze and implement all tests based on the current standard draft Signed-off-by: Markus Hentsch --- Standards/scs-0114-v1-secure-connections.md | 5 +- Tests/iaas/secure-connections/tls-checker.py | 276 ++++++++++++++++--- 2 files changed, 235 insertions(+), 46 deletions(-) diff --git a/Standards/scs-0114-v1-secure-connections.md b/Standards/scs-0114-v1-secure-connections.md index 4e56ef29f..e6b1e2175 100644 --- a/Standards/scs-0114-v1-secure-connections.md +++ b/Standards/scs-0114-v1-secure-connections.md @@ -169,4 +169,7 @@ You MAY refer to [TLS proxies and HTTP services](https://docs.openstack.org/secu Conformance tests are limited to communication channels exposed to users, such as the public API interfaces. - +There is a test suite in [`tls-checker.py`](https://github.com/SovereignCloudStack/standards/blob/main/Tests/iaas/secure-connections/tls-checker.py). +The test suite connects to the OpenStack API and retrieves all public API endpoints from the service catalog. +It then connects to each endpoint and verifies the compliance to the standard by checking SSL/TLS protocol versions and cipher suites offered by the server against the guidelines of this standard. + diff --git a/Tests/iaas/secure-connections/tls-checker.py b/Tests/iaas/secure-connections/tls-checker.py index 276b7afed..cd69c8b7b 100644 --- a/Tests/iaas/secure-connections/tls-checker.py +++ b/Tests/iaas/secure-connections/tls-checker.py @@ -1,24 +1,54 @@ -import openstack +"""SSL/TLS checker for OpenStack API endpoints + +This script retrieves the endpoint catalog from Keystone using the OpenStack +SDK and connects to each to each public endpoint to check its SSL/TLS settings. +The script relies on an OpenStack SDK compatible clouds.yaml file for +authentication with Keystone. + +For each endpoint, SSL/TLS protocol versions and ciphers supported by the +server are checked using the SSLyze Python library. +The script will fail with a non-zero exit code in case any standard violation +is discovered such as deprecated/insecure TLS versions or weak ciphers as +determined by the standard. -import socket -import ssl +For guidelines marked as OPTIONAL, SHOULD or SHOULD NOT in the standard, +appropriate warnings are printed in the log output for each endpoint. +""" + +import argparse +import getpass +import os +import typing + +import openstack +import sslyze -def connect(cloud_name: str) -> openstack.connection.Connection: +def connect(cloud_name: str, password: typing.Optional[str] = None + ) -> openstack.connection.Connection: """Create a connection to an OpenStack cloud :param string cloud_name: The name of the configuration to load from clouds.yaml. + :param string password: + Optional password override for the connection. + :returns: openstack.connnection.Connection """ - return openstack.connect( - cloud=cloud_name, - ) + if password: + return openstack.connect( + cloud=cloud_name, + password=password + ) + else: + return openstack.connect( + cloud=cloud_name, + ) -def enumerate_endpoints(conn: openstack.connection.Connection) \ +def retrieve_endpoints(conn: openstack.connection.Connection) \ -> dict[str, dict[str, str]]: """Enumerate all endpoints of the service catalog returned by the current connection categorized by interface type and service. @@ -43,47 +73,203 @@ def enumerate_endpoints(conn: openstack.connection.Connection) \ subdict = ret.setdefault(enp_type, {}) subdict[svc_name] = enp_url + print(f"\nINFO: the following public endpoints have been retrieved from " + f"the service catalog:") + for svc_name in ret["public"].keys(): + print( + f"↳ {svc_name} @ {ret['public'][svc_name]}" + ) + return ret -conn = connect("devstack") -endpoints_catalog = enumerate_endpoints(conn) -assert "public" in endpoints_catalog, ( - "ERR: No public endpoints returned in the service catalog" -) -endpoints = endpoints_catalog["public"] +def verify_tls(service: str, host: str, port: int) -> None: + """Use SSLyze library to scan the SSL/TLS interface of the server. -for service in endpoints: + Evaluates the SSL/TLS versions the server reports to support as well as + the cipher suites it accepts. + Checks the protocol versions and cipher suites against the rules + established by the standard to assure conformance. + """ - url = endpoints[service] - assert url.startswith("https://"), ( - f"ERR: Public endpoint URL of '{service}' " - f"does not start with 'https://'" - ) - url = url.replace("https://", '') - url = url.replace("http://", '') # DELETEME, unreachable - if ':' in url: - host, appendix = url.split(':', 1) - port = int(appendix.split('/', 1)[0]) - else: - host, _ = url.split('/', 1) - port = 443 - print(host, port) - - context = ssl.create_default_context() - - try: - with socket.create_connection((host, port)) as sock: - with context.wrap_socket(sock, server_hostname=host) as ssl_socket: - ssl_version = ssl_socket.version() - assert ssl_version not in ["TLSv1.0", "TLSv1.1"], ( - "ERR: Service endpoint for '{service}' uses invalid TLS " - "version '{ssl_version}'" - ) + # The following are sslyze.ServerScanResult.scan_result class attrs + # mapped to a boolean value that indicates whether the SSL/TLS version + # is permittted (True) or deprecated/insecure/disallowed (False). + # In case of the latter, the server is expectedf *not* to offer this + # protocol version at all. + cipher_suite_categories = { + "ssl_2_0_cipher_suites": False, + "ssl_3_0_cipher_suites": False, + "tls_1_0_cipher_suites": False, + "tls_1_1_cipher_suites": False, + "tls_1_2_cipher_suites": True, + "tls_1_3_cipher_suites": True, + } + + # The following string patterns will be matched against to identify + # algorithms, modes or key lengths which are considered insecure by + # the standard and will throw errors if found. + # Note: for an exhaustive list of available ciphers, see + # https://www.openssl.org/docs/man1.0.2/man1/ciphers.html + insecure_cipher_patterns = { + "RC4", # RC4 encryption + "MD5", # MD5 hashing + "DES", # DES encryption + "_56", # algorithms with 56-bit keys + "_64", # algorithms with 64-bit keys + } - # TODO: catch all possible SSL exceptions - except ssl.SSLEOFError as e: - raise Exception( - f"ERR: Service '{service}' violated SSL protocol, " - f"{str(e)}" + server = sslyze.ServerNetworkLocation(host, port) + scans = { + sslyze.ScanCommand.SSL_2_0_CIPHER_SUITES, + sslyze.ScanCommand.SSL_3_0_CIPHER_SUITES, + sslyze.ScanCommand.TLS_1_0_CIPHER_SUITES, + sslyze.ScanCommand.TLS_1_1_CIPHER_SUITES, + sslyze.ScanCommand.TLS_1_2_CIPHER_SUITES, + sslyze.ScanCommand.TLS_1_3_CIPHER_SUITES + } + req = sslyze.ServerScanRequest(server, scan_commands=scans) + scanner = sslyze.Scanner() + scanner.queue_scans([req]) + for result in scanner.get_results(): + assert result.scan_result, ( + f"Service '{service}' at {host}:{port} did not respond to " + f"TLS connection" ) + for suite_cat in cipher_suite_categories.keys(): + protocol = suite_cat.replace("_cipher_suites", "") + attempt = getattr(result.scan_result, suite_cat) + assert ( + attempt.status == sslyze.ScanCommandAttemptStatusEnum.COMPLETED + ), ( + f"'{service}' at {host}:{port} failed to respond to " + f"{protocol} scan" + ) + + # If the cipher suite was marked as disallowed, assert that the + # server does not accept it. + server_cipher_suites = attempt.result.accepted_cipher_suites + if not cipher_suite_categories[suite_cat]: + assert ( + len(server_cipher_suites) == 0 + ), ( + f"'{service}' at {host}:{port} accepts cipher " + f"suites for prohibited SSL/TLS version: {protocol}" + ) + print( + f"↳ Checking denial of deprecated or insecure " + f"protocol version {protocol}: PASS") + else: + # else inspect the cipher suites that the server is claiming + # to accept for cipher suites prohibited by the standard + for suite in server_cipher_suites: + name = suite.cipher_suite.name + for pat in insecure_cipher_patterns: + assert pat not in str(name), ( + f"'{service}' at {host}:{port} accepts " + f"insecure cipher suite including the algorithm, " + f"mode or key length '{pat}' for " + f"{protocol}: {name}" + ) + + # Check some OPTIONAL guidelines of the standard and print + # a warning if any is found. + if "CBC" in name: + print( + f"↳ WARN: Server accepts cipher in 'CBC' mode, " + f"which SHOULD NOT be used: {name}" + ) + if "_DH" in name and "_DHE" not in name: + print( + f"↳ WARN: Server accepts cipher with 'DH' " + f"algorithm but 'DHE' SHOULD be used: {name}" + ) + if "_ECDH" in name and "_ECDHE" not in name: + print( + f"↳ WARN: Server accepts cipher with 'ECDH' " + f"algorithm but 'ECDHE' SHOULD be used: {name}" + ) + print( + f"↳ Checking denial of weak or deprecated ciphers " + f"on protocol version {protocol}: PASS" + ) + + +def check_endpoints(endpoints: dict[str, str], + ignore: typing.Optional[str]) -> None: + ignore_list = ignore.split(',') if ignore else [] + for service in endpoints: + url = endpoints[service] + host_ref = url.split("://", 1)[-1].split("/", 1)[0] + + # Check if the endpoint matches any of the given ignore patterns. + ignored = False + for ignore_pattern in ignore_list: + if ignore_pattern in host_ref: + print( + f"WARN: matching ignore rule for '{ignore_pattern}', " + f"ignoring endpoint: {url}" + ) + ignored = True + break + if ignored: + continue + + if ':' in host_ref: + host, port = host_ref.split(':', 1) + else: + host = host_ref + port = 443 + + print(f"\nINFO: Checking public endpoint {host}:{port} ...") + verify_tls(service, host, int(port)) + + +def main(): + parser = argparse.ArgumentParser( + description="SCS Domain Manager Conformance Checker") + parser.add_argument( + "--os-cloud", type=str, + help="Name of the cloud from clouds.yaml, alternative " + "to the OS_CLOUD environment variable" + ) + parser.add_argument( + "--ask", + help="Ask for password interactively instead of reading it from the " + "clouds.yaml", + action="store_true" + ) + parser.add_argument( + "--ignore", type=str, + help="Comma-separated list of host names or host:port combinations " + "to exclude from testing", + ) + parser.add_argument( + "--debug", action="store_true", + help="Enable OpenStack SDK debug logging" + ) + args = parser.parse_args() + openstack.enable_logging(debug=args.debug) + + # parse cloud name for lookup in clouds.yaml + cloud = os.environ.get("OS_CLOUD", None) + if args.os_cloud: + cloud = args.os_cloud + assert cloud, ( + "You need to have the OS_CLOUD environment variable set to your " + "cloud name or pass it via --os-cloud" + ) + conn = connect( + cloud, + password=getpass.getpass("Enter password: ") if args.ask else None + ) + endpoints_catalog = retrieve_endpoints(conn) + assert "public" in endpoints_catalog, ( + "No public endpoints returned in the service catalog" + ) + endpoints = endpoints_catalog["public"] + check_endpoints(endpoints, args.ignore) + + +if __name__ == "__main__": + main() From 2ff4d9007ca83ff81dbe8b750efa8843b3d1411d Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Tue, 9 Apr 2024 11:52:02 +0200 Subject: [PATCH 11/51] Add testing README and reference Signed-off-by: Markus Hentsch --- Standards/scs-0114-v1-secure-connections.md | 2 +- Tests/iaas/secure-connections/README.md | 59 +++++++++++++++++++ .../iaas/secure-connections/requirements.txt | 2 + 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 Tests/iaas/secure-connections/README.md create mode 100644 Tests/iaas/secure-connections/requirements.txt diff --git a/Standards/scs-0114-v1-secure-connections.md b/Standards/scs-0114-v1-secure-connections.md index e6b1e2175..e6120a1e7 100644 --- a/Standards/scs-0114-v1-secure-connections.md +++ b/Standards/scs-0114-v1-secure-connections.md @@ -172,4 +172,4 @@ Conformance tests are limited to communication channels exposed to users, such a There is a test suite in [`tls-checker.py`](https://github.com/SovereignCloudStack/standards/blob/main/Tests/iaas/secure-connections/tls-checker.py). The test suite connects to the OpenStack API and retrieves all public API endpoints from the service catalog. It then connects to each endpoint and verifies the compliance to the standard by checking SSL/TLS protocol versions and cipher suites offered by the server against the guidelines of this standard. - +Please consult the associated [README.md](https://github.com/SovereignCloudStack/standards/blob/main/Tests/iaas/secure-connections/README.md) for detailed setup and testing instructions. diff --git a/Tests/iaas/secure-connections/README.md b/Tests/iaas/secure-connections/README.md new file mode 100644 index 000000000..5fc04bd60 --- /dev/null +++ b/Tests/iaas/secure-connections/README.md @@ -0,0 +1,59 @@ +# Secure Connections Standard Test Suite + +## Test Environment Setup + +> **NOTE:** The test execution procedure does not require cloud admin rights. + +A valid cloud configuration for the OpenStack SDK in the shape of "`clouds.yaml`" is mandatory[^1]. +**This file is expected to be located in the current working directory where the test script is executed unless configured otherwise.** + +[^1]: [OpenStack Documentation: Configuring OpenStack SDK Applications](https://docs.openstack.org/openstacksdk/latest/user/config/configuration.html) + +The test execution environment can be located on any system outside of the cloud infrastructure that has OpenStack API access. +Make sure that the API access is configured properly in "`clouds.yaml`". + +It is recommended to use a Python virtual environment[^2]. +Next, install the libraries required by the test suite: + +```bash +pip3 install -r requirements.txt +``` + +Within this environment execute the test suite. + +[^2]: [Python 3 Documentation: Virtual Environments and Packages](https://docs.python.org/3/tutorial/venv.html) + +## Test Execution + +The test suite is executed as follows: + +```bash +python3 tls-checker.py --os-cloud mycloud +``` + +As an alternative to "`--os-cloud`", the "`OS_CLOUD`" environment variable may be specified instead. +The parameter is used to look up the correct cloud configuration in "`clouds.yaml`". +For the example command above, this file should contain a `clouds.mycloud` section like this: + +```yaml +--- +clouds: + mycloud: + auth: + auth_url: ... + ... + ... +``` + +For any further options consult the output of "`python3 tls-checker.py --help`". + +### Script Behavior & Test Results + +The script will print all actions and passed tests to `stdout`. + +If all tests pass, the script will return with an exit code of `0`. + +If any test fails, the script will halt, print the exact error to `stderr` and return with a non-zero exit code. + +Any tests that indicate a recommendation of the standard is not met, will print a warning message under the corresponding endpoint output. +However, unmet recommendations will not count as errors. diff --git a/Tests/iaas/secure-connections/requirements.txt b/Tests/iaas/secure-connections/requirements.txt new file mode 100644 index 000000000..835d17011 --- /dev/null +++ b/Tests/iaas/secure-connections/requirements.txt @@ -0,0 +1,2 @@ +openstacksdk>=3.0.0 +sslyze>=6.0.0 \ No newline at end of file From 0d35174f39a64c948b68f0416152ce538f237b0e Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Tue, 9 Apr 2024 14:21:22 +0200 Subject: [PATCH 12/51] Address review feedback Signed-off-by: Markus Hentsch --- Standards/scs-0114-v1-secure-connections.md | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/Standards/scs-0114-v1-secure-connections.md b/Standards/scs-0114-v1-secure-connections.md index e6120a1e7..3b6bc83ba 100644 --- a/Standards/scs-0114-v1-secure-connections.md +++ b/Standards/scs-0114-v1-secure-connections.md @@ -5,13 +5,6 @@ status: Draft track: IaaS # | IaaS | Ops | KaaS | IAM --- - - ## Introduction A lot of internal and external connectivity is established to and within a cloud infrastructure. @@ -57,10 +50,10 @@ Notes about the classification categories and implications: 2. The database frontend interface is the primary connection target for the OpenStack services. OpenStack supports using TLS for database connections. 3. For the message queue, AMQP-based solutions such as RabbitMQ and QPid do offer TLS natively which is also supported by OpenStack. ZeroMQ does not and requires IPsec or CIPSO instead. 4. External API endpoints can be protected easily by using a TLS proxy. They can then be registered with their HTTPS endpoint in the Keystone service catalog. The certificates of external APIs usually need to be signed by a well-known CA in order to be accepted by arbitrary external clients. -5. Internal API endpoints can use the same TLS proxy mechanisms as the internal ones. Optionally, the TLS certificate provider and PKI can differ to the internal ones. It is often sufficient for the CA of internal TLS endpoints to be accepted within the infrastructure and doesn't need to be a common public CA. +5. Internal API endpoints can be treated and secured similarly to the external ones. Optionally, the TLS certificate provider and PKI can differ to the external ones. It is often sufficient for the CA of internal TLS endpoints to be accepted within the infrastructure and doesn't need to be a common public CA. 6. For protecting the data transferred between compute nodes during live-migration of VMs, [Nova offers support for QEMU-native TLS](https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html). As an alternative, SSH is also a channel that Nova can be configured to use between hosts for this but requires passwordless SSH keys with root access to all other compute nodes which in turn requires further hardening. 7. Neutron's external network traffic leaves the IaaS infrastructure. This part is twofold: connections initiated by the VMs themselves (egress) and connections reaching VMs from the outside (ingress). The CSP cannot influence the egress connections but can offer VPNaaS for the ingress direction. -8. Neutron's internal network traffic one of the hardest aspects to address. Due to the highly dynamic nature of SDN, connection endpoints and relations are constantly changing. There is no holistic approach currently offered or recommended by OpenStack itself. IPsec could be established between all involved nodes but requires sophisticated and reliable key management. A per-tenant/per-customer encryption is very hard to establish this way. +8. Neutron's internal network traffic is one of the hardest aspects to address. Due to the highly dynamic nature of SDN, connection endpoints and relations are constantly changing. There is no holistic approach currently offered or recommended by OpenStack itself. IPsec could be established between all involved nodes but requires sophisticated and reliable key management. A per-tenant/per-customer encryption is very hard to establish this way. ### Options considered @@ -147,10 +140,10 @@ You MAY refer to [TLS proxies and HTTP services](https://docs.openstack.org/secu - If using libvirt on compute nodes, the libvirt port (as per `listen_addr`) MUST NOT be exposed to the network in an unauthenticated and unprotected fashion. It SHOULD be bound to `127.0.0.1`. - If QEMU and libvirt are used as the hypervisor interface in Nova, QEMU-native TLS SHOULD be used. See [Secure live migration with QEMU-native TLS](https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html). - ### External VM Connections -- As an OPTIONAL measure to assist customers in protecting external connections to their OpenStack networks and VMs, the Neutron VPNaaS service MAY be integrated into the infrastructure and the Neutron VPNaaS API extension offered to users. See the [Neutron VPNaaS documentation](https://docs.openstack.org/neutron-vpnaas/latest/). +- As an OPTIONAL measure to assist customers in protecting external connections to their OpenStack networks and VMs, the infrastructure MAY provide VPNaaS solutions to users. + - For example the Neutron VPNaaS service MAY be integrated into the infrastructure with the Neutron VPNaaS API extension enabled. See the [Neutron VPNaaS documentation](https://docs.openstack.org/neutron-vpnaas/latest/). ### Internal Neutron Connections From 3a9efd902498e797711752a356f6716d8c374c5b Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Tue, 9 Apr 2024 14:24:41 +0200 Subject: [PATCH 13/51] Fix typo in test script comment Signed-off-by: Markus Hentsch --- Tests/iaas/secure-connections/tls-checker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/iaas/secure-connections/tls-checker.py b/Tests/iaas/secure-connections/tls-checker.py index cd69c8b7b..2b7d68250 100644 --- a/Tests/iaas/secure-connections/tls-checker.py +++ b/Tests/iaas/secure-connections/tls-checker.py @@ -94,7 +94,7 @@ def verify_tls(service: str, host: str, port: int) -> None: # The following are sslyze.ServerScanResult.scan_result class attrs # mapped to a boolean value that indicates whether the SSL/TLS version - # is permittted (True) or deprecated/insecure/disallowed (False). + # is permitted (True) or deprecated/insecure/disallowed (False). # In case of the latter, the server is expectedf *not* to offer this # protocol version at all. cipher_suite_categories = { From 333f953939ab86ac94033bda6a39ffe05a7af7d0 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Fri, 19 Apr 2024 15:17:59 +0200 Subject: [PATCH 14/51] Add glossary and rephrase "SCS" to "SCS project" Signed-off-by: Markus Hentsch --- Standards/scs-0114-v1-secure-connections.md | 24 +++++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/Standards/scs-0114-v1-secure-connections.md b/Standards/scs-0114-v1-secure-connections.md index 3b6bc83ba..f9f76d876 100644 --- a/Standards/scs-0114-v1-secure-connections.md +++ b/Standards/scs-0114-v1-secure-connections.md @@ -11,7 +11,17 @@ A lot of internal and external connectivity is established to and within a cloud Due to the nature of the IaaS approach, many communication channels may occasionally or even primarily carry potentially sensitive data of customers. To protect this data from both tampering and unintended disclosure, communication channels need to be properly secured. -For this reason, [SCS](https://scs.community) standardizes the use of common protection mechanisms for communication channels in OpenStack infrastructures. +For this reason, the [SCS project](https://scs.community) standardizes the use of common protection mechanisms for communication channels in OpenStack infrastructures. + +### Glossary + +| Term | Meaning | +|---|---| +| CSP | Cloud Service Provider, provider managing the OpenStack infrastructure | +| SSL | Secure Sockets Layer, the predecessor of TLS | +| TLS | Transport Layer Security | +| PKI | Public Key Infrastructure | +| SDN | Software-Defined Networking | ## Motivation @@ -19,13 +29,13 @@ As mentioned above, a lot of communication channels in an OpenStack infrastructu For example this includes authentication data of customers and internal OpenStack configuration data such as encryption keys among others. OpenStack does not generically mandate or preconfigure the use of specific protection mechanisms by itself and instead only makes recommendations about best practices in its offical [Security Guide](https://docs.openstack.org/security-guide/). -To address the potential lack of implementation of such mechanisms by a CSP and to establish a reliable foundation for communication data protection in SCS clouds, SCS formulates this standard for securing communication channels in the infrastructure, so that a customer can rely on adequate security mechanisms being in use. +To address the potential lack of implementation of such mechanisms by a CSP and to establish a reliable foundation for communication data protection in SCS clouds, the SCS project formulates this standard for securing communication channels in the infrastructure, so that a customer can rely on adequate security mechanisms being in use. ## Design Considerations There are many communication channels in OpenStack with different characteristics, location and eligible means of protection. Not all channels are equally easy to secure and some protection mechanisms might put unbearable burdens on a CSP. -Hence, careful assessment is required to determine for which SCS will either mandate or recommend the use of a protection mechanism. +Hence, careful assessment is required to determine for which the SCS standard will either mandate or recommend the use of a protection mechanism. For this distinction to be made, communication channels must be categorized and classified accordingly. @@ -62,14 +72,14 @@ Notes about the classification categories and implications: This option would reach the highest security standard and establish protection on all identified communication channels simultaneously. However, this would burden CSPs greatly due to the difficulty of addressing some of the channels and properly maintaining the solution. Also there is a risk of making this incompatible with existing infrastructures due to some of their specifics being mutually exclusive to the more intricate protection mechanisms such as cross-node IPsec configurations. -As a third aspect, not all mechanisms might fulfill the CSPs requirements regarding performance and stability and SCS cannot in good faith force CSPs to use technologies not suited to their infrastructures. +As a third aspect, not all mechanisms might fulfill the CSPs requirements regarding performance and stability and the SCS standard cannot in good faith force CSPs to use technologies not suited to their infrastructures. This seems like a bad option from many perspectives. It also allows very little flexibility and might even make SCS conformance unappealing to CSPs due to the immense effort required to reach it. #### Option 2: only make recommendations -This option would limit SCS to only recommend mechanisms in this standard like presented in the OpenStack Security Guide. +This option would limit the SCS project to only recommend mechanisms in this standard like presented in the OpenStack Security Guide. Although this can increase awareness about the best practices recommended by OpenStack and maybe encourage CSPs to abide by them, it would actually contribute very little to the security baseline of SCS infrastructures as a whole since everything would stay optional. This option would be very easy to standardize and get consensus on due to its lightweight and optional nature. @@ -80,7 +90,7 @@ However, the actual added value for SCS is questionable at best. This option forms a middle ground between options 1 and 2. For this, the standard needs to carefully assess each communication channel, mechanisms for protecting it and the effort required to do so as well as the implications. Then, only for mechanisms that are known to be reliable, are feasible to implement and for which the benefits clearly outweigh the integration effort required, should this standard enforce their implementation in a permissive way. -For any remaining mechanisms SCS should only make recommendations and refer to known best practices where applicable. +For any remaining mechanisms the SCS standard should only make recommendations and refer to known best practices where applicable. This option would still offer improvements over arbitrary OpenStack clouds by establishing a baseline that goes beyond mere recommendations while still taking into account that not all communication channels are equally easy to secure and allowing necessary flexibility for the CSP. @@ -88,7 +98,7 @@ This option would still offer improvements over arbitrary OpenStack clouds by es ### Verifying standard conformance for internal mechanisms -Most of the mentioned communication channels to be secured are part of the internal IaaS infrastructure of an SCS cloud. +Most of the mentioned communication channels to be secured are part of the internal IaaS infrastructure of a SCS cloud. When an internal protection mechanism is implemented by the CSP it cannot be verified from outside of the infrastructure without administrative access to the infrastructure. Thus, the SCS community is unable to fully assess a CSPs conformance to this standard without a dedicated audit of the infrastructure. From d69af20f5ad4c3631e1c7dd7980da0fc8c366954 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Mon, 22 Apr 2024 16:19:50 +0200 Subject: [PATCH 15/51] Rename standard filename due to conflicting counter Signed-off-by: Markus Hentsch --- ...v1-secure-connections.md => scs-01XX-v1-secure-connections.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Standards/{scs-0114-v1-secure-connections.md => scs-01XX-v1-secure-connections.md} (100%) diff --git a/Standards/scs-0114-v1-secure-connections.md b/Standards/scs-01XX-v1-secure-connections.md similarity index 100% rename from Standards/scs-0114-v1-secure-connections.md rename to Standards/scs-01XX-v1-secure-connections.md From 13d850d99be3a667f67c88fc3200ef686b199140 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Tue, 30 Apr 2024 13:26:47 +0200 Subject: [PATCH 16/51] Refine the scope in regards to the communication channels Signed-off-by: Markus Hentsch --- Standards/scs-01XX-v1-secure-connections.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Standards/scs-01XX-v1-secure-connections.md b/Standards/scs-01XX-v1-secure-connections.md index f9f76d876..4fc5b44ea 100644 --- a/Standards/scs-01XX-v1-secure-connections.md +++ b/Standards/scs-01XX-v1-secure-connections.md @@ -33,11 +33,14 @@ To address the potential lack of implementation of such mechanisms by a CSP and ## Design Considerations -There are many communication channels in OpenStack with different characteristics, location and eligible means of protection. +There are many internal communication channels in OpenStack with different characteristics, location and eligible means of protection. Not all channels are equally easy to secure and some protection mechanisms might put unbearable burdens on a CSP. Hence, careful assessment is required to determine for which the SCS standard will either mandate or recommend the use of a protection mechanism. -For this distinction to be made, communication channels must be categorized and classified accordingly. +Note that this standard only focuses on security considerations for securing the Openstack API as well as inter-component connections, which a CSP has full control over on an infrastructure level. +This standard will not address the security of customer-deployed instances and services on top of OpenStack or other IaaS implementations. + +For this distinction to be made, applicable communication channels must be categorized and classified accordingly. ### Communication Channels @@ -45,8 +48,8 @@ The following overview will classify the main communication channels. | # | Classification | Details | Example solution | |---|---|---|---| -| 1 | Database backend traffic | Replication and sync between database instances | SSL/TLS | -| 2 | Database frontend traffic | Communication between OpenStack services and databases | SSL/TLS | +| 1 | OpenStack database backend traffic | Replication and sync between database instances of the OpenStack services' databases | SSL/TLS | +| 2 | OpenStack database frontend traffic | Communication between OpenStack services and their corresponding databases | SSL/TLS | | 3 | Message queue traffic | Message queue communication between OpenStack components as provided by oslo.messaging | SSL/TLS | | 4 | External API communication | HTTP traffic to services registered as external endpoints in the Keystone service catalog | SSL/TLS | | 5 | Internal API communication | HTTP traffic to services registered as internal endpoints in the Keystone service catalog | SSL/TLS | From 914631cf824cc6e126c814802c2fb104b71c7341 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Tue, 30 Apr 2024 13:41:34 +0200 Subject: [PATCH 17/51] s/IPsec/WireGuard/ Signed-off-by: Markus Hentsch --- Standards/scs-01XX-v1-secure-connections.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Standards/scs-01XX-v1-secure-connections.md b/Standards/scs-01XX-v1-secure-connections.md index 4fc5b44ea..21da14fdb 100644 --- a/Standards/scs-01XX-v1-secure-connections.md +++ b/Standards/scs-01XX-v1-secure-connections.md @@ -55,18 +55,18 @@ The following overview will classify the main communication channels. | 5 | Internal API communication | HTTP traffic to services registered as internal endpoints in the Keystone service catalog | SSL/TLS | | 6 | Nova VM migration traffic | Nova VM migration data transfer traffic between compute nodes | QEMU-native TLS | | 7 | External Neutron network traffic | VM-related traffic between the network/controller nodes and external networks (e.g. internet) established through routed provider networks and floating IPs | VPN | -| 8 | Internal Neutron network traffic | Traffic within Neutron SDN networks exchanged between internal systems such as network/controller and compute nodes | IPsec | +| 8 | Internal Neutron network traffic | Traffic within Neutron SDN networks exchanged between internal systems such as network/controller and compute nodes | WireGuard | Notes about the classification categories and implications: 1. Most database clustering solutions (e.g. MariaDB Galera) offer TLS-based encryption of their backend channels. This needs no additional configuration in OpenStack and is a configuration solely concerning the database cluster. 2. The database frontend interface is the primary connection target for the OpenStack services. OpenStack supports using TLS for database connections. -3. For the message queue, AMQP-based solutions such as RabbitMQ and QPid do offer TLS natively which is also supported by OpenStack. ZeroMQ does not and requires IPsec or CIPSO instead. +3. For the message queue, AMQP-based solutions such as RabbitMQ and QPid do offer TLS natively which is also supported by OpenStack. ZeroMQ does not and requires WireGuard or CIPSO instead. 4. External API endpoints can be protected easily by using a TLS proxy. They can then be registered with their HTTPS endpoint in the Keystone service catalog. The certificates of external APIs usually need to be signed by a well-known CA in order to be accepted by arbitrary external clients. 5. Internal API endpoints can be treated and secured similarly to the external ones. Optionally, the TLS certificate provider and PKI can differ to the external ones. It is often sufficient for the CA of internal TLS endpoints to be accepted within the infrastructure and doesn't need to be a common public CA. 6. For protecting the data transferred between compute nodes during live-migration of VMs, [Nova offers support for QEMU-native TLS](https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html). As an alternative, SSH is also a channel that Nova can be configured to use between hosts for this but requires passwordless SSH keys with root access to all other compute nodes which in turn requires further hardening. 7. Neutron's external network traffic leaves the IaaS infrastructure. This part is twofold: connections initiated by the VMs themselves (egress) and connections reaching VMs from the outside (ingress). The CSP cannot influence the egress connections but can offer VPNaaS for the ingress direction. -8. Neutron's internal network traffic is one of the hardest aspects to address. Due to the highly dynamic nature of SDN, connection endpoints and relations are constantly changing. There is no holistic approach currently offered or recommended by OpenStack itself. IPsec could be established between all involved nodes but requires sophisticated and reliable key management. A per-tenant/per-customer encryption is very hard to establish this way. +8. Neutron's internal network traffic is one of the hardest aspects to address. Due to the highly dynamic nature of SDN, connection endpoints and relations are constantly changing. There is no holistic approach currently offered or recommended by OpenStack itself. Encrypted tunnels could be established between all involved nodes but would require a scalable solution and reliable key management. WireGuard could be considered a good starting point for this. A per-tenant/per-customer encryption remains very hard to establish this way though. ### Options considered @@ -74,7 +74,7 @@ Notes about the classification categories and implications: This option would reach the highest security standard and establish protection on all identified communication channels simultaneously. However, this would burden CSPs greatly due to the difficulty of addressing some of the channels and properly maintaining the solution. -Also there is a risk of making this incompatible with existing infrastructures due to some of their specifics being mutually exclusive to the more intricate protection mechanisms such as cross-node IPsec configurations. +Also there is a risk of making this incompatible with existing infrastructures due to some of their specifics being mutually exclusive to the more intricate protection mechanisms such as cross-node WireGuard configurations. As a third aspect, not all mechanisms might fulfill the CSPs requirements regarding performance and stability and the SCS standard cannot in good faith force CSPs to use technologies not suited to their infrastructures. This seems like a bad option from many perspectives. @@ -160,7 +160,7 @@ You MAY refer to [TLS proxies and HTTP services](https://docs.openstack.org/secu ### Internal Neutron Connections -- As an OPTIONAL measure to protect Neutron SDN traffic between physical nodes within the infrastructure, IPsec tunnels MAY be established between nodes involved in Neutron networks, such as compute and network controller nodes, at the network interfaces configured in Neutron. +- As an OPTIONAL measure to protect Neutron SDN traffic between physical nodes within the infrastructure, encrypted tunnels MAY be established between nodes involved in Neutron networks, such as compute and network controller nodes, at the network interfaces configured in Neutron (e.g. via WireGuard or similar solutions). ## Related Documents From 096675b97d0eebc5add1bf72c64546cced983412 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Tue, 30 Apr 2024 15:12:20 +0200 Subject: [PATCH 18/51] Fix option references for oslo.messaging ssl Signed-off-by: Markus Hentsch --- Standards/scs-01XX-v1-secure-connections.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Standards/scs-01XX-v1-secure-connections.md b/Standards/scs-01XX-v1-secure-connections.md index 21da14fdb..e89f46e19 100644 --- a/Standards/scs-01XX-v1-secure-connections.md +++ b/Standards/scs-01XX-v1-secure-connections.md @@ -21,6 +21,7 @@ For this reason, the [SCS project](https://scs.community) standardizes the use o | SSL | Secure Sockets Layer, the predecessor of TLS | | TLS | Transport Layer Security | | PKI | Public Key Infrastructure | +| CA | Certificate Authority | | SDN | Software-Defined Networking | ## Motivation @@ -143,7 +144,15 @@ You MAY refer to [TLS proxies and HTTP services](https://docs.openstack.org/secu ### Message Queue Connections - If using RabbitMQ or Qpid as the message queue service, the SSL functionality of the message broker MUST be enabled and used by the OpenStack services. See [Messaging transport security](https://docs.openstack.org/security-guide/messaging/security.html#messaging-transport-security). - - If using RabbitMQ, the OpenStack services' oslo.messaging configuration for RabbitMQ MUST use the `kombu_ssl_*` options accordingly to enable SSL. + - If using RabbitMQ, all OpenStack services' oslo.messaging configuration for RabbitMQ MUST specify options accordingly to enable SSL: + ```ini + [oslo_messaging_rabbit] + ssl = true + ssl_ca_file = /path/to/file + ssl_key_file = + ssl_cert_file = + ``` + (`ssl_ca_file` MUST be set to the path of the CA certificate, `ssl_key_file` and `ssl_cert_file` for client certificates are OPTIONAL) - If using Qpid, the OpenStack services' oslo.messaging configuration for Qpid MUST set the `qpid_protocol` option to `ssl` to enable SSL. - If using Apache Kafka, the server listener MUST be configured to accept SSL connections. See [Apache Kafka Listener Configuration](https://kafka.apache.org/documentation/#listener_configuration). - The OpenStack services' oslo.messaging configuration for Kafka MUST specify `security_protocol` as either `SSL` or `SASL_SSL` and the related options appropriately. See [Kafka Driver Options](https://docs.openstack.org/oslo.messaging/latest/admin/kafka.html#driver-options). From 73dce0a00e99ed956314bb2a7205154fac42f373 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Tue, 30 Apr 2024 15:12:39 +0200 Subject: [PATCH 19/51] Add RFC link for TLS deprecation Signed-off-by: Markus Hentsch --- Standards/scs-01XX-v1-secure-connections.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Standards/scs-01XX-v1-secure-connections.md b/Standards/scs-01XX-v1-secure-connections.md index e89f46e19..0be294720 100644 --- a/Standards/scs-01XX-v1-secure-connections.md +++ b/Standards/scs-01XX-v1-secure-connections.md @@ -179,6 +179,7 @@ You MAY refer to [TLS proxies and HTTP services](https://docs.openstack.org/secu - [OpenStack Security Guide: Messaging transport security](https://docs.openstack.org/security-guide/messaging/security.html#messaging-transport-security) - [Nova Documentation: Secure live migration with QEMU-native TLS](https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html) - [Guide to TLS Standards Compliance](https://www.ssl.com/guide/tls-standards-compliance/) +- [RFC 8996: Deprecating TLS 1.0 and TLS 1.1](https://www.ietf.org/rfc/rfc8996.html) ## Conformance Tests From 0ed970d8218882b6ff1ea585204aa00978a59f57 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Tue, 30 Apr 2024 15:21:52 +0200 Subject: [PATCH 20/51] Don't endorse internal CAs specifically Signed-off-by: Markus Hentsch --- Standards/scs-01XX-v1-secure-connections.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Standards/scs-01XX-v1-secure-connections.md b/Standards/scs-01XX-v1-secure-connections.md index 0be294720..03f430d80 100644 --- a/Standards/scs-01XX-v1-secure-connections.md +++ b/Standards/scs-01XX-v1-secure-connections.md @@ -64,7 +64,7 @@ Notes about the classification categories and implications: 2. The database frontend interface is the primary connection target for the OpenStack services. OpenStack supports using TLS for database connections. 3. For the message queue, AMQP-based solutions such as RabbitMQ and QPid do offer TLS natively which is also supported by OpenStack. ZeroMQ does not and requires WireGuard or CIPSO instead. 4. External API endpoints can be protected easily by using a TLS proxy. They can then be registered with their HTTPS endpoint in the Keystone service catalog. The certificates of external APIs usually need to be signed by a well-known CA in order to be accepted by arbitrary external clients. -5. Internal API endpoints can be treated and secured similarly to the external ones. Optionally, the TLS certificate provider and PKI can differ to the external ones. It is often sufficient for the CA of internal TLS endpoints to be accepted within the infrastructure and doesn't need to be a common public CA. +5. Internal API endpoints can be treated and secured similarly to the external ones using a TLS proxy and adequate certificates. 6. For protecting the data transferred between compute nodes during live-migration of VMs, [Nova offers support for QEMU-native TLS](https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html). As an alternative, SSH is also a channel that Nova can be configured to use between hosts for this but requires passwordless SSH keys with root access to all other compute nodes which in turn requires further hardening. 7. Neutron's external network traffic leaves the IaaS infrastructure. This part is twofold: connections initiated by the VMs themselves (egress) and connections reaching VMs from the outside (ingress). The CSP cannot influence the egress connections but can offer VPNaaS for the ingress direction. 8. Neutron's internal network traffic is one of the hardest aspects to address. Due to the highly dynamic nature of SDN, connection endpoints and relations are constantly changing. There is no holistic approach currently offered or recommended by OpenStack itself. Encrypted tunnels could be established between all involved nodes but would require a scalable solution and reliable key management. WireGuard could be considered a good starting point for this. A per-tenant/per-customer encryption remains very hard to establish this way though. From a2f3e77e86a7dadfbd4280f35bbbf2908ca038bf Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Tue, 21 May 2024 16:21:23 +0200 Subject: [PATCH 21/51] Refactor test script to check Mozilla TLS recommendations Signed-off-by: Markus Hentsch --- Tests/iaas/secure-connections/tls-checker.py | 167 +++++++------------ 1 file changed, 57 insertions(+), 110 deletions(-) diff --git a/Tests/iaas/secure-connections/tls-checker.py b/Tests/iaas/secure-connections/tls-checker.py index 2b7d68250..6f9aa5d31 100644 --- a/Tests/iaas/secure-connections/tls-checker.py +++ b/Tests/iaas/secure-connections/tls-checker.py @@ -5,23 +5,29 @@ The script relies on an OpenStack SDK compatible clouds.yaml file for authentication with Keystone. -For each endpoint, SSL/TLS protocol versions and ciphers supported by the -server are checked using the SSLyze Python library. +For each endpoint, SSL/TLS protocol parameters supported by the server are +checked using the SSLyze Python library. The script will fail with a non-zero exit code in case any standard violation -is discovered such as deprecated/insecure TLS versions or weak ciphers as -determined by the standard. - -For guidelines marked as OPTIONAL, SHOULD or SHOULD NOT in the standard, -appropriate warnings are printed in the log output for each endpoint. +is discovered such as endpoints being non-conformant to the corresponding +Mozilla TLS recommendations. +Details about the conformance issues will be printed for each endpoint to +help with identifying and addressing the violations of the Mozilla TLS preset. """ import argparse import getpass import os +import sys import typing import openstack import sslyze +from sslyze.mozilla_tls_profile.mozilla_config_checker import ( + SCAN_COMMANDS_NEEDED_BY_MOZILLA_CHECKER, MozillaTlsConfigurationChecker, + MozillaTlsConfigurationEnum, ServerNotCompliantWithMozillaTlsConfiguration) + +# The Mozilla recommendation preset to use +MOZILLA_TLS_PRESET = MozillaTlsConfigurationEnum.INTERMEDIATE def connect(cloud_name: str, password: typing.Optional[str] = None @@ -73,8 +79,8 @@ def retrieve_endpoints(conn: openstack.connection.Connection) \ subdict = ret.setdefault(enp_type, {}) subdict[svc_name] = enp_url - print(f"\nINFO: the following public endpoints have been retrieved from " - f"the service catalog:") + print("\nINFO: the following public endpoints have been retrieved from " + "the service catalog:") for svc_name in ret["public"].keys(): print( f"↳ {svc_name} @ {ret['public'][svc_name]}" @@ -83,121 +89,50 @@ def retrieve_endpoints(conn: openstack.connection.Connection) \ return ret -def verify_tls(service: str, host: str, port: int) -> None: +def verify_tls(service: str, host: str, port: int) -> bool: """Use SSLyze library to scan the SSL/TLS interface of the server. - Evaluates the SSL/TLS versions the server reports to support as well as - the cipher suites it accepts. - Checks the protocol versions and cipher suites against the rules - established by the standard to assure conformance. - """ - - # The following are sslyze.ServerScanResult.scan_result class attrs - # mapped to a boolean value that indicates whether the SSL/TLS version - # is permitted (True) or deprecated/insecure/disallowed (False). - # In case of the latter, the server is expectedf *not* to offer this - # protocol version at all. - cipher_suite_categories = { - "ssl_2_0_cipher_suites": False, - "ssl_3_0_cipher_suites": False, - "tls_1_0_cipher_suites": False, - "tls_1_1_cipher_suites": False, - "tls_1_2_cipher_suites": True, - "tls_1_3_cipher_suites": True, - } + Evaluates the SSL/TLS configurations the server reports as supported. + Checks the scan results against the Mozilla TLS recommendation preset. + Prints any issues found with details. - # The following string patterns will be matched against to identify - # algorithms, modes or key lengths which are considered insecure by - # the standard and will throw errors if found. - # Note: for an exhaustive list of available ciphers, see - # https://www.openssl.org/docs/man1.0.2/man1/ciphers.html - insecure_cipher_patterns = { - "RC4", # RC4 encryption - "MD5", # MD5 hashing - "DES", # DES encryption - "_56", # algorithms with 56-bit keys - "_64", # algorithms with 64-bit keys - } + Returns True if no errors were encountered, False otherwise. + """ + errors_encountered = 0 server = sslyze.ServerNetworkLocation(host, port) - scans = { - sslyze.ScanCommand.SSL_2_0_CIPHER_SUITES, - sslyze.ScanCommand.SSL_3_0_CIPHER_SUITES, - sslyze.ScanCommand.TLS_1_0_CIPHER_SUITES, - sslyze.ScanCommand.TLS_1_1_CIPHER_SUITES, - sslyze.ScanCommand.TLS_1_2_CIPHER_SUITES, - sslyze.ScanCommand.TLS_1_3_CIPHER_SUITES - } - req = sslyze.ServerScanRequest(server, scan_commands=scans) + scans = SCAN_COMMANDS_NEEDED_BY_MOZILLA_CHECKER + request = sslyze.ServerScanRequest(server, scan_commands=scans) scanner = sslyze.Scanner() - scanner.queue_scans([req]) + scanner.queue_scans([request]) + mozilla_checker = MozillaTlsConfigurationChecker.get_default() for result in scanner.get_results(): assert result.scan_result, ( f"Service '{service}' at {host}:{port} did not respond to " f"TLS connection" ) - for suite_cat in cipher_suite_categories.keys(): - protocol = suite_cat.replace("_cipher_suites", "") - attempt = getattr(result.scan_result, suite_cat) - assert ( - attempt.status == sslyze.ScanCommandAttemptStatusEnum.COMPLETED - ), ( - f"'{service}' at {host}:{port} failed to respond to " - f"{protocol} scan" + try: + mozilla_checker.check_server(MOZILLA_TLS_PRESET, result) + print( + f"Service '{service}' at {host}:{port} complies to " + f"TLS recommendations: PASS" ) + except ServerNotCompliantWithMozillaTlsConfiguration as e: + print( + f"Service '{service}' at {host}:{port} complies to " + f"TLS recommendations: FAIL" + ) + for criteria, error_description in e.issues.items(): + print(f"↳ {criteria}: {error_description}") + errors_encountered += 1 - # If the cipher suite was marked as disallowed, assert that the - # server does not accept it. - server_cipher_suites = attempt.result.accepted_cipher_suites - if not cipher_suite_categories[suite_cat]: - assert ( - len(server_cipher_suites) == 0 - ), ( - f"'{service}' at {host}:{port} accepts cipher " - f"suites for prohibited SSL/TLS version: {protocol}" - ) - print( - f"↳ Checking denial of deprecated or insecure " - f"protocol version {protocol}: PASS") - else: - # else inspect the cipher suites that the server is claiming - # to accept for cipher suites prohibited by the standard - for suite in server_cipher_suites: - name = suite.cipher_suite.name - for pat in insecure_cipher_patterns: - assert pat not in str(name), ( - f"'{service}' at {host}:{port} accepts " - f"insecure cipher suite including the algorithm, " - f"mode or key length '{pat}' for " - f"{protocol}: {name}" - ) - - # Check some OPTIONAL guidelines of the standard and print - # a warning if any is found. - if "CBC" in name: - print( - f"↳ WARN: Server accepts cipher in 'CBC' mode, " - f"which SHOULD NOT be used: {name}" - ) - if "_DH" in name and "_DHE" not in name: - print( - f"↳ WARN: Server accepts cipher with 'DH' " - f"algorithm but 'DHE' SHOULD be used: {name}" - ) - if "_ECDH" in name and "_ECDHE" not in name: - print( - f"↳ WARN: Server accepts cipher with 'ECDH' " - f"algorithm but 'ECDHE' SHOULD be used: {name}" - ) - print( - f"↳ Checking denial of weak or deprecated ciphers " - f"on protocol version {protocol}: PASS" - ) + return errors_encountered == 0 def check_endpoints(endpoints: dict[str, str], ignore: typing.Optional[str]) -> None: ignore_list = ignore.split(',') if ignore else [] + error_count = 0 for service in endpoints: url = endpoints[service] host_ref = url.split("://", 1)[-1].split("/", 1)[0] @@ -207,7 +142,7 @@ def check_endpoints(endpoints: dict[str, str], for ignore_pattern in ignore_list: if ignore_pattern in host_ref: print( - f"WARN: matching ignore rule for '{ignore_pattern}', " + f"INFO: Matching ignore rule for '{ignore_pattern}', " f"ignoring endpoint: {url}" ) ignored = True @@ -215,14 +150,26 @@ def check_endpoints(endpoints: dict[str, str], if ignored: continue + # Default to port 443 if no port is specified if ':' in host_ref: host, port = host_ref.split(':', 1) else: host = host_ref port = 443 - print(f"\nINFO: Checking public endpoint {host}:{port} ...") - verify_tls(service, host, int(port)) + print(f"INFO: Checking public '{service}' endpoint {host}:{port} ...") + # Collect errors instead of failing immediately; this makes the output + # more useful since all endpoints are checked in one run and the + # printed output will cover all of them, logging all issues at once + error_count = error_count if verify_tls(service, host, int(port)) \ + else error_count + 1 + + print( + f"INFO: Number of endpoints that failed compliance check: " + f"{error_count} (out of {len(endpoints)})" + ) + if error_count > 0: + sys.exit(1) def main(): @@ -265,7 +212,7 @@ def main(): ) endpoints_catalog = retrieve_endpoints(conn) assert "public" in endpoints_catalog, ( - "No public endpoints returned in the service catalog" + "No public endpoints found in the service catalog" ) endpoints = endpoints_catalog["public"] check_endpoints(endpoints, args.ignore) From 4885429aa06543d618850de750a58314dc90355a Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Tue, 21 May 2024 16:54:39 +0200 Subject: [PATCH 22/51] Update standard to reference Mozilla's TLS recommendations Signed-off-by: Markus Hentsch --- Standards/scs-01XX-v1-secure-connections.md | 27 +++++++++------------ 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/Standards/scs-01XX-v1-secure-connections.md b/Standards/scs-01XX-v1-secure-connections.md index 03f430d80..fc5c36b09 100644 --- a/Standards/scs-01XX-v1-secure-connections.md +++ b/Standards/scs-01XX-v1-secure-connections.md @@ -69,6 +69,15 @@ Notes about the classification categories and implications: 7. Neutron's external network traffic leaves the IaaS infrastructure. This part is twofold: connections initiated by the VMs themselves (egress) and connections reaching VMs from the outside (ingress). The CSP cannot influence the egress connections but can offer VPNaaS for the ingress direction. 8. Neutron's internal network traffic is one of the hardest aspects to address. Due to the highly dynamic nature of SDN, connection endpoints and relations are constantly changing. There is no holistic approach currently offered or recommended by OpenStack itself. Encrypted tunnels could be established between all involved nodes but would require a scalable solution and reliable key management. WireGuard could be considered a good starting point for this. A per-tenant/per-customer encryption remains very hard to establish this way though. +### TLS Configuration Recommendations + +Server-side TLS configuration is complex and involves a lot of choices for protocol versions, cipher suites and algorithms. +Determining and maintaining secure configuration guidelines for this is non-trivial for a community project as it requires a high level security expertise and consistent evaluation. +For this reason, the standard should reference widely accepted best practices and established third party guidelines instead of creating and maintaining its own set of rules. + +[Mozilla publishes and maintains](https://wiki.mozilla.org/Security/Server_Side_TLS) TLS recommendations and corresponding presets for configuration and testing. +Considering Mozilla's well-established name in the internet and open source communities, this could qualify as a good basis for the standard concerning the TLS configurations. + ### Options considered #### Option 1: fully mandate securing all channels without differentiation @@ -114,18 +123,7 @@ It will reference documents like the [OpenStack Security Guide](https://docs.ope ### Transport Layer Security (TLS) -All server-side TLS configurations integrated into the infrastructure as covered by this standard MUST adhere to the folllowing rules: - -- The following deprecated TLS versions MUST NOT be used: - - v1.0 - - v1.1 -- The following cipher suites MUST NOT be used: - - any RC4 cipher suite - - any DES cipher suite - - any cipher suite involving MD5 hash algorithms - - any cipher suite with less than 128-bit encryption -- Cipher suites utilizing CBC mode SHOULD NOT be used -- Cipher suites with Perfect Forward Secrecy (using ephemeral keys with the 'E' suffix, e.g. DHE, ECDHE) SHOULD be used instead of their static key counterpart (e.g. DH, ECDH) +- All server-side TLS configurations integrated into the infrastructure as covered by this standard MUST adhere to the ["Intermediate" Mozilla TLS configuration](https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28recommended.29). ### API Interfaces @@ -178,8 +176,7 @@ You MAY refer to [TLS proxies and HTTP services](https://docs.openstack.org/secu - [OpenStack Security Guide: Database transport security](https://docs.openstack.org/security-guide/databases/database-transport-security.html) - [OpenStack Security Guide: Messaging transport security](https://docs.openstack.org/security-guide/messaging/security.html#messaging-transport-security) - [Nova Documentation: Secure live migration with QEMU-native TLS](https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html) -- [Guide to TLS Standards Compliance](https://www.ssl.com/guide/tls-standards-compliance/) -- [RFC 8996: Deprecating TLS 1.0 and TLS 1.1](https://www.ietf.org/rfc/rfc8996.html) +- [MozillaWiki: Security / Server Side TLS](https://wiki.mozilla.org/Security/Server_Side_TLS) ## Conformance Tests @@ -187,5 +184,5 @@ Conformance tests are limited to communication channels exposed to users, such a There is a test suite in [`tls-checker.py`](https://github.com/SovereignCloudStack/standards/blob/main/Tests/iaas/secure-connections/tls-checker.py). The test suite connects to the OpenStack API and retrieves all public API endpoints from the service catalog. -It then connects to each endpoint and verifies the compliance to the standard by checking SSL/TLS protocol versions and cipher suites offered by the server against the guidelines of this standard. +It then connects to each endpoint and verifies the compliance to the standard by checking SSL/TLS properties against the Mozilla TLS preset. Please consult the associated [README.md](https://github.com/SovereignCloudStack/standards/blob/main/Tests/iaas/secure-connections/README.md) for detailed setup and testing instructions. From 1cbd1d01803c530b1e61fdf5ca89e7420ada4fe6 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Wed, 22 May 2024 17:00:08 +0200 Subject: [PATCH 23/51] Migrate test script requirements to requirements.in Signed-off-by: Markus Hentsch --- Tests/iaas/secure-connections/README.md | 4 +++- Tests/iaas/secure-connections/requirements.txt | 2 -- Tests/requirements.in | 1 + Tests/requirements.txt | 18 +++++++++++++++++- 4 files changed, 21 insertions(+), 4 deletions(-) delete mode 100644 Tests/iaas/secure-connections/requirements.txt diff --git a/Tests/iaas/secure-connections/README.md b/Tests/iaas/secure-connections/README.md index 5fc04bd60..9262f1ee2 100644 --- a/Tests/iaas/secure-connections/README.md +++ b/Tests/iaas/secure-connections/README.md @@ -16,9 +16,11 @@ It is recommended to use a Python virtual environment[^2]. Next, install the libraries required by the test suite: ```bash -pip3 install -r requirements.txt +pip3 install openstacksdk sslyze ``` +> Note: the version of the sslyze library determines the [version of the Mozilla TLS recommendation JSON](https://wiki.mozilla.org/Security/Server_Side_TLS#JSON_version_of_the_recommendations) that it checks against. + Within this environment execute the test suite. [^2]: [Python 3 Documentation: Virtual Environments and Packages](https://docs.python.org/3/tutorial/venv.html) diff --git a/Tests/iaas/secure-connections/requirements.txt b/Tests/iaas/secure-connections/requirements.txt deleted file mode 100644 index 835d17011..000000000 --- a/Tests/iaas/secure-connections/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -openstacksdk>=3.0.0 -sslyze>=6.0.0 \ No newline at end of file diff --git a/Tests/requirements.in b/Tests/requirements.in index 128fed5c0..cdc7f4da7 100644 --- a/Tests/requirements.in +++ b/Tests/requirements.in @@ -6,3 +6,4 @@ python-dateutil PyYAML openstacksdk requests +sslyze==6.0.0 \ No newline at end of file diff --git a/Tests/requirements.txt b/Tests/requirements.txt index e225645b2..9f7843eae 100644 --- a/Tests/requirements.txt +++ b/Tests/requirements.txt @@ -10,6 +10,8 @@ aiohttp==3.9.5 # kubernetes-asyncio aiosignal==1.3.1 # via aiohttp +annotated-types==0.7.0 + # via pydantic async-timeout==4.0.3 # via aiohttp attrs==23.2.0 @@ -32,6 +34,7 @@ cryptography==42.0.8 # via # openstacksdk # paramiko + # sslyze decorator==5.1.1 # via # dogpile-cache @@ -71,6 +74,8 @@ multidict==6.0.5 # via # aiohttp # yarl +nassl==5.2.0 + # via sslyze netifaces==0.11.0 # via openstacksdk openstacksdk==3.1.0 @@ -91,6 +96,10 @@ platformdirs==4.2.2 # via openstacksdk pycparser==2.22 # via cffi +pydantic==2.6.4 + # via sslyze +pydantic-core==2.16.3 + # via pydantic pynacl==1.5.0 # via paramiko python-dateutil==2.9.0.post0 @@ -112,12 +121,19 @@ six==1.16.0 # via # kubernetes-asyncio # python-dateutil +sslyze==6.0.0 + # via -r requirements.in stevedore==5.2.0 # via # dogpile-cache # keystoneauth1 +tls-parser==2.0.1 + # via sslyze typing-extensions==4.12.2 - # via dogpile-cache + # via + # dogpile-cache + # pydantic + # pydantic-core urllib3==2.2.2 # via # kubernetes-asyncio From 6a0920ad4cdf90c2a0e9f3643e60ac07bad5b3f3 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Thu, 23 May 2024 17:48:39 +0200 Subject: [PATCH 24/51] Add libvirt security choices to design considerations Signed-off-by: Markus Hentsch --- Standards/scs-01XX-v1-secure-connections.md | 66 ++++++++++++++++++++- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/Standards/scs-01XX-v1-secure-connections.md b/Standards/scs-01XX-v1-secure-connections.md index fc5c36b09..57f4183b4 100644 --- a/Standards/scs-01XX-v1-secure-connections.md +++ b/Standards/scs-01XX-v1-secure-connections.md @@ -17,12 +17,13 @@ For this reason, the [SCS project](https://scs.community) standardizes the use o | Term | Meaning | |---|---| +| CA | Certificate Authority | | CSP | Cloud Service Provider, provider managing the OpenStack infrastructure | -| SSL | Secure Sockets Layer, the predecessor of TLS | -| TLS | Transport Layer Security | | PKI | Public Key Infrastructure | -| CA | Certificate Authority | | SDN | Software-Defined Networking | +| SSL | Secure Sockets Layer, the predecessor of TLS | +| TLS | Transport Layer Security | +| Compute Host | System within the IaaS infrastructure that runs the hypervisor services and hosts virtual machines | ## Motivation @@ -69,6 +70,65 @@ Notes about the classification categories and implications: 7. Neutron's external network traffic leaves the IaaS infrastructure. This part is twofold: connections initiated by the VMs themselves (egress) and connections reaching VMs from the outside (ingress). The CSP cannot influence the egress connections but can offer VPNaaS for the ingress direction. 8. Neutron's internal network traffic is one of the hardest aspects to address. Due to the highly dynamic nature of SDN, connection endpoints and relations are constantly changing. There is no holistic approach currently offered or recommended by OpenStack itself. Encrypted tunnels could be established between all involved nodes but would require a scalable solution and reliable key management. WireGuard could be considered a good starting point for this. A per-tenant/per-customer encryption remains very hard to establish this way though. +### libvirt Hypervisor Interface on Compute Nodes + +Live migration of virtual machines between compute hosts requires communication between the hypervisor services of the involved hosts. +In OpenStack, the libvirt virtualization API is used to control the hypervisor on compute nodes as well as to enable the live migration communication. +This libvirt interface allows direct control of the hypervisor. +Besides control of virtual machines themselves, in OpenStack this also includes attaching and detaching volumes, setting or retrieving their encryption keys and controlling network attachments. +As such, severe risks are associated with unauthorized access to this interface as it can easily compromise sensitive data of arbitrary tenants if abused. + +This is acknowledged in the OpenStack Security Note [OSSN-0007](https://wiki.openstack.org/wiki/OSSN/OSSN-0007), which recommends either configuring SASL and/or TLS for libvirt connections or utilizing the UNIX socket in combination with SSH. + +The OpenStack kolla-ansible documentation on Nova libvirt connections states[^1]: + +> This should not be considered as providing a secure, encrypted channel, since the username/password SASL mechanisms available for TCP are no longer considered cryptographically secure. + +[^1]: https://docs.openstack.org/kolla-ansible/latest/reference/compute/libvirt-guide.html#sasl-authentication + +This leaves only TLS or UNIX socket with SSH as viable options for securing the channel. + +#### TLS for libvirt and live migration + +Since the Stein release of OpenStack, Nova supports QEMU-native TLS[^2] which protects the migration data streams using TLS. +It requires to add `LIBVIRTD_ARGS="--listen"` to the QEMU configuration, which will lead to TLS being active on the libvirt interface per default (due to `listen_tls` defaulting to being enabled[^3]). +This protects data streams for migration as well as the hypervisor control channel data flow with TLS but does not restrict access. +Client certificates must be deployed additionally and libvirt configured accordingly[^4] in order to meaningfully restrict access to the interface as advised by the OSSN-0007 document. + +[^2]: https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html + +[^3]: https://libvirt.org/remote.html#libvirtd-configuration-file + +[^4]: https://wiki.libvirt.org/TLSDaemonConfiguration.html#restricting-access + +#### UNIX socket and SSH live migration + +As an alternative to the TLS setup, libvirt can be configured to use a local UNIX socket and Nova can be configured to use SSH to this socket for live migrations instead. +The regular libvirt port can then be limited to localhost (`127.0.0.1`) which will make it inaccessible from outside the host but still enables local connections to use it. +The challenge of this approach lies in restricting the SSH access on the compute nodes appropriately to avoid full root access across compute nodes for the SSH user identity that Nova will use for live migration. + +A basic setup for combining the UNIX socket with SSH live migration settings is illustrated below. + +Libvirt configuration: + +```conf +listen_tcp = 1 +listen_addr = "127.0.0.1" +unix_sock_group = "libvirt" +unix_sock_ro_perms = "0770" +unix_sock_rw_perms = "0770" +``` + +Nova configuration: + +```ini +[libvirt] +connection_uri= +live_migration_uri=qemu+ssh://... +live_migration_scheme = ssh + +``` + ### TLS Configuration Recommendations Server-side TLS configuration is complex and involves a lot of choices for protocol versions, cipher suites and algorithms. From 59c7bc858a2000cbf24d515962f2bd49dea4e093 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Tue, 18 Jun 2024 16:09:20 +0200 Subject: [PATCH 25/51] Add open question about libvirt hardening Signed-off-by: Markus Hentsch --- Standards/scs-01XX-v1-secure-connections.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Standards/scs-01XX-v1-secure-connections.md b/Standards/scs-01XX-v1-secure-connections.md index 57f4183b4..637c8e515 100644 --- a/Standards/scs-01XX-v1-secure-connections.md +++ b/Standards/scs-01XX-v1-secure-connections.md @@ -169,6 +169,12 @@ This option would still offer improvements over arbitrary OpenStack clouds by es ## Open questions +### Choosing the best protection for the libvirt hypervisor interface + +As described in the design considerations section, there are multiple ways of securing the libvirt interface using TLS or SSH. +Each approach holds its own challenges and requires a robust provisioning and lifecycle mechanism for the cryptographic assets (e.g. client keys or certificates) to ensure proper configuration of all involved nodes, even if the set of nodes changes. +Aside from extensive testing required to select the best approach, this goes beyond simple component configuration and relies on sophisticated key management which this standard alone does not provide. + ### Verifying standard conformance for internal mechanisms Most of the mentioned communication channels to be secured are part of the internal IaaS infrastructure of a SCS cloud. From 3bdc8a6e4c30410b1057f909f517159b67eaff67 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Tue, 18 Jun 2024 16:24:37 +0200 Subject: [PATCH 26/51] Relax the requirement for the libvirt port Signed-off-by: Markus Hentsch --- Standards/scs-01XX-v1-secure-connections.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Standards/scs-01XX-v1-secure-connections.md b/Standards/scs-01XX-v1-secure-connections.md index 637c8e515..6fd5e4a3c 100644 --- a/Standards/scs-01XX-v1-secure-connections.md +++ b/Standards/scs-01XX-v1-secure-connections.md @@ -101,7 +101,7 @@ Client certificates must be deployed additionally and libvirt configured accordi [^4]: https://wiki.libvirt.org/TLSDaemonConfiguration.html#restricting-access -#### UNIX socket and SSH live migration +#### Local UNIX socket and SSH live migration As an alternative to the TLS setup, libvirt can be configured to use a local UNIX socket and Nova can be configured to use SSH to this socket for live migrations instead. The regular libvirt port can then be limited to localhost (`127.0.0.1`) which will make it inaccessible from outside the host but still enables local connections to use it. @@ -223,8 +223,8 @@ You MAY refer to [TLS proxies and HTTP services](https://docs.openstack.org/secu ### Hypervisor and Live Migration Connections -- If using libvirt on compute nodes, the libvirt port (as per `listen_addr`) MUST NOT be exposed to the network in an unauthenticated and unprotected fashion. It SHOULD be bound to `127.0.0.1`. - If QEMU and libvirt are used as the hypervisor interface in Nova, QEMU-native TLS SHOULD be used. See [Secure live migration with QEMU-native TLS](https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html). +- If using libvirt on compute nodes, the libvirt port (as per `listen_addr`) SHOULD NOT be exposed to the network in an unauthenticated and unprotected fashion. It is RECOMMENDED to either to enforce TLS with client certificate authentication or limit the libvirt port/socket to the local host in conjunction with SSH-based live migration connections. See the [corresponding Design Considerations section](#libvirt-hypervisor-interface-on-compute-nodes) for details. ### External VM Connections From d166e7e590d5e7a5734b15fce3177d56dc6875f6 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Thu, 20 Jun 2024 14:49:39 +0200 Subject: [PATCH 27/51] Rephrase and clarify libvirt security recommendations and questions Signed-off-by: Markus Hentsch --- Standards/scs-01XX-v1-secure-connections.md | 29 ++++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/Standards/scs-01XX-v1-secure-connections.md b/Standards/scs-01XX-v1-secure-connections.md index 6fd5e4a3c..86d8da243 100644 --- a/Standards/scs-01XX-v1-secure-connections.md +++ b/Standards/scs-01XX-v1-secure-connections.md @@ -104,8 +104,9 @@ Client certificates must be deployed additionally and libvirt configured accordi #### Local UNIX socket and SSH live migration As an alternative to the TLS setup, libvirt can be configured to use a local UNIX socket and Nova can be configured to use SSH to this socket for live migrations instead. -The regular libvirt port can then be limited to localhost (`127.0.0.1`) which will make it inaccessible from outside the host but still enables local connections to use it. +The regular libvirt port can then be limited to localhost (`127.0.0.1`) which will make it inaccessible from outside the host but still enables local connections to use it. The challenge of this approach lies in restricting the SSH access on the compute nodes appropriately to avoid full root access across compute nodes for the SSH user identity that Nova will use for live migration. +This can be addressed by restricting the command set that is available and the paths that are accessible to these target SSH user identities on compute nodes, limiting them to the scope strictly required by the live migration. A basic setup for combining the UNIX socket with SSH live migration settings is illustrated below. @@ -169,11 +170,20 @@ This option would still offer improvements over arbitrary OpenStack clouds by es ## Open questions -### Choosing the best protection for the libvirt hypervisor interface +### Choosing the best protection mechanism for the libvirt hypervisor interface -As described in the design considerations section, there are multiple ways of securing the libvirt interface using TLS or SSH. -Each approach holds its own challenges and requires a robust provisioning and lifecycle mechanism for the cryptographic assets (e.g. client keys or certificates) to ensure proper configuration of all involved nodes, even if the set of nodes changes. -Aside from extensive testing required to select the best approach, this goes beyond simple component configuration and relies on sophisticated key management which this standard alone does not provide. +As described in the Design Considerations section, there are multiple ways of securing the libvirt interface and live migration channels using TLS or SSH mechanisms. +Upon closer inspection, this consists of two problems to address: + +1) encrypting migration traffic utilizing the libvirt interface itself +2) identifying/authenticating connecting clients and properly restricting their permission set + +When considering problem no. 1 in an isolated fashion, the QEMU-native TLS approach could be considered preferable simply due to it being officially recommended and documented by upstream OpenStack and tightly integrated into QEMU. + +However, once problem no. 2 is taken into account, the choice does not seem as obvious anymore due to the fact that in order to properly authenticate clients in the TLS case, X.509 client certificate authentication along with a corresponding PKI as well as key management would be required. +Although similar aspects would be relevant for the SSH approach where SSH key and identity management as well as proper permission restriction would need to be implemented, the SSH approach could turn out less complex due to the fact that the foundation for SSH identities most likely already exists on a node-level and does not need to rely on a full PKI. + +To properly compare both possible approaches of securing the libvirt interface, extensive testing and evaulation would be necessary along with a sophisticated key and node identity management for compute nodes which this standard alone does not provide. ### Verifying standard conformance for internal mechanisms @@ -223,8 +233,13 @@ You MAY refer to [TLS proxies and HTTP services](https://docs.openstack.org/secu ### Hypervisor and Live Migration Connections -- If QEMU and libvirt are used as the hypervisor interface in Nova, QEMU-native TLS SHOULD be used. See [Secure live migration with QEMU-native TLS](https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html). -- If using libvirt on compute nodes, the libvirt port (as per `listen_addr`) SHOULD NOT be exposed to the network in an unauthenticated and unprotected fashion. It is RECOMMENDED to either to enforce TLS with client certificate authentication or limit the libvirt port/socket to the local host in conjunction with SSH-based live migration connections. See the [corresponding Design Considerations section](#libvirt-hypervisor-interface-on-compute-nodes) for details. +- The live migration connections between compute nodes SHOULD be secured by encryption. + - If QEMU and libvirt are used, QEMU-native TLS is an approach officially documented by OpenStack. See [Secure live migration with QEMU-native TLS](https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html). As an alternative, SSH-based live migration MAY be configured instead. +- If using libvirt as the hypervisor interface on compute nodes the libvirt port (as per its `listen_addr` configuration option) SHOULD NOT be exposed to the network in an unauthenticated and unprotected fashion: + - For the QEMU-native TLS configuration, it is RECOMMENDED to enforce TLS client certificate authentication and assign corresponding client identities to connecting compute nodes. + - For the SSH-based live migration approach, it is RECOMMENDED to limit the libvirt port/socket to the local host and establish SSH key pairs for compute nodes in conjunction with restricted SSH permissions. + +See the [corresponding Design Considerations section](#libvirt-hypervisor-interface-on-compute-nodes) for more details about the mentioned approaches. ### External VM Connections From e757dd25083e8d200449059c0cc5d93d2e0baf80 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Fri, 28 Jun 2024 14:52:12 +0200 Subject: [PATCH 28/51] Add Mozilla TLS JSON override option to test script Signed-off-by: Markus Hentsch --- Tests/iaas/secure-connections/tls-checker.py | 46 +++++++++++++++++--- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/Tests/iaas/secure-connections/tls-checker.py b/Tests/iaas/secure-connections/tls-checker.py index 6f9aa5d31..252ccd6e9 100644 --- a/Tests/iaas/secure-connections/tls-checker.py +++ b/Tests/iaas/secure-connections/tls-checker.py @@ -16,6 +16,7 @@ import argparse import getpass +import json import os import sys import typing @@ -24,7 +25,8 @@ import sslyze from sslyze.mozilla_tls_profile.mozilla_config_checker import ( SCAN_COMMANDS_NEEDED_BY_MOZILLA_CHECKER, MozillaTlsConfigurationChecker, - MozillaTlsConfigurationEnum, ServerNotCompliantWithMozillaTlsConfiguration) + MozillaTlsConfigurationEnum, ServerNotCompliantWithMozillaTlsConfiguration, + _MozillaTlsProfileAsJson) # The Mozilla recommendation preset to use MOZILLA_TLS_PRESET = MozillaTlsConfigurationEnum.INTERMEDIATE @@ -89,13 +91,20 @@ def retrieve_endpoints(conn: openstack.connection.Connection) \ return ret -def verify_tls(service: str, host: str, port: int) -> bool: +def verify_tls(service: str, host: str, port: int, + mozilla_json_preset: typing.Optional[dict] = None) -> bool: """Use SSLyze library to scan the SSL/TLS interface of the server. Evaluates the SSL/TLS configurations the server reports as supported. Checks the scan results against the Mozilla TLS recommendation preset. Prints any issues found with details. + If `mozilla_json_preset` is passed into this function, it is interpreted + as the Mozilla TLS Profile JSON to be used. If this argument is None or + not specified, the default JSON shipped with the respective SSLyze release + is used instead. The format of this optional argument is expected to be + the parsed JSON as dict. + Returns True if no errors were encountered, False otherwise. """ @@ -105,7 +114,13 @@ def verify_tls(service: str, host: str, port: int) -> bool: request = sslyze.ServerScanRequest(server, scan_commands=scans) scanner = sslyze.Scanner() scanner.queue_scans([request]) - mozilla_checker = MozillaTlsConfigurationChecker.get_default() + if mozilla_json_preset: + # Load a specific Mozilla TLS Profile JSON file; this mimicks the + # internal behavior of MozillaTlsConfigurationChecker.get_default() + parsed_profile = _MozillaTlsProfileAsJson(**mozilla_json_preset) + mozilla_checker = MozillaTlsConfigurationChecker(parsed_profile) + else: + mozilla_checker = MozillaTlsConfigurationChecker.get_default() for result in scanner.get_results(): assert result.scan_result, ( f"Service '{service}' at {host}:{port} did not respond to " @@ -130,7 +145,8 @@ def verify_tls(service: str, host: str, port: int) -> bool: def check_endpoints(endpoints: dict[str, str], - ignore: typing.Optional[str]) -> None: + ignore: typing.Optional[str], + mozilla_json_preset: typing.Optional[dict]) -> None: ignore_list = ignore.split(',') if ignore else [] error_count = 0 for service in endpoints: @@ -161,8 +177,9 @@ def check_endpoints(endpoints: dict[str, str], # Collect errors instead of failing immediately; this makes the output # more useful since all endpoints are checked in one run and the # printed output will cover all of them, logging all issues at once - error_count = error_count if verify_tls(service, host, int(port)) \ - else error_count + 1 + error_count = error_count if verify_tls( + service, host, int(port), mozilla_json_preset + ) else error_count + 1 print( f"INFO: Number of endpoints that failed compliance check: " @@ -195,6 +212,11 @@ def main(): "--debug", action="store_true", help="Enable OpenStack SDK debug logging" ) + parser.add_argument( + "--mozilla-json", type=str, + help="Path to the Mozilla TLS Profile JSON to be used as the basis " + "for the checks (optional)", + ) args = parser.parse_args() openstack.enable_logging(debug=args.debug) @@ -210,12 +232,22 @@ def main(): cloud, password=getpass.getpass("Enter password: ") if args.ask else None ) + endpoints_catalog = retrieve_endpoints(conn) assert "public" in endpoints_catalog, ( "No public endpoints found in the service catalog" ) endpoints = endpoints_catalog["public"] - check_endpoints(endpoints, args.ignore) + + # load the Mozilla TLS Profile from JSON if specified + mozilla_json = None + if args.mozilla_json: + print(f"INFO: Loading custom Mozilla TLS Profile JSON from " + f"{args.mozilla_json}") + with open(args.mozilla_json, 'r') as json_file: + mozilla_json = json.load(json_file) + + check_endpoints(endpoints, args.ignore, mozilla_json) if __name__ == "__main__": From 042e5f39653db7109a6d180931350f974ff52e96 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Fri, 28 Jun 2024 16:01:58 +0200 Subject: [PATCH 29/51] Fully parameterize Mozilla TLS config in test script Signed-off-by: Markus Hentsch --- Tests/iaas/secure-connections/tls-checker.py | 103 +++++++++++++++---- 1 file changed, 82 insertions(+), 21 deletions(-) diff --git a/Tests/iaas/secure-connections/tls-checker.py b/Tests/iaas/secure-connections/tls-checker.py index 252ccd6e9..6db8e6c94 100644 --- a/Tests/iaas/secure-connections/tls-checker.py +++ b/Tests/iaas/secure-connections/tls-checker.py @@ -28,8 +28,71 @@ MozillaTlsConfigurationEnum, ServerNotCompliantWithMozillaTlsConfiguration, _MozillaTlsProfileAsJson) -# The Mozilla recommendation preset to use -MOZILLA_TLS_PRESET = MozillaTlsConfigurationEnum.INTERMEDIATE + +class MozillaTlsValidator(object): + """Configurable wrapper for MozillaTlsConfigurationChecker + + Configures the MozillaTlsConfigurationChecker of SSLyze according + to given parameters concerning the Mozilla TLS Profile JSON to use + and configuration level to select (old, intermediate, modern). + + For reference see: https://wiki.mozilla.org/Security/Server_Side_TLS + """ + + def __init__(self, configuration_level: str, + json_path: typing.Optional[str]) -> None: + """Create a connection to an OpenStack cloud + + :param string configuration_level: + Name of the Mozilla TLS configuration level to select. + + :param string json_path: + Optional path to a JSON file containing the Mozilla TLS + recommendations. + + :returns: MozillaTlsValidator + """ + if json_path: + print(f"INFO: Loading custom Mozilla TLS Profile JSON from " + f"{json_path}") + if not os.path.exists(json_path) or not os.path.isfile(json_path): + raise Exception( + f"No such file '{json_path}'" + ) + with open(json_path, 'r') as json_file: + json_content = json.load(json_file) + self.profile = _MozillaTlsProfileAsJson(**json_content) + else: + self.profile = None + + for level in MozillaTlsConfigurationEnum: + if level.value == configuration_level: + self.config_level = level + print(f"INFO: Using profile level '{level.value}' of the " + f"Mozilla TLS configuration") + break + else: + valid_levels = [ + level.value for level in MozillaTlsConfigurationEnum + ] + raise Exception( + f"Mozilla TLS configuration profile level " + f"'{configuration_level}' is invalid, valid " + f"options are: {valid_levels}" + ) + + def check_scan_result(self, result: sslyze.ServerScanResult): + """ + Validate the given ServerScanResult against the Mozilla TLS Profile. + + Will raise a ServerNotCompliantWithMozillaTlsConfiguration exception + if any violations of the TLS profile are detected. + """ + if self.profile: + mozilla_checker = MozillaTlsConfigurationChecker(self.profile) + else: + mozilla_checker = MozillaTlsConfigurationChecker.get_default() + mozilla_checker.check_server(self.config_level, result) def connect(cloud_name: str, password: typing.Optional[str] = None @@ -92,7 +155,7 @@ def retrieve_endpoints(conn: openstack.connection.Connection) \ def verify_tls(service: str, host: str, port: int, - mozilla_json_preset: typing.Optional[dict] = None) -> bool: + mozilla_tls: MozillaTlsValidator) -> bool: """Use SSLyze library to scan the SSL/TLS interface of the server. Evaluates the SSL/TLS configurations the server reports as supported. @@ -114,20 +177,13 @@ def verify_tls(service: str, host: str, port: int, request = sslyze.ServerScanRequest(server, scan_commands=scans) scanner = sslyze.Scanner() scanner.queue_scans([request]) - if mozilla_json_preset: - # Load a specific Mozilla TLS Profile JSON file; this mimicks the - # internal behavior of MozillaTlsConfigurationChecker.get_default() - parsed_profile = _MozillaTlsProfileAsJson(**mozilla_json_preset) - mozilla_checker = MozillaTlsConfigurationChecker(parsed_profile) - else: - mozilla_checker = MozillaTlsConfigurationChecker.get_default() for result in scanner.get_results(): assert result.scan_result, ( f"Service '{service}' at {host}:{port} did not respond to " f"TLS connection" ) try: - mozilla_checker.check_server(MOZILLA_TLS_PRESET, result) + mozilla_tls.check_scan_result(result) print( f"Service '{service}' at {host}:{port} complies to " f"TLS recommendations: PASS" @@ -146,7 +202,7 @@ def verify_tls(service: str, host: str, port: int, def check_endpoints(endpoints: dict[str, str], ignore: typing.Optional[str], - mozilla_json_preset: typing.Optional[dict]) -> None: + mozilla_tls: MozillaTlsValidator) -> None: ignore_list = ignore.split(',') if ignore else [] error_count = 0 for service in endpoints: @@ -178,7 +234,7 @@ def check_endpoints(endpoints: dict[str, str], # more useful since all endpoints are checked in one run and the # printed output will cover all of them, logging all issues at once error_count = error_count if verify_tls( - service, host, int(port), mozilla_json_preset + service, host, int(port), mozilla_tls ) else error_count + 1 print( @@ -217,6 +273,13 @@ def main(): help="Path to the Mozilla TLS Profile JSON to be used as the basis " "for the checks (optional)", ) + moz_tls_default_level = "intermediate" + parser.add_argument( + "--mozilla-preset-level", type=str, + default=moz_tls_default_level, + help=f"Name of the Mozilla TLS Profile configuration level name " + f"(default: {moz_tls_default_level})", + ) args = parser.parse_args() openstack.enable_logging(debug=args.debug) @@ -239,15 +302,13 @@ def main(): ) endpoints = endpoints_catalog["public"] - # load the Mozilla TLS Profile from JSON if specified - mozilla_json = None - if args.mozilla_json: - print(f"INFO: Loading custom Mozilla TLS Profile JSON from " - f"{args.mozilla_json}") - with open(args.mozilla_json, 'r') as json_file: - mozilla_json = json.load(json_file) + mozilla_tls = MozillaTlsValidator( + args.mozilla_preset_level, + # load the Mozilla TLS Profile from JSON if specified + args.mozilla_json if args.mozilla_json else None + ) - check_endpoints(endpoints, args.ignore, mozilla_json) + check_endpoints(endpoints, args.ignore, mozilla_tls) if __name__ == "__main__": From 23423b8cedd95e2c38cd5506d2ef243e206b7773 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Fri, 28 Jun 2024 16:04:31 +0200 Subject: [PATCH 30/51] Rename cli args in test script Signed-off-by: Markus Hentsch --- Tests/iaas/secure-connections/tls-checker.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/iaas/secure-connections/tls-checker.py b/Tests/iaas/secure-connections/tls-checker.py index 6db8e6c94..d080c4123 100644 --- a/Tests/iaas/secure-connections/tls-checker.py +++ b/Tests/iaas/secure-connections/tls-checker.py @@ -269,13 +269,13 @@ def main(): help="Enable OpenStack SDK debug logging" ) parser.add_argument( - "--mozilla-json", type=str, + "--mozilla-profile-json", type=str, help="Path to the Mozilla TLS Profile JSON to be used as the basis " "for the checks (optional)", ) moz_tls_default_level = "intermediate" parser.add_argument( - "--mozilla-preset-level", type=str, + "--mozilla-profile-level", type=str, default=moz_tls_default_level, help=f"Name of the Mozilla TLS Profile configuration level name " f"(default: {moz_tls_default_level})", @@ -303,9 +303,9 @@ def main(): endpoints = endpoints_catalog["public"] mozilla_tls = MozillaTlsValidator( - args.mozilla_preset_level, + args.mozilla_profile_level, # load the Mozilla TLS Profile from JSON if specified - args.mozilla_json if args.mozilla_json else None + args.mozilla_profile_json if args.mozilla_profile_json else None ) check_endpoints(endpoints, args.ignore, mozilla_tls) From e9dacb86b88f6c7c7e146d6ea3061ec5951e2c26 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Fri, 28 Jun 2024 16:10:46 +0200 Subject: [PATCH 31/51] Add Mozilla TLS JSON copy and staging YAML entry Signed-off-by: Markus Hentsch --- .../mozilla-tls-profiles/5.7.json | 209 ++++++++++++++++++ .../mozilla-tls-profiles/README.md | 2 + Tests/testing/scs-compatible-test.yaml | 49 ++++ 3 files changed, 260 insertions(+) create mode 100644 Tests/iaas/secure-connections/mozilla-tls-profiles/5.7.json create mode 100644 Tests/iaas/secure-connections/mozilla-tls-profiles/README.md diff --git a/Tests/iaas/secure-connections/mozilla-tls-profiles/5.7.json b/Tests/iaas/secure-connections/mozilla-tls-profiles/5.7.json new file mode 100644 index 000000000..764aadaeb --- /dev/null +++ b/Tests/iaas/secure-connections/mozilla-tls-profiles/5.7.json @@ -0,0 +1,209 @@ +{ + "version": 5.7, + "href": "https://ssl-config.mozilla.org/guidelines/5.7.json", + "configurations": { + "modern": { + "certificate_curves": ["prime256v1", "secp384r1"], + "certificate_signatures": ["ecdsa-with-SHA256", "ecdsa-with-SHA384", "ecdsa-with-SHA512"], + "certificate_types": ["ecdsa"], + "ciphers": { + "caddy": [], + "go": [], + "iana": [], + "openssl": [] + }, + "ciphersuites": [ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256" + ], + "dh_param_size": null, + "ecdh_param_size": 256, + "hsts_min_age": 63072000, + "maximum_certificate_lifespan": 90, + "ocsp_staple": true, + "oldest_clients": ["Firefox 63", "Android 10.0", "Chrome 70", "Edge 75", "Java 11", "OpenSSL 1.1.1", "Opera 57", "Safari 12.1"], + "recommended_certificate_lifespan": 90, + "rsa_key_size": null, + "server_preferred_order": false, + "tls_curves": ["X25519", "prime256v1", "secp384r1"], + "tls_versions": ["TLSv1.3"] + }, + "intermediate": { + "certificate_curves": ["prime256v1", "secp384r1"], + "certificate_signatures": ["sha256WithRSAEncryption", "ecdsa-with-SHA256", "ecdsa-with-SHA384", "ecdsa-with-SHA512"], + "certificate_types": ["ecdsa", "rsa"], + "ciphers": { + "caddy": [ + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" + ], + "go": [ + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305" + ], + "iana": [ + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256" + ], + "openssl": [ + "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", + "DHE-RSA-CHACHA20-POLY1305" + ] + }, + "ciphersuites": [ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256" + ], + "dh_param_size": 2048, + "ecdh_param_size": 256, + "hsts_min_age": 63072000, + "maximum_certificate_lifespan": 366, + "ocsp_staple": true, + "oldest_clients": ["Firefox 27", "Android 4.4.2", "Chrome 31", "Edge", "IE 11 on Windows 7", "Java 8u31", "OpenSSL 1.0.1", "Opera 20", "Safari 9"], + "recommended_certificate_lifespan": 90, + "rsa_key_size": 2048, + "server_preferred_order": false, + "tls_curves": ["X25519", "prime256v1", "secp384r1"], + "tls_versions": ["TLSv1.2", "TLSv1.3"] + }, + "old": { + "certificate_curves": ["prime256v1", "secp384r1"], + "certificate_signatures": ["sha256WithRSAEncryption"], + "certificate_types": ["rsa"], + "ciphers": { + "caddy": [ + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384", + "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_3DES_EDE_CBC_SHA" + ], + "go": [ + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384", + "TLS_RSA_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_3DES_EDE_CBC_SHA" + ], + "iana": [ + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", + "TLS_RSA_WITH_AES_128_GCM_SHA256", + "TLS_RSA_WITH_AES_256_GCM_SHA384", + "TLS_RSA_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_AES_256_CBC_SHA256", + "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_RSA_WITH_AES_256_CBC_SHA", + "TLS_RSA_WITH_3DES_EDE_CBC_SHA" + ], + "openssl": [ + "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", + "DHE-RSA-CHACHA20-POLY1305", + "ECDHE-ECDSA-AES128-SHA256", + "ECDHE-RSA-AES128-SHA256", + "ECDHE-ECDSA-AES128-SHA", + "ECDHE-RSA-AES128-SHA", + "ECDHE-ECDSA-AES256-SHA384", + "ECDHE-RSA-AES256-SHA384", + "ECDHE-ECDSA-AES256-SHA", + "ECDHE-RSA-AES256-SHA", + "DHE-RSA-AES128-SHA256", + "DHE-RSA-AES256-SHA256", + "AES128-GCM-SHA256", + "AES256-GCM-SHA384", + "AES128-SHA256", + "AES256-SHA256", + "AES128-SHA", + "AES256-SHA", + "DES-CBC3-SHA" + ] + }, + "ciphersuites": [ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256" + ], + "dh_param_size": 1024, + "ecdh_param_size": 256, + "hsts_min_age": 63072000, + "maximum_certificate_lifespan": 366, + "ocsp_staple": true, + "oldest_clients": ["Firefox 1", "Android 2.3", "Chrome 1", "Edge 12", "IE8 on Windows XP", "Java 6", "OpenSSL 0.9.8", "Opera 5", "Safari 1"], + "recommended_certificate_lifespan": 90, + "rsa_key_size": 2048, + "server_preferred_order": true, + "tls_curves": ["X25519", "prime256v1", "secp384r1"], + "tls_versions": ["TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"] + } + } +} diff --git a/Tests/iaas/secure-connections/mozilla-tls-profiles/README.md b/Tests/iaas/secure-connections/mozilla-tls-profiles/README.md new file mode 100644 index 000000000..5e469ab8c --- /dev/null +++ b/Tests/iaas/secure-connections/mozilla-tls-profiles/README.md @@ -0,0 +1,2 @@ +Files in this folder are used for automated testing. +They are pulled from https://wiki.mozilla.org/Security/Server_Side_TLS#JSON_version_of_the_recommendations \ No newline at end of file diff --git a/Tests/testing/scs-compatible-test.yaml b/Tests/testing/scs-compatible-test.yaml index 5b37c8904..480223d27 100644 --- a/Tests/testing/scs-compatible-test.yaml +++ b/Tests/testing/scs-compatible-test.yaml @@ -1,6 +1,55 @@ name: SCS Compatible url: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Tests/scs-compatible.yaml +variables: + - os_cloud versions: + - version: v5 + standards: + - name: Secure Connections + url: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Standards/scs-01XX-v1-secure-connections.md + parameters: + - mozilla_tls_profile_version: "5.7" + - mozilla_tls_profile_preset: "intermediate" + checks: + - executable: ./iaas/secure-connections/tls-checker.py + args: --os-cloud {os_cloud} --mozilla-profile-json ./iaas/secure-connections/mozilla-tls-profiles/{mozilla_tls_profile_version}.json --mozilla-profile-level {mozilla_tls_profile_preset} + id: tls-configuration-check + - name: OpenStack Powered Compute v2022.11 + url: https://opendev.org/openinfra/interop/src/branch/master/guidelines/2022.11.json + # Unfortunately, no wrapper to run refstack yet, needs to be added + - name: Flavor naming + url: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Standards/scs-0100-v3-flavor-naming.md + checks: + - executable: ./iaas/flavor-naming/flavor-names-openstack.py + args: -c {os_cloud} --mand=./iaas/scs-0100-v3-flavors.yaml + # Note: --v2plus would outlaw the v1 flavor names. Don't do this yet. + id: flavor-name-check + - name: Entropy + url: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Standards/scs-0101-v1-entropy.md + checks: + - executable: ./iaas/entropy/entropy-check.py + args: -c {os_cloud} -d + id: entropy-check + - name: Image metadata + url: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Standards/scs-0102-v1-image-metadata.md + checks: + - executable: ./iaas/image-metadata/image-md-check.py + args: -c {os_cloud} -s -v + id: image-metadata-check + - name: Standard flavors + url: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Standards/scs-0103-v1-standard-flavors.md + checks: + - executable: ./iaas/standard-flavors/flavors-openstack.py + args: -c {os_cloud} -d ./iaas/scs-0103-v1-flavors.yaml + id: standard-flavors-check + - name: Standard images + url: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Standards/scs-0104-v1-standard-images.md + parameters: + image_spec: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Tests/iaas/scs-0104-v1-images.yaml + checks: + - executable: ./iaas/standard-images/images-openstack.py + args: -c {os_cloud} -d {image_spec} + id: standard-images-check - version: v4 standards: - name: Standard flavors From 8d92617349fa6083b56289582d8b8bd2a049365a Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Fri, 28 Jun 2024 16:24:49 +0200 Subject: [PATCH 32/51] Add remark about internal audits Signed-off-by: Markus Hentsch --- Standards/scs-01XX-v1-secure-connections.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Standards/scs-01XX-v1-secure-connections.md b/Standards/scs-01XX-v1-secure-connections.md index 86d8da243..132a9e0c4 100644 --- a/Standards/scs-01XX-v1-secure-connections.md +++ b/Standards/scs-01XX-v1-secure-connections.md @@ -262,6 +262,7 @@ See the [corresponding Design Considerations section](#libvirt-hypervisor-interf ## Conformance Tests Conformance tests are limited to communication channels exposed to users, such as the public API interfaces. +Internal channels and APIs are currently not part of the automated conformance tests because they are not exposed and cannot be audited without direct access to the infrastructure. There is a test suite in [`tls-checker.py`](https://github.com/SovereignCloudStack/standards/blob/main/Tests/iaas/secure-connections/tls-checker.py). The test suite connects to the OpenStack API and retrieves all public API endpoints from the service catalog. From 5f7ccd236f9e85620285c27ce97ee276c1a08a57 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Fri, 26 Jul 2024 17:40:47 +0200 Subject: [PATCH 33/51] Remove specific MQ SSL config examples, refer to docs Signed-off-by: Markus Hentsch --- Standards/scs-01XX-v1-secure-connections.md | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/Standards/scs-01XX-v1-secure-connections.md b/Standards/scs-01XX-v1-secure-connections.md index 132a9e0c4..4ea6b762a 100644 --- a/Standards/scs-01XX-v1-secure-connections.md +++ b/Standards/scs-01XX-v1-secure-connections.md @@ -218,18 +218,7 @@ You MAY refer to [TLS proxies and HTTP services](https://docs.openstack.org/secu ### Message Queue Connections - If using RabbitMQ or Qpid as the message queue service, the SSL functionality of the message broker MUST be enabled and used by the OpenStack services. See [Messaging transport security](https://docs.openstack.org/security-guide/messaging/security.html#messaging-transport-security). - - If using RabbitMQ, all OpenStack services' oslo.messaging configuration for RabbitMQ MUST specify options accordingly to enable SSL: - ```ini - [oslo_messaging_rabbit] - ssl = true - ssl_ca_file = /path/to/file - ssl_key_file = - ssl_cert_file = - ``` - (`ssl_ca_file` MUST be set to the path of the CA certificate, `ssl_key_file` and `ssl_cert_file` for client certificates are OPTIONAL) - - If using Qpid, the OpenStack services' oslo.messaging configuration for Qpid MUST set the `qpid_protocol` option to `ssl` to enable SSL. -- If using Apache Kafka, the server listener MUST be configured to accept SSL connections. See [Apache Kafka Listener Configuration](https://kafka.apache.org/documentation/#listener_configuration). - - The OpenStack services' oslo.messaging configuration for Kafka MUST specify `security_protocol` as either `SSL` or `SASL_SSL` and the related options appropriately. See [Kafka Driver Options](https://docs.openstack.org/oslo.messaging/latest/admin/kafka.html#driver-options). +- If using Apache Kafka, the server listener MUST be configured to accept SSL connections. See [Apache Kafka Listener Configuration](https://kafka.apache.org/documentation/#listener_configuration). OpenStack services MUST be configured to use an SSL setting for the Kafka driver. See [Kafka Driver Security Options](https://docs.openstack.org/oslo.messaging/latest/admin/kafka.html#security-options). ### Hypervisor and Live Migration Connections From 71a663c5e8cd4204db5208e43b74e56b8a2be878 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Mon, 19 Aug 2024 17:16:49 +0200 Subject: [PATCH 34/51] Align header naming with latest standards template Signed-off-by: Markus Hentsch --- Standards/scs-01XX-v1-secure-connections.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Standards/scs-01XX-v1-secure-connections.md b/Standards/scs-01XX-v1-secure-connections.md index 4ea6b762a..a0a69bbfd 100644 --- a/Standards/scs-01XX-v1-secure-connections.md +++ b/Standards/scs-01XX-v1-secure-connections.md @@ -13,7 +13,7 @@ To protect this data from both tampering and unintended disclosure, communicatio For this reason, the [SCS project](https://scs.community) standardizes the use of common protection mechanisms for communication channels in OpenStack infrastructures. -### Glossary +## Terminology | Term | Meaning | |---|---| @@ -192,7 +192,7 @@ When an internal protection mechanism is implemented by the CSP it cannot be ver Thus, the SCS community is unable to fully assess a CSPs conformance to this standard without a dedicated audit of the infrastructure. -## Decision +## Standard This standard will mandate or recommend appropriate measures for securing the communication channels based on existing standards and recommendations. It will reference documents like the [OpenStack Security Guide](https://docs.openstack.org/security-guide/) where applicable. From c9984db521159e4c59aad955d7cb464cfdbfcaeb Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Thu, 12 Sep 2024 16:21:02 +0200 Subject: [PATCH 35/51] Add storage channels Signed-off-by: Markus Hentsch --- Standards/scs-01XX-v1-secure-connections.md | 26 +++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Standards/scs-01XX-v1-secure-connections.md b/Standards/scs-01XX-v1-secure-connections.md index a0a69bbfd..00e889af8 100644 --- a/Standards/scs-01XX-v1-secure-connections.md +++ b/Standards/scs-01XX-v1-secure-connections.md @@ -58,6 +58,10 @@ The following overview will classify the main communication channels. | 6 | Nova VM migration traffic | Nova VM migration data transfer traffic between compute nodes | QEMU-native TLS | | 7 | External Neutron network traffic | VM-related traffic between the network/controller nodes and external networks (e.g. internet) established through routed provider networks and floating IPs | VPN | | 8 | Internal Neutron network traffic | Traffic within Neutron SDN networks exchanged between internal systems such as network/controller and compute nodes | WireGuard | +| 9 | Storage network frontend traffic | Traffic exchanged between OpenStack and network storage backends (e.g. Ceph) | N/A* | +| 10 | Storage network replication traffic | Traffic exchanged between individual storage nodes within the network storage backend for replication purposes | N/A* | + +\* The characteristics of the storage network traffic is highly specific to the individual storage backend and no generic solution can be stated here. Notes about the classification categories and implications: @@ -69,6 +73,10 @@ Notes about the classification categories and implications: 6. For protecting the data transferred between compute nodes during live-migration of VMs, [Nova offers support for QEMU-native TLS](https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html). As an alternative, SSH is also a channel that Nova can be configured to use between hosts for this but requires passwordless SSH keys with root access to all other compute nodes which in turn requires further hardening. 7. Neutron's external network traffic leaves the IaaS infrastructure. This part is twofold: connections initiated by the VMs themselves (egress) and connections reaching VMs from the outside (ingress). The CSP cannot influence the egress connections but can offer VPNaaS for the ingress direction. 8. Neutron's internal network traffic is one of the hardest aspects to address. Due to the highly dynamic nature of SDN, connection endpoints and relations are constantly changing. There is no holistic approach currently offered or recommended by OpenStack itself. Encrypted tunnels could be established between all involved nodes but would require a scalable solution and reliable key management. WireGuard could be considered a good starting point for this. A per-tenant/per-customer encryption remains very hard to establish this way though. +9. The available means of securing frontend storage communication are dependent on the protocol used for communication between OpenStack and the storage backend. Some storage solutions and protocols might offer authentication and encryption functionality by default but that cannot be assumed to be the case for every possible backend. Furthermore, storage is highly sensitive to latency and performance impacts imposed by such measures. Due to the fact that OpenStack's volume encryption functionality encrypts block storage data before it enters the storage network, an unsecured communication channel may be considered not as much of a problem here as it is for other channels\*. +10. Storage network replication traffic is highly specific to the storage backend solution and its method of operation. For some backends this channel might not even exists, depending on their architecture. As such, in most cases it is up to the storage solution to provide adequate measures for protection of this channel. As with the frontend storage traffic, due to the possible at-rest encryption implemented by OpenStack, only already encrypted data is transferred here for some resources\*. + +\* Encryption of data implemented by OpenStack before it is passed to the storage backend currently only applies to block data of volumes that use an encrypted volume type. Other data (e.g. of unencrypted volumes, images) is transferred to and from the storage in plaintext. ### libvirt Hypervisor Interface on Compute Nodes @@ -139,6 +147,18 @@ For this reason, the standard should reference widely accepted best practices an [Mozilla publishes and maintains](https://wiki.mozilla.org/Security/Server_Side_TLS) TLS recommendations and corresponding presets for configuration and testing. Considering Mozilla's well-established name in the internet and open source communities, this could qualify as a good basis for the standard concerning the TLS configurations. +### Storage network protection + +As stated in the overview of communication channels, the existence and characteristics of the storage frontend and replication networks are highly specific to the storage backend solution in use. +In conjunction with the fact that storage performance is easily impacted by anything that introduces latency or reduces throughput on these channels, there is no easy recommendation on how to secure them that can be made here. + +This is partially mitigated by OpenStack's ability to encrypt storage data before it enters the storage backend, protecting the data regardless of the storage channels characteristics. +But this only applies to block data of volumes that use an encrypted volume type and does not apply to other data put into the storage backend by OpenStack, for example images. +As such, this does not fully address unsecured storage channels. + +However, requiring the network storage channels to be dedicated physical connections separate from the other channels like tenant VM traffic or API communication can increase both the reliability as well as security of the storage connections. +Therefore this standard should at least recommend a dedicated network infrastructure to be implemented for the storage if network storage backends are used, such as Ceph. + ### Options considered #### Option 1: fully mandate securing all channels without differentiation @@ -239,6 +259,12 @@ See the [corresponding Design Considerations section](#libvirt-hypervisor-interf - As an OPTIONAL measure to protect Neutron SDN traffic between physical nodes within the infrastructure, encrypted tunnels MAY be established between nodes involved in Neutron networks, such as compute and network controller nodes, at the network interfaces configured in Neutron (e.g. via WireGuard or similar solutions). +### Storage Connections + +- For storage backends that are connected to OpenStack over the network, the network connections between the OpenStack components and the storage backend SHOULD be located on a separate physical network with dedicated interfaces at the involved nodes. +- For storage backends that transfer replication data between individual storage nodes, the connections between those nodes SHOULD be implemented by a dedicated physical network. +- Where applicable, storage traffic between OpenStack components and the storage backend (frontend traffic) as well as storage replication traffic between storage nodes themselves (backend traffic) MAY be encrypted using the storage protocols native security features (if any) or a generic solution such as WireGuard. + ## Related Documents - [OpenStack Security Guide](https://docs.openstack.org/security-guide/) From 540530440376f9d503e8eebd95f98e748a7395d6 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Fri, 18 Oct 2024 16:20:27 +0200 Subject: [PATCH 36/51] Assign document number 0122 Signed-off-by: Markus Hentsch --- ...v1-secure-connections.md => scs-0122-v1-secure-connections.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Standards/{scs-01XX-v1-secure-connections.md => scs-0122-v1-secure-connections.md} (100%) diff --git a/Standards/scs-01XX-v1-secure-connections.md b/Standards/scs-0122-v1-secure-connections.md similarity index 100% rename from Standards/scs-01XX-v1-secure-connections.md rename to Standards/scs-0122-v1-secure-connections.md From 2c47877eba61e9c489268f8badd1c8cb91ffc053 Mon Sep 17 00:00:00 2001 From: Markus Hentsch Date: Fri, 18 Oct 2024 16:31:24 +0200 Subject: [PATCH 37/51] Update scs-compatible-test.yaml Signed-off-by: Markus Hentsch --- Tests/testing/scs-compatible-test.yaml | 52 ++++++++++---------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/Tests/testing/scs-compatible-test.yaml b/Tests/testing/scs-compatible-test.yaml index 480223d27..2d37c6bf3 100644 --- a/Tests/testing/scs-compatible-test.yaml +++ b/Tests/testing/scs-compatible-test.yaml @@ -6,50 +6,38 @@ versions: - version: v5 standards: - name: Secure Connections - url: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Standards/scs-01XX-v1-secure-connections.md + url: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Standards/scs-0122-v1-secure-connections.md parameters: - mozilla_tls_profile_version: "5.7" - mozilla_tls_profile_preset: "intermediate" - checks: + check_tools: - executable: ./iaas/secure-connections/tls-checker.py args: --os-cloud {os_cloud} --mozilla-profile-json ./iaas/secure-connections/mozilla-tls-profiles/{mozilla_tls_profile_version}.json --mozilla-profile-level {mozilla_tls_profile_preset} id: tls-configuration-check - - name: OpenStack Powered Compute v2022.11 - url: https://opendev.org/openinfra/interop/src/branch/master/guidelines/2022.11.json - # Unfortunately, no wrapper to run refstack yet, needs to be added - - name: Flavor naming - url: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Standards/scs-0100-v3-flavor-naming.md - checks: - - executable: ./iaas/flavor-naming/flavor-names-openstack.py - args: -c {os_cloud} --mand=./iaas/scs-0100-v3-flavors.yaml - # Note: --v2plus would outlaw the v1 flavor names. Don't do this yet. - id: flavor-name-check - - name: Entropy - url: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Standards/scs-0101-v1-entropy.md - checks: - - executable: ./iaas/entropy/entropy-check.py - args: -c {os_cloud} -d - id: entropy-check - - name: Image metadata - url: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Standards/scs-0102-v1-image-metadata.md - checks: - - executable: ./iaas/image-metadata/image-md-check.py - args: -c {os_cloud} -s -v - id: image-metadata-check - name: Standard flavors url: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Standards/scs-0103-v1-standard-flavors.md - checks: + check_tools: - executable: ./iaas/standard-flavors/flavors-openstack.py - args: -c {os_cloud} -d ./iaas/scs-0103-v1-flavors.yaml - id: standard-flavors-check + args: "./iaas/scs-0103-v1-flavors.yaml" - name: Standard images url: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Standards/scs-0104-v1-standard-images.md - parameters: - image_spec: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Tests/iaas/scs-0104-v1-images.yaml - checks: + check_tools: - executable: ./iaas/standard-images/images-openstack.py - args: -c {os_cloud} -d {image_spec} - id: standard-images-check + args: "./iaas/scs-0104-v1-flavors.yaml" + - name: Flavor naming + url: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Standards/scs-0100-v3-flavor-naming.md + check_tools: + - executable: ./iaas/flavor-naming/flavor-names-openstack.py + args: "--mand=./iaas/scs-0100-v3-flavors.yaml" + - name: Image metadata + url: https://raw.githubusercontent.com/SovereignCloudStack/standards/main/Standards/scs-0102-v1-image-metadata.md + check_tools: + - executable: ./iaas/image-metadata/image-md-check.py + args: -s -v + - name: OpenStack Powered Compute v2022.11 + url: https://opendev.org/openinfra/interop/src/branch/master/guidelines/2022.11.json + condition: mandatory + # Unfortunately, no wrapper to run refstack yet, needs to be added - version: v4 standards: - name: Standard flavors From b57c3b500417beaf4534e5dd3a417eaf70a253d5 Mon Sep 17 00:00:00 2001 From: Anja Strunk Date: Tue, 19 Nov 2024 14:55:11 +0100 Subject: [PATCH 38/51] Remove bare URLs Signed-off-by: Anja Strunk --- Standards/scs-0122-v1-secure-connections.md | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/Standards/scs-0122-v1-secure-connections.md b/Standards/scs-0122-v1-secure-connections.md index 00e889af8..b3ab4a8dd 100644 --- a/Standards/scs-0122-v1-secure-connections.md +++ b/Standards/scs-0122-v1-secure-connections.md @@ -88,26 +88,18 @@ As such, severe risks are associated with unauthorized access to this interface This is acknowledged in the OpenStack Security Note [OSSN-0007](https://wiki.openstack.org/wiki/OSSN/OSSN-0007), which recommends either configuring SASL and/or TLS for libvirt connections or utilizing the UNIX socket in combination with SSH. -The OpenStack kolla-ansible documentation on Nova libvirt connections states[^1]: +The OpenStack [kolla-ansible documentation](https://docs.openstack.org/kolla-ansible/latest/reference/compute/libvirt-guide.html#sasl-authentication) on Nova libvirt connections state: > This should not be considered as providing a secure, encrypted channel, since the username/password SASL mechanisms available for TCP are no longer considered cryptographically secure. -[^1]: https://docs.openstack.org/kolla-ansible/latest/reference/compute/libvirt-guide.html#sasl-authentication - This leaves only TLS or UNIX socket with SSH as viable options for securing the channel. #### TLS for libvirt and live migration -Since the Stein release of OpenStack, Nova supports QEMU-native TLS[^2] which protects the migration data streams using TLS. -It requires to add `LIBVIRTD_ARGS="--listen"` to the QEMU configuration, which will lead to TLS being active on the libvirt interface per default (due to `listen_tls` defaulting to being enabled[^3]). +Since the Stein release of OpenStack, Nova supports [QEMU-native TLS](https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html) which protects the migration data streams using TLS. +It requires to add `LIBVIRTD_ARGS="--listen"` to the [QEMU configuration](https://libvirt.org/remote.html#libvirtd-configuration-file), which will lead to TLS being active on the libvirt interface per default (due to `listen_tls` defaulting to being enabled). This protects data streams for migration as well as the hypervisor control channel data flow with TLS but does not restrict access. -Client certificates must be deployed additionally and libvirt configured accordingly[^4] in order to meaningfully restrict access to the interface as advised by the OSSN-0007 document. - -[^2]: https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html - -[^3]: https://libvirt.org/remote.html#libvirtd-configuration-file - -[^4]: https://wiki.libvirt.org/TLSDaemonConfiguration.html#restricting-access +Client certificates must be deployed additionally and libvirt configured accordingly[^4] in order to meaningfully restrict access to the interface as advised by the OSSN-0007 document, see restricting-access in [Libvirt doc](https://wiki.libvirt.org/TLSDaemonConfiguration.html#restricting-access). #### Local UNIX socket and SSH live migration From 2ae9612892fe130ea67f360761c3ce5aa3d8eb6f Mon Sep 17 00:00:00 2001 From: Anja Strunk Date: Tue, 19 Nov 2024 14:57:30 +0100 Subject: [PATCH 39/51] Remove tailing whitespaces Signed-off-by: Anja Strunk --- Standards/scs-0122-v1-secure-connections.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Standards/scs-0122-v1-secure-connections.md b/Standards/scs-0122-v1-secure-connections.md index b3ab4a8dd..b2df96743 100644 --- a/Standards/scs-0122-v1-secure-connections.md +++ b/Standards/scs-0122-v1-secure-connections.md @@ -104,7 +104,7 @@ Client certificates must be deployed additionally and libvirt configured accordi #### Local UNIX socket and SSH live migration As an alternative to the TLS setup, libvirt can be configured to use a local UNIX socket and Nova can be configured to use SSH to this socket for live migrations instead. -The regular libvirt port can then be limited to localhost (`127.0.0.1`) which will make it inaccessible from outside the host but still enables local connections to use it. +The regular libvirt port can then be limited to localhost (`127.0.0.1`) which will make it inaccessible from outside the host but still enables local connections to use it. The challenge of this approach lies in restricting the SSH access on the compute nodes appropriately to avoid full root access across compute nodes for the SSH user identity that Nova will use for live migration. This can be addressed by restricting the command set that is available and the paths that are accessible to these target SSH user identities on compute nodes, limiting them to the scope strictly required by the live migration. @@ -192,7 +192,7 @@ Upon closer inspection, this consists of two problems to address: When considering problem no. 1 in an isolated fashion, the QEMU-native TLS approach could be considered preferable simply due to it being officially recommended and documented by upstream OpenStack and tightly integrated into QEMU. -However, once problem no. 2 is taken into account, the choice does not seem as obvious anymore due to the fact that in order to properly authenticate clients in the TLS case, X.509 client certificate authentication along with a corresponding PKI as well as key management would be required. +However, once problem no. 2 is taken into account, the choice does not seem as obvious anymore due to the fact that in order to properly authenticate clients in the TLS case, X.509 client certificate authentication along with a corresponding PKI as well as key management would be required. Although similar aspects would be relevant for the SSH approach where SSH key and identity management as well as proper permission restriction would need to be implemented, the SSH approach could turn out less complex due to the fact that the foundation for SSH identities most likely already exists on a node-level and does not need to rely on a full PKI. To properly compare both possible approaches of securing the libvirt interface, extensive testing and evaulation would be necessary along with a sophisticated key and node identity management for compute nodes which this standard alone does not provide. From b6076a5b4c131267da1ff298c64c09c93a5b1010 Mon Sep 17 00:00:00 2001 From: Anja Strunk Date: Tue, 19 Nov 2024 15:00:43 +0100 Subject: [PATCH 40/51] Fix markdown linter Signed-off-by: Anja Strunk --- Tests/iaas/secure-connections/mozilla-tls-profiles/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/iaas/secure-connections/mozilla-tls-profiles/README.md b/Tests/iaas/secure-connections/mozilla-tls-profiles/README.md index 5e469ab8c..91b812712 100644 --- a/Tests/iaas/secure-connections/mozilla-tls-profiles/README.md +++ b/Tests/iaas/secure-connections/mozilla-tls-profiles/README.md @@ -1,2 +1,4 @@ +# Mozilla TLS Profiles + Files in this folder are used for automated testing. -They are pulled from https://wiki.mozilla.org/Security/Server_Side_TLS#JSON_version_of_the_recommendations \ No newline at end of file +They are pulled from https://wiki.mozilla.org/Security/Server_Side_TLS#JSON_version_of_the_recommendations From aeaab38121ade776cad06cc731597aef01ad48d9 Mon Sep 17 00:00:00 2001 From: Anja Strunk Date: Tue, 19 Nov 2024 15:02:24 +0100 Subject: [PATCH 41/51] remove bare URLs Signed-off-by: Anja Strunk --- Tests/iaas/secure-connections/mozilla-tls-profiles/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/iaas/secure-connections/mozilla-tls-profiles/README.md b/Tests/iaas/secure-connections/mozilla-tls-profiles/README.md index 91b812712..08c1328fd 100644 --- a/Tests/iaas/secure-connections/mozilla-tls-profiles/README.md +++ b/Tests/iaas/secure-connections/mozilla-tls-profiles/README.md @@ -1,4 +1,4 @@ # Mozilla TLS Profiles Files in this folder are used for automated testing. -They are pulled from https://wiki.mozilla.org/Security/Server_Side_TLS#JSON_version_of_the_recommendations +They are pulled from [Mozilla Wiki: Security/Server Side TLS](https://wiki.mozilla.org/Security/Server_Side_TLS#JSON_version_of_the_recommendations) From 837c3e12c8fd3df3aa24931daa5a59f17a14e20f Mon Sep 17 00:00:00 2001 From: Anja Strunk Date: Mon, 25 Nov 2024 11:21:34 +0100 Subject: [PATCH 42/51] Fix markdown lint errors Signed-off-by: Anja Strunk --- Standards/scs-0214-v2-k8s-node-distribution.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Standards/scs-0214-v2-k8s-node-distribution.md b/Standards/scs-0214-v2-k8s-node-distribution.md index 3b4915492..04e5d3518 100644 --- a/Standards/scs-0214-v2-k8s-node-distribution.md +++ b/Standards/scs-0214-v2-k8s-node-distribution.md @@ -83,7 +83,7 @@ These labels MUST be kept up to date with the current state of the deployment. - `topology.kubernetes.io/zone` - Corresponds with the label described in [K8s labels documentation][k8s-labels-docs]. + Corresponds with the label described in [K8s labels documentation](https://kubernetes.io/docs/reference/labels-annotations-taints/#topologykubernetesiozone). It provides a logical zone of failure on the side of the provider, e.g. a server rack in the same electrical circuit or multiple machines bound to the internet through a singular network structure. How this is defined exactly is up to the plans of the provider. @@ -125,5 +125,5 @@ requirements regarding node labeling. [k8s-ha]: https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/ [k8s-large-clusters]: https://kubernetes.io/docs/setup/best-practices/cluster-large/ [scs-0213-v1]: https://github.com/SovereignCloudStack/standards/blob/main/Standards/scs-0213-v1-k8s-nodes-anti-affinity.md -[k8s-labels-docs]: https://kubernetes.io/docs/reference/labels-annotations-taints/#topologykubernetesiozone +[k8s-labels-docs]: [k8s-zones]: https://kubernetes.io/docs/setup/best-practices/multiple-zones/ From 9202d9218840dbc74a43fd9e8183e09d19d0a0c6 Mon Sep 17 00:00:00 2001 From: Anja Strunk Date: Mon, 25 Nov 2024 11:25:14 +0100 Subject: [PATCH 43/51] Fix markdown lint errors Signed-off-by: Anja Strunk --- Standards/scs-0214-v2-k8s-node-distribution.md | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/Standards/scs-0214-v2-k8s-node-distribution.md b/Standards/scs-0214-v2-k8s-node-distribution.md index 04e5d3518..f3105cc8d 100644 --- a/Standards/scs-0214-v2-k8s-node-distribution.md +++ b/Standards/scs-0214-v2-k8s-node-distribution.md @@ -41,15 +41,15 @@ of the whole cluster. ## Design Considerations Most design considerations of this standard follow the previously written Decision Record -[Kubernetes Nodes Anti Affinity][scs-0213-v1] as well as the Kubernetes documents about -[High Availability][k8s-ha] and [Best practices for large clusters][k8s-large-clusters]. +[Kubernetes Nodes Anti Affinity](https://github.com/SovereignCloudStack/standards/blob/main/Standards/)[scs-0213-v1]) as well as the Kubernetes documents about +[High Availability](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/) and [Best practices for large clusters](https://kubernetes.io/docs/setup/best-practices/cluster-large/). SCS wishes to prefer distributed, highly-available systems due to their obvious advantages like fault-tolerance and data redundancy. But it also understands the costs and overhead for the providers associated with this effort, since the infrastructure needs to have hardware which will just be used to provide fail-over safety or duplication. -The document [Best practices for large clusters][k8s-large-clusters] describes the concept of a failure zone. +The document [Best practices for large clusters](https://kubernetes.io/docs/setup/best-practices/cluster-large/) describes the concept of a failure zone. This term isn't defined any further, but can in this context be described as a number of physical (computing) machines in such a vicinity to each other (either through physical or logical interconnection in some way), that specific problems inside this zone would put @@ -67,7 +67,7 @@ This standard formulates the requirement for the distribution of Kubernetes node to provide a fault-tolerant and available Kubernetes cluster infrastructure. The control plane nodes MUST be distributed over multiple physical machines. -Kubernetes provides [best-practices][k8s-zones] on this topic, which are also RECOMMENDED by SCS. +Kubernetes provides [best-practices](https://kubernetes.io/docs/setup/best-practices/multiple-zones/) on this topic, which are also RECOMMENDED by SCS. At least one control plane instance MUST be run in each "failure zone" used for the cluster, more instances per "failure zone" are possible to provide fault-tolerance inside a zone. @@ -92,7 +92,7 @@ These labels MUST be kept up to date with the current state of the deployment. - `topology.kubernetes.io/region` - Corresponds with the label described in [K8s labels documentation][k8s-labels-docs]. + Corresponds with the label described in [K8s labels documentation](https://kubernetes.io/docs/reference/labels-annotations-taints/#topologykubernetesiozone). It describes the combination of one or more failure zones into a region or domain, therefore showing a larger entity of logical failure zone. An example for this could be a building containing racks that are put into such a zone, since they're all prone to failure, if e.g. @@ -121,9 +121,3 @@ It also produces warnings and informational outputs, e.g., if labels don't seem This is version 2 of the standard; it extends [version 1](scs-0214-v1-k8s-node-distribution.md) with the requirements regarding node labeling. - -[k8s-ha]: https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/ -[k8s-large-clusters]: https://kubernetes.io/docs/setup/best-practices/cluster-large/ -[scs-0213-v1]: https://github.com/SovereignCloudStack/standards/blob/main/Standards/scs-0213-v1-k8s-nodes-anti-affinity.md -[k8s-labels-docs]: -[k8s-zones]: https://kubernetes.io/docs/setup/best-practices/multiple-zones/ From a687c61f8a347ef0bf7671c8d0cd9262bc299656 Mon Sep 17 00:00:00 2001 From: Anja Strunk Date: Mon, 25 Nov 2024 11:55:56 +0100 Subject: [PATCH 44/51] Fix markdown lint errors Signed-off-by: Anja Strunk --- Standards/scs-0214-v2-k8s-node-distribution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Standards/scs-0214-v2-k8s-node-distribution.md b/Standards/scs-0214-v2-k8s-node-distribution.md index f3105cc8d..6b969ce82 100644 --- a/Standards/scs-0214-v2-k8s-node-distribution.md +++ b/Standards/scs-0214-v2-k8s-node-distribution.md @@ -41,7 +41,7 @@ of the whole cluster. ## Design Considerations Most design considerations of this standard follow the previously written Decision Record -[Kubernetes Nodes Anti Affinity](https://github.com/SovereignCloudStack/standards/blob/main/Standards/)[scs-0213-v1]) as well as the Kubernetes documents about +[Kubernetes Nodes Anti Affinity](https://github.com/SovereignCloudStack/standards/blob/main/Standards/scs-0213-v1-k8s-nodes-anti-affinity.md) as well as the Kubernetes documents about [High Availability](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/) and [Best practices for large clusters](https://kubernetes.io/docs/setup/best-practices/cluster-large/). SCS wishes to prefer distributed, highly-available systems due to their obvious advantages From 9efbaebeebf30dac0baffdb7b9804be74fffa995 Mon Sep 17 00:00:00 2001 From: Anja Strunk Date: Mon, 25 Nov 2024 11:58:05 +0100 Subject: [PATCH 45/51] Fix markdown lint errors Signed-off-by: Anja Strunk --- Standards/scs-0214-v2-k8s-node-distribution.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Standards/scs-0214-v2-k8s-node-distribution.md b/Standards/scs-0214-v2-k8s-node-distribution.md index 6b969ce82..d99da2999 100644 --- a/Standards/scs-0214-v2-k8s-node-distribution.md +++ b/Standards/scs-0214-v2-k8s-node-distribution.md @@ -83,12 +83,6 @@ These labels MUST be kept up to date with the current state of the deployment. - `topology.kubernetes.io/zone` - Corresponds with the label described in [K8s labels documentation](https://kubernetes.io/docs/reference/labels-annotations-taints/#topologykubernetesiozone). - It provides a logical zone of failure on the side of the provider, e.g. a server rack - in the same electrical circuit or multiple machines bound to the internet through a - singular network structure. How this is defined exactly is up to the plans of the provider. - The field gets autopopulated most of the time by either the kubelet or external mechanisms - like the cloud controller. - `topology.kubernetes.io/region` From b96fe9294fa5019bffe7e1bebec264ce13124767 Mon Sep 17 00:00:00 2001 From: Anja Strunk Date: Mon, 25 Nov 2024 12:00:00 +0100 Subject: [PATCH 46/51] Fix markdown lint errors Signed-off-by: Anja Strunk --- .../scs-0214-v1-k8s-node-distribution.md | 3 +-- .../scs-0214-v2-k8s-node-distribution.md | 22 ++++++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Standards/scs-0214-v1-k8s-node-distribution.md b/Standards/scs-0214-v1-k8s-node-distribution.md index ce70e605e..03b9ff044 100644 --- a/Standards/scs-0214-v1-k8s-node-distribution.md +++ b/Standards/scs-0214-v1-k8s-node-distribution.md @@ -83,5 +83,4 @@ If the standard is used by a provider, the following decisions are binding and v [k8s-ha]: https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/ [k8s-large-clusters]: https://kubernetes.io/docs/setup/best-practices/cluster-large/ -[scs-0213-v1]: https://github.com/SovereignCloudStack/standards/blob/main/Standards/scs-0213-v1-k8s-nodes-anti-affinity.md -[k8s-labels-docs]: https://kubernetes.io/docs/reference/labels-annotations-taints/#topologykubernetesiozone +[scs-0213-v1]: https://github.com/SovereignCloudStack/standards/blob/main/Standards/scs-0213-v1-k8s-nodes-anti-affinity.md \ No newline at end of file diff --git a/Standards/scs-0214-v2-k8s-node-distribution.md b/Standards/scs-0214-v2-k8s-node-distribution.md index d99da2999..3b4915492 100644 --- a/Standards/scs-0214-v2-k8s-node-distribution.md +++ b/Standards/scs-0214-v2-k8s-node-distribution.md @@ -41,15 +41,15 @@ of the whole cluster. ## Design Considerations Most design considerations of this standard follow the previously written Decision Record -[Kubernetes Nodes Anti Affinity](https://github.com/SovereignCloudStack/standards/blob/main/Standards/scs-0213-v1-k8s-nodes-anti-affinity.md) as well as the Kubernetes documents about -[High Availability](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/) and [Best practices for large clusters](https://kubernetes.io/docs/setup/best-practices/cluster-large/). +[Kubernetes Nodes Anti Affinity][scs-0213-v1] as well as the Kubernetes documents about +[High Availability][k8s-ha] and [Best practices for large clusters][k8s-large-clusters]. SCS wishes to prefer distributed, highly-available systems due to their obvious advantages like fault-tolerance and data redundancy. But it also understands the costs and overhead for the providers associated with this effort, since the infrastructure needs to have hardware which will just be used to provide fail-over safety or duplication. -The document [Best practices for large clusters](https://kubernetes.io/docs/setup/best-practices/cluster-large/) describes the concept of a failure zone. +The document [Best practices for large clusters][k8s-large-clusters] describes the concept of a failure zone. This term isn't defined any further, but can in this context be described as a number of physical (computing) machines in such a vicinity to each other (either through physical or logical interconnection in some way), that specific problems inside this zone would put @@ -67,7 +67,7 @@ This standard formulates the requirement for the distribution of Kubernetes node to provide a fault-tolerant and available Kubernetes cluster infrastructure. The control plane nodes MUST be distributed over multiple physical machines. -Kubernetes provides [best-practices](https://kubernetes.io/docs/setup/best-practices/multiple-zones/) on this topic, which are also RECOMMENDED by SCS. +Kubernetes provides [best-practices][k8s-zones] on this topic, which are also RECOMMENDED by SCS. At least one control plane instance MUST be run in each "failure zone" used for the cluster, more instances per "failure zone" are possible to provide fault-tolerance inside a zone. @@ -83,10 +83,16 @@ These labels MUST be kept up to date with the current state of the deployment. - `topology.kubernetes.io/zone` + Corresponds with the label described in [K8s labels documentation][k8s-labels-docs]. + It provides a logical zone of failure on the side of the provider, e.g. a server rack + in the same electrical circuit or multiple machines bound to the internet through a + singular network structure. How this is defined exactly is up to the plans of the provider. + The field gets autopopulated most of the time by either the kubelet or external mechanisms + like the cloud controller. - `topology.kubernetes.io/region` - Corresponds with the label described in [K8s labels documentation](https://kubernetes.io/docs/reference/labels-annotations-taints/#topologykubernetesiozone). + Corresponds with the label described in [K8s labels documentation][k8s-labels-docs]. It describes the combination of one or more failure zones into a region or domain, therefore showing a larger entity of logical failure zone. An example for this could be a building containing racks that are put into such a zone, since they're all prone to failure, if e.g. @@ -115,3 +121,9 @@ It also produces warnings and informational outputs, e.g., if labels don't seem This is version 2 of the standard; it extends [version 1](scs-0214-v1-k8s-node-distribution.md) with the requirements regarding node labeling. + +[k8s-ha]: https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/ +[k8s-large-clusters]: https://kubernetes.io/docs/setup/best-practices/cluster-large/ +[scs-0213-v1]: https://github.com/SovereignCloudStack/standards/blob/main/Standards/scs-0213-v1-k8s-nodes-anti-affinity.md +[k8s-labels-docs]: https://kubernetes.io/docs/reference/labels-annotations-taints/#topologykubernetesiozone +[k8s-zones]: https://kubernetes.io/docs/setup/best-practices/multiple-zones/ From 666b549822878c9410e454bddc31efabc76a64ab Mon Sep 17 00:00:00 2001 From: Anja Strunk Date: Mon, 25 Nov 2024 12:05:45 +0100 Subject: [PATCH 47/51] Change verison number of secure connection standard as it conflicts with node to node encryption DR Signed-off-by: Anja Strunk --- ...v1-secure-connections.md => scs-0125-v1-secure-connections.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Standards/{scs-0122-v1-secure-connections.md => scs-0125-v1-secure-connections.md} (100%) diff --git a/Standards/scs-0122-v1-secure-connections.md b/Standards/scs-0125-v1-secure-connections.md similarity index 100% rename from Standards/scs-0122-v1-secure-connections.md rename to Standards/scs-0125-v1-secure-connections.md From 3dbb7d7ae8ddb23cf7da913c6bc0deb7ef2da5b1 Mon Sep 17 00:00:00 2001 From: Anja Strunk Date: Mon, 25 Nov 2024 12:10:37 +0100 Subject: [PATCH 48/51] Add new linke char at the end of file to fix MD047 Signed-off-by: Anja Strunk --- Standards/scs-0214-v1-k8s-node-distribution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Standards/scs-0214-v1-k8s-node-distribution.md b/Standards/scs-0214-v1-k8s-node-distribution.md index 03b9ff044..7e48e1389 100644 --- a/Standards/scs-0214-v1-k8s-node-distribution.md +++ b/Standards/scs-0214-v1-k8s-node-distribution.md @@ -83,4 +83,4 @@ If the standard is used by a provider, the following decisions are binding and v [k8s-ha]: https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/ [k8s-large-clusters]: https://kubernetes.io/docs/setup/best-practices/cluster-large/ -[scs-0213-v1]: https://github.com/SovereignCloudStack/standards/blob/main/Standards/scs-0213-v1-k8s-nodes-anti-affinity.md \ No newline at end of file +[scs-0213-v1]: https://github.com/SovereignCloudStack/standards/blob/main/Standards/scs-0213-v1-k8s-nodes-anti-affinity.md From 4c75d5970d5789a0f69b20fc25c8177f8085458f Mon Sep 17 00:00:00 2001 From: Anja Strunk Date: Mon, 25 Nov 2024 12:33:14 +0100 Subject: [PATCH 49/51] Replace absolute dead links with relative links Signed-off-by: Anja Strunk --- Standards/scs-0125-v1-secure-connections.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Standards/scs-0125-v1-secure-connections.md b/Standards/scs-0125-v1-secure-connections.md index b2df96743..bf50c6f69 100644 --- a/Standards/scs-0125-v1-secure-connections.md +++ b/Standards/scs-0125-v1-secure-connections.md @@ -271,7 +271,7 @@ See the [corresponding Design Considerations section](#libvirt-hypervisor-interf Conformance tests are limited to communication channels exposed to users, such as the public API interfaces. Internal channels and APIs are currently not part of the automated conformance tests because they are not exposed and cannot be audited without direct access to the infrastructure. -There is a test suite in [`tls-checker.py`](https://github.com/SovereignCloudStack/standards/blob/main/Tests/iaas/secure-connections/tls-checker.py). +There is a test suite in [`tls-checker.py`](Tests/iaas/secure-connections/tls-checker.py). The test suite connects to the OpenStack API and retrieves all public API endpoints from the service catalog. It then connects to each endpoint and verifies the compliance to the standard by checking SSL/TLS properties against the Mozilla TLS preset. -Please consult the associated [README.md](https://github.com/SovereignCloudStack/standards/blob/main/Tests/iaas/secure-connections/README.md) for detailed setup and testing instructions. +Please consult the associated [README.md](Tests/iaas/secure-connections/README.md) for detailed setup and testing instructions. From 5fcfacda6fc1ecaa4277f18b1ecc55f59e70d16d Mon Sep 17 00:00:00 2001 From: Anja Strunk Date: Mon, 25 Nov 2024 12:35:06 +0100 Subject: [PATCH 50/51] Fix dead links Signed-off-by: Anja Strunk --- Standards/scs-0125-v1-secure-connections.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Standards/scs-0125-v1-secure-connections.md b/Standards/scs-0125-v1-secure-connections.md index bf50c6f69..c76ac0dd5 100644 --- a/Standards/scs-0125-v1-secure-connections.md +++ b/Standards/scs-0125-v1-secure-connections.md @@ -271,7 +271,7 @@ See the [corresponding Design Considerations section](#libvirt-hypervisor-interf Conformance tests are limited to communication channels exposed to users, such as the public API interfaces. Internal channels and APIs are currently not part of the automated conformance tests because they are not exposed and cannot be audited without direct access to the infrastructure. -There is a test suite in [`tls-checker.py`](Tests/iaas/secure-connections/tls-checker.py). +There is a test suite in [`tls-checker.py`](../Tests/iaas/secure-connections/tls-checker.py). The test suite connects to the OpenStack API and retrieves all public API endpoints from the service catalog. It then connects to each endpoint and verifies the compliance to the standard by checking SSL/TLS properties against the Mozilla TLS preset. -Please consult the associated [README.md](Tests/iaas/secure-connections/README.md) for detailed setup and testing instructions. +Please consult the associated [README.md](../Tests/iaas/secure-connections/README.md) for detailed setup and testing instructions. From 1c2b6a9a889aaca552116e7df8dff90d0a6130de Mon Sep 17 00:00:00 2001 From: Anja Strunk Date: Mon, 25 Nov 2024 12:36:40 +0100 Subject: [PATCH 51/51] Use absolute path as relative pathes are not allowed Signed-off-by: Anja Strunk --- Standards/scs-0125-v1-secure-connections.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Standards/scs-0125-v1-secure-connections.md b/Standards/scs-0125-v1-secure-connections.md index c76ac0dd5..b2df96743 100644 --- a/Standards/scs-0125-v1-secure-connections.md +++ b/Standards/scs-0125-v1-secure-connections.md @@ -271,7 +271,7 @@ See the [corresponding Design Considerations section](#libvirt-hypervisor-interf Conformance tests are limited to communication channels exposed to users, such as the public API interfaces. Internal channels and APIs are currently not part of the automated conformance tests because they are not exposed and cannot be audited without direct access to the infrastructure. -There is a test suite in [`tls-checker.py`](../Tests/iaas/secure-connections/tls-checker.py). +There is a test suite in [`tls-checker.py`](https://github.com/SovereignCloudStack/standards/blob/main/Tests/iaas/secure-connections/tls-checker.py). The test suite connects to the OpenStack API and retrieves all public API endpoints from the service catalog. It then connects to each endpoint and verifies the compliance to the standard by checking SSL/TLS properties against the Mozilla TLS preset. -Please consult the associated [README.md](../Tests/iaas/secure-connections/README.md) for detailed setup and testing instructions. +Please consult the associated [README.md](https://github.com/SovereignCloudStack/standards/blob/main/Tests/iaas/secure-connections/README.md) for detailed setup and testing instructions.