Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
985950b
Add TLS termination and ingress passthrough support to Barbican
bbobrov Mar 22, 2026
c17f9f3
Add TLS termination and ingress passthrough support to Keystone
bbobrov Mar 22, 2026
a0c6294
Add TLS bootstrap Job and weekly rotation CronJob to Keystone
bbobrov Mar 22, 2026
0822dbd
Add TLS bootstrap Job and weekly rotation CronJob to Barbican
bbobrov Mar 22, 2026
1ca16e3
Add Prometheus alerts for TLS certificate rotation failures
bbobrov Mar 25, 2026
1cbbd6c
Use Keystone LOCI image for TLS init container instead of busybox
bbobrov Mar 29, 2026
9916149
Lower TLS rotation alert severity from critical to warning
bbobrov Mar 30, 2026
603bda8
Use DigicertIssuer (namespace-scoped) instead of ClusterDigicertIssuer
bbobrov Mar 30, 2026
f6ef1b0
Move TLS manager RBAC out of Helm hook into regular templates
bbobrov Mar 30, 2026
308c494
Make TLS manager RBAC a pre-install hook with weight -10
bbobrov Mar 30, 2026
302c279
Enable mod_ssl for TLS termination via read-only conf for Barbican
bbobrov Mar 30, 2026
8477e1a
Move TLS hardening Include outside VirtualHost block
bbobrov Mar 30, 2026
d5ae952
Remove duplicate Listen 443 — ports.conf already declares it
bbobrov Mar 30, 2026
9f6730a
Disable Apache default site when TLS is enabled
bbobrov Mar 30, 2026
755cc70
Move x509 client cert verification from ingress to Apache in passthro…
bbobrov Mar 30, 2026
8ee71b7
Add ingress.kubernetes.io prefix for ssl-passthrough and backend-prot…
bbobrov Mar 30, 2026
d8692e4
Change issuerKind default from DigicertIssuer to ClusterIssuer
bbobrov Mar 30, 2026
726f600
Enable ssl-passthrough on the ingress-nginx controller
bbobrov Mar 31, 2026
397c0ed
Suppress tls-acme ingress annotation whenever pod-level TLS is enabled
bbobrov Apr 1, 2026
cbbf332
Drop Deployment RBAC and --deployment-name from TLS rotation CronJobs
bbobrov Apr 2, 2026
fc365c9
Add pluggable key lifecycle configuration with Helm validation
bbobrov Apr 7, 2026
8117baf
Add internal-k8s-secret storage option and wire --allow-insecure-storage
bbobrov Aug 15, 2026
2afcc22
Replace ingress TLS passthrough with direct /32 exposure for Keystone…
bbobrov Aug 16, 2026
14e79c9
Announce Keystone TLS /32 via LoadBalancer and Calico BGP
bbobrov Aug 17, 2026
c03eb82
Rebuild client-certificate headers for cc_x509 at Apache TLS
bbobrov Aug 18, 2026
4df157c
Set pod fsGroup so the non-root tls-init can read the TLS Secret
bbobrov Aug 18, 2026
d375298
Support non-Calico external IP for Keystone TLS service
bbobrov Aug 18, 2026
7015eff
Probe served TLS certificate and alert on expiry and stale rotation
bbobrov Aug 20, 2026
58c154c
Replace runtime a2enmod/a2dissite with static Apache config for Keystone
bbobrov Aug 21, 2026
e88f5a3
Add LoadBalancer TLS service, DNS record, and Calico support for Barb…
bbobrov Aug 21, 2026
4978ee2
Default the TLS service to spec.externalIPs for Keystone and Barbican
bbobrov Aug 24, 2026
bff7901
Harden Barbican pod-level TLS and pin the TLS lifecycle image
bbobrov Aug 24, 2026
ba5fff7
Harden Apache TLS ciphers, add HTTP security headers and server harde…
bbobrov Aug 25, 2026
ef5424c
Suppress absence alerting on the TLS rotation failure alerts
bbobrov Aug 25, 2026
8acb16f
Remove non-functional tls-secret-hash pod annotation
bbobrov Aug 26, 2026
37f97ec
Include per-tenant SAML config in the TLS vhost
bbobrov Aug 26, 2026
0958691
Require an external IP when pod-level TLS is enabled
bbobrov Aug 27, 2026
9dfb2b5
Harden x509 header handling, unify Barbican WSGI group, restore keyst…
bbobrov Aug 27, 2026
49198b4
Allow the WebSSO auto-submit script under the Keystone CSP
bbobrov Aug 28, 2026
150f956
Store the OIDC session in the client cookie for multi-replica keystone
bbobrov Aug 28, 2026
9dd9525
Set the RoleBinding subject namespace for the TLS manager
bbobrov Aug 29, 2026
e3b0283
Gate the apache-sites override on pod-level TLS
bbobrov Aug 29, 2026
4d09252
Drop the redundant tls-hardening include from the TLS vhost
bbobrov Aug 29, 2026
2bf1532
Validate the TLS configuration on every render path
bbobrov Aug 29, 2026
33be8fb
Make the TLS rotation schedule configurable
bbobrov Aug 29, 2026
22c4f98
Ignore client proxy and trust-key headers on the direct TLS endpoint
bbobrov Aug 30, 2026
a80d4b4
Share one WSGI daemon group across the keystone TLS and internal vhosts
bbobrov Aug 30, 2026
1cf559a
Scope the TLS rotation-failed alert to the latest job
bbobrov Aug 31, 2026
eba65ed
Drop the broken, out-of-scope SAML assertion-failure alert
bbobrov Aug 31, 2026
bece5ab
Bump chart versions for TLS support
bbobrov Mar 22, 2026
e92ecd9
Always strip inbound client-cert headers on the TLS endpoint
bbobrov Sep 3, 2026
5116ee2
Bound the TLS rotation job runtime with activeDeadlineSeconds
bbobrov Sep 7, 2026
4ab6e94
Move the TLS rotation-failed alert to the kubernetes Prometheus
bbobrov Sep 7, 2026
a2c0b7b
Refuse to disable pod TLS while the public endpoint is live
bbobrov Sep 7, 2026
d4645f0
Revert pod-TLS teardown guard
bbobrov Sep 11, 2026
5566246
Drive pod TLS with a tls.state machine
bbobrov Sep 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion openstack/barbican/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ appVersion: flamingo
description: A Helm chart for Openstack Barbican
icon: https://www.openstack.org/themes/openstack/images/project-mascots/Barbican/OpenStack_Project_Barbican_vertical.png
name: barbican
version: 0.9.3
version: 0.10.0
dependencies:
- condition: mariadb.enabled
name: mariadb
Expand Down
55 changes: 55 additions & 0 deletions openstack/barbican/alerts/kubernetes/openstack-barbican.alerts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,58 @@ groups:
annotations:
description: 'barbican-api pod {{ $labels.pod }} not ready; recreate pod. See playbook.'
summary: 'barbican-api pod not ready'

