Scala config lookup secrets - scala

I have application.conf file which contains secrets(password for DB etc..) And this secret will be mounted as a file(the file content will contain the actual secrets) in the running pod. How can scala config library be tweaked to handle this. i.e
instead of normal application.conf
db {
user = "username"
password = "xxx"
}
I would have something like this...
db {
user = "username"
password = "${file_location}"
}
As the file is parsed, it should identify that the value of key password, needs to be resolved by looking up the file and loading its contents.
A simple function can be written to load the content of this file, how can this is be integrated with seamlessly with scala config. ie. The rest of the code will continue to use
config.getString(db.password)

I assume you are using configuration of HOCON format and Typesafe configuration library for it.
I don't think it has such feature out of the box, but as an possible alternative you can take a look at include feature - you can include content of another file into your application.conf:
db {
user = "username"
}
include /path/to/pod.conf //include env specific configuration file
and put inside /path/to/pod.conf:
db {
password = "pod_db_pass"
}
So eventually contents of both files will be merged inside application during loading, and your final config will contain password at path db.password
UPDATE
Another possible option load password from file and merge into config file with withFallback method. Example:
import com.typesafe.config._
val passord = "password_from_file"
val passwordConfig = ConfigFactory.parseString(s"db.password=$passord")
val applicationConfig = ConfigFactory.parseString(s"db.user=db_user")// Replace this with `ConfigFactory.load()`
val config = applicationConfig.withFallback(passwordConfig)
println(config)
Printout result:
Config(SimpleConfigObject({"db":{"password":"password_from_file","user":"db_user"}}))
Scatie: https://scastie.scala-lang.org/WW3weuqiT9WRUKfdrZgwcw

Related

How to get property from application.property in Gatling

I'm trying to get some properties from an application.properties file in Gatling-Scala. I tried.
val properties: Config = ConfigFactory.load("application.properties")
val clientId: String = properties.getString("api.clientId")
I keep getting "com.typesafe.config.ConfigException$Missing No configuration setting found for key 'api'". I put the application.properties file inside src/test/resources/application.properties and also in the root folder of the project.
I tried also to put the same information inside src/test/resources/gatling.conf as follows:
gatling {
api {
clientId = "..."
}
}
But I get the error:
com.typesafe.config.ConfigException$Missing No configuration setting found for key 'gatling'
Is there something I'm missing?
I managed to get the information in the gatling.conf file by installing the plugin HOCON for .conf files and formatting it correctly.

SBT - How can I add/modify values to application.conf file based on an external source

I read that SBT has functionality to generate source code and resource files.
In my case I want to add/modify a field in an application.conf file during compilation/packaging of the project (leaving the others in place)
For instance my application.conf file has something like:
A {
B = "Some Value"
C = "Some value to be modified"
}
I would like in the SBT to read an external file and change or add the value of A.B or A.C
So if it is possible to do something along the lines of:
build.sbt
lazy val myProject = project.in(file('myproject')
// pseudo code - How do I do this?
.sourceGenerators in Compile += "Read file /path/to/external/file and add or replace the value of application.conf A.B = some external value"
You can replace the values with environment variable values provided while compiling / building your project. For that you'd have to
A {
B = "Some Value"
B = ${?B_ENV}
C = "Some value to be modified"
C = ${?C_ENV}
}
Where B_ENV and C_ENV are the environment variables you set in your terminal either before build or within the build command (before it)
$ B_ENV=1 C_ENV=2 sbt run
Source: https://www.playframework.com/documentation/2.6.x/ProductionConfiguration#using-environment-variables
In this case you can do without sbt and this approach would also work with maven or cradle.
The *.conf support orignates from typesafe config (https://github.com/lightbend/config).
There is a feature to get environment variables to be used in the configuration which should be a good fit to solve the problem.
There are two approaches I would suggest to use
1.) Fail on missing configuration
If configuration of this vallue is important and to prevent the deplyment of misconfigurated application the startup should fail on missing environment variables.
in application.conf
key=${TEST} // expects "TEST" to be set, fails otherwise
2.) Hardcoded value with override
If there is a sensible default behaviour that only in some circumstances should be changed.
in application.conf
key="test" // hardcoded key
key=${?TEST} // override "key" with 3nv "$TEST" value, when it is given

