-
Notifications
You must be signed in to change notification settings - Fork 0
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
Set up stage-specific config #12
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,30 @@ | ||
# Gatehouse | ||
|
||
## Configuration | ||
|
||
The app configuration has three levels of precedence. Any values repeated at a higher level will override those at a lower | ||
level. | ||
The levels are, in order of precedence: | ||
|
||
### 1. SSM parameters | ||
Secret and private settings are stored as | ||
[AWS SSM parameters](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html), | ||
named in the format: | ||
`/<stage>/identity/gatehouse/<param key>` | ||
where `param key` is a slash-separated | ||
[Hocon](https://github.com/lightbend/config/blob/main/HOCON.md) key. | ||
|
||
Eg. | ||
`/CODE/identity/gatehouse/play/http/secret/key` | ||
would give us a `play.http.secret.key` value. | ||
|
||
Secrets are stored as `SecureString` parameters. | ||
Private settings are stored as `String` parameters. | ||
|
||
### 2. Stage-specific settings | ||
Settings that aren't private but vary between deployment stages are set in the stage-specific config files in | ||
the `conf` directory. These might be values that we expose in browsers, for example. | ||
|
||
### 3. Global settings | ||
Finally, settings that aren't private and are the same for all deployment stages are set in the `conf/application.conf` | ||
file. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,52 @@ | ||
package load | ||
|
||
import com.gu.conf.{ | ||
ComposedConfigurationLocation, | ||
ConfigurationLoader, | ||
ResourceConfigurationLocation, | ||
SSMConfigurationLocation | ||
} | ||
import com.gu.{AppIdentity, AwsIdentity} | ||
import com.typesafe.config.Config | ||
import play.api.* | ||
import play.api.ApplicationLoader.Context | ||
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider | ||
|
||
import scala.util.{Failure, Success, Try} | ||
|
||
class AppLoader extends ApplicationLoader { | ||
|
||
private val appName = "gatehouse" | ||
|
||
private def buildConfig(context: Context): Try[Config] = { | ||
val credentialsProvider = DefaultCredentialsProvider.create() | ||
val isDev = context.environment.mode == Mode.Dev | ||
for { | ||
identity <- | ||
if (isDev) | ||
Success(AwsIdentity(app = appName, stack = "identity", stage = "DEV", region = "eu-west-1")) | ||
else | ||
AppIdentity.whoAmI(defaultAppName = appName, credentialsProvider) | ||
config <- Try(ConfigurationLoader.load(identity, credentialsProvider) { case identity: AwsIdentity => | ||
ComposedConfigurationLocation( | ||
List( | ||
SSMConfigurationLocation.default(identity), | ||
ResourceConfigurationLocation(s"${identity.stage}.conf"), | ||
) | ||
) | ||
}) | ||
} yield config | ||
} | ||
|
||
override def load(context: Context): Application = { | ||
LoggerConfigurator(context.environment.classLoader).foreach { | ||
_.configure(context.environment, context.initialConfiguration, Map.empty) | ||
LoggerConfigurator(context.environment.classLoader) foreach { _.configure(context.environment) } | ||
buildConfig(context) match { | ||
case Success(config) => | ||
val newContext = | ||
context.copy(initialConfiguration = Configuration(config).withFallback(context.initialConfiguration)) | ||
new AppComponents(newContext).application | ||
case Failure(exception) => | ||
throw exception | ||
} | ||
new AppComponents(context).application | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,8 +15,8 @@ lazy val root = (project in file(".")) | |
s"-J-Dlogs.home=/var/log/${packageName.value}", | ||
), | ||
libraryDependencies ++= Seq( | ||
"software.amazon.awssdk" % "ssm" % "2.23.10", | ||
"net.logstash.logback" % "logstash-logback-encoder" % "7.3", | ||
("com.gu" %% "simple-configuration-ssm" % "1.6.4").cross(CrossVersion.for3Use2_13), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's no Scala 3 version of the library yet |
||
"org.scalatestplus.play" %% "scalatestplus-play" % "7.0.1" % Test, | ||
), | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,7 +34,7 @@ export class Gatehouse extends GuStack { | |
userData: { | ||
distributable: { | ||
fileName: `${ec2App}.deb`, | ||
executionStatement: `dpkg -i /${ec2App}/${ec2App}.deb && echo "stage=${this.stage}" | sudo tee "/etc/gatehouse/stage.conf" > /dev/null`, | ||
executionStatement: `dpkg -i /${ec2App}/${ec2App}.deb`, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because we're getting the stage from EC2 tags, we no longer need to write a file with the stage value in it. |
||
}, | ||
}, | ||
certificateProps: { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include "application.conf" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include "application.conf" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include "application.conf" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,3 @@ | ||
# https://www.playframework.com/documentation/latest/Configuration | ||
include file("/etc/gatehouse/stage.conf") | ||
|
||
play.application.loader=load.AppLoader | ||
|
||
play.application.loader = load.AppLoader | ||
play.filters.hosts.routeModifiers.whiteList = [anyhost] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are you planning to to use play secret rotation ? I think it's still the recommendation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I started looking at that. Thanks for the reminder