Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
scottfrederick opened this issue Jun 22, 2023 · 17 comments
Closed

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

scottfrederick opened this issue Jun 22, 2023 · 17 comments
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@scottfrederick
Copy link
Contributor

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
Copy link

erwinc1 commented Jun 23, 2023

Perfect, thanks @scottfrederick !

@tristanchanson
Copy link

@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
Copy link
Contributor Author

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

@philwebb philwebb changed the title Support base 64 encoded JKS key stores in SSL bundles Support loading of base 64 encoded values from the Environment Sep 11, 2023
@philwebb philwebb modified the milestones: 3.2.x, 3.x Sep 11, 2023
@ipsi-apant
Copy link

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
Copy link
Contributor Author

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
Copy link

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

This comment was marked as resolved.

@philwebb

This comment was marked as resolved.

@scottfrederick scottfrederick modified the milestones: 3.x, 3.3.0-M3 Mar 20, 2024
@vpavic
Copy link
Contributor

vpavic commented Mar 21, 2024

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
Copy link
Contributor Author

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

See spring-projects/spring-framework#32539

@gertvv
Copy link

gertvv commented Jul 5, 2024

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
Copy link
Member

@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
Copy link
Contributor Author

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

@gertvv
Copy link

gertvv commented Jul 20, 2024

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

@krismarc
Copy link

krismarc commented Sep 20, 2024

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/[email protected]
    keytab-location: base64:${vcap.services.secrets-store.credentials.keytab}

Best regards,
K.M.

@wilkinsona
Copy link
Member

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
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

10 participants