Private Service Connectを使用して、EC2からBigQueryにVPN経由でアクセスする方法 (Part1: 環境準備編)

AWS/Google Cloud間をVPNで接続し、EC2からBigQueryへVPN経由でアクセスする方法を試してみました。Private Service Connectを使用して、Google CloudのVPN内にエンドポイントを作成してGoogle Cloud APIへプライベート接続が可能です。また、Google Cloud APIのDNSをAWSでも使えるようにしてみました。この記事では、検証環境を準備した内容を記載します。
2021.10.11

データアナリティクス事業本部の笠原です。

AWSとGCPをVPN接続して、EC2からBigQueryへアクセスする方法を試してみました。

以下、3つの記事に分けて掲載いたします。

  1. 環境準備編 (この記事)
  2. VPN構築編
  3. PSC/DNS設定編

この記事では、VPN構築する前に準備する、今回の検証用環境について説明します。 VPC/サブネットや仮想マシンを用意する内容ですので、すでに知っているという方は読み飛ばしていただいて構いません。

構成内容

最終的には以下のような構成になります。

AWSからGCPへVPN経由で接続し、Private Service ConnectエンドポイントからBigQueryへ接続します。

本記事では以下のような構成の検証用環境を準備したいと思います。

AWSとGCPにVPCとサブネットを構成し、各サブネットに仮想マシンを用意したいと思います。

GCPは接続確認用で使います。EC2 ⇒ BigQueryへのアクセスには不要になりますので、最終的には削除します。

また、EC2にBigQueryへアクセスする際に使用する bq コマンドを使いたいので、Google Cloud SDKをEC2にインストールするのですが、インストール中にインターネットアクセスが必要です。方法はいくつか考えられますが、今回はNAT Gatewayを利用することで一時的にインターネットアクセスできるようにしたいと思います。NAT GatewayはGoogle Cloud SDKインストール後に削除します。

設定項目

AWS / GCP に分けて説明します。今回はAWS、GCPとも東京リージョンを使用します。

  • AWS: ap-northeast-1
  • GCP: asia-northeast1

また、AWSのVPCは 10.128.0.0/20 、privateサブネットは 10.128.1.0/24 とし、GCPのサブネットは 10.146.0.0/24 としました。

AWS設定

マネジメントコンソール上の操作内容は省略いたしますが、設定に使用したAWS CLIコマンドを掲載いたしますので、ご参考ください。

VPC

  • VPC名: bigquery_vpn_test
  • CIDR: 10.128.0.0/20
aws ec2 create-vpc --cidr-block 10.128.0.0/20
#=> VpcId: vpc-028bdb0ee3a9213b4
aws ec2 create-tags --resources vpc-028bdb0ee3a9213b4 --tags Key=Name,Value=bigquery_vpn_test

Subnet

EC2を配置するprivateサブネットを追加します。

  • Subnet名: bigquery_vpn_test_private_subnet-1
  • CIDR: 10.128.1.0/24
  • アベイラビリティゾーン: ap-northeast-1d
aws ec2 create-subnet --vpc-id vpc-028bdb0ee3a9213b4 --cidr-block 10.128.1.0/24 --availability-zone ap-northeast-1d
#=> SubnetId: subnet-03e945e9c28079b4f
aws ec2 create-tags --resources subnet-03e945e9c28079b4f --tags Key=Name,Value=bigquery_vpn_test_private_subnet-1

NATゲートウェイ用のpublicサブネットも追加します。

  • Subnet名: bigquery_vpn_test_public_subnet-1
  • CIDR: 10.128.0.0/24
  • アベイラビリティゾーン: ap-northeast-1a
aws ec2 create-subnet --vpc-id vpc-028bdb0ee3a9213b4 --cidr-block 10.128.0.0/24 --availability-zone ap-northeast-1a
#=> SubnetId: subnet-054f3f50f4e3047e8
aws ec2 create-tags --resources subnet-054f3f50f4e3047e8 --tags Key=Name,Value=bigquery_vpn_test_public_subnet-1

サブネットをパブリックにする

publicサブネットにインターネットゲートウェイをアタッチしてルーティング設定します。

