Spring Boot でパスワードなどのパラメータをセキュアに扱う方法を調べていて、AWS Secrets Manager との連携についても試してみたので、簡単にまとめてみます。
AWS Secrets Manager とは
シークレット(パラメータと値)をセキュアに管理できるAWSのサービスです。DBのパスワードなどをアプリケーションの設定ファイルに定義する代わりに Secrets Manager に保存し、使用時にアプリケーションが取得することによってセキュリティを高めます。
シークレットは自動更新(ローテーション)することもできますが、これはLambda関数が作成されて、対象のシステムのパスワードと Secrets Manager のシークレットを同時に更新することによって実現しているようです。
Spring Boot からの使い方
Spring Cloud のプロジェクトを追加するだけですぐに使えるようになりました。
まずは build.gradle に次の依存関係を追加します。
implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-aws-secrets-manager-config', version: '2.2.6.RELEASE'
これによってアプリの起動時に内部で Secrets Manager へアクセスするクライアントが生成され、自動的にシークレットを取得してくれます。使用する認証情報は AWS SDK の例に漏れず、環境変数や credentials、EC2インスタンスの場合はプロファイルのものとなります。
この状態で「/secret/{アプリケーション名}」という名前のシークレットを作成し、上のような値を保存します。
@RestController
public class SimpleResponseController {
/** a secret parameter stored in AWS Secrets Manager */
@Value("${application.auth.password}")
private String password;
@RequestMapping(path = "/", method = RequestMethod.GET)
public String index() {
return "password = " + password;
}
}
あとはapplication.ymlの値を参照するのと同様に@Valueでキーを指定してあげるだけで使用できます。すごく簡単!(色々あってここにたどり着くまで苦労したけどな!w) ちなみにapplication.ymlと Secrets Manager の両方に同じパラメータがある場合は Secrets Manager のものが優先されます。
設定方法や仕様
Secrets Manager のアプリケーション側の設定は、application.ymlではなくbootstrap.yml(または.properties)に記述する必要があります。項目はこのページの通りで、有効・無効を切り替える以外はデフォルト値でも問題ありません。
aws:
secretsmanager:
# prefix: /sercet
# defaultContext: application
# profileSeparator: _
# failFast: true
# name: minimal-api
enabled: true
# region: ap-northeast-1
ちなみにこのbootstrap.ymlは Spring Cloud で使用するものらしく、application.ymlよりも先に読み込まれます。Spring Cloud には Spring Cloud Config という、設定をクラウドから取得するようなプロジェクトもあるので、それらとの兼ね合いでbootstrap.ymlが必要になったのかなと推測しています。
Spring Boot のプロファイルも活用することができ、例えばdevを指定すると「/secret/{アプリケーション名}_dev」というシークレットを見に行ってくれます。
また、Secrets Manager ではAPIコールの回数によって料金が発生しますが(10,000コール当たり0.05$/月とごく僅かですが)、実装を見るとアプリの起動時にGetSecretValueで一括してシークレットを取得しているので、シークレットの数だけ問い合わせが発生するということもなさそうです。
雑感
仕組みさえ分かれば簡単に使えるので、アプリへの導入はすぐに行えます。設定だけで実装が不要なのも嬉しいところ。ただ、起動時に取得した値を使い続ける Spring Boot だとローテーションを活かすことは難しく、それならば単に暗号化のライブラリを追加してちょこっと実装する方がいいのかなと思いました。