UPDATE (more appropropriate question): How to use a value (stored within a user-provided PCF service) in a log4j2.xml file on startup of a spring-boot application.
We use a spring-boot application deployed to PCF in combination with an external library to log to Splunk (com.splunk.logging:splunk-library-javalogging). The implementation/Plugin requires data within an XML file (e.g. log4j2.xml) including a secret token.
Excerpt (all irrelevant entries are omitted):
<?xml version="1.0" encoding="UTF-8"?>
<SplunkHttp token="dummyToken">
</SplunkHttp>
Below the list of my (failed) attempts to get a valid token from external sources into the .xml file
Hardcoding the token (token="secretToken")
This approach works fine and the connection can be established, but it is still no option for us (various reasons, the obvious one is that a hardcoded token would be available within sourcecode)
Using an environment variable (token="${env:SPLUNK_TOKEN}"
This works fine for local environments. As soon as we want to use it within PCF we need to make the environment variable available within PCF
make use of "Cloud Foundry environment variables"
Variables can be easily added via the cf cli (see cf set-env). Unfortunately, the CF documentation does not recommend this approach for credentials
"Important Do not use user-provided environment variables for security-sensitive information such as credentials. They might unintentionally show up in cf CLI output and Cloud Controller logs. Use user-provided service instances instead. The system-provided environment variable VCAP_SERVICES is properly redacted for user roles such as Space Supporter and in Cloud Controller log files" [https://docs.cloudfoundry.org/devguide/deploy-apps/environment-variable.html]
make use of "User-Provided Services"
We're able to setup those services via "cf cups splunk-credentials -p "SPLUNK_TOKEN" (documentation https://docs.cloudfoundry.org/devguide/services/user-provided.html)
Once service and apps have a binding we're able to see the content of the environment variable (see below for content). The value is a JSON Object and the relevant data is nested within. Therefore, using the complete environment variable does not work. Within java code and .properties we can access the value via ${vcap.services.splunk-credentials.credentials.SPLUNK_TOKEN}. Using this value in the above mentioned XML file excerpt seems to be not applicable. The provided variable is not set/replaced. The token is therefore not added properly and no data is send to Splunk anymore.
How can we extract relevant data from the JSON Object within the environment variable in the XML file itself?
"Compared with other regular expression flavors, the XML schema flavor is quite limited in features. Since it’s only used to validate whether an entire element matches a pattern or not, rather than for extracting matches from large blocks of data, you won’t really miss the features often found in other flavors" https://www.regular-expressions.info/xml.html#:~:text=The%20W3C%20XML%20Schema%20standard,valid%20US%20social%20security%20number.
Another answer to a similar question suggests to rely on a liberty buildpack
But the title already specifies the OpenLiberty dependency, that we do not intend to use
Excerpt of environment variable VCAP_SERVICES:
{
"user-provided": [
{
"label": "user-provided",
"name": "splunk-credentials",
"tags": [],
"instance_guid": "omitted",
"instance_name": "splunk-credentials",
"binding_guid": "omitted",
"binding_name": null,
"credentials": {
"SPLUNK_TOKEN": "dummyToken"
},
"syslog_drain_url": "",
"volume_mounts": []
}
]
}
I was able to solve my initial issue: How to use a value (stored within a user-provided PCF service) in a log4j2.xml file on startup of a spring-boot application.
Answer: According to the log4j documentation about Spring Boot Lookups it's allowed to access values from Spring properties. Example
<?xml version="1.0" encoding="UTF-8"?>
<SplunkHttp token="${spring:my-application.splunk-token}">
</SplunkHttp>
This Lookup will return null values until Spring Boot initializes application logging. The Spring Boot Lookup requires the log4j-spring-boot jar be included as a dependency.
gradle:
implementation 'org.apache.logging.log4j:log4j-spring-boot:2.20.0
Use your user-provided credentials as usual (e.g. within application.properties)
my-application.splunk-token=${vcap.services.splunk-credentials.credentials.splunk-token}