インターネットゲートウェイ生成

aws ec2 create-internet-gateway
#=> InternetGatewayId: igw-097c7e4fe3ab80ee5

VPCにインターネットゲートウェイをアタッチ

aws ec2 attach-internet-gateway --vpc-id vpc-028bdb0ee3a9213b4 --internet-gateway-id igw-097c7e4fe3ab80ee5

VPCに対してカスタムルートテーブル作成

aws ec2 create-route-table --vpc-id vpc-028bdb0ee3a9213b4
#=> RouteTableId: rtb-0f51593375201bf25

インターネットゲートウェイへのすべてのトラフィック ( 0.0.0.0/0 ) をポイントするルートを作成

aws ec2 create-route --route-table-id rtb-0f51593375201bf25 --destination-cidr-block 0.0.0.0/0 --gateway-id igw-097c7e4fe3ab80ee5

publicサブネットに作成したカスタムルートテーブルを関連付け

aws ec2 associate-route-table  --subnet-id subnet-054f3f50f4e3047e8 --route-table-id rtb-0f51593375201bf25

privateサブネット内にEC2起動

キーペアの作成 (キー名: gcp-vpn-test-kasahara )

aws ec2 create-key-pair --key-name gcp-vpn-test-kasahara --query "KeyMaterial" --output text > gcp-vpn-test-kasahara.pem

カレントディレクトリにキーが出力されるので、 chmod しておきます。

chmod 400 gcp-vpn-test-kasahara.pem

セキュリティグループの作成 (SG名: bigquery_vpn_test-sg )

今回はセキュリティグループのルール追加は無しです。

aws ec2 create-security-group --group-name bigquery_vpn_test-sg --description "sg for bigquery_vpn_test" --vpc-id vpc-028bdb0ee3a9213b4
#=> GroupId: sg-039e68d4778071712

EC2を起動

  • Amazon Linux 2 (x86-64) (image-id: ami-0701e21c502689c31 )
  • インスタンスタイプ: t3a.micro
  • プライベートサブネットに配置
  • 先ほど作成したキーペアとセキュリティグループを指定
aws ec2 run-instances --image-id ami-0701e21c502689c31 --count 1 --instance-type t3a.micro --key-name gcp-vpn-test-kasahara --security-group-ids sg-039e68d4778071712 --subnet-id subnet-03e945e9c28079b4f
#=> InstanceId: i-03c71fcc4ef8e6b20
aws ec2 create-tags --resources i-03c71fcc4ef8e6b20 --tags Key=Name,Value=bigquery_vpn_test

しばらくしてRunningになっているか確認します。

aws ec2 describe-instances --instance-id i-03c71fcc4ef8e6b20

SSM経由でEC2にSSHログインするための設定

プライベートサブネット上のEC2にSSM経由でログインするために以下の内容を実施してます。

  1. EC2にIAMロール付与
  2. SSM用VPCエンドポイント追加

今回はAWS CLIで実施してます。

SSM経由でEC2にSSHログインするために、IAMロールの付与

AWS管理ポリシーの中から、 AmazonEC2RoleforSSM のARNを確認します。

aws iam list-policies --scope AWS --query "Policies[?PolicyName == 'AmazonEC2RoleforSSM']"
#=> "Arn": "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"

以下のjsonドキュメントをカレントディレクトリ配下のjsonファイルに保存します。

今回は EC2AssumeRolePolicy.json としました。

{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Principal": {
            "Service": "ec2.amazonaws.com"
        },
        "Action": "sts:AssumeRole"
    }
}

IAMロール作成 (ロール名: GcpVpnEc2SsmRole )

aws iam create-role --role-name GcpVpnEc2SsmRole --assume-role-policy-document file://EC2AssumeRolePolicy.json

ロールに AmazonEC2RoleforSSM ポリシーをアタッチします。

aws iam attach-role-policy --role-name GcpVpnEc2SsmRole --policy-arn "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM"

インスタンスプロファイル作成 (インスタンスプロファイル名: GcpVpnEc2SsmInstanceProfile )

