[アップデート] AWS PrivateLink がクロスリージョン接続をサポートしました

[アップデート] AWS PrivateLink がクロスリージョン接続をサポートしました

サービスプロバイダー側もコンシューマー側も嬉しいアップデート
Clock Icon2024.12.02

複数リージョンにVPCエンドポイントサービスを立てるの大変

こんにちは、のんピ(@non____97)です。

皆さんVPCエンドポイントサービスを用意して、複数リージョンに用意したくなった場面に直面したことはありますか? 私はあります。

VPCエンドポイントサービスは各リージョンに対して展開を行います。

サービスプロバイダーが仮に複数リージョンに対してVPCエンドポイントサービスを公開したい場合は、各リージョンごとにそのVPCエンドポイントサービスのバックエンドを構築するか、NLBを各リージョンに作成し、ターゲットがあるリージョンのVPCとVPCピアリングやTransit Gatewayで接続する必要がありました。単純に面倒です。

また、VPCエンドポイントサービスの利用者からすると、サービスエンドポイントがあるリージョンにInterface型のVPCエンドポイントを作成し、クライアントが存在するVPCとクロスリージョンでVPCピアリングやTransit Gatewayで接続するといったことが必要でした。こちらも面倒ですね。実際の方法は以下re:Postをご覧ください。

https://repost.aws/ja/knowledge-center/vpc-endpoints-cross-region-aws-services

今回、Interface型のエンドポイントを介して、同じAWSパーティション内の他AWSリージョン上のVPCエンドポイントサービスに接続できるようになりました。

https://aws.amazon.com/jp/about-aws/whats-new/2024/11/aws-privatelink-across-region-connectivity/

これによって、各リージョンごとにVPCエンドポイントサービスのバックエンドを用意したり、クロスリージョンのVPCピアリングやTransit Gatewayが不要になります。

デカいアップデートですね。

実際に試してみました。

いきなりまとめ

  • PrivateLink ReadyパートナーのサービスやNLBとGWLBを使用するエンドポイントサービスについてクロスリージョンで接続可能
    • エンドポイントサービスが公開されているリージョン名を指定する必要がある
  • AWSのサービスに対するGateway型VPCエンドポイント、Interface型 wVPCエンドポイント経由でクロスリージョンで操作することはできない
    • 東京リージョンのS3のVPCエンドポイントを介して、大阪リージョンのS3バケットの操作を行うことはできない
  • VPCエンドポイントサービス側でサポートするリージョンをサービスリージョンとして指定する
    • 複数指定可能
  • 追加課金要素は以下
    • Interface型VPCエンドポイント所有者 : 追加で通常のクロスリージョンのデータ転送料金がかかる
    • VPCエンドポイントサービスの所有者 : アクティブなリモートリージョンごとに固定の時間料金がかかる
  • クロスリージョンをサポートするVPCエンドポイントサービスはNLBが複数AZでデプロイされている必要がある

料金

まず、気になるのは料金です。

AWS公式ドキュメントには以下のような記載がありました。

Cross-Region Connectivity Pricing

You can use Interface endpoints to connect to supported VPC endpoint services outside your AWS region. There is no premium for accessing a service in another region. You incur standard PrivateLink charges for data processing and hours. In addition, AWS cross-region data transfer rates will apply. The Interface endpoint owner will be charged for each Gigabyte transferred inter-region regardless of the directionality of the data transfer. Please visit the Data Transfer section of the Amazon EC2 pricing page for specific data transfer rates between regions.

The service provider incurs a fixed hourly charge per active remote region regardless of the number of VPC endpoints using your service. A region is considered active if it has at least one Interface endpoint connected to the service. You are charged for each hour (or partial hour) that a remote AWS Region is active. The service provider does not incur any additional charges for inter-region data transfer.

(以下機械翻訳)

リージョン間接続の料金

インターフェースエンドポイントを使用して、自分のAWSリージョン外のサポートされているVPCエンドポイントサービスに接続できます。他のリージョンのサービスにアクセスする際の追加料金はありません。データ処理と時間に対する標準のPrivateLinkの料金が発生します。さらに、AWSのリージョン間データ転送料金が適用されます。データ転送の方向に関係なく、リージョン間で転送された各ギガバイトについて、インターフェースエンドポイントの所有者に料金が請求されます。リージョン間の具体的なデータ転送料金については、Amazon EC2料金ページのデータ転送セクションをご参照ください。

サービスプロバイダーは、そのサービスを使用するVPCエンドポイントの数に関係なく、アクティブなリモートリージョンごとに固定の時間料金が発生します。リージョンは、少なくとも1つのインターフェースエンドポイントがサービスに接続されている場合、アクティブとみなされます。リモートAWSリージョンがアクティブである各時間(または部分的な時間)に対して料金が発生します。サービスプロバイダーには、リージョン間のデータ転送に対する追加料金は発生しません。

AWS PrivateLink Pricing – AWS

要するに以下です。

  • Interface型VPCエンドポイント所有者 :
    • 追加で通常のクロスリージョンのデータ転送料金がかかる
    • それ以外の追加料金はなし
  • VPCエンドポイントサービスの所有者 :
    • アクティブなリモートリージョンごとに固定の時間料金がかかる
    • それ以外の追加料金はなし

