Dashboard service (horizon) security
Use the Dashboard service (horizon) as a portal to provision your cloud resources. Horizon runs as a pod in the openstack namespace, exposed with a Red Hat OpenShift Container Platform (RHOCP) Route.
Apply configuration through customServiceConfig in the OpenStackControlPlane CR by using Python Django settings syntax, not ini-style configuration. There is no HAProxy on controller nodes, no local_settings.py on disk, and no httpd.conf managed by Puppet.
Treat the security of the Dashboard with the same sensitivity as the OpenStack APIs. The Dashboard is a direct interface to the API. Vulnerabilities in the Dashboard can compromise your cloud.
Dashboard service debugging Copy linkLink copied!
In production environments, keep the default DEBUG setting of False. If DEBUG is True, Django outputs stack traces to browser users that contain sensitive server state, and the ALLOWED_HOSTS setting is disabled, which defeats host header validation.
To enable debug temporarily for investigation or in a test environment, inject the setting through customServiceConfig:
spec:
horizon:
template:
customServiceConfig: |
DEBUG = True
DEBUG setting to False immediately after investigation. Never leave DEBUG = True enabled in a production environment. The operator reconciles the setting on the next pod restart.Domain name selection Copy linkLink copied!
For security, deploy the Dashboard service (horizon) on a dedicated second-level domain, such as https://dashboard.example.com, and not a shared subdomain such as https://dashboard.public-cloud.example.com. The same-origin policy of a browser isolates cookies and security tokens by domain.
In Red Hat OpenStack Services on OpenShift (RHOSO) 18.0, the Dashboard URL is determined by the Red Hat OpenShift Container Platform (RHOCP) Route hostname. You can configure the Route hostname in the apiOverride section of the horizon configuration if you need a custom domain:
spec:
horizon:
apiOverride:
route:
spec:
host: dashboard.example.com
ALLOWED_HOSTS configuration Copy linkLink copied!
The Dashboard service (horizon) uses Django’s ALLOWED_HOSTS setting to reject HTTP requests with incorrect Host headers to prevent HTTP Host header attacks. The Dashboard service operator sets ALLOWED_HOSTS based on the Route hostname.
If you use a custom domain or need to add additional allowed hosts, you can set it through customServiceConfig:
spec:
horizon:
template:
customServiceConfig: |
ALLOWED_HOSTS = [get_pod_ip(), 'dashboard.example.com', 'horizon-openstack.apps.ocp.example.com']
ALLOWED_HOSTS to the wildcard character, [*]. This disables host header validation and opens the Dashboard to Host header poisoning attacks.Cross-site scripting protection Copy linkLink copied!
The Dashboard service (horizon) accepts the full Unicode character set in most fields. Malicious actors could exploit this to test for cross-site scripting (XSS) vulnerabilities. The Dashboard service includes Django’s built-in XSS protections.
When auditing custom dashboards or panels, pay attention to the following configurations:
- Use of the
mark_safefunction - The
is_safeflag on custom template tags - The
safetemplate tag - Anywhere auto-escaping is disabled
- Any JavaScript that evaluates improperly escaped data
Cross-site request forgery protection Copy linkLink copied!
Audit Dashboard service (horizon) dashboards for Cross-site Request Forgery (CSRF) and check for inappropriate use of the @csrf_exempt decorator. Configure your web server or IngressController to send a restrictive Cross-Origin Resource Sharing (CORS) header with each response.
Allow only the Dashboard domain and protocol:
Access-Control-Allow-Origin: https://dashboard.example.com
Never allow the wildcard origin (*). Evaluate any dashboard that relaxes CORS restrictions before deploying it.
Iframe embedding configuration Copy linkLink copied!
The DISALLOW_IFRAME_EMBED setting prevents the Dashboard service (horizon) dashboard from iframe embedding and mitigates cross-frame scripting (XFS) attacks. The DISALLOW_IFRAME_EMBED setting defaults to True.
DISALLOW_IFRAME_EMBED to False if you have a specific requirement for iframe embedding and fully understand the XFS risks.HTTP Strict Transport Security Copy linkLink copied!
Prevent browser fallback to insecure connections after an initial secure connection. Configure HSTS when you deploy the Dashboard service (horizon) on a public or untrusted zone.
In Red Hat OpenStack Platform (RHOSP) 17.1, you configured HSTS through a Puppet or HAProxy template such as tripleo::haproxy::horizon::options. In Red Hat OpenStack Services on OpenShift (RHOSO) 18.0, the dashboard is behind a Red Hat OpenShift Container Platform (RHOCP) Route. In RHOSO you can configure HSTS on the RHOCP IngressController or by using Route annotations.
To enable HSTS globally for all Routes including horizon, configure the httpHeaders policy for the IngressController:
apiVersion: operator.openshift.io/v1
kind: IngressController
metadata:
name: default
namespace: openshift-ingress-operator
spec:
httpHeaders:
actions:
response:
- name: Strict-Transport-Security
action:
type: Set
set:
value: "max-age=31536000; includeSubDomains"
You can verify HSTS with the following command:
$ curl -s -D- https://dashboard.example.com | grep -i strict
The output resembles the following:
strict-transport-security: max-age=31536000; includeSubDomains
Front-end caching Copy linkLink copied!
Do not use front-end caching tools, such as Varnish, with the Dashboard service (horizon). The Dashboard service renders dynamic content directly from OpenStack API requests. A caching layer can serve stale or incorrect content. Django already uses standard HTTP caching headers for static media.
Session back end Copy linkLink copied!
The default session back end for the Dashboard service (horizon) is django.contrib.sessions.backends.cache, backed by memcached. This configuration supports horizontal scaling and avoids local-memory session stores.
You can enable memcached authentication in the OpenStackControlPlane CR to restrict access to cached session data. By default, memcached does not require authentication.
memcached connections from the Dashboard service are encrypted automatically. Unlike the MemcachedTLS heat parameter from Red Hat OpenStack Platform (RHOSP) 17.1, you do not need to configure separate memcached TLS.Dashboard SECRET_KEY management and rotation Copy linkLink copied!
The Dashboard service (horizon) depends on a shared SECRET_KEY for cryptographic signing of sessions and Cross-site Request Forgery (CSRF) tokens. Compromise of this key could allow remote code execution.
In Red Hat OpenStack Services on OpenShift (RHOSO) 18.0, the horizon-operator automatically generates the SECRET_KEY and stores it in a dedicated Kubernetes Secret named horizon in the openstack namespace, under the key horizon-secret. This secret is mounted into all horizon pod replicas and read by Django at startup. It is separate from the osp-secret referenced in the Horizon CR’s secret field, which serves only as a dependency gate and change-detection input.
The generated key is 10 random alphanumeric characters. For production environments, set the key value to at least 64 randomly generated characters. Editing the key invalidates all existing user sessions and cached data. Never commit the key to version control or store it in the OpenStackControlPlane CR spec in plain text. To rotate the secret key, update the value in the Kubernetes Secret and restart the horizon pods:
$ oc patch secret horizon -n openstack
-p '{"data":{"horizon-secret":"'$(openssl rand -base64 64 | tr -d '\n' | base64 -w 0)'"}}'
--type merge
$ oc rollout restart deployment/horizon -n openstack
horizon-secret key is empty.Session cookie security settings Copy linkLink copied!
Protect session cookies from JavaScript access. When the Dashboard service (horizon) endpoint uses HTTPS, those settings are enabled by default.
You can configure the settings by using customServiceConfig:
spec:
horizon:
template:
customServiceConfig: |
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE and CSRF_COOKIE_SECURE ensure cookies are only sent over HTTPS. SESSION_COOKIE_HTTPONLY prevents JavaScript from reading the session cookie, mitigating session theft from Cross-Site Scripting (XSS).
Dashboard password security parameters Copy linkLink copied!
The ENFORCE_PASSWORD_CHECK setting displays an Admin Password field on the Change Password form to verify that an administrator initiated the change. This is set to True by default.
ENFORCE_PASSWORD_CHECK setting as there are security implications. Without ENFORCE_PASSWORD_CHECK = True, any user who gains access to the Change Password form could reset passwords without needing to prove that they know the current admin password.The DISABLE_PASSWORD_REVEAL setting removes the password reveal button from the login and password fields. The default value of DISABLE_PASSWORD_REVEAL is True.
Logon banner for regulatory compliance Copy linkLink copied!
Regulated industries such as Health Insurance Portability and Accountability Act (HIPAA), Payment Card Industry Data Security Standard (PCI-DSS), or government might require a user logon banner. Configure this with a custom theme and modified login template with extraMounts.
File upload size limits Copy linkLink copied!
In Red Hat OpenStack Platform (RHOSP) 17.1, you edited LimitRequestBody in httpd.conf files to configure upload size limits. In Red Hat OpenStack Services on OpenShift (RHOSO) 18.0, you configure the httpd timeout with extraMounts to load a custom httpd.conf into the horizon pod.
You can set the FILE_UPLOAD_MAX_MEMORY_SIZE and DATA_UPLOAD_MAX_MEMORY_SIZE Django settings through customServiceConfig:
spec:
horizon:
template:
customServiceConfig: |
FILE_UPLOAD_MAX_MEMORY_SIZE = 10737418240
DATA_UPLOAD_MAX_MEMORY_SIZE = 10737418240
Note that both settings work at the same time. If you increase the Django httpd settings above the default value, then you must also increase the settings in the LimitRequestBody httpd configuration.
RHOSP 17.1 to RHOSO 18.0 Dashboard service hardening comparison Copy linkLink copied!
Review the Dashboard service (horizon) hardening differences between Red Hat OpenStack Platform (RHOSP) 17.1 and Red Hat OpenStack Services on OpenShift (RHOSO) 18.0.
| RHOSP 17.1 mechanism | RHOSO 18.0 equivalent | Notes |
|---|---|---|
|
The heat parameter |
|
Python list syntax in Django settings. |
|
The Puppet parameters |
|
All Puppet parameters are replaced by Django settings. |
|
|
RHOCP |
HSTS is set at the ingress layer, not |
|
The heat parameter |
Kubernetes Secret |
Managed as a Kubernetes Secret and rotated with oc patch. |
|
The heat parameter |
|
Set as Django settings. |
|
The heat parameters |
|
|
|
|
|
No Puppet, persistent and auditable. |
|
Unmanaged editing |
|
Survives redeployment. |
|
The Puppet parameters |
|
|