aws iam create-instance-profile --instance-profile-name GcpVpnEc2SsmInstanceProfile

プロファイルにロールを追加します。

aws iam add-role-to-instance-profile --instance-profile-name GcpVpnEc2SsmInstanceProfile --role-name GcpVpnEc2SsmRole

EC2にアタッチするために、一旦EC2を停止します。

aws ec2 stop-instances --instance-id i-03c71fcc4ef8e6b20

EC2にアタッチ

aws ec2 associate-iam-instance-profile --iam-instance-profile Name=GcpVpnEc2SsmInstanceProfile --instance-id i-03c71fcc4ef8e6b20

SSM経由でEC2にSSHログインするために、SSM用のVPCエンドポイント追加

以下のページを参考にします。

エンドポイント用のセキュリティグループを作成 (SG名: bigquery_vpn_test-ssm-endpoint-sg )

aws ec2 create-security-group --group-name bigquery_vpn_test-ssm-endpoint-sg --description "sg for ssm endpoint" --vpc-id vpc-028bdb0ee3a9213b4
#=> GroupId: sg-0f43c64ef09c225d7

EC2のSG (sg-039e68d4778071712 ) をソースとして、 443 ポートを許可するルールを追加します。

aws ec2 authorize-security-group-ingress --group-id sg-0f43c64ef09c225d7 --protocol tcp --port 443 --source-group sg-039e68d4778071712

エンドポイントのサービス名を確認します。

aws ec2 describe-vpc-endpoint-services --query "ServiceDetails[?contains(ServiceName,\`ssm\`) || contains(ServiceName, \`ec2message\`)].{ServiceName:ServiceName,ServiceType:ServiceType[*].ServiceType}"
[
    {
        "ServiceName": "com.amazonaws.ap-northeast-1.ec2messages",
        "ServiceType": [
            "Interface"
        ]
    },
    {
        "ServiceName": "com.amazonaws.ap-northeast-1.ssm",
        "ServiceType": [
            "Interface"
        ]
    },
    {
        "ServiceName": "com.amazonaws.ap-northeast-1.ssmmessages",
        "ServiceType": [
            "Interface"
        ]
    }
]

エンドポイント追加の前に、VPCのDNSホスト名を有効化する必要があるので、有効化します。

aws ec2 modify-vpc-attribute --enable-dns-hostnames --vpc-id vpc-028bdb0ee3a9213b4

有効化されているか確認します。

aws ec2 describe-vpc-attribute --attribute enableDnsHostnames --vpc-id vpc-028bdb0ee3a9213b4
{
    "VpcId": "vpc-028bdb0ee3a9213b4",
    "EnableDnsHostnames": {
        "Value": true
    }
}

VPCのprivateサブネットに各エンドポイントを作成 (ssm , ssmmessage , ec2message )

aws ec2 create-vpc-endpoint --vpc-id vpc-028bdb0ee3a9213b4 --vpc-endpoint-type Interface --service-name com.amazonaws.ap-northeast-1.ssm --subnet-id subnet-03e945e9c28079b4f --security-group-id sg-0f43c64ef09c225d7
aws ec2 create-vpc-endpoint --vpc-id vpc-028bdb0ee3a9213b4 --vpc-endpoint-type Interface --service-name com.amazonaws.ap-northeast-1.ssmmessages --subnet-id subnet-03e945e9c28079b4f --security-group-id sg-0f43c64ef09c225d7
aws ec2 create-vpc-endpoint --vpc-id vpc-028bdb0ee3a9213b4 --vpc-endpoint-type Interface --service-name com.amazonaws.ap-northeast-1.ec2messages --subnet-id subnet-03e945e9c28079b4f --security-group-id sg-0f43c64ef09c225d7

EC2を起動後、しばらく経ってからssmで、インスタンス情報が取得できればOKです。

aws ec2 start-instances --instance-id i-03c71fcc4ef8e6b20
aws ssm describe-instance-information

あとはローカルの ~/.ssh/config に SSHセッション設定を記載します。 (AWS CLIで使用しているAWSプロファイル名は、適宜変更してください)