前者については送信元と送信先、つまりVPCエンドポイントと、公開されているVPCエンドポイントのリージョンの組み合わせで値段が異なります。VPCエンドポイントが東京リージョンの場合、いずれのリージョンに対しても転送料金0.09USD/GB発生します。

EC2 On-Demand Instance Pricing – Amazon Web Services

後者については東京リージョンの場合、0.05USD/h発生します。

やってみた

S3のGateway型VPCエンドポイントの場合

What's NewにはGateway型VPCエンドポイントについて言及がありませんでした。

せっかくなのでGateway型VPCエンドポイントの場合から試してみます。

検証環境は以下のとおりです

S3 Gateway VPCエンドポイント検証環境構成図.png

S3のGateway型VPCエンドポイントを用意しました。Internet Gatewayは用意していないので、S3のAPIを叩くにはVPCエンドポイントを経由するしかない状態です。

EC2インスタンスにはEC2 Instance Connect Endpointを用いて接続します。

VPCはバージニア北部リージョンに作成しました。この状態で東京リージョンのS3バケットのオブジェクトを参照できるかどうか確認します。

まず、バージニア北部リージョンのS3バケットにアクセスします。

$ aws s3api list-objects \
  --max-items 1 \
  --bucket amazon-macie-test-20220426
{
    "Contents": [
        {
            "Key": "/mail/0h6dh494avllegh3fa75bv57psn85p4l83tmilo1",
            "LastModified": "2024-07-25T11:50:51+00:00",
            "ETag": "\"bc839cf24a95b8cb99262d3b82500ea5\"",
            "Size": 7163,
            "StorageClass": "STANDARD",
            "Owner": {
                "DisplayName": "members-31263",
                "ID": "5db712c384fdf0396e5194d45476f176ff2da617c72f50108a1a515684f2d49b"
            }
        }
    ],
    "RequestCharged": null,
    "NextToken": "eyJNYXJrZXIiOiBudWxsLCAiYm90b190cnVuY2F0ZV9hbW91bnQiOiAxfQ=="
}

問題なくアクセスできました。

それでは、次に東京リージョンのS3バケットにアクセスします。

$ aws s3api list-objects \
  --max-items 1 \
  --bucket session-manager-log-ap-northeast-1

1分ほど待ちましたが、変わりありません。

debugモードで再度実行してみます。

$ aws s3api list-objects \
  --max-items 1 \
  --bucket session-manager-log-ap-northeast-1 \
  --debug
2024-11-30 08:28:04,037 - MainThread - awscli.clidriver - DEBUG - CLI version: aws-cli/2.15.30 Python/3.9.16 Linux/6.1.115-126.197.amzn2023.x86_64 source/x86_64.amzn.2023
2024-11-30 08:28:04,037 - MainThread - awscli.clidriver - DEBUG - Arguments entered to CLI: ['s3api', 'list-objects', '--max-items', '1', '--bucket', 'session-manager-log-ap-northeast-1', '--debug']
.
.
(中略)
.
.
20241130/ap-northeast-1/s3/aws4_request
30e27c7e79edcecbea3cc2c877f2cf2241c8a1a78c816b3b049e339faffa0915
2024-11-30 08:28:04,248 - MainThread - botocore.auth - DEBUG - Signature:
754e808b1d113939df81fe577fb6762c6cf14180df4fe344567d36ffc5217627
2024-11-30 08:28:04,248 - MainThread - botocore.endpoint - DEBUG - Sending http request: <AWSPreparedRequest stream_output=False, method=GET, url=https://session-manager-log-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/?encoding-type=url, headers={'User-Agent': b'aws-cli/2.15.30 Python/3.9.16 Linux/6.1.115-126.197.amzn2023.x86_64 source/x86_64.amzn.2023 prompt/off command/s3api.list-objects', 'X-Amz-Date': b'20241130T082804Z', 'X-Amz-Security-Token': b'<セキュリティトークン>', 'X-Amz-Content-SHA256': b'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', 'Authorization': b'AWS4-HMAC-SHA256 Credential=<一時アクセスきー>/20241130/ap-northeast-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=754e808b1d113939df81fe577fb6762c6cf14180df4fe344567d36ffc5217627'}>
2024-11-30 08:28:04,248 - MainThread - botocore.httpsession - DEBUG - Certificate path: /etc/pki/tls/certs/ca-bundle.crt
2024-11-30 08:28:04,248 - MainThread - urllib3.connectionpool - DEBUG - Starting new HTTPS connection (1): session-manager-log-ap-northeast-1.s3.ap-northeast-1.amazonaws.com:443

session-manager-log-ap-northeast-1.s3.ap-northeast-1.amazonaws.comに対して接続しようとして止まっていました。

東京リージョンのサービスエンドポイントにアクセスしようとして以降の処理が実行できていないことが分かります。

ちなみに、--region ap-northeast-1で明示的にリージョンを指定しても変わりありませんでした。

ということで、今回のアップデートはGateway型VPCエンドポイントの場合には影響無いようです。