- alert: OpenstackBarbicanTLSCertificateExpiresCritical
expr: (probe_ssl_earliest_cert_expiry{instance=~"https://keymanager-3\\..*"} - time()) / 86400 < 7
Comment thread
tz3 marked this conversation as resolved.
for: 1h
labels:
no_alert_on_absence: "true"
context: security
dashboard: barbican
service: barbican
severity: critical
tier: os
support_group: identity
playbook: 'docs/support/playbook/barbican/alerts/tls-certificate-expiry/#openstackbarbicantlscertificateexpirescritical'
annotations:
description: The TLS certificate served by Barbican at {{ $labels.instance }} expires in less than 7 days. External HTTPS access will break when it expires. Check the rotation CronJob and cert-manager.
summary: Barbican served TLS certificate expires within 7 days

- alert: OpenstackBarbicanTLSRotationStale
expr: >
time() - kube_cronjob_created{cronjob="barbican-tls-rotation"} >= 8*24*60*60
and on(cronjob) (time() - kube_cronjob_status_last_successful_time{cronjob="barbican-tls-rotation"}
or on(cronjob) kube_cronjob_status_last_schedule_time{cronjob="barbican-tls-rotation"}) >= 8*24*60*60
Comment thread
bbobrov marked this conversation as resolved.
Comment thread
tz3 marked this conversation as resolved.
Comment thread
rajivmucheli marked this conversation as resolved.
for: 1h
labels:
no_alert_on_absence: "true"
context: security
dashboard: barbican
service: barbican
severity: warning
tier: os
support_group: identity
playbook: 'docs/support/playbook/barbican/alerts/tls-certificate-expiry/#openstackbarbicantlsrotationstale'
annotations:
description: The Barbican TLS certificate rotation CronJob has not completed successfully in over 8 days. If not resolved, the certificate will expire and external HTTPS access will break. Check the CronJob and its Jobs.
summary: Barbican TLS certificate rotation is stale