Host gcp-vpn-test-kasahara
    ProxyCommand sh -c "aws ssm start-session --target i-03c71fcc4ef8e6b20 --document-name AWS-StartSSHSession --parameters 'portNumber=%p' --region ap-northeast-1 --profile <AWSプロファイル名>"
    User ec2-user
    IdentityFile ~/.ssh/gcp-vpn-test-kasahara/gcp-vpn-test-kasahara.pem

SSHでEC2にログインできればOKです。

ssh gcp-vpn-test-kasahara

一旦ログアウトして、EC2を停止しておきます。

aws ec2 stop-instances --instance-id i-03c71fcc4ef8e6b20

gcloudコマンドインストール (with NATゲートウェイの導入)

確認用に bq コマンドを使えるようにします。 gcloud コマンドをインストールすると、 bq コマンドも使えるようになります。

ただ、 gcloud コマンドインストール時にインターネット接続が必要なので、今回は一時的にNATゲートウェイを導入してプライベートサブネットからインターネット接続できるようにします。

NATゲートウェイ用のElastic IPを取得

aws ec2 allocate-address
#=> AllocationId: eipalloc-0d7457f38318f3690

NATゲートウェイの作成

NATゲートウェイはパブリックサブネットに作成します。

aws ec2 create-nat-gateway --subnet-id subnet-054f3f50f4e3047e8 --allocation-id eipalloc-0d7457f38318f3690
#=> NatGatewayId: nat-0634c1ebc49a7feca

プライベートサブネットで使用しているルートテーブルに、NAT Gatewayへの経路を追加します。

aws ec2 describe-route-tables --filters Name=vpc-id,Values=vpc-028bdb0ee3a9213b4
#=> RouteTableId: rtb-0bc6e62228e1012cb
#=> コマンド実行結果から、VPC(10.128.0.0/20)へのルーティングしか設定していないルートテーブルのIDを参照する
aws ec2 create-route --route-table-id rtb-0bc6e62228e1012cb --destination-cidr-block 0.0.0.0/0 --nat-gateway-id nat-0634c1ebc49a7feca

これでプライベートサブネット上のEC2もインターネットアクセス可能になったので、 EC2インスタンスを起動してからSSHログインしてgcloudインストールします。

aws ec2 start-instances --instance-id i-03c71fcc4ef8e6b20
ssh gcp-vpn-test-kasahara

## EC2上での実行
curl -O https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-359.0.0-linux-x86_64.tar.gz
tar xvf google-cloud-sdk-359.0.0-linux-x86_64.tar.gz
./google-cloud-sdk/install.sh
./google-cloud-sdk/bin/gcloud init

インストールが終了したら、NAT Gatewayは削除しておきます。

## ローカルマシン上で実行
aws ec2 delete-nat-gateway --nat-gateway-id nat-0634c1ebc49a7feca

NAT Gatewayで使用したElastic IPの解放します。

aws ec2 release-address --allocation-id eipalloc-0d7457f38318f3690

プライベートサブネットのルーティングを修正します。 (NAT Gatewayへの経路を削除)

aws ec2 delete-route --route-table-id rtb-0bc6e62228e1012cb --destination-cidr-block 0.0.0.0/0

以上で、AWS側の準備は完了です。

GCP設定

私がGCPに慣れていないため、こちらはマネジメントコンソール上の操作内容を掲載しております。設定時に gcloud コマンドの内容が取得できるので、参考までに掲載しております。

VPC / Subnet

左側メニューの [ネットワーキング] ⇒ [VPCネットワーク] ⇒ [VPCネットワーク] へ。 Compute Engine APIがまだ有効化されていない場合は、有効にしておきます。

「VPCネットワークを作成」をクリックします。

今回は、VPC内のサブネットは東京リージョンのみ1つだけ作成します。

  • VPC名: aws-vpn-test-vpc
  • VPC説明: vpc for aws-vpn-test
  • サブネット:
    • カスタム
    • 新しいサブネット
      • サブネット名: aws-vpn-test-asne1-subnet-1
      • サブネット説明: subnet on asia-northeast1 for aws-vpn-test
      • リージョン: asia-northeast1
      • IPアドレス範囲: 10.146.0.0/24
      • 限定公開のGoogleアクセス: オン
      • フローログ: オフ
      • 「完了」をクリック
  • 動的ルーティングモード: グローバル
  • 最大伝送単位 (MTU): 1460 (default)