S3のInterface型VPCエンドポイントの場合

続いて、Interface型VPCエンドポイントの場合です。

構成図は以下のとおりです。

S3 Interface VPCエンドポイント検証環境構成図.png

Interface型のVPCエンドポイントを作成しました。Gateway型VPCエンドポイントへのルートは削除しているので、S3のサービスエンドポイントに接続するためにはInterface型のVPCエンドポイントを経由する必要があります。

まず、バージニア北部リージョンのS3バケット上のオブジェクトを確認してみます。

$ aws s3api list-objects \
  --max-items 1 \
  --bucket amazon-macie-test-20220426 \
  --endpoint-url https://bucket.vpce-05d3b2639158d4a11-1t4kz00l.s3.us-east-1.vpce.amazonaws.com
{
    "Contents": [
        {
            "Key": "/mail/0h6dh494avllegh3fa75bv57psn85p4l83tmilo1",
            "LastModified": "2024-07-25T11:50:51+00:00",
            "ETag": "\"bc839cf24a95b8cb99262d3b82500ea5\"",
            "Size": 7163,
            "StorageClass": "STANDARD",
            "Owner": {
                "DisplayName": "members-31263",
                "ID": "5db712c384fdf0396e5194d45476f176ff2da617c72f50108a1a515684f2d49b"
            }
        }
    ],
    "RequestCharged": null,
    "NextToken": "eyJNYXJrZXIiOiBudWxsLCAiYm90b190cnVuY2F0ZV9hbW91bnQiOiAxfQ=="
}

問題なく接続できました。

それでは、東京リージョンのS3バケットにアクセスします。

$ aws s3api list-objects \
  --max-items 1 \
  --bucket session-manager-log-ap-northeast-1 \
  --endpoint-url https://bucket.vpce-05d3b2639158d4a11-1t4kz00l.s3.us-east-1.vpce.amazonaws.com

An error occurred (PermanentRedirect) when calling the ListObjects operation: The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint: session-manager-log-ap-northeast-1.s3-ap-northeast-1.amazonaws.com
You can fix this issue by explicitly providing the correct region location using the --region argument, the AWS_DEFAULT_REGION environment variable, or the region variable in the AWS CLI configuration file.  You can get the bucket's location by running "aws s3api get-bucket-location --bucket BUCKET".

$ aws s3api list-objects \
  --max-items 1 \
  --bucket session-manager-log-ap-northeast-1 \
  --endpoint-url https://bucket.vpce-05d3b2639158d4a11-1t4kz00l.s3.us-east-1.vpce.amazonaws.com \
  --region ap-northeast-1

An error occurred (PermanentRedirect) when calling the ListObjects operation: The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint: session-manager-log-ap-northeast-1.s3-ap-northeast-1.amazonaws.com
You can fix this issue by explicitly providing the correct region location using the --region argument, the AWS_DEFAULT_REGION environment variable, or the region variable in the AWS CLI configuration file.  You can get the bucket's location by running "aws s3api get-bucket-location --bucket BUCKET".

$ aws s3api list-objects \
  --max-items 1 \
  --bucket session-manager-log-ap-northeast-1.s3-ap-northeast-1.amazonaws.com \
  --endpoint-url https://bucket.vpce-05d3b2639158d4a11-1t4kz00l.s3.us-east-1.vpce.amazonaws.com

An error occurred (NoSuchBucket) when calling the ListObjects operation: The specified bucket does not exist

接続できません。debugのログを確認してみます。

$ aws s3api list-objects \
  --max-items 1 \
  --bucket session-manager-log-ap-northeast-1 \
  --endpoint-url https://bucket.vpce-05d3b2639158d4a11-1t4kz00l.s3.us-east-1.vpce.amazonaws.com \
  --region ap-northeast-1 \
  --debug
