AWS(ECS / EC2)で、データベースのパスワードやRSAの秘密鍵を使う場合は、 AWS Secrets Managerから取得すると良い
Terraformの設定
AWS Secrets Manager
AWS Secrets Managerをterraformで作成する
resource "aws_secretsmanager_secret" "something" {
name = "${var.app_name}/${terraform.workspace}/something"
kms_key_id = "${aws_kms_key.main.key_id}"
}
resource "aws_secretsmanager_secret_version" "something" {
secret_id = "${aws_secretsmanager_secret.something.id}"
secret_string = "{}"
lifecycle {
ignore_changes = ["secret_string"]
}
}
IAM Role
AWS Secrets Managerから読みこむための権限を追加する
AWS Secrets Managerのデータは暗号化されているので、復号のためにKMSへのアクセス権も必要になる
data "aws_caller_identity" "current" {}
resource "aws_iam_role_policy" "something" {
name = "${var.app_name}_${terraform.workspace}_something_secrets"
role = "${aws_iam_role.something.id}"
policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [ "secretsmanager:GetSecretValue" ],
"Resource": "arn:aws:secretsmanager:${var.aws_region}:${data.aws_caller_identity.current.account_id}:secret:${var.app_name}/${terraform.workspace}/something-*"
},
{
"Action": [
"kms:Decrypt"
],
"Resource": "${aws_kms_key.main.arn}",
"Effect": "Allow"
}
]
}
POLICY
}
ECS
Spring BootからAWS Secrets Managerにアクセスするための情報を環境変数にセットする
resource "aws_ecs_task_definition" "something" {
container_definitions = <<CONTAINER_DEF
[
{
...
"environment": [
{
"name": "AWS_SECRETSMANAGER_ENABLED",
"value": "true"
},
{
"name": "AWS_SECRETSMANAGER_NAME",
"value": "${var.app_name}/${terraform.workspace}/something"
},
{
"name": "AWS_SECRETSMANAGER_REGION",
"value": "${var.aws_region}"
}
]
}
]
CONTAINER_DEF
}
依存関係
依存関係にAWS SDK for Javaを追加する
// build.gradle
buildscript {
dependencies {
classpath "io.spring.gradle:dependency-management-plugin:1.0.3.RELEASE"
}
}
apply plugin: "io.spring.dependency-management"
dependencyManagement {
imports {
mavenBom 'com.amazonaws:aws-java-sdk-bom:1.11.343'
}
}
dependencies {
compile "com.amazonaws:aws-java-sdk-secretsmanager"
}
SpringのEnvironmentにAWS Secrets Managerから取得したデータをセットする
package org.example
import com.amazonaws.services.secretsmanager.*
import com.amazonaws.services.secretsmanager.model.*
import com.fasterxml.jackson.databind.*
import org.springframework.boot.*
import org.springframework.boot.env.*
import org.springframework.core.env.*
class AwsSecretsManagerEnvironmentPostProcessor : EnvironmentPostProcessor {
override fun postProcessEnvironment(env: ConfigurableEnvironment, application: SpringApplication) {
// AWS上で動いているときのみにAWS Secrets Managerを使う
if (!env.getProperty("aws.secretsmanager.enabled", Boolean::class.java, false)) {
return
}
val req = GetSecretValueRequest()
req.secretId = env.getProperty("aws.secretsmanager.name") ?: return
val region = env.getProperty("aws.secretsmanager.region") ?: return
val client = AWSSecretsManagerClientBuilder.standard()
.withRegion(region)
.build()
val secretString = client.getSecretValue(req).secretString
@Suppress("UNCHECKED_CAST")
val map = ObjectMapper().readValue(secretString, Map::class.java) as Map<String, Any>
env.propertySources.addFirst(MapPropertySource("secrets", map))
}
}
EnvironmentPostProcessorをSpringに登録する
src/main/resources/META-INF/spring.factoriesに追記する
org.springframework.boot.env.EnvironmentPostProcessor=org.example.AwsSecretsManagerEnvironmentPostProcessor