- alert: OpenstackBarbicanTLSRotationFailed
expr: >
kube_job_status_failed{job_name=~"barbican-tls-rotation.*"} > 0
and on (namespace, job_name)
kube_job_created{job_name=~"barbican-tls-rotation.*"}
== on (namespace) group_left()
max by (namespace) (kube_job_created{job_name=~"barbican-tls-rotation.*"})
for: 1h
labels:
context: security
dashboard: barbican
service: barbican
severity: warning
tier: os
support_group: identity
no_alert_on_absence: "true"
annotations:
description: The weekly TLS certificate rotation CronJob for Barbican has failed. If not resolved, the TLS certificate will expire and external HTTPS access will break. Check the CronJob logs.
summary: Barbican TLS certificate rotation failed
53 changes: 53 additions & 0 deletions openstack/barbican/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this
{{- printf "%s-%s" .Release.Name $name | trunc 63 | replace "_" "-" | trimSuffix "-" -}}
{{- end -}}

{{- define "barbican.external_ip" -}}
{{- $svc := .Values.services | default dict -}}
{{- .Values.global.barbican_external_ip | default $svc.externalip -}}
{{- end -}}

{{- define "barbican.db_service" }}
{{- include "utils.db_host" . }}
{{- end }}
Expand All @@ -39,3 +44,51 @@ We truncate at 63 chars because some Kubernetes name fields are limited to this
{{- .Release.Name }}-{{ $name }}-{{ substr 0 4 $hash }}-{{ .Values.imageVersionBarbicanApi | required "Please set barbican.imageVersionBarbicanApi" }}
{{- end }}
{{- end }}

{{- define "barbican.tls.serving" -}}
{{- if or (eq .Values.tls.state "transition") (eq .Values.tls.state "enabled") -}}true{{- end -}}
{{- end -}}

{{- define "barbican.tls.ingressActive" -}}
{{- if or (eq .Values.tls.state "disabled") (eq .Values.tls.state "transition") -}}true{{- end -}}
{{- end -}}

{{- define "barbican.tls.validate" -}}
{{- if not (has .Values.tls.state (list "disabled" "transition" "enabled")) }}
{{- fail "tls.state must be one of: disabled, transition, enabled" }}
{{- end }}
{{- if include "barbican.tls.serving" . }}
{{- if not .Values.tls.keyGeneration }}
{{- fail "tls.keyGeneration is required when TLS is serving (options: go-crypto, hsm-entropy, hsm-full, tpm-entropy)" }}
{{- end }}
{{- if not .Values.tls.keyWrapping }}
{{- fail "tls.keyWrapping is required when TLS is serving (options: none, vault-transit, hsm, tpm)" }}
{{- end }}
{{- if not .Values.tls.keyStorage }}
{{- fail "tls.keyStorage is required when TLS is serving (options: internal-k8s-secret, k8s-secret, vault-secret)" }}
{{- end }}
{{- if and (eq .Values.tls.keyWrapping "none") (eq .Values.tls.keyStorage "k8s-secret") (not .Values.tls.allowInsecureStorage) }}
Comment thread
rajivmucheli marked this conversation as resolved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[High] Insecure storage guard misses internal-k8s-secret

The check only blocks keyWrapping=none + keyStorage=k8s-secret. Using internal-k8s-secret (which is labeled as the recommended option in values.yaml) with keyWrapping=none slips through silently and writes an unencrypted private key to a plain-text Kubernetes Secret. Same gap in the Keystone helpers.

