Amazon VPC LatticeでIAM認証を使って通信元を制限してみた

2023.08.17

こんにちは、AWS事業本部の木村です。

今回はAmazon VPC LatticeでIAM認証を使って通信元を制限する機会がありましたので、記事にしたいと思います。

Latticeについて

今回はLatticeの詳細な作成方法の説明や概要については取り扱いません。

作成方法や概要は以下記事をご参照ください。

概要

作成方法

Latticeの認証について

Latticeの認証について要点をまとめて説明したいと思います。

詳細は以下の公式ページをご参照ください

https://docs.aws.amazon.com/ja_jp/vpc-lattice/latest/ug/auth-policies.html

LatticeのIAM認証ですが、LatticeサービスネットワークとLatticeサービスの2箇所で設定することができます。
両方に認証を設定している場合、両方で明示的なAllowである場合のみ実行することが可能です。

LatticeサービスはLatticeサービスネットワークに対して複数紐付けることになりますので、Latticeサービスネットワークの認証はそれに紐づく全てのLatticeサービスの実行を制限する形となります。
ですので、全体に対するガードレール的な設定をLatticeサービスネットワークで設定する。細かい制御はLatticeサービスで設定するという方法が良いのではないかと思っております。

またそれぞれの認証にてprincipalを指定した場合、対象となるリソースにLatticeのInvoke権限と認証リクエストが必要になります。

それぞれの設定方法に関しては後ほどの項目の中で説明したいと思います。

今まで説明した要素が一つでも欠けていると実行ができませんので、認証が失敗してしまう際には何か設定が欠けていないかご確認ください。

どちらかの認証でprincipalを指定している場合をフローにしてみるとこのようになります。

作っておいてなんですが、わかりにくいですね。

条件を羅列すると以下になります。
①Latticeサービスネットワークの認証で明示的なAllowがあるorそもそも認証が設定されていない
②Latticeサービスの認証で明示的なAllowがあるorそもそも認証が設定されていない
③実行する対象(IAMロール、ユーザー)に対して、LatticeのInvoke権限が付与されている
④認証リクエストを行っている
の全てを満たす必要があり、一つでも欠けるとDenyされてしまいます。

Latticeサービスネットワーク、Latticeサービスともに認証を設定していない
もしくは
Latticeサービスネットワーク、Latticeサービスで認証を設定しているがprincipalを設定していない場合は
①Latticeサービスネットワークの認証で明示的なAllowがあるorそもそも認証が設定されていない
②Latticeサービスの認証で明示的なAllowがあるorそもそも認証が設定されていない
の2つを満たせば実行が可能です。

今回はprincipalを指定して、IAM認証を設定していきますので、4つの条件を満たすように作成を行います。

やってみる

今回作成する構成がこちらです。

インスタンスAとインスタンスBが存在するVPCからLatticeを通じて、別のVPCにあるLambdaを実行します。

IAM認証を設定しない場合は、インスタンスAとインスタンスBの双方からLambdaAとLambdaBの実行を行うことができますが、
IAM認証を利用することで以下のように、対象を制限した通信ができることを目標に設定を行なっていきます。

では早速作成を行っていきたいと思います。

IAMロール作成

インスタンスの引き受けたインスタンスプロファイルを指定して、制限を行うこともできるのですが汎用性を考えて今回はロールを指定して制限を行っていきたいと思います。

ですのでEC2の引き受ける、2つのロールを作成していきます。

ではロールを作成していきます。

EC2に引き受けさせるので、EC2を選択してください。

後々SSM接続を利用しますので、「AmazonSSMManagedInstanceCore」を選択しアタッチしてください。

ロール名は二つの区別が着くように、任意の名前を設定して作成してください。

同じ作業を繰り返し行って、2つ分のロールを作成します。

この後が注意点なのですが、IAM認証を追加すると実行ロールにLatticeのInvoke権限が必要になります。

認証をなしにしている場合は、Invoke権限がなくても実行できたので気にすることはありませんでした。

しかしIAM認証の設定を行うと(厳密にはpricipalでワイルドカード以外を指定する)実行ロールにLatticeのInvoke権限があるかチェックされているようで、LatticeのInvoke権限ないと実行を行うことができませんでした。

見落としがちな点かと思いますので、設定の際はご注意ください。

ではポリシーを作成してアタッチしていきます。

作成画面で直接JSONを編集して作成してください。

作成の際は以下をコピペして貼り付けてください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "vpc-lattice-svcs:Invoke"
            ],
            "Resource": "*",
            "Effect": "Allow"
        }
    ]
}

ポリシーが作成できたら、先ほど作成したロールにポリシーをアタッチします。

これを二つのロールに設定したら、IAMロールの準備は完了です。

インスタンスAにロールA、インスタンスBにロールBといった形でロールを設定してそれぞれインスタンスを起動してください。

Lambdaの作成

LambdaA successとLambdaB successと返すLambdaを作成します。

文字列を返すのみですので、作成方法は割愛します。

