のぴぴのメモ

自分用のLinuxとかの技術メモ

AWS Secrets ManagerをVPC閉塞空間で利用するメモ

はじめに

AWS Secrets Managerとは

DBMSアクセスなどで利用するユーザ/パスワードを、アプリケーションのコードに埋め込むとか、APサーバに設定ファイルとしてで腹持ちさせて参照させるとか、セキュリティ的に良くないですがやってしまいがちだと思います。

AWS Secrets Manager はそのような、ユーザ/パスワードなどのシークレット情報を、所有する暗号化キーで暗号化し、AWS Key Management Service (KMS) に保管するサービスです。保管しているシークレート情報は、必要都度に取得して利用します。取得はIAMのきめ細かいポリシーを使用して制限できます。

ここではAWS Secrets ManagerをVPC閉塞空間で利用するための設定し、かつリソースポリシーでシークレット情報を取得可能なVPCを制限する手順を説明します。

  • 特徴*1
    • シークレットのセキュアなストレージ
    • アプリケーションに影響を与えずにシークレットを自動更新(Lambdaを利用(VPC内のLambdaも可能))
    • プログラムでのシークレットの取得
    • シークレットの使用状況の監査と監視
  • 料金: シークレット 1 件あたり 0.40 USD/月、10,000 回の API コールあたり 0.05 USD(2019/2現在)*2

ここでは説明しないこと

このページでは、下記については言及していません。必要に応じて他の情報源を参照して下さい。

  • ネットワーク(VPC、subnet、routeなど)
  • EC2インスタンスの作成(検証用EC2とFowardProxyのセットアップ)
  • RDS Auroraのセットアップ

アーキテクチャ

この手順で作成するSecretsManagerのアーキテクチャ図を示します。

f:id:nopipi:20190212224922p:plain

  • 対象VPC CIDR 10.11.0.0/16

設定手順(SecretsManagerからの情報取得)

SecretsManager用のKMSの鍵作成

SecretsManagerのデフォルトの鍵で暗号化することもできますが、ここでは独自作成したKMSの鍵で暗号化することとし、事前にKMSの鍵を作成します。

  • サービスからKMSのサービス画面に移動する

f:id:nopipi:20190212200743p:plain:w400

  • KMS鍵の名称を入力します

f:id:nopipi:20190212201109p:plain:w400

  • 「タグの追加」はスキップ
  • キーポリシー設定
    • キー管理者の設定:このキーを作成しているユーザのロールを指定します
    • キーの使用アクセス許可: 一旦未指定のままにします(後で作成する、SecretsManagerでシークレット情報を取得するロールを指定します)

新しいシークレットの作成

  • (1)「新しいシークレットの作成」をクリック

f:id:nopipi:20190212195728p:plain:w300

  • (2)シークレットの設定
    • シークレットタイプの選択
      • タイプ: ここでは「RDS データベース認証情報」を選択します
      • 対象DBユーザ: 管理したいDBユーザの、ユーザ名とパスワードを入力します。
      • 暗号化キーを選択: 作成したKMSの鍵を選択します
      • RDS データベースを選択: 対象のRDSを選択します。

f:id:nopipi:20190212210626p:plain:w400

  • (3)新しいシークレットの保存
    • シークレット名称を指定します
  • (4)自動ローテーションの設定
    • 一旦スキップします
  • (5)新しいシークレットの保存
    • 設定したシークレットキーを保存します。

VPC PrivateLinkの作成

Private Link用のセキュリティグループを作成する

対象VPC内からのアクセスを許可するように、対象VPCのCIDRに対してInbound許可を与えます。

タイプ プロトコル ポート範囲 ソース
HTTPS TCP 443 10.11.0.0/16
  • より厳密に設定する場合は、下記2箇所からのHttpsのInboundアクセスを許可させます。その場合、それぞれのSecurity Groupを作成し、そのSecurity Groupをhttpsのインバウンどのソースとして指定するのが効率的で良いです。
    • APサーバ(DBアクセスに必要なユーザ/パスワードのSecretsManagerから取得する)
    • VPC内のLambda(後述するローテーションで利用)
Secrets Manager用のVPC PrivateLinkの作成
  • エンドポイントのサービス名: com.amazonaws.ap-northeast-1.secretsmanager
  • VPCとSubnet: 対象のVPCとSubnetを選択します。今回は、PrivateSubnet1とPrivateSubnet2を選択します。
  • プライベート DNS 名を有効にする: このエンドポイントで有効にする(デフォルト設定のまま)
  • 上記で作成したPrivate Link用のセキュリティグループを選択します。

EC2インスタンスロール

APサーバからSecretsManagerのシークレット情報を取得するためのロールを作成します。ロールにはSecretsManagerからの情報取得のポリシーと、KMSからの鍵取得のポリシーを設定します。
EC2インスタンスから、SecretsManagerからパスワードを取得するIAMロールを作成して、EC2インスタンスにアタッチします。

インラインポリシー*3

下記の2つのポリシーを指定します(ARNは適時修正してください)。

  • (1) SecretsManagerからシークレット情報を取得するためのインラインポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "secretsmanager:GetSecretValue",
                "secretsmanager:DescribeSecret",
                "secretsmanager:ListSecrets"
            ],
            "Resource": "arn:aws:secretsmanager:ap-northeast-1:445629031529:secret:Prod/System-A/RDS/testuser-6l08Sp"
        }
    ]
}
  • (2) KMSから鍵を取得するためのインラインポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "kms:DescribeKey"
            ],
            "Resource": "arn:aws:kms:ap-northeast-1:445629031529:key/df0849ea-0c1a-44e3-b86b-43ae43396384"
        }
    ]
}
信頼関係ポリシー
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
作成ロールのSecretsManager用KMS鍵のキーユーザへの登録

