So, for anyone reading this post my concern was for security.
I wanted to keep using the Docker secrets mechanism to give a
secret.properties to my application instead of using a volume, which is
less safe.
First I created a secret in my Docker compose:
secrets:
secrets.properties:
file: ./secrets/secrets.properties
and I exposed this secret for the CAS container
echempad-cas:
(...)
secrets:
- secrets.properties
After that I configured CATALINA_OPTS to point to the location where Docker
will mount the secret:
echempad-cas:
(...)
- SPRING_PROFILES_ACTIVE=standalone,ldap,db,prod,container,secrets
-
CATALINA_OPTS=-Dspring.config.additional-location=/run/secrets/secrets.properties
I also added the declaration of SPRING_PROFILES_ACTIVE containing a value
"secrets", which is the name for the profile that I want active in CAS in
order to load the variables declared in secrets.properties
That was most of it. I created a small script tool to read all the
individual secrets and create the secrets.properties file, so I can work
faster if I need to regenerate my work environment.
El viernes, 11 de octubre de 2024 a las 17:38:23 UTC+2, Aleix Mariné
escribió:
> Ray,
>
> I confirm that your approach of giving a destination location to tomcat
> for a application.properties for the secrets worked (with minor adjusts).
>
> Thank you for your fast response.
>
> I will detail how my solution works in a future post in this
> conversationfor the record.
>
> Meanwhile, you can mark this conversation as closed if applicable.
>
> Thank you so much.
>
>
> Aleix
>
>
>
> El jueves, 10 de octubre de 2024 a las 5:10:07 UTC+2, Ray Bon escribió:
>
>> Aleix,
>>
>> You can use variable substitution for secrets (or anything that might
>> change between dev and prod). For example, in cas
>> src/main/resources/application.yml:
>> cas:
>> authn:
>> oauth:
>> access-token:
>> crypto:
>> encryption:
>> key: ${variable-name}
>>
>> Create an application.properties file (the one in docker secrets) with
>> the variable definitions:
>> variable-name=123abc...
>>
>> You can also put the entire definition in application.properties:
>> cas.service-registry.ldap.bind-credential=password
>>
>> Then provide the destination location to tomcat (or the app server you
>> are using) on startup:
>>
>> CATALINA_OPTS="-Dspring.config.additional-location=/run/secrets/application.properties
>>
>> ..."
>>
>> Cas will look in /etc/cas by default (in this case /etc/cas/config), if
>> you want to put application.properties there (I am not sure what options
>> you have with docker secrets).
>>
>> Ray
>>
>> P.S. I like the variable approach because all cas config is in one file
>> and it is stored in our cas-overlay-template git repo. Ops only has to
>> supply the variable file. You could of course put all config in
>> application.properites.
>>
>>
>> On Wed, 2024-10-09 at 02:48 -0700, Aleix Mariné wrote:
>>
>> You don't often get email from [email protected]. Learn why this is
>> important <https://aka.ms/LearnAboutSenderIdentification>
>>
>> Hello,
>>
>> I am working with CAS 6.6.12 with WAR overlay, standalone and no spring
>> cloud. I am building a Docker container with my CAS.
>>
>> Right now I am trying to set some java properties (application
>> properties) that are secret into the CAS container, but even though they
>> are set, they do not seem to affect the behavior of CAS as if they were
>> introduced using a profile config file or other accepted method. I also
>> could introduce these properties using system variables, command-line args
>> or profile configuration files, but they are less secure than using Docker
>> secrets. Due to that, I want to use Docker secrets (which simply put a file
>> with the secret inside the container, then the app needs to read it and use
>> it), which forces me to declare the application property programmatically
>> at startup after reading its value from the corresponding Docker secret.
>>
>> That is why I am reading all Docker secrets from /run/secrets and setting
>> them into the corresponding Java property on startup time. To do that I
>> created a custom class to execute this code on startup.
>>
>>
>> @Component
>> public class StartupSecretsLoadingimplements
>> ApplicationListener<ApplicationEnvironmentPreparedEvent>
>> {
>>
>>
>>
>> private final static String SECRETS_FOLDER = "/run/secrets/";
>>
>> /**
>> * Reads a secret and introduces it into the environment of .application
>> properties.
>> *
>>
>> * @paramsecretName name of the secret to read from /run/secrets default
>> Docker secrets folder.
>> * @paramproperty Property to write / update.
>> * @parampropertyOverridesProvides access to a map with all the
>> properties that will be loaded into Java env.
>> */
>> private voidaddSecretProperty(String secretName, String property,
>> Map<String, Object> propertyOverrides)
>>
>>
>> {
>> String secretPath = SECRETS_FOLDER + secretName;
>>
>> try {
>> String secretContent = Files.readString(Path.of(secretPath));
>>
>> // Remove trailing newlines (\n or \r\n) but leave spaces intact
>> secretContent = secretContent.replaceAll("[\\r\\n]+$","");
>>
>> // is this line really setting a Java property?
>> System.setProperty(property, secretContent);
>>
>> // Alternative to set the Java property?
>> propertyOverrides.put(secretName, secretContent);
>>
>> Logger.getGlobal().warning("Read the secret: "+ secretPath + " with
>> content " + secretContent);
>> } catch (IOException e) {
>> Logger.getGlobal().warning("Failed to read the secret: "+
>> e.getMessage());
>> }
>> }
>>
>> /**
>> * Loads all secrets into the Java properties environment
>> */
>>
>> private voidloadSecrets(ConfigurableEnvironment environment) {
>>
>>
>>
>> Map<String, Object> propertyOverrides = new LinkedHashMap<>();
>>
>> try {
>> this.addSecretProperty("CAS_TGC_CRYPTO_ENCRYPTION_KEY",
>> "cas.tgc.crypto.encryption.key", propertyOverrides);
>> this.addSecretProperty("CAS_TGC_CRYPTO_SIGNING_KEY",
>> "cas.tgc.crypto.signing.key", propertyOverrides);
>> this.addSecretProperty("CAS_WEBFLOW_CRYPTO_SIGNING_KEY",
>> "cas.webflow.crypto.signing.key", propertyOverrides);
>> this.addSecretProperty("CAS_WEBFLOW_CRYPTO_ENCRYPTION_KEY",
>> "cas.webflow.crypto.encryption.key", propertyOverrides);
>> this.addSecretProperty("LDAP_TOKEN","cas.authn.ldap[0].bindCredential",
>> propertyOverrides);
>> this.addSecretProperty("DB_PASSWORD","cas.authn.jdbc.query[0].password",
>> propertyOverrides);
>> this.addSecretProperty("ORCID_TOKEN","cas.authn.pac4j.oauth2[0].secret",
>> propertyOverrides);
>> } catch (Exception e) {
>> throw new RuntimeException("Failed to load secrets from "+
>> StartupSecretsLoading.SECRETS_FOLDER, e);
>> }
>>
>> // Add the loaded properties to the environment
>>
>> environment.getPropertySources().addFirst(newMapPropertySource(
>> "customSecrets", propertyOverrides));
>>
>>
>> }
>>
>> /**
>> * This method is executed before loading beans and after the basic
>> environment initializations. You can inject data
>> * needed for the initialization of those beans.
>> * <p>
>>
>> *@param event Event object that contains information about the
>> ApplicationEnvironmentPreparedEvent event.
>> */
>> @Override
>> public voidonApplicationEvent(ApplicationEnvironmentPreparedEvent event)
>> {
>>
>>
>> Logger.getGlobal().warning("Loading secrets from "+ SECRETS_FOLDER);
>> this.loadSecrets(event.getEnvironment());
>> Logger.getGlobal().warning("Finished loading secrets from "+
>> SECRETS_FOLDER);
>> }
>>
>>
>>
>> So in this method I was trying two different methods of injecting
>> variables. The first to appear is System.setProperty(property,
>> secretContent);, which seems to leave the variable empty anyway.
>>
>> The second that I tried is propertyOverrides.put(secretName,
>> secretContent);, continued by environment.getPropertySources().addFirst(new
>> MapPropertySource("customSecrets", propertyOverrides));, which also does
>> not work.
>>
>> I read
>> https://apereo.github.io/cas/7.0.x/configuration/Configuration-Management-Reload.html
>>
>> from the official documentation, and it seems that loading application
>> properties programmatically on startup is not trivial. Can someone with
>> more knowledge hint me in the right direction or explain me how I must
>> proceed to read a file on startup and declare using its data an application
>> property that affect the behaviour of CAS as if the property was loaded
>> using an application profile file?
>>
>> Thank you very much, I am lost in here and need some help.
>>
>>
>> Aleix
>>
>>
>>
--
- Website: https://apereo.github.io/cas
- List Guidelines: https://goo.gl/1VRrw7
- Contributions: https://goo.gl/mh7qDG
---
You received this message because you are subscribed to the Google Groups "CAS
Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/a/apereo.org/d/msgid/cas-user/9a95efbe-4f55-4ed5-9283-329ff0eef80bn%40apereo.org.