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/4da5318a688c78107a3c399ab153f77f03159061.camel%40uvic.ca.