Suggested change
{{- if and (eq .Values.tls.keyWrapping "none") (eq .Values.tls.keyStorage "k8s-secret") (not .Values.tls.allowInsecureStorage) }}
{{- if and (eq .Values.tls.keyWrapping "none") (or (eq .Values.tls.keyStorage "k8s-secret") (eq .Values.tls.keyStorage "internal-k8s-secret")) (not .Values.tls.allowInsecureStorage) }}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. This is intentional and safe, and it was already discussed in an earlier round. internal-k8s-secret is different from k8s-secret: with internal-k8s-secret the private key is written straight into the Kubernetes API and stays inside the cluster — the operator never gets the key as an output. That is why it is the recommended option and why it does not need allowInsecureStorage. The guard only has to block the one truly unsafe combination (wrapping=none together with k8s-secret, where the key would be handed out as output). This is the behavior agreed in the ADR, so I would keep it as is.

{{- fail "tls: unwrapped keys cannot be stored as plain-text K8s Secrets. Set tls.keyWrapping or tls.keyStorage, or set tls.allowInsecureStorage: true to acknowledge." }}
{{- end }}
{{- $svc := .Values.services | default dict }}
{{- if not (.Values.global.barbican_external_ip | default $svc.externalip) }}
{{- fail "TLS serving requires an external IP (global.barbican_external_ip or services.externalip): the public TLS Service only renders once the external IP is set." }}
{{- end }}
{{- end }}
{{- $dep := lookup "apps/v1" "Deployment" .Release.Namespace "barbican-api" }}
{{- if $dep }}
{{- $current := index (default dict $dep.metadata.annotations) "cloud.sap/tls-state" }}
{{- if has $current (list "disabled" "transition" "enabled") }}
{{- if or (and (eq $current "disabled") (eq .Values.tls.state "enabled")) (and (eq $current "enabled") (eq .Values.tls.state "disabled")) }}
{{- fail (printf "tls.state cannot change directly from %s to %s; move through transition first." $current .Values.tls.state) }}
{{- end }}
{{- end }}
{{- end }}
{{- if eq .Values.tls.state "disabled" }}
{{- $recName := include "barbican_api_endpoint_host_public" . }}
{{- $rec := lookup "disco.stable.sap.cc/v1" "Record" .Release.Namespace $recName }}
{{- if not (empty $rec) }}
{{- fail (printf "tls.state is disabled but the disco Record %s still exists. Delete it and point %s to the ingress address by hand, then re-run." $recName $recName) }}
{{- end }}
{{- end }}
{{- end }}
62 changes: 61 additions & 1 deletion openstack/barbican/templates/api-deployment.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{{- include "barbican.tls.validate" . }}
kind: Deployment
apiVersion: apps/v1