作成したEC2インスタンスロールを利用し、KMSのキーを取得できるように、KMS鍵のキーユーザに作成したロールを追加します。

  • KMSのサービス画面から「カスタマー管理型のキー」を選択し利用する鍵をクリックする
  • 「キーユーザー」に作成したロールを追加する

f:id:nopipi:20190212213205p:plain:w400

APサーバ上のAWS CLI設定

AWS CLIにProxy設定をしている場合、Proxyの除外設定にSecretsManagerのエンドポイントのURL(東京リージョンの場合”secretsmanager.ap-northeast-1.amazonaws.com”)を追加します。追加した後は再ログインして環境変数が反映されていることを確認します。

export HTTPS_PROXY=http://10.1.173.17:3128
export HTTP_PROXY=http://10.1.173.17:3128
export NO_PROXY=169.254.169.254,s3.ap-northeast-1.amazonaws.comi,secretsmanager.ap-northeast-1.amazonaws.com

APサーバでのシークレット情報取得テスト

aws CLIコマンドの" aws secretsmanager get-secret-value"を利用しシークレット情報を取得します。

 aws secretsmanager get-secret-value --secret-id arn:aws:secretsmanager:ap-northeast-1:445629031529:secret:Prod/System-A/RDS/testuser-6l08Sp

RDBにアクセスできるかを確認します。(この例ではMySQLエンジンを利用しています)

mysql --host=<RDSのエンドポイントDNS> --port=<Port番号> --user=<ユーザID> --password='<パスワード>'

リソースポリシーでシークレット情報取得を許可するVPCを制限する

SecretsManagerは、リソースポリシーを設定することが可能です。ただしマネージメントコンソールでは設定できなず、AWS CLIでの設定が必要になります。(ここではAWS CLIでSecrets Managerの管理設定を行うための準備作業は割愛します)

リソースポリシーの設定

今回は特定のVPC Endpoint以外からのリソース情報取得のためのアクセス(GetSecretValue API)を拒否するリソースポリシーを設定します。

AWS CLIを実行する端末上でリソースポリシー用のjsonファイルを用意します。"aws:sourceVpce"には先に作成した、SecretsManager用のVPC EndpointのARNを指定します。

{
   "Version": "2012-10-17",
   "Statement": [
     {
       "Effect": "Deny",
       "Principal": "*",
       "Action": "secretsmanager:GetSecretValue",
       "Resource": "*",
       "Condition": {
         "StringNotEquals": {
           "aws:sourceVpce": "vpce-0b2b52e1dc7772d50"
         }
       }
     }
   ]
}
リソースポリシーのアタッチ*4

AWS CLIの”aws secretsmanager put-resource-policy ”を利用し、SecretsManagerのシークレット情報にリソースポリシーをアタッチします。

aws secretsmanager put-resource-policy --secret-id arn:aws:secretsmanager:ap-northeast-1:445629031529:secret:Prod/System-A/RDS/testuser-6l08Sp --resource-policy file://policy.json
動作テスト
  • (1) VPC内のAPサーバインスタンスからシークレット情報を取得可能なことを確認

AWS CLIを利用し、シークレット情報を取得します。(実際のアプリケーションではAWS SDKを利用しシークレット情報を取得します)

 aws secretsmanager get-secret-value --secret-id arn:aws:secretsmanager:ap-northeast-1:445629031529:secret:Prod/System-A/RDS/testuser-6l08Sp
  • (2)マネージメントコンソールからシークレット情報が取得できないことを確認

f:id:nopipi:20190212230338p:plain:w450

設定手順(ローテーションの設定)

RDBのDB管理者ユーザのログイン情報をシークレットに登録

ローテーション用のLambdaの中でDBMSのユーザ&パスワード更新を実行するため、admin権限のあるDBユーザをSecretsManagerに登録します。

リソースポリシーの一時解除

先に設定したリソースポリシーをアタッチしたままでは、ローテーションの設定が一部できないため、リソースポリシーを一時的に解除します。

aws secretsmanager delete-resource-policy --secret-id arn:aws:secretsmanager:ap-northeast-1:445629031529:secret:Prod/System-A/RDS/testuser-6l08Sp

ローテーションの有効化

  • 「ローテーションの編集」からローテーション設定を行います
  • 自動ローテーションを「有効化」します
  • ローテーションの間隔は、1-365日の間で設定します。
  • 「新しいLambda関数を作成して・・・」を選択します。これを選択するとCloudFormationからLamdbaやLambda実行に必要なIAMロールなどがデプロイされます
  • AWSシークレットマネージャで以前保存したシークレットを資料」を選択し、DBのadminユーザのシークレットを選択します。

f:id:nopipi:20190212231449p:plain

なお私の環境では、VPC内のLambdaで実行しようとするとLambda実行用のIAMロールのcondition設定がうまく働かずLambdaからSecretsManagerへの情報取得が失敗しました。一旦Condition句を削除して動作させるようにしています。

リソースポリシーの再アタッチ

AWS CLIの”aws secretsmanager put-resource-policy ”を利用し、SecretsManagerのシークレット情報にリソースポリシーを再アタッチします。

aws secretsmanager put-resource-policy --secret-id arn:aws:secretsmanager:ap-northeast-1:445629031529:secret:Prod/System-A/RDS/testuser-6l08Sp --resource-policy file://policy.json

ローテーションの確認

マネージメントコンソールの「すぐにシークレットを更新」か、AWS CLIの"aws secrets manager rotate-secret"を利用しシークレットの更新を行います。

f:id:nopipi:20190212233116p:plain:w400

(参考)ローテーション用のLambda関数の作成

ローテーション用のLambda関数を自作することもできます。自作する場合、下記にサンプルのローテーション関数があるのでこちらを参考にするのが良いと思います。