2024-12-01 08:16:23,476 - MainThread - awscli.clidriver - DEBUG - CLI version: aws-cli/2.15.30 Python/3.9.16 Linux/6.1.115-126.197.amzn2023.x86_64 source/x86_64.amzn.2023
2024-12-01 08:16:23,476 - MainThread - awscli.clidriver - DEBUG - Arguments entered to CLI: ['s3api', 'list-objects', '--max-items', '1', '--bucket', 'session-manager-log-ap-northeast-1', '--endpoint-url', 'https://bucket.vpce-05d3b2639158d4a11-1t4kz00l.s3.us-east-1.vpce.amazonaws.com', '--region', 'ap-northeast-1', '--debug']
.
.
(中略)
.
.
20241201/ap-northeast-1/s3/aws4_request
149beee502a427760a8fe9e9df25c3de5644d2c9c44e8ebfbd583b77b0cd77aa
2024-12-01 08:16:23,754 - MainThread - botocore.auth - DEBUG - Signature:
fd940891f494a3d98b45095333025a3f4b9ee4b67bf8e3aa593ef27f91d61d3c
2024-12-01 08:16:23,754 - MainThread - botocore.endpoint - DEBUG - Sending http request: <AWSPreparedRequest stream_output=False, method=GET, url=https://bucket.vpce-05d3b2639158d4a11-1t4kz00l.s3.us-east-1.vpce.amazonaws.com/session-manager-log-ap-northeast-1?encoding-type=url, headers={'User-Agent': b'aws-cli/2.15.30 Python/3.9.16 Linux/6.1.115-126.197.amzn2023.x86_64 source/x86_64.amzn.2023 prompt/off command/s3api.list-objects', 'X-Amz-Date': b'20241201T081623Z', 'X-Amz-Security-Token': b'<セキュリティトークン>', 'X-Amz-Content-SHA256': b'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', 'Authorization': b'AWS4-HMAC-SHA256 Credential=<一時アクセスキー>/20241201/ap-northeast-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=fd940891f494a3d98b45095333025a3f4b9ee4b67bf8e3aa593ef27f91d61d3c'}>
2024-12-01 08:16:23,755 - MainThread - botocore.httpsession - DEBUG - Certificate path: /etc/pki/tls/certs/ca-bundle.crt
2024-12-01 08:16:23,759 - MainThread - urllib3.connectionpool - DEBUG - https://bucket.vpce-05d3b2639158d4a11-1t4kz00l.s3.us-east-1.vpce.amazonaws.com:443 "GET /session-manager-log-ap-northeast-1?encoding-type=url HTTP/1.1" 301 None
2024-12-01 08:16:23,760 - MainThread - botocore.parsers - DEBUG - Response headers: {'x-amz-bucket-region': 'ap-northeast-1', 'x-amz-request-id': 'EEEBGXQB62TNT4NC', 'x-amz-id-2': 'jyRYQZD40GdGfKEL5Osj0j04tqA+BlIpf+JgJiX/aC+eV3M01kWo8scLGELl4jnL2rq+mAjYzn0=', 'Content-Type': 'application/xml', 'Transfer-Encoding': 'chunked', 'Date': 'Sun, 01 Dec 2024 08:16:23 GMT', 'Server': 'AmazonS3'}
2024-12-01 08:16:23,760 - MainThread - botocore.parsers - DEBUG - Response body:
b'<?xml version="1.0" encoding="UTF-8"?>\n<Error><Code>PermanentRedirect</Code><Message>The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.</Message><Endpoint>session-manager-log-ap-northeast-1.s3-ap-northeast-1.amazonaws.com</Endpoint><Bucket>session-manager-log-ap-northeast-1</Bucket><RequestId>EEEBGXQB62TNT4NC</RequestId><HostId>jyRYQZD40GdGfKEL5Osj0j04tqA+BlIpf+JgJiX/aC+eV3M01kWo8scLGELl4jnL2rq+mAjYzn0=</HostId></Error>'
2024-12-01 08:16:23,760 - MainThread - botocore.hooks - DEBUG - Event needs-retry.s3.ListObjects: calling handler <bound method RetryHandler.needs_retry of <botocore.retries.standard.RetryHandler object at 0x7f23f10b1a60>>
2024-12-01 08:16:23,760 - MainThread - botocore.retries.standard - DEBUG - Not retrying request.
2024-12-01 08:16:23,760 - MainThread - botocore.hooks - DEBUG - Event needs-retry.s3.ListObjects: calling handler <bound method S3RegionRedirectorv2.redirect_from_error of <botocore.utils.S3RegionRedirectorv2 object at 0x7f23f10b1af0>>
2024-12-01 08:16:23,760 - MainThread - botocore.utils - DEBUG - S3 request was previously redirected, not redirecting.
2024-12-01 08:16:23,761 - MainThread - botocore.hooks - DEBUG - Event after-call.s3.ListObjects: calling handler <function decode_list_object at 0x7f23f390a160>
2024-12-01 08:16:23,761 - MainThread - botocore.hooks - DEBUG - Event after-call.s3.ListObjects: calling handler <function enhance_error_msg at 0x7f23f2645430>
2024-12-01 08:16:23,761 - MainThread - botocore.hooks - DEBUG - Event after-call.s3.ListObjects: calling handler <bound method RetryQuotaChecker.release_retry_quota of <botocore.retries.standard.RetryQuotaChecker object at 0x7f23f10b1550>>
2024-12-01 08:16:23,761 - MainThread - awscli.clidriver - DEBUG - Exception caught in main()
Traceback (most recent call last):
  File "/usr/lib/python3.9/site-packages/awscli/clidriver.py", line 460, in main
    return command_table[parsed_args.command](remaining, parsed_args)
  File "/usr/lib/python3.9/site-packages/awscli/clidriver.py", line 595, in __call__
    return command_table[parsed_args.operation](remaining, parsed_globals)
  File "/usr/lib/python3.9/site-packages/awscli/clidriver.py", line 798, in __call__
    return self._operation_caller.invoke(
  File "/usr/lib/python3.9/site-packages/awscli/clidriver.py", line 931, in invoke
    self._display_response(operation_name, response, parsed_globals)
  File "/usr/lib/python3.9/site-packages/awscli/clidriver.py", line 953, in _display_response
    formatter(command_name, response, stream)
  File "/usr/lib/python3.9/site-packages/awscli/formatter.py", line 77, in __call__
    response_data = response.build_full_result()
  File "/usr/lib/python3.9/site-packages/awscli/botocore/paginate.py", line 446, in build_full_result
    for response in self:
  File "/usr/lib/python3.9/site-packages/awscli/botocore/paginate.py", line 252, in __iter__
    response = self._make_request(current_kwargs)
  File "/usr/lib/python3.9/site-packages/awscli/botocore/paginate.py", line 329, in _make_request
    return self._method(**current_kwargs)
  File "/usr/lib/python3.9/site-packages/awscli/botocore/client.py", line 357, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/usr/lib/python3.9/site-packages/awscli/botocore/client.py", line 724, in _make_api_call
    raise error_class(parsed_response, operation_name)
botocore.exceptions.ClientError: An error occurred (PermanentRedirect) when calling the ListObjects operation: The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint: session-manager-log-ap-northeast-1.s3-ap-northeast-1.amazonaws.com
You can fix this issue by explicitly providing the correct region location using the --region argument, the AWS_DEFAULT_REGION environment variable, or the region variable in the AWS CLI configuration file.  You can get the bucket's location by running "aws s3api get-bucket-location --bucket BUCKET".

An error occurred (PermanentRedirect) when calling the ListObjects operation: The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint: session-manager-log-ap-northeast-1.s3-ap-northeast-1.amazonaws.com
You can fix this issue by explicitly providing the correct region location using the --region argument, the AWS_DEFAULT_REGION environment variable, or the region variable in the AWS CLI configuration file.  You can get the bucket's location by running "aws s3api get-bucket-location --bucket BUCKET".

リダイレクトが上手くいっていないように見えます。

S3の場合は相性が悪いのでしょうか。

SSMのInterface型VPCエンドポイントの場合

ふと、マネジメントコンソールからAWSサービスのVPCエンドポイントを作成する場合、S3のGateway型、Interface型のVPCエンドポイントのどちらもサービスリージョンがus-east-1となっていました。

1.AWSのサービスの場合.png

サービスリージョンが-のものはクロスリージョンで接続できたりするのでしょうか。

切り分けの第一歩として、サービスリージョンがus-east-1となっているSSMのInterface型VPCエンドポイントを作成します。検証環境は以下のとおりです。

SSM Interface VPCエンドポイント検証環境構成図.png

作成後、SSMのバージニア北部のサービスエンドポイント名を名前解決した際に、プライベートIPアドレスが返ってくることを確認します。

$ dig ssm.us-east-1.amazonaws.com +short
10.10.10.138

各リージョンにはSecure StringのSSM Parameter Storeを作成しました。

まず、バージニア北部リージョンのSSM Parameter Storeの値を取得してみます。

$ aws ssm get-parameter \
  --name /test-parameter/us-east-1 \
  --with-decryption
{
    "Parameter": {
        "Name": "/test-parameter/us-east-1",
        "Type": "SecureString",
        "Value": "test-parameter_us-east-1",
        "Version": 1,
        "LastModifiedDate": "2024-12-01T08:24:42.814000+00:00",
        "ARN": "arn:aws:ssm:us-east-1:<AWSアカウントID>:parameter/test-parameter/us-east-1",
        "DataType": "text"
    }
}

問題なく、取得できました。

続いて、東京リージョンのSSM Parameter Storeの値を取得してみます。

$ aws ssm get-parameter \
  --name /test-parameter/ap-northeast-1 \
  --with-decryption

An error occurred (ParameterNotFound) when calling the GetParameter operation: 

$ aws ssm get-parameter \
  --name /test-parameter/ap-northeast-1 \
  --with-decryption \
  --region ap-northeast-1
.
.
(待てどもレスポンス返って来ず)
.
.

$ aws ssm get-parameter \
  --name /test-parameter/ap-northeast-1 \
  --with-decryption \
  --endpoint-url https://vpce-07ebca63de4df3556-cc8eha3u.ssm.us-east-1.vpce.amazonaws.com \
  --region ap-northeast-1

An error occurred (InvalidSignatureException) when calling the GetParameter operation: Credential should be scoped to a valid region. 

はい、何をしても取得できませんでした。

EventBridgeのInterface型VPCエンドポイントの場合

サービスリージョンが-となっているEventBridgeのInterface型VPCエンドポイントを作成します。

VPCエンドポイント作成後、各リージョンのdefaultのEvent Busを取得します。

$ aws events describe-event-bus --name default
{
    "Name": "default",
    "Arn": "arn:aws:events:us-east-1:<AWSアカウントID>:event-bus/default"
}

$ aws events describe-event-bus --name default --region ap-northeast-1
.
.
(待てどもレスポンス返って来ず)
.
.

$ aws events describe-event-bus --name default --region ap-northeast-1 --endpoint-url https://vpce-04105dafdc7c21094vpce-04105dafdc7c21094-1phebdan.events.us-east-1.vpce.amazonaws.com

An error occurred (InvalidSignatureException) when calling the DescribeEventBus operation: Credential should be scoped to a valid region. 

はい、クロスリージョンでは情報取得できませんでした。

また、マネジメントコンソールからタイプAWSのサービスを選択してサービスリージョンを確認すると、先ほどは-だったEventBridgeのサービスエンドポイントがus-east-1になっていました。

2.サービスリージョンがus-east-1として設定されてしまう.png

どうやら、AWSのサービスに対するGateway型VPCエンドポイント、Interface型VPCエンドポイント経由でクロスリージョンで操作することはできないように思えます。

AWS CLIでバージニア北部のVPC上に東京リージョンのSSMのInterface型VPCエンドポイントを作成する場合

このアップデートが行われた時のAWSのAPI更新情報を確認してみます。

CreateVpcEndpoint (updated)

Changes (request, response)

Request

{'ServiceRegion': 'string'}

Response

{'VpcEndpoint': {'ServiceRegion': 'string'}}

Creates a VPC endpoint. A VPC endpoint provides a private connection between the specified VPC and the specified endpoint service. You can use an endpoint service provided by Amazon Web Services, an Amazon Web Services Marketplace Partner, or another Amazon Web Services account. For more information, see the Amazon Web Services PrivateLink User Guide.

AWS API Changes

新たにServiceRegionというオプションが追加されたようですね。

ServiceRegionsと複数のサービスリージョンを指定できないないことから、一つのVPCエンドポイントで複数リージョンへのサービスエンドポイントの接続をしてくれるというものではないようです。

AWSマネジメントコンソールから作成したSSMのInterface型VPCエンドポイントとS3のGateway型VPCエンドポイントの情報を確認します。

> aws ec2 describe-vpc-endpoints --vpc-endpoint-ids vpce-09dced73f5f987917
{
    "VpcEndpoints": [
        {
            "VpcEndpointId": "vpce-09dced73f5f987917",
            "VpcEndpointType": "Interface",
            "VpcId": "vpc-09c0d18682d679c39",
            "ServiceName": "com.amazonaws.us-east-1.ssm",
            "State": "available",
            "PolicyDocument": "{\n  \"Statement\": [\n    {\n      \"Action\": \"*\", \n      \"Effect\": \"Allow\", \n      \"Principal\": \"*\", \n      \"Resource\": \"*\"\n    }\n  ]\n}",
            "RouteTableIds": [],
            "SubnetIds": [
                "subnet-07da63c0cd55acd8b"
            ],
            "Groups": [
                {
                    "GroupId": "sg-04eece19476ae0dba",
                    "GroupName": "launch-wizard-5"
                }
            ],
            "IpAddressType": "ipv4",
            "DnsOptions": {
                "DnsRecordIpType": "ipv4"
            },
            "PrivateDnsEnabled": true,
            "RequesterManaged": false,
            "NetworkInterfaceIds": [
                "eni-0a8a1116e22519ca9"
            ],
            "DnsEntries": [
                {
                    "DnsName": "vpce-09dced73f5f987917-00kjrm2f.ssm.us-east-1.vpce.amazonaws.com",
                    "HostedZoneId": "Z7HUB22UULQXV"
                },
                {
                    "DnsName": "vpce-09dced73f5f987917-00kjrm2f-us-east-1a.ssm.us-east-1.vpce.amazonaws.com",
                    "HostedZoneId": "Z7HUB22UULQXV"
                },
                {
                    "DnsName": "ssm.us-east-1.amazonaws.com",
                    "HostedZoneId": "Z06296902E0PQ5RJV27C2"
                }
            ],
            "CreationTimestamp": "2024-12-01T14:26:46.122000+00:00",
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "ssm"
                }
            ],
            "OwnerId": "<AWSアカウントID>",
            "ServiceRegion": "us-east-1"
        }
    ]
}

