spring-projects / spring-boot

Spring Boot
https://spring.io/projects/spring-boot
Apache License 2.0
74.87k stars 40.61k forks source link

Support loading of base 64 encoded values from the Environment #36033

Closed scottfrederick closed 6 months ago

scottfrederick commented 1 year ago

The SSL bundle properties spring.ssl.bundle.jks.myname.keystore.location and spring.ssl.bundle.jks.myname.truststore.location currently require the value to be a file that can be accessed as a URL. In some cases it is useful to provide the JKS or PKCS#12 content as base 64 encoded text instead of in files.

In order to know for sure the type of the content, we'd like to introduce a base64: prefix that can be used to reference resources in this format. The base64: resource type can be applied to the JKS location properties now, and possibly to other resource property types in the future.

erwinc1 commented 1 year ago

Perfect, thanks @scottfrederick !

tristanchanson commented 1 year ago

@scottfrederick Is this something you are open to contribution for? I have a POC that leverages the ResourceLoader and a custom protocol resolver to achieve this same functionality.

scottfrederick commented 1 year ago

@tristanchanson Thanks for the offer, but I have changes in progress for this.

ipsi-apant commented 11 months ago

Hi @scottfrederick , thank you for adding this support. Any idea when this can be available and version ?

Can this value be retrieved using spring.config.import ? The app I am working on runs on AWS ECS. Developers do not have access to production environment. Therefore, having certs in resources is not an option. Looking for a way to supply these certs and keys either from SecretsManager (4 KB limit) or DynamoDB (if it is outside of limit)

scottfrederick commented 11 months ago

Any idea when this can be available and version ?

We don't know yet, as we're still working through some design. It won't make it into Spring Boot 3.2.

having certs in resources is not an option. Looking for a way to supply these certs and keys either from SecretsManager (4 KB limit) or DynamoDB (if it is outside of limit)

You might want to look at creating a custom implementation of an SslBundleRegistrar. The registrar can add an SSL bundle that contributes material from whatever source you'd like. You can look at PropertiesSslBundle and WebServerSslBundle for examples of how you might create an SslBundle to register.

ipsi-apant commented 11 months ago

Hi @scottfrederick , thank you for your inputs. Appreciate it!

I gave a try using these classes and able to read certificate string stored as base64 string in AWS secrets manager. Also, able to decode to plain text for keystore. However, it fails with exception when trying to read certs from classpath.

After investigating logs, it appears when this SslAutoConfiguration#sslBundleRegistry() is executing, it is trying to register multiple registrars (screenshot below). My understandings, when it tries to process SslPropertiesBundleRegistrar, it is using PemContent#load() to load from a file path and it fails because the value is a base64 string.

Maybe I need to exclude the SslPropertiesBundleRegistrar (default) when there is a custom implementation present.

What is the best way to use custom registrar when it is present ? Or maybe I am doing it incorrect. Happy to provide implementation classes if that would help for more clarity.

spring:
  cloud:
    aws:
      endpoint: http://localhost:4566
  config:
    import:
      - aws-secretsmanager:CERT-CHAIN
      - aws-secretsmanager:CERT-KEY
  ssl:
    bundle:
      pem:
        demo-ssl:
          key:
            alias: client
          keystore:
            certificate: ${CERT-CHAIN:fake-default}
            private-key: ${CERT-KEY:fake-default}
            type: PKCS12

image

lukasdancak commented 11 months ago

You might want to look at creating a custom implementation of an SslBundleRegistrar. The registrar can add an SSL bundle that contributes material from whatever source you'd like. You can look at PropertiesSslBundle and WebServerSslBundle for examples of how you might create an SslBundle to register.

Hi, little OT but not so much.....Thank you for your work, but why there is no clear info, in official Spring documentations, about really important fact that the spring.sll.bundle.pem.* properties can read data both from PEM type file and PEM style String, So you can use SLL certificates and key as enviroment variables. I found this info randomly thanks to post of this guy: https://stackoverflow.com/a/76465640 It burned at least one day of my life of searching for simple solution :( I am posting this also because it can help somebody in future.....

philwebb commented 11 months ago

@lukasdancak Thanks for raising the documentation issue. I've now added a note in our reference guide so more folks can find out about that feature.

vpavic commented 6 months ago

Thanks for adding support for this. It was sorely needed as working with configuration properties of type org.springframework.core.io.Resource was difficult in environments without a traditional filesystem (and basically required a custom ProtocolResolver like the one introduced here).

Out of curiosity, as support for loading base64 encoded values is something that's IMO generally very useful (and not only in the context of Spring Boot and configuration properties), was it considered to have support for this in Spring Framework?

scottfrederick commented 6 months ago

was it considered to have support for this in Spring Framework?

See https://github.com/spring-projects/spring-framework/issues/32539

gertvv commented 3 months ago

I've upgraded to spring-boot 3.3.1 to try and use this feature:

spring:
  security:
    saml2:
      relyingparty:
        registration:
          keycloak:
            entity-id: "saml-test"
            signing:
              credentials:
                - private-key-location: classpath:local.key
                  certificate-location: base64:LS...

But am getting the error Certificate location 'ServletContext resource [/base64:LS...]' does not exist.

  1. Did this feature get released in spring-boot 3.3.1?
  2. Does anything need to be done to enable it?
  3. Is the configuration for SAML2 even using the ResourceLoader/ProtocolResolver?
wilkinsona commented 3 months ago

@gertvv please open a new issue and we can take a look. First impression is that we are indeed missing the use of ApplicationResourceLoader in SamlRelyingPartyRegistrationConfiguration.

scottfrederick commented 3 months ago

@gertvv This change for Spring Boot 3.4 should allow base64: resources to be used as in your example.

gertvv commented 2 months ago

Perfect! Indeed I had discovered I could get it to work by manually bootstrapping SpringApplication with an ApplicationResourceLoader.

krismarc commented 3 weeks ago

Hey, wondering if combination of vcap_services and base64 encoding would work out of the box for providing keytab in kerberos spring security? So my idea would be to store encoded keytab within secret-store as a part of vcap_services and make direct reference to it in security configuration.

https://stackoverflow.com/questions/45353535/referencing-vcap-variables-in-application-properties https://spring.io/blog/2015/04/27/binding-to-data-services-with-spring-boot-in-cloud-foundry https://github.com/pivotal/blog/blob/master/content/post/spring-boot-injecting-credentials.md https://docs.spring.io/spring-security-kerberos/reference/samples.html

basically something like:

app:
    service-principal: HTTP/neo.example.org@EXAMPLE.ORG
    keytab-location: base64:${vcap.services.secrets-store.credentials.keytab}

Best regards, K.M.

wilkinsona commented 3 weeks ago

Why not try it for yourself and see? The base64 protocol resolver neither knows nor cares where the value that it is resolving has come from so I can see no reason why it wouldn't work.

krismarc commented 3 weeks ago

I'm going to do so ;) I just found this thread so I assume it's worth leaving a question so others might benefit from it as well. Thx for you reply.