送信元 IPアドレス に基づいて AWS へのアクセスを拒否する際に追加で設定しておきたいこと

GA technologies SREチームの永冶です。
弊社のオフィスが2019年2月25日から六本木に移転するため、IPアドレス制限の設定変更などに追われていました。。

今回はIPアドレス制限の設定変更と関連して、
送信元 IPアドレスに基づいて AWS へのアクセスを拒否する上でハマったことを書き、何が問題でどう対処すれば良いのかを書きます。
AWSを利用していて、今後同じ状況に立った人が、迅速に対応できることを目的にしています。

「送信元 IPアドレスに基づいて AWS へのアクセスを拒否する」とは

AWSコンソールの使用、AWS CLIの操作が指定したIPアドレス以外からできなくなります。
送信元 IPアドレスに基づいて AWS へのアクセスを拒否されていれば、AWS認証情報が仮に漏洩しても、外部のネットワークであればリソースを操作できません。

AWS: Denies Access to AWS Based on the Source IPの通りにIAMポリシー作成し、IAMグループにポリシーを設定し、制限をかけたいIAMユーザーをグループに所属させることで、基本的な設定ができます。

IAMポリシーは下記のようになります。ip_address_1ip_address_2には実際に使用しているネットワークのグローバルIPアドレスを設定します。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VisualEditor0",
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "NotIpAddress": {
          "aws:SourceIp": [
            "ip_address_1/32",
            "ip_address_2/32"
          ]
        }
      }
    }
  ]
}

発生した問題

ドキュメント通りの設定である程度触っていると、問題がいくつか発生していました。

  1. Secrets Managerのクレデンシャルが作成できません。
  2. AWSコンソール上でLambdaの環境変数の値が取得できません。
  3. AWSコンソール上でSSMパラメータストアの一覧を取得できません。

1. Secrets Managerのクレデンシャルが作成できません。

An error occurred (AccessDeniedException) when calling the GetSecretValue operation: Access to KMS is not allowed」というエラーメッセージが表示されました。
IAMの権限を確認し、エラーメッセージでググってみましたが、有益な情報が得られませんでした。

2. Lambdaの環境変数の値が取得できません。

Lambda was unable to decrypt your environment variables because the KMS access was denied. Please check your KMS permissions. KMS Exception: AccessDeniedException KMS Message: The ciphertext refers to a customer master key that does not exist, does not exist in this region, or you are not allowed to access.」というエラーメッセージが表示されました。

3. SSMパラメータストアの一覧を取得できません。

User: arn:aws:iam::****:user/**** is not authorized to perform: ssm:DescribeParameters on resource: arn:aws:ssm:****:****:* with an explicit deny」というエラーメッセージが表示されました。
調査したところ、CLIでは普通に一覧が取得できました。AWSコンソールでのみ発生する問題のようです。

解決方法

ググっても有益な情報がなかったのでサポートに投げました。。 サポートの回答を元に解決方法を記載します。

Secrets Manager、Lambdaの問題に対する解決方法

1、2はともにKMS関連のエラーでした。 送信元IPアドレス制限を使用して、特定のIPアドレス以外からのすべてのアクセスを拒否してる場合、ユーザーに代わって呼び出しを行うサービスでエラーが発生することがあるとのことでした。

f:id:t_nagaya:20190220191010j:plain
Secrets ManagerからKMSへのリクエストがポリシーに反しておりエラーになっていました
解決方法としてはKMS 条件キーのkms:ViaServiceを使用するのが良いとのことでした。kms:ViaServiceは、Secrets Manager等、特定のサービスを経由してKMSにアクセスするという条件を指定することが可能となります。

変更した後のIAMポリシーは下記の通りです。regionには使用するSecrets Managerのリージョンを記載してください。(東京リージョンであればap-northeast-1)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VisualEditor0",
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "NotIpAddress": {
          "aws:SourceIp": [
            "ip_address_1/32",
            "ip_address_2/32"
          ]
        },
        "StringNotEquals": {
          "kms:ViaService": [
            "secretsmanager.region.amazonaws.com"
           ]
        }
      }
    }
  ]
}

f:id:t_nagaya:20190220191125j:plain
kms:ViaServiceでSecrets ManagerからのKMS呼び出しを許可すればOKです
f:id:t_nagaya:20190220191212j:plain
Lambdaに関しても同様です

Lambdaのエラーについても同様に対処できます。
変更した後のIAMポリシーは下記の通りです。regionには使用するSecrets Managerのリージョンを記載してください。(東京リージョンであればap-northeast-1)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VisualEditor0",
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "NotIpAddress": {
          "aws:SourceIp": [
            "ip_address_1/32",
            "ip_address_2/32"
          ]
        },
        "StringNotEquals": {
          "kms:ViaService": [
            "secretsmanager.region.amazonaws.com",
            "lambda.region.amazonaws.com"
           ]
        }
      }
    }
  ]
}

SSMの問題に対する解決方法

AWSコンソール上で実行されるAPIがAWS内部のAPIで呼ばれたことで、アクセス制限にひっかかってしまったようです。 対策としては「ロールの切り替え」機能を利用するのがいいのではということです。

f:id:t_nagaya:20190222094438j:plain
ロールの切り替え

ロール切り替えの準備

下記の内容で信頼関係のポリシーのあるロールを作成します。aws_account_idに使用しているAWSのアカウントIDを入力します。usernameにロール切り替えを許可するユーザ名を入力します。 ロールには別途必要なポリシーを設定してください。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::aws_account_id:user/username"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "IpAddress": {
          "aws:SourceIp": [
            "ip_address_1/32",
            "ip_address_2/32"
          ]
        }
      }
    }
  ]
}

ロール切り替え

IAMロール作成後、

  1. IAM ユーザーでAWSコンソールにログインします。
  2. ロールの切り替え機能で先程作成したロールに切り替えます。
  3. 切り替えられたロールに付与されたポリシーで Systems Manager を操作します。

公式のドキュメントはこちらです。IAM ロールへの切り替え
CLIの場合はIAM ロールへの切り替え (AWS CLI)を参考にやれば良さそうです。

ここでのIPアドレス制限はロールの切り替え時のIPアドレスで判断されます。なので社内ネットワークにいなければ、ロールの切り替えができないということになります。

備考

IP アドレス条件演算子にはそもそも下記のように記載があります。

aws:SourceIp 条件キーは、テストされた API をユーザーとして直接呼び出す場合に JSON ポリシーでのみ機能します。代わりにサービスを使用してターゲットサービスを呼び出した場合、ターゲットサービスは元のユーザーの IP アドレスではなく呼び出し元サービスの IP アドレスを認識します。これは、AWS CloudFormation を使用して Amazon EC2 を呼び出すことでインスタンスを自動的に作成した場合などに生じることがあります。現在のところ、JSON ポリシーで評価を行うために、発信元サービスを通じて元の IP アドレスをターゲットサービスに渡す方法はありません。これらのタイプのサービス API 呼び出しでは、aws:SourceIp 条件キーを使用しないでください。

サポートに問い合わせるまでもなく、ドキュメントを読めば、
AWSのサービスを使用してターゲットサービスを呼び出した場合、ターゲットサービスは呼び出し元サービスのIPアドレスを認識するということはわかりました。。

まとめ

kms:ViaServiceとロール切り替えを併用すれば、IPアドレス制限をかけつつ、制限前と同様に操作することができそうです。