> aws ec2 describe-vpc-endpoints --vpc-endpoint-ids vpce-0aee7d1c1c1caa666
{
    "VpcEndpoints": [
        {
            "VpcEndpointId": "vpce-0aee7d1c1c1caa666",
            "VpcEndpointType": "Gateway",
            "VpcId": "vpc-09c0d18682d679c39",
            "ServiceName": "com.amazonaws.us-east-1.s3",
            "State": "available",
            "PolicyDocument": "{\"Version\":\"2008-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"*\",\"Resource\":\"*\"}]}",
            "RouteTableIds": [],
            "SubnetIds": [],
            "Groups": [],
            "PrivateDnsEnabled": false,
            "RequesterManaged": false,
            "NetworkInterfaceIds": [],
            "DnsEntries": [],
            "CreationTimestamp": "2024-11-30T07:27:40+00:00",
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "test-vpcA-vpce-s3"
                }
            ],
            "OwnerId": "<AWSアカウントID>"
        }
    ]
}

SSMのInterface型VPCエンドポイントについてはServiceRegionが設定されていますが、S3のGateway型VPCエンドポイントには設定されていませんね。

このことからもGateway型のVPCエンドポイント経由でクロスリージョン接続はできないようです。

2024/12/1時点でModifyVpcEndpointにサービスリージョンを変更するオプションはありません。

