セキュリティ
一口にセキュリティと言ってもその対象範囲はあまりにも広いため、ここでは秘匿すべき設定情報をどう扱うか、ポイントをお話しします。秘匿すべき設定情報とは、データベースユーザーのパスワードやクラウドサービスの認証キーのことです。人間が脳に記憶しておくべきパスワードと違って、Webアプリケーションが使うパスワードはどこかに平文(または平文に復元しうる状態)で維持せざるをえません。
Web上に公開されているサンプルコードなどでよく見かけるのが、アプリケーションのソースコードまたは設定ファイルに直接書き込んでおいて、そのままビルド、デプロイする方法です。この場合、ソースコードリポジトリにアクセスできるエンジニア全員が秘匿情報にアクセス可能になってしまいます。また、秘匿情報を変更するだけの場面でもいちいちアプリケーションをビルドし直す必要があります。それは面倒なので本番DBのパスワードを変更しないという運用が生まれます。長らく変更しないでいると、その方法や影響範囲が曖昧になっていき、ますます変更が怖くなってしまいます。「ソースコードの変更(リファクタリング)を恐れるな!」と言うエンジニアがDBパスワードの変更を尻込みするのは滑稽です。
秘匿情報がRDBMSのパスワードだけならよいのですが、先述の通り、1つのWebアプリケーションであっても複数のデータ層、複数の外部クラウドサービスを使っていることがあるため、秘匿情報はその数だけあります。数が増えると管理がおざなりになっていきます。
The Twelve-Factor Appの第3章「設定」では次のように提唱されています。
アプリケーションは時に設定を定数としてコード内に格納する。これはTwelve-Factorに違反している。Twelve-Factorは設定をコードから厳密に分離することを要求する。設定はデプロイごとに大きく異なるが、コードはそうではない。
アプリケーションがすべての設定をコードの外部に正しく分離できているかどうかの簡単なテストは、認証情報を漏洩させることなく、コードベースを今すぐにでもオープンソースにすることができるかどうかである。
(中略)
Twelve-Factor Appは設定を環境変数に格納する。 環境変数は、コードを変更することなくデプロイごとに簡単に変更できる。設定ファイルとは異なり、誤ってリポジトリにチェックインされる可能性はほとんどない。また、独自形式の設定ファイルやJava System Propertiesなど他の設定の仕組みとは異なり、環境変数は言語やOSに依存しない標準である。
「設定値をソースコードから厳密に分離する」「設定値の媒介としてOS環境変数を活用する」といった点がポイントです。そのOS環境変数の設定値として秘匿情報をどう安全に渡すのかといった問題は残りますが、少なくとも、アプリケーションのソースコード上に格納し変更したら、いちいちビルドする(それが面倒なので変更しない運用につながる)状態よりはずっとましです。
もう少し現実的に言うなら、百歩譲って設定値がソースコードや設定ファイルに直接書き込まれていてもいいので、それをアプリケーションの外側から上書きできる状態にする。まずそこを目指すとよいでしょう。Spring 3.1以上であれば、SystemEnvironmentPropertySourceが使えます。例えば、以下の通りです。
$ export FOO_BAR=hoge $ java ... (Webアプリケーションの起動コマンド)
そしてWebアプリケーションのコード上はこれで”hoge”で上書きすることができます。
import org.springframework.beans.factory.annotation.Value;
@Component
public FooLogic {
@Value("${foo.bar}")
private String fooBar = "xyz";
// デフォルトでxyzだがOS環境変数あるいは
// Javaシステムプロパティで上書きできる
}