同等の gcloud コマンドは以下の通りです。プロジェクト名は適宜変更ください。

gcloud compute networks create aws-vpn-test-vpc --project=<プロジェクト名> --description=vpc\ for\ aws-vpn-test --subnet-mode=custom --mtu=1460 --bgp-routing-mode=global
gcloud compute networks subnets create aws-vpn-test-asne1-subnet-1 --project=<プロジェクト名> --description=subnet\ on\ asia-northeast1\ for\ aws-vpn-test --range=10.146.0.0/24 --network=aws-vpn-test-vpc --region=asia-northeast1 --enable-private-ip-google-access

以下のように一覧にVPCが作成できればOKです。

ファイアウォールルール作成

VMインスタンスに対してコンソール上でSSHを行うために、以下のファイアウォールルールを作成します。 Identity-Aware Proxy(35.235.240.0/20)に対して、SSH(tcp:22)を許可します。

[VPCネットワーキング] ⇒ [ファイアウォール]にて、「ファイアウォールルールを作成」をクリックします。

  • ファイアウォールルール名: aws-vpn-test-allow-iap
  • ログ: オフ (default)
  • ネットワーク: aws-vpn-test-vpc
  • 優先度: 1000
  • トラフィックの方向: 上り
  • 一致したときのアクション: 許可
  • ターゲット: ネットワーク上のすべてのインスタンス
  • ソースフィルタ: IP範囲
  • ソースIPの範囲: 35.235.240.0/20
  • プロトコルとポート: 指定したプロトコルとポート
    • tcp: 22

gcloud compute --project=<プロジェクト名> firewall-rules create aws-vpn-test-allow-iap --direction=INGRESS --priority=1000 --network=aws-vpn-test-vpc --action=ALLOW --rules=tcp:22 --source-ranges=35.235.240.0/20

VMインスタンス作成

[コンピューティング] ⇒ [Compute Engine] ⇒ [VMインスタンス] へ遷移し、「インスタンスを作成」をクリックします。

  • インスタンス名: aws-vpn-test-instance-1
  • リージョン: asia-northeast1
  • ゾーン: asia-northeast1-a
  • シリーズ: E2
  • マシンタイプ: e2-micro (2 vCPU / 1 GB メモリ)
  • サービスアカウント: Compute Engine default service account
  • アクセススコープ: デフォルトのアクセス権を許可
  • ネットワーキング:
    • ネットワークインターフェース:
      • ネットワーク: aws-vpn-test-vpc
      • サブネットワーク: aws-vpn-test-asne1-subnet-1
      • プライマリ内部IP: エフェメラル (自動)
      • 外部IP: エフェメラル
      • 「完了」をクリック

他はデフォルト設定でOKです。

ネットワーキングは省略すると default VPCに設置されます。今回は作成したVPC/Subnetを明示的に指定してあげないと、VPN接続時の疎通確認に失敗します。

gcloud compute instances create aws-vpn-test-instance-1 --project=<プロジェクト名> --zone=asia-northeast1-a --machine-type=e2-micro --network-interface=network-tier=PREMIUM,subnet=aws-vpn-test-asne1-subnet-1 --maintenance-policy=MIGRATE --service-account=<サービスアカウント名>
#...省略...

VMインスタンスが起動できたら、コンソール上の「SSH」をクリックします。ブラウザ上でSSHログインできます。

以降の作業で nslookup を使用するので、SSHログインしてインストールしておきます。

## VMインスタンス上で実行
sudo apt-get install dnsutils

以上で、GCP側環境の準備ができました。

まとめ

今回はCLIベースでの構築ができるようにAWS/GCPでCLIコマンドを用意しました。

Webコンソール上での操作やCfn/CDKなどのツールに慣れている方は適宜読み替えていただければと思います。次はVPN接続設定作業を行います。