https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifyVpcEndpoint.html

そのため、サービスリージョンは作成時に指定する必要がありそうです。

ただし、2024/12/1時点でAWSサービスのInterface型VPCエンドポイントを作成する際にサービスリージョンを指定する項目は表示されません。

ということでAWS CLIでバージニア北部のVPC上に東京リージョンのSSMのInterface型VPCエンドポイントを作成してみましょう。

> aws ec2 create-vpc-endpoint \
  --vpc-id vpc-09c0d18682d679c39 \
  --vpc-endpoint-type Interface \
  --service-name com.amazonaws.us-east-1.ssm \
  --subnet-ids subnet-07da63c0cd55acd8b \
  --security-group-id sg-04eece19476ae0dba \
  --service-region ap-northeast-1

An error occurred (InternalError) when calling the CreateVpcEndpoint operation (reached max retries: 2): An internal error has occurred

> aws ec2 create-vpc-endpoint \
  --vpc-id vpc-09c0d18682d679c39 \
  --vpc-endpoint-type Interface \
  --service-name com.amazonaws.ap-northeast-1.ssm \
  --subnet-ids subnet-07da63c0cd55acd8b \
  --security-group-id sg-04eece19476ae0dba \
  --service-region ap-northeast-1

An error occurred (InvalidServiceName) when calling the CreateVpcEndpoint operation: The Vpc Endpoint Service 'com.amazonaws.ap-northeast-1.ssm' does not exist