ターゲットグループの作成

続いてLatticeのターゲットグループを設定していきます。

ターゲットタイプにLambdaを指定します。

LambdaAを対象として指定して作成します。

同様の手順でLambdaBを対象とした、ターゲットグループも同様の手順で作成します。

ターゲットグループの作成は以上です。

Latticeサービスの作成

続いてLatticeサービスを設定していきます。

任意の名前を設定して、次へ進みます。認証前には両方から通信を行えることを確認したいので、この時点では認証は設定しません。

続いてリスナールールを設定します。それぞれのパスを指定した際に先ほど作成した指定のターゲットグループに紐づくように設定します。

この際、デフォルトアクションが必要となりますので任意の値を指定してください。

その後は設定を変更せず、デフォルトのまま作成してください。

Latticeサービスの作成は以上です。

Latticeサービスネットワークの作成

最後にLatticeサービスネットワークを設定していきます。

任意の名前を設定して、先ほど作ったLatticeサービスとEC2インスタンスを設置したVPCの関連付けを行って作成してください。

ここまでで、事前の準備は完了です。

認証がない状態でテストしてみる

では事前の準備が完了したので、疎通を行ってみましょう。

この時点では認証を行っていないので、以下の図の状態になるはずです。

実施に実行してみましょう。

インスタンスA

インスタンスB

どちらのインスタンスからもどちらのLambdaにも疎通を取ることができました。

では、ここから本題の認証を行い通信を制限していきます。

認証の設定

前項で説明した通り、LatticeサービスネットワークにもLatticeサービスにもIAM認証を設定できるのですが、今回は設定するケースが多そうなLatticeサービスにIAM認証を設定していきたいと思います。

作成したLatticeサービスを選択し、アクセスタブからアクセス設定を編集を選択してください。

認証タイプをAWS IAMを選択するとポリシーを適用できる画面が表示されます。

実行するためには、認証ポリシーにそれぞれのインスタンスからの明示的なAllowが必要となりますのでそれぞれのリソースを許可するようにポリシーを作成していく必要があります。

今回は以下のようなポリシーを設定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "<インスタンスA用のロールのARN>"
            },
            "Action": "vpc-lattice-svcs:Invoke",
            "Resource": "<先ほど作成したサービスのARN>/lambdaa"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "<インスタンスB用のロールのARN>"
            },
            "Action": "vpc-lattice-svcs:Invoke",
            "Resource": "<先ほど作成したサービスのARN>/lambdab"
        }
    ]
}

<>内はそれぞれの環境に合わせて置き換えてください。

この内容で設定を更新してください。

設定は以上です。

疎通確認

では設定通り通信の制限ができているか確認しましょう。

IAM認証を行うと追加で認証の設定が必要となります。

https://docs.aws.amazon.com/ja_jp/vpc-lattice/latest/ug/sigv4-authenticated-requests.html

公式ドキュメントを参考にSIGv4の認証リクエストを作成します。

今回はインスタンスからPythonを実行する形で行います。

以下ファイルをインスタンス上で作成してください。

from botocore.auth import SigV4Auth
import requests 
from botocore.awsrequest import AWSRequest
from botocore.credentials import Credentials
import botocore.session

if __name__ == '__main__':
    session = botocore.session.Session()
    sigv4 = SigV4Auth(session.get_credentials(), 'vpc-lattice-svcs', 'ap-northeast-1')
    endpoint = 'http://<サービスのドメイン/パス>'
    data = None
    headers = {'Content-Type': 'application/json'}
    request = AWSRequest(method='POST', url=endpoint, data=data, headers=headers)
    request.context["payload_signing_enabled"] = False # payload signing is not supported
    sigv4.add_auth(request)
    
    prepped = request.prepare()
    
    response = requests.post(prepped.url, headers=prepped.headers, data=data)

    print(response.text)

<>内は環境に合わせて置き換えを行い、lambdaaとlambdabの二つ分をそれぞれのインスタンスに準備してください。

ではそれぞれのインスタンスで試していきます。

今回Amazon Linux2で検証を行っていますがその際はライブラリが不足していましたので、以下コマンドを事前に実行しております。

pip3 install botocore
pip3 install requests

インスタンスA

無事Lambdaaのみ通信でき、Lambdabの実行ができないことが確認できました。

インスタンスB

こちらでも無事Lambdabのみ通信でき、Lambdaaの実行ができないことが確認できました。

以上にてIAM認証の確認を終了します。

まとめ

きめ細かい通信の限定ができるLatticeのIAM認証を設定してみました。
VPCからアクセスできる絞りたいというケースは結構あるかと思いますので、その際試して見てください!
公式ドキュメントやワークショップなどを見ながら検証を行っていたのですが、IAM側にもInvoke権限が必要なことや認証の設定が必要なことに気づけず検証に時間がかかってしまいました。
この記事によって見てくださった方の作業時間が短縮につながれば幸いです。
以上、AWS事業本部の木村でした。

参考