Expand All @@ -12,8 +13,9 @@ metadata:
type: api
component: barbican
annotations:
secret.reloader.stakater.com/reload: "{{ .Release.Name }}-secrets"
secret.reloader.stakater.com/reload: "{{ .Release.Name }}-secrets{{- if (include "barbican.tls.serving" .) }},{{ .Values.tls.secretName | default "barbican-tls" }}{{- end }}"
deployment.reloader.stakater.com/pause-period: "60s"
cloud.sap/tls-state: {{ .Values.tls.state | quote }}
spec:
replicas: {{ required ".Values.api.replicas is missing" .Values.api.replicas }}
revisionHistoryLimit: {{ .Values.pod.lifecycle.upgrades.deployments.revisionHistory }}
Expand All @@ -39,12 +41,23 @@ spec:
annotations:
configmap-etc-hash: {{ include (print $.Template.BasePath "/etc-configmap.yaml") . | sha256sum }}
configmap-bin-hash: {{ include (print $.Template.BasePath "/configmap-bin.yaml") . | sha256sum }}
{{- if (include "barbican.tls.serving" .) }}
config.linkerd.io/skip-inbound-ports: "443"
{{- end }}
{{- if .Values.proxysql.mode }}
prometheus.io/scrape: "true"
prometheus.io/targets: {{ required ".Values.alerts.prometheus missing" .Values.alerts.prometheus | quote }}
{{- end }}
{{- include "utils.linkerd.pod_and_service_annotation" . | indent 8 }}
spec:
{{- if (include "barbican.tls.serving" .) }}
securityContext:
# distroless "nonroot" gid of the tls-lifecycle-manager image; lets the
# non-root tls-init container read the 0440 tls-input Secret while keeping
# the key group-restricted (not world-readable) per the BSI least-privilege
# requirement (Sicherheitsarchitektur 4.1: non-root, restriktive Berechtigungen).
fsGroup: 65532
{{- end }}
{{- if .Values.rbac.enabled }}
serviceAccountName: {{ .Release.Name }}
{{- end }}
Expand All @@ -59,6 +72,22 @@ spec:
{{- if .Values.proxysql.native_sidecar }}
{{- include "utils.proxysql.container" . | indent 6 }}
{{- end }}
{{- if (include "barbican.tls.serving" .) }}
- name: tls-init
image: {{ .Values.tls.lifecycle.image }}:{{ .Values.tls.lifecycle.imageTag }}
imagePullPolicy: IfNotPresent
args:
- --mode=unwrap
- --input-dir=/tls-input
- --output-dir=/mnt/secrets
- --key-wrapping={{ required "tls.keyWrapping is required" .Values.tls.keyWrapping }}
volumeMounts:
- name: tls-input
mountPath: /tls-input
readOnly: true
- name: tls-secrets
mountPath: /mnt/secrets
{{- end }}
containers:
- name: barbican-api
image: {{required ".Values.global.registry is missing" .Values.global.registry }}/loci-barbican:{{required "Values.imageVersionBarbicanApi is missing" .Values.imageVersionBarbicanApi}}
Expand Down Expand Up @@ -115,6 +144,10 @@ spec:
ports:
- name: barbican-api
containerPort: {{.Values.api_port_internal}}
{{- if (include "barbican.tls.serving" .) }}
- name: barbican-tls
containerPort: 443
{{- end }}
volumeMounts:
- name: etcbarbican
mountPath: /etc/barbican
Expand All @@ -138,6 +171,23 @@ spec:
mountPath: /etc/barbican/logging.ini
subPath: logging.ini
readOnly: true
{{- if (include "barbican.tls.serving" .) }}
- name: tls-secrets
mountPath: /mnt/secrets
readOnly: true
- name: barbican-etc
mountPath: /etc/apache2/conf-enabled/00-ssl-load.conf
subPath: ssl-load.conf
readOnly: true
- name: barbican-etc
mountPath: /etc/apache2/conf-enabled/tls-hardening.conf
subPath: tls-hardening.conf
readOnly: true
- name: barbican-etc
mountPath: /etc/apache2/conf-enabled/apache-hardening.conf
subPath: apache-hardening.conf
readOnly: true
{{- end }}
- mountPath: /etc/barbican/barbican.conf.d
name: barbican-etc-confd
readOnly: true
Expand Down Expand Up @@ -334,3 +384,13 @@ spec:
{{- end }}
{{- include "utils.proxysql.volumes" . | indent 8 }}
{{- include "utils.trust_bundle.volumes" . | indent 8 }}
{{- if (include "barbican.tls.serving" .) }}
- name: tls-input
secret:
secretName: {{ .Values.tls.secretName | default "barbican-tls" }}
defaultMode: 0440
- name: tls-secrets
emptyDir:
medium: Memory
sizeLimit: 1Mi
{{- end }}
47 changes: 47 additions & 0 deletions openstack/barbican/templates/cronjob-tls-rotation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{{- if (include "barbican.tls.serving" .) }}
{{- include "barbican.tls.validate" . }}
apiVersion: batch/v1
kind: CronJob
metadata:
name: {{ .Release.Name }}-tls-rotation
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
component: barbican
type: tls-rotation
spec:
schedule: {{ .Values.tls.rotationSchedule | default "0 3 * * 1" | quote }}
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
activeDeadlineSeconds: 600
template:
spec:
restartPolicy: Never
serviceAccountName: {{ .Release.Name }}-tls-manager
containers:
- name: tls-rotation
image: {{ .Values.tls.lifecycle.image }}:{{ .Values.tls.lifecycle.imageTag }}
imagePullPolicy: IfNotPresent
args:
- --mode=rotation
- --namespace={{ .Release.Namespace }}
- --secret-name={{ .Values.tls.secretName | default "barbican-tls" }}
- --key-algorithm={{ .Values.tls.keyAlgorithm | default "ECDSAP256" }}
- --issuer-name={{ .Values.tls.issuerName | default "digicert-issuer" }}
- --issuer-kind={{ .Values.tls.issuerKind | default "ClusterIssuer" }}
- --issuer-group={{ .Values.tls.issuerGroup | default "certmanager.cloud.sap" }}
- --common-name={{ include "barbican_api_endpoint_host_public" . }}
- --san-dns={{ include "barbican_api_endpoint_host_public" . }}
- --renewal-threshold-days=30
- --key-generation={{ required "tls.keyGeneration is required" .Values.tls.keyGeneration }}
- --key-wrapping={{ required "tls.keyWrapping is required" .Values.tls.keyWrapping }}
- --key-storage={{ required "tls.keyStorage is required" .Values.tls.keyStorage }}
{{- if .Values.tls.allowInsecureStorage }}
- --allow-insecure-storage
{{- end }}
backoffLimit: 3
Comment thread
tz3 marked this conversation as resolved.
{{- end }}
8 changes: 8 additions & 0 deletions openstack/barbican/templates/etc-configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ data:
{{ include (print .Template.BasePath "/etc/_barbican-api-paste.ini.tpl") . | indent 4 }}
barbican.conf: |
{{ include (print .Template.BasePath "/etc/_barbican.conf.tpl") . | indent 4 }}
{{- if (include "barbican.tls.serving" .) }}
ssl-load.conf: |
{{ include (print .Template.BasePath "/etc/_ssl-load.conf.tpl") . | indent 4 }}
tls-hardening.conf: |
{{ include (print .Template.BasePath "/etc/_tls-hardening.conf.tpl") . | indent 4 }}
apache-hardening.conf: |
{{ include (print .Template.BasePath "/etc/_apache-hardening.conf.tpl") . | indent 4 }}
{{- end }}
policy.yaml: |
{{ include (print .Template.BasePath "/etc/_barbican-policy.yaml.tpl") . | indent 4 }}
logging.ini: |
Expand Down
17 changes: 17 additions & 0 deletions openstack/barbican/templates/etc/_apache-hardening.conf.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{{/*
Server-level Apache hardening: suppress the version banner, disable the TRACE
method, and turn off directory listing for the document root. Parsed after the
packaged apache2.conf so these directives take precedence.
*/}}