はい、できませんでした。

やはり、AWSのサービスに対するInterface型VPCエンドポイント経由でクロスリージョンで操作することはできません。

自作サービスエンドポイントを用意する

ふとマネジメントコンソールでVPCエンドポイントを作成する際にタイプをPrivateLink Ready パートナーのサービスNLB と GWLB を使用するエンドポイントサービスに指定した場合はクロスリージョンエンドポイントを有効にするというオプションがあることを見つけました。

3.PrivateLink Ready パートナーのサービス.png

4.NLB と GWLB を使用するエンドポイントサービス.png

その他のタイプを選択した際は表示されませんでした。

現時点ではこのタイプに当てはまるもののみクロスリージョン接続できるのでしょうね。

試しに触ってみましょう。

構成図は以下のとおりです。

自作VPCエンドポイント検証環境構成図.png

東京リージョンのVPC上にEC2インスタンスやNLBを作成し、VPCエンドポイントサービスを用意します。

VPCやEC2インスタンス、セキュリティグループは作成済みで、EC2インスタンスではNginxを起動させています。

ターゲットグループとNLBの作成はAWS CLIでささっと行います。

# ターゲットグループの作成
> aws elbv2 create-target-group \
  --name nginx \
  --protocol TCP \
  --port 80 \
  --vpc-id vpc-081ab1b7c99573078 \
  --region ap-northeast-1
{
    "TargetGroups": [
        {
            "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:targetgroup/nginx/d85d4c142b67c750",
            "TargetGroupName": "nginx",
            "Protocol": "TCP",
            "Port": 80,
            "VpcId": "vpc-081ab1b7c99573078",
            "HealthCheckProtocol": "TCP",
            "HealthCheckPort": "traffic-port",
            "HealthCheckEnabled": true,
            "HealthCheckIntervalSeconds": 30,
            "HealthCheckTimeoutSeconds": 10,
            "HealthyThresholdCount": 5,
            "UnhealthyThresholdCount": 2,
            "TargetType": "instance",
            "IpAddressType": "ipv4"
        }
    ]
}

# ターゲットグループへターゲットとなるEC2インスタンスの登録
aws elbv2 register-targets \
  --target-group-arn arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:targetgroup/nginx/d85d4c142b67c750 \
  --targets Id=i-071caad5001856f65 \
  --region ap-northeast-1

# NLBの作成
aws elbv2 create-load-balancer \
  --name nlb-with-sg \
  --type network \
  --subnets subnet-0675d22c0de0d3172 \
  --scheme internal \
  --security-groups sg-0395aa79f959e68ee \
  --region ap-northeast-1
{
    "LoadBalancers": [
        {
            "LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:loadbalancer/net/nlb-with-sg/0ec979406c1bec9d",
            "DNSName": "nlb-with-sg-0ec979406c1bec9d.elb.ap-northeast-1.amazonaws.com",
            "CanonicalHostedZoneId": "Z31USIVHYNEOWT",
            "CreatedTime": "2024-12-01T15:05:43.908000+00:00",
            "LoadBalancerName": "nlb-with-sg",
            "Scheme": "internal",
            "VpcId": "vpc-081ab1b7c99573078",
            "State": {
                "Code": "provisioning"
            },
            "Type": "network",
            "AvailabilityZones": [
                {
                    "ZoneName": "ap-northeast-1a",
                    "SubnetId": "subnet-0675d22c0de0d3172",
                    "LoadBalancerAddresses": []
                }
            ],
            "SecurityGroups": [
                "sg-0395aa79f959e68ee"
            ],
            "IpAddressType": "ipv4",
            "EnablePrefixForIpv6SourceNat": "off"
        }
    ]
}

