Problem Statement
The challenge is the dynamic updating and management of certificates in an application that supports mTLS and interacts with client services that are frequently added and removed.
Suppose your application needs to support mTLS with two well-known client services, foo and bar, each having a specific intermediate CA (Certificate Authority). Client services are dynamically installed/removed from the cluster. For improved resiliency/manageability, you do not 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.
Proposed Solution
This PR aims to address this issue by allowing certificates to be marked as optional. With this feature, the application can start and continue running regardless of the availability of these certificates. And allows the addition of multiple certificates as mentioned here.
Current Status
This pull request is currently a draft/proof of concept. It does not yet include tests or documentation and is intended to gather feedback. The implementation includes several TODOs.
An example of an application.yaml with multiple/optional certificates would look like:
spring.ssl.bundle.pem.server.truststore.certificates[0]=optional:/var/secrets/foo/ca.crt
spring.ssl.bundle.pem.server.truststore.certificates[1]=optional:/var/secrets/bar/ca.crt
spring.ssl.bundle.pem.server.truststore.certificates[2]=/var/secrets/other/ca.crt
Some use cases:
1.The configuration with the deprecated property continues to work as expected:
spring.ssl.bundle.pem.server.keystore.certificate=classpath:certs/server.crt
spring.ssl.bundle.pem.server.keystore.private-key=classpath:certs/server.key
spring.ssl.bundle.pem.server.truststore.certificate=classpath:certs/ca.crt
spring.ssl.bundle.pem.server.reload-on-update=true
server.ssl.client-auth=need
TODO: Since the structure for loading certificates is the same for both keystore and truststore, should there be limitations on optionality and multiple certificates in the keystore? Should the certificate property allow optionality?
TODO: Consider creating a validation to ensure that certificate and certificates cannot be used simultaneously.
- In this case, both certificates in the truststore will be required for proper functionality.
spring.ssl.bundle.pem.server.keystore.certificates=classpath:certs/server.crt
spring.ssl.bundle.pem.server.keystore.private-key=classpath:certs/server.key
spring.ssl.bundle.pem.server.truststore.certificates[0]=/resources/main/ca.crt
spring.ssl.bundle.pem.server.truststore.certificates[1]=/resources/main/ca_cert.crt
spring.ssl.bundle.pem.server.reload-on-update=true
server.ssl.client-auth=need
- If the files (
ca.crtandca_cert) do not exist, they will be treated as empty, as no certificates will be available for loading at that moment. However, since thereload-on-updateproperty is set to true, the parent directory will be monitored. Once changes are detected and the files become available, they will be loaded.
spring.ssl.bundle.pem.server.keystore.certificates=classpath:certs/server.crt
spring.ssl.bundle.pem.server.keystore.private-key=classpath:certs/server.key
spring.ssl.bundle.pem.server.truststore.certificates[0]=optional:/resources/main/ca.crt
spring.ssl.bundle.pem.server.truststore.certificates[1]=optional:/resources/main/ca_cert.crt
spring.ssl.bundle.pem.server.reload-on-update=true
server.ssl.client-auth=need
- In this case, if the
isReloadOnUpdateproperty is set totrue, theca.crtcertificate will still be observed.
spring.ssl.bundle.pem.server.keystore.certificates=classpath:certs/server.crt
spring.ssl.bundle.pem.server.keystore.private-key=classpath:certs/server.key
spring.ssl.bundle.pem.server.truststore.certificates[0]=optional:/resources/main/ca.crt
spring.ssl.bundle.pem.server.truststore.certificates[1]=`---BEGIN CERTIFICATE-----
MIID1zCCAr+gAwIBAgIUNM5QQv8IzVQsgSmmdPQNaqyzWs4wDQYJKoZIhvcNAQEL
...
V0IJjcmYjEZbTvpjFKznvaFiOUv+8L7jHQ1/Yf+9c3C8gSjdUfv88m17pqYXd+Ds
ngX6JBJI7fw7tXoqWSLHNiBODM88fUlQSho8
-----END CERTIFICATE-----
spring.ssl.bundle.pem.server.reload-on-update=true
server.ssl.client-auth=need
TODO: Or should we keep the exception if one or more items in the list are not observable?
Related Issue
This PR is related to this comment in the issue #38754
Comment From: pivotal-cla
@elisabeteaprcd Please sign the Contributor License Agreement!
Click here to manually synchronize the status of this Pull Request.
See the FAQ for frequently asked questions.
Comment From: scottfrederick
@elisabeteaprcd Thanks for the suggestion. We will take a look at the changes and give some feedback.
An alternative to these changes would be a boolean property at the top of the bundle structure such as spring.ssl.bundle.pem.server.required: false or spring.ssl.bundle.pem.server.ignore-non-existing: true that would provide the same "optional" behavior for all certificates in the bundle, without needing to introduce a new optional: keyword to the certificate property value. Would that also meet your needs?
Comment From: chicobento
Hi @scottfrederick,
Im also working with @elisabeteaprcd on this. While the scope of this change is to support optionality for the single item - which is what is currently supported by SB, the end goal is to have it working with multiple items as proposed in https://github.com/spring-projects/spring-boot/issues/38754#issuecomment-2274269939.
So, in the scenario of multiple CAs we should be able to define which ones are mandatory for the service to start and which ones are optional, and in this sense your single-property proposal would not work at the spring boot level, however it could be expressed at the k8s deployment level by making the volume mounts mandatory.
Comment From: pivotal-cla
@elisabeteaprcd Thank you for signing the Contributor License Agreement!
Comment From: chicobento
hi @scottfrederick , just a heads-up that this has been now updated with support for multiple/optional certificates (initial PR had just support for optional)