# Suppress server version banner and disable TRACE
ServerTokens Prod
ServerSignature Off
TraceEnable Off

# Disable directory listing for the document root
<Directory /var/www/>
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
9 changes: 9 additions & 0 deletions openstack/barbican/templates/etc/_ssl-load.conf.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{{/*
Load mod_ssl and its socache dependency via read-only conf so the module is
available under a read-only root filesystem without a2enmod. mod_headers is
required for the HTTP security response headers set in the TLS vhost.
*/}}

LoadModule socache_shmcb_module /usr/lib/apache2/modules/mod_socache_shmcb.so
LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so
LoadModule headers_module /usr/lib/apache2/modules/mod_headers.so
36 changes: 36 additions & 0 deletions openstack/barbican/templates/etc/_tls-hardening.conf.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{{/*
Apache TLS protocol hardening configuration.
Configures TLS 1.3/1.2 with compliant cipher suites, PFS, AEAD modes,
and brainpool curve preference. Shared between Keystone and Barbican.
*/}}

# TLS Protocol Versions: only 1.3 and 1.2
SSLProtocol -all +TLSv1.3 +TLSv1.2

# TLS 1.2 Cipher Suites (ECDHE + AEAD only, PFS required)
SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256

# TLS 1.3 Cipher Suites (AES-GCM and AES-CCM)
SSLCipherSuite TLSv1.3 TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256

# Server chooses cipher order
SSLHonorCipherOrder on

# ECDHE Curve Preference: brainpool first, NIST as fallback
SSLOpenSSLConfCmd Curves brainpoolP256r1:brainpoolP384r1:prime256v1:secp384r1

# Signature algorithms preference
SSLOpenSSLConfCmd SignatureAlgorithms ecdsa_secp256r1_sha256:ecdsa_secp384r1_sha384:rsa_pss_rsae_sha256:rsa_pss_rsae_sha384

# Session cache
SSLSessionCache shmcb:/run/apache2/ssl_scache(512000)
SSLSessionCacheTimeout 300

# Disable session tickets (for PFS)
SSLSessionTickets off

# Strict SNI
SSLStrictSNIVHostCheck on

# Disable TLS compression (CRIME mitigation)
SSLCompression off
Loading
Loading