# NLBのリスナー作成
> aws elbv2 create-listener \
  --load-balancer-arn arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:loadbalancer/net/nlb-with-sg/0ec979406c1bec9d \
  --protocol TCP \
  --port 80 \
  --default-actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:targetgroup/nginx/d85d4c142b67c750 \
  --region ap-northeast-1
{
    "Listeners": [
        {
            "ListenerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:listener/net/nlb-with-sg/0ec979406c1bec9d/30c7f071e41420c6",
            "LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:loadbalancer/net/nlb-with-sg/0ec979406c1bec9d",
            "Port": 80,
            "Protocol": "TCP",
            "DefaultActions": [
                {
                    "Type": "forward",
                    "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:targetgroup/nginx/d85d4c142b67c750",
                    "ForwardConfig": {
                        "TargetGroups": [
                            {
                                "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:targetgroup/nginx/d85d4c142b67c750"
                            }
                        ]
                    }
                }
            ]
        }
    ]
}

# ターゲットグループのヘルスチェックの状態確認
> aws elbv2 describe-target-health \
  --target-group-arn arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:targetgroup/nginx/d85d4c142b67c750 \
  --region ap-northeast-1
{
    "TargetHealthDescriptions": [
        {
            "Target": {
                "Id": "i-071caad5001856f65",
                "Port": 80
            },
            "HealthCheckPort": "80",
            "TargetHealth": {
                "State": "healthy"
            },
            "AdministrativeOverride": {
                "State": "no_override",
                "Reason": "AdministrativeOverride.NoOverride",
                "Description": "No override is currently active on target"
            }
        }
    ]
}

ターゲットグループのヘルスチェックが完了したことまでを確認したら、サービスエンドポイントの作成からはマネジメントコンソールで行います。

サービスリージョンはバージニア北部リージョンと東京リージョンの2つを設定しました。

5.サービスリージョンを複数指定可能.png

その他は以下のように作成します。プライベートDNS名は勢いで指定しただけで実際には使用しません。

6.エンドポイントサービスの作成.png

こちらでエンドポイントサービスを作成しようとすると、Services must support at least 2 availability zones for cross regionと怒られてしまいました。

7.Services must support at least 2 availability zones for cross region.png

NLBの足が生えるサブネットが複数AZになるように変更したのち、リトライするとVPCエンドポイントサービスが正常に作成できました。

8.VPCエンドポイントサービス.png

サービスリージョンも正しく設定できていますね。

それではVPCエンドポイントを作成します。

バージニア北部リージョンにて、クロスリージョンエンドポイントを有効にするで東京リージョンを指定しない場合、こちらのVPCエンドポイントサービスのサービス名の検証に失敗します。

9.サービス名を検証できませんでした。.png

一方、クロスリージョンエンドポイントを有効にするで東京リージョンを指定した場合はービス名の検証に成功します。

10.サービス名が検証されました。.png

良さそうですね。

あとはVPCエンドポイントを作成するだけです。

VPCエンドポイントの作成リクエストを行い、VPCエンドポイントサービス側では接続リクエストの承諾を行います。

11.エンドポイント接続リクエストの承諾.png

正常にVPCエンドポイントサービスの作成が完了しました。

12.VPCエンドポイントが作成されたことを確認.png

それでは動作確認です。

バージニア北部リージョンのEC2インスタンスからVPCエンドポイントのDNS名を用いてアクセスします。

$ curl http://vpce-0d64b36d8587f9cbc-9ppwcycs.vpce-svc-02aa2052f8c181885.ap-northeast-1.vpce.amazonaws.com -v
* Host vpce-0d64b36d8587f9cbc-9ppwcycs.vpce-svc-02aa2052f8c181885.ap-northeast-1.vpce.amazonaws.com:80 was resolved.
* IPv6: (none)
* IPv4: 10.10.10.133
*   Trying 10.10.10.133:80...
* Connected to vpce-0d64b36d8587f9cbc-9ppwcycs.vpce-svc-02aa2052f8c181885.ap-northeast-1.vpce.amazonaws.com (10.10.10.133) port 80
> GET / HTTP/1.1
> Host: vpce-0d64b36d8587f9cbc-9ppwcycs.vpce-svc-02aa2052f8c181885.ap-northeast-1.vpce.amazonaws.com
> User-Agent: curl/8.5.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: nginx/1.26.2
< Date: Sun, 01 Dec 2024 15:30:10 GMT
< Content-Type: text/html
< Content-Length: 615
< Last-Modified: Tue, 22 Oct 2024 19:08:53 GMT
< Connection: keep-alive
< ETag: "6717f845-267"
< Accept-Ranges: bytes
< 
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
* Connection #0 to host vpce-0d64b36d8587f9cbc-9ppwcycs.vpce-svc-02aa2052f8c181885.ap-northeast-1.vpce.amazonaws.com left intact

はい、Nginxのコンテンツが返ってきましたね。

サービスプロバイダー側もコンシューマー側も嬉しいアップデート

AWS PrivateLink がクロスリージョン接続をサポートしたアップデートを紹介しました。

サービスプロバイダー側もコンシューマー側もどちらも手間が減る嬉しいアップデートですね。

AWSのサービスに対するGateway型VPCエンドポイント、Interface型VPCエンドポイント経由でクロスリージョンで操作することはできないので注意しましょう。

この記事が誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.