At the moment, PEM SslBundles can be instantiated through the following properties:
spring:
ssl:
bundle:
pem:
client:
truststore:
certificate: "classpath:client.crt"
Where client.crt can contain multiple certificates.
In some situations, multiple very different certificates need to be trusted. For instance: * An external service changes the CA it uses to sign the certificate it exposes. Both the old one and the new one need to be trusted on the client side to avoid downtime. * When exposing a service with mutual authentication enabled, and when the corporate CA is re-used for multiple systems, it can be somewhat easy to obtain a keypair for a given FQDN. Trusting the CA is not an option, the trust store must contain all the allowed certificates.
While concatenating all the trusted certificates in the same file is an option, it makes it quite hard to see at a glance which certificates are trusted, as they are PEM-encoded. It would be nice to be able to use file names to identify the certificates:
spring:
ssl:
bundle:
pem:
client:
truststore:
certificates:
- "classpath:allowed-client1.crt"
- "classpath:allowed-client2.crt"
Comment From: philwebb
There might be some overlap here with #38242 where we are looking to support directory glob patterns. If the order of the certificates isn't important we might be able to support something like this:
spring:
ssl:
bundle:
pem:
client:
truststore:
certificate: "/my/certs/allowed-*.crt"
select: all
Comment From: bgK
I hadn't seen #38242. Indeed, it fills almost the same need. It's nice in that the properties are backwards compatible and makes it easy to have large numbers of certificates.
Here's a use case that I don't think is easily covered by #38242. A Spring Boot app deployed in Kubernetes. It calls an external service for which some instances are hosted in the same cluster, some instances are scaled out to an external provider. The internal instances are exposed using the Kubernetes CA, the other instances use some other CA. Kubernetes bind mounts the CA at a fixed location inside the pod /var/run/secrets/kubernetes.io/serviceaccount/ca.crt:
spring:
ssl:
bundle:
pem:
client:
truststore:
certificates:
- "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
- "classpath:other-ca.crt"
IMO, me both #38754 and this are good enhancements.
Comment From: dopsun
Add to this ticket about a similar but not same use case:
to allow multiple certs from a folder for different hostnames. This may open the possibility to support one Spring Boot application serving traffic for multiple domains.
Underlying TomCat 8.5 already "allows multiple certificates with different names to be associated with a single TLS connector" (link).
Comment From: scottfrederick
@dopsun Spring Boot 3.3 added support for configuring SSL bundles for hostnames (SNI). Does this meet your requirement?
Comment From: dopsun
@scottfrederick Thanks for sharing this, I have not been aware of this feature yet. A quick look at the link you shared, it seems what I'm waiting for. Will try it out ASAP.
Comment From: quarky42
I also need to be able to add multiple PEM format certificates to the truststore. Being able to add them in with wildcard or by name would be very helpful.
Having it be limited per hostname is not useful in my case and, my case would be covered by the other two options. I can see how mapping certs to specific hostnames is a good and useful config in other situations.
Comment From: chicobento
I hadn't seen #38242. Indeed, it fills almost the same need. It's nice in that the properties are backwards compatible and makes it easy to have large numbers of certificates.
Here's a use case that I don't think is easily covered by #38242. A Spring Boot app deployed in Kubernetes. It calls an external service for which some instances are hosted in the same cluster, some instances are scaled out to an external provider. The internal instances are exposed using the Kubernetes CA, the other instances use some other CA. Kubernetes bind mounts the CA at a fixed location inside the pod
/var/run/secrets/kubernetes.io/serviceaccount/ca.crt:
yaml spring: ssl: bundle: pem: client: truststore: certificates: - "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" - "classpath:other-ca.crt"IMO, me both #38754 and this are good enhancements.
That's a great idea. I'd also like to add a little bit of salt here. Suppose that your application has 2 well-known potential client services, foo and bar and you want to support mTLS. Each client service has a specific intermediate CA. Client services are dynamically installed/removed from the cluster. For improved resiliency/manageability, you dont want to change the deployment of your application whenever a new client service is installed in the cluster: the client CAs must be dynamically added/removed to your server truststore as their services installed/removed from the cluster.
With k8s you should be able to mount the volumes as optional:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mypod
image: myimage
volumeMounts:
- name: foo-ca
mountPath: /var/run/secrets/foo/ca.crt
- name: bar-ca
mountPath: /var/run/secrets/bar/ca.crt
volumes:
- name: foo-ca
secret:
secretName: foo-ca
optional: true
- name: bar-ca
secret:
secretName: bar-ca
optional: true
In this scenario, there should be a way to flag the SSLBundle API that the CA is optional, and when not available it should still attempt to load the other CAs and not prevent the service from starting.
As the client services are installed/uninstalled, the secrets and mounts will be updated and a new SSLBundle should be emitted via SslBundles.addBundleUpdateHandler callback so components supporting hot-reload will be able to reconfigure themselves. In the absence of the CAs (in case none of the services are installed), we should consider whatever the default behavior is, i.e: not trust any CA.
For supporting this feature we can extend your proposal with something like:
yaml spring: ssl: bundle: pem: client: truststore: certificates: - "optional:/var/run/secrets/foo/ca.crt" - "optional:/var/run/secrets/bar/ca.crt"
Comment From: chicobento
Regarding my comment above, we currently have an in-house component for supporting this and we are willing to contribute if thats acceptable from spring team side. Please let me know your views on this so we can start.