Typesafe: Read array of configs

My tasks.conf file looks like below
tasks = [
{
prop_1 = "string-1"
prop_2 = "string-2"
prop_3 = 3
},
{
prop_1 = "string-1"
prop_2 = "string-2"
prop_3 = 3
}
]
After successfully parsing the task.conf file (located outside jar / classpath) using val config: Config = ConfigFactory.parseFile(file), I've tried reading it as follows without success
config.getObjectList("tasks")
config.getConfigList("tasks")
It complains
ConfigException$Missing: No configuration setting found for key
'tasks'
Upon asserting whether or not the path exists using config.hasPath("tasks"), it returns false.
My queries are as follows:
Is the structure of my conf file correct? Even if it's correct, is there a better way to structure it?
If the structure of conf file is correct (since parseFile succeeds), then where am I going wrong in reading the file?
Looks like your config file could not be read! Your application is probably trying to read the default application.conf, and your tasks config key is not found there.
You could probably try:
ConfigSource.FromFile(path)
Use the complete absolute path and give it a try!

Load application.conf from folder in deployed Scala app

I have an application that loads configuration from application.conf using ConfigFactory: lazy val myConfig = ConfigFactory.load(pathToConfig)
The application.conf is initially located in src/main/resources
When I deploy my application I want it to load the config from APP_HOME/conf/application.conf
To do so, I excluded the application.conf from the resource folder when building the Rmp and I have added my APP_HOME/conf to the class path.
jar {
exclude '*.conf'
}
and
startScripts {
classpath += files('src/main/resources')
doLast {
def windowsScriptFile = file getWindowsScript()
def unixScriptFile = file getUnixScript()
println('unix script is ' + unixScriptFile.text)
windowsScriptFile.text = windowsScriptFile.text.replace('%APP_HOME%\\lib\\resources', '%APP_HOME%\\conf')
unixScriptFile.text = unixScriptFile.text.replace('\$APP_HOME/lib/resources', '\$APP_HOME/conf')
println('after unix script is ' + unixScriptFile.text)
}
}
The odd thing is that when I modify the $APP_HOME/conf/application.conf and restart the app, the changes are not picked up: ie the old configuration is still being used
Any idea what might cause this or how I can print where the config is being loaded from would be helpful
With many attempts, I got it to work by calling lazy val myConfig = ConfigFactory.load() without specifying the conf file name or path.
Although it solved my issue I still don't understand why calling load with the file name or file path didn't work

Scala Config: Include another file.conf

Currently, I have a resources/application.conf file which has the following keys:
development {
server = www.myapp.com
aws_key = my_aws_key
aws_secret = my_aws_secret
}
I would like to remove my aws_key and aws_secret from the file.
I was thinking of creating another file called resources/credentials.conf and storing my personal authentications there.
credentials {
aws_key = my_aws_key
aws_secret = my_aws_secret
}
and then include it some way in my application.conf or merge that config to the Config object in addition to application.conf.
credentials.conf would be git ignored. A sample file would be checked in credentials-sample.conf which each developer would change according to his own credentials and rename the sample file to credentials.conf
I tried different variation of include like
include "credentials"
include "credentials.conf"
include "./credentials.conf"
include file("./credentials.conf")
and so on.
I know I can pass it via system variables but I would like to try it like mentioned above. If you know of a better way, please let me know.
Typesafe Config provide the way to fallback from one configuration to another. You can try the ConfigFactory.Load() to load different config and use withFallback to line them up in your designated order. Such as:
ConfigFactory.Load("credentials.conf") withFallback ConfigFactory.Load("application.conf")
Inside your conf file, add
include "another_file.conf"
ie: https://github.com/cicco94/scala-akka-slick-demo/blob/master/src/main/resources/application.conf