インターネットを経由せずにClaude Codeを使ってみた(Amazon Bedrock + PrivateLink検証)

記事タイトルとURLをコピーする

インターネットを経由せずにClaude Codeを使ってみた(Amazon Bedrock + PrivateLink検証)

こんにちは。 アプリケーションサービス本部 ディベロップメントサービス2課(AS本部DS2課)の松尾です。 AWS Summit Japan 2026 に参加された皆様、お疲れ様でした!

最近はターミナルを開くとほぼ確実にClaude Codeを起動しているのですが、「これ、パブリックインターネットに出さずに使えないの?」と聞かれることがちらほらあり、実際に検証しました。

3行まとめ

  • Amazon BedrockのVPCエンドポイント(PrivateLink)を使えば、Claude CodeとBedrock間のモデル呼び出しをインターネットに出さない構成が作れる
  • 「動いているように見える」だけでは不安なので、DNS解決結果とVPCフローログの2点でちゃんと裏付けを取った
  • 検証環境の入り口にAWS Client VPNを使ったが、ここで3つほど地味にハマったので補足に残しておく

はじめに

セキュリティポリシー上、業務端末からパブリックインターネットへの直接アクセスを許可できない、という現場は意外とよくあります。そういった環境でもClaude Codeを使いたい場合の選択肢が、Amazon Bedrock経由でAnthropicのClaudeモデルを呼び出し、かつBedrockへのアクセスをVPCエンドポイント(AWS PrivateLink)に閉じる構成です。この構成が取れれば、Claude CodeからBedrockへのモデル呼び出しはパブリックインターネットに出ず、AWSの閉域網の中だけで完結します。

というわけで、今回は「本当にインターネットを経由せずにClaude Codeが動くのか」を、設定を見て満足するのではなく、実際の通信ログまで確認して検証してみました。

構成の考え方

閉域でClaude Codeを使うために必要な要素は、大きく2つだけです。

  1. Claude CodeをAmazon Bedrock経由で動かすCLAUDE_CODE_USE_BEDROCK=1などの環境変数を設定すれば、Claude CodeはAnthropicのパブリックAPIではなくAmazon Bedrockを呼び出すようになります。
  2. BedrockへのアクセスをPrivateLinkに閉じる:VPCにbedrock-runtimeのインターフェイスエンドポイントを作成すると、Amazon Bedrock Runtimeへの通信がインターネットを経由せず、AWSのプライベートネットワーク内で処理されます。

あとは、この構成にどうやって到達するかです。社内からDirect ConnectやSite-to-Site VPNでVPCに接続できる環境ならそのまま使えますが、今回は個人の検証用としてAWS Client VPNでVPCへの経路だけ用意しました。Client VPNはあくまで「VPCへの入り口」の一つで、主役はあくまでBedrockのPrivateLink化のほうです。

構成図にすると、こんなイメージです。

構成イメージ

検証環境はこんな感じです。

  • リージョン:アジアパシフィック(東京)(ap-northeast-1
  • 使用サービス:Amazon VPC、VPCインターフェイスエンドポイント(bedrock-runtime)、AWS Client VPN、Amazon Bedrock(Anthropic Claude Sonnet 4.6)
  • 構築方法:CloudFormation
  • 検証日:2026年7月2日

動作確認:本当にインターネットを経由していないか

Claude Codeが「動いた」だけでは、実はまだインターネットを経由していない証明にはなりません。ここは2段階でチェックしました。

① DNS解決先がプライベートIPになっているか

まず、bedrock-runtime.ap-northeast-1.amazonaws.comの名前解決結果が、VPCエンドポイントのプライベートIP(10.0.x.x)になっているかを見ます。パブリックIPが返ってきた時点で、それはインターネット経由になってしまっています。

dscacheutil -q host -a name bedrock-runtime.ap-northeast-1.amazonaws.com

② VPCフローログで、実際の通信を裏付ける

DNSが正しくても、そもそもTCP接続が失敗していたら意味がありません。VPCエンドポイントのENIにVPCフローログを設定し、Bedrockモードで起動したClaude Codeから実際にプロンプトを送信して記録を見てみました。

送信元 → 10.0.1.175:443(VPCエンドポイント)   リクエスト、約3.5KB、ACCEPT
10.0.1.175:443 → 送信元                      レスポンス、約5.9KB、ACCEPT

このタイムスタンプ、実際にclaudeへプロンプトを送った時刻とちゃんと一致していました。数KB規模のデータが双方向で流れているので、疎通確認レベルの話ではなく、実際のプロンプトとClaudeの応答のやり取りがPrivateLink経由で処理されたと言えそうです。

まとめ

Amazon BedrockのVPCエンドポイント(PrivateLink)を使えば、Claude CodeからBedrockへのモデル呼び出しをパブリックインターネットに出さない構成が作れます。「動いていそうだから大丈夫」で終わらせず、DNS解決結果とVPCフローログの2点で裏を取っておくと安心です。社内ネットワークからVPCへの経路(Direct Connect、Site-to-Site VPN、Client VPNなど)が確保できる組織であれば、同じ考え方でセキュリティ要件を満たしたままClaude Codeを使えるはずです。

検証が終わったら、作成したVPCエンドポイントやVPCフローログ(Client VPNを使った場合はそのエンドポイントとACM証明書も)を忘れずに削除しておきましょう。地味に費用がかさみます。

少し駆け足なご紹介でしたが、この内容が何かのお役に立てば幸いです。


補足:AWS Client VPNで検証環境を作るときにハマった3点

今回はVPCへの入り口にAWS Client VPNを使ったのですが、構築中にいくつか地味なところでハマったので、同じように検証環境を組む方向けに残しておきます。

1. aws acm list-certificatesはデフォルトで一部の証明書を隠してくる

mTLS用の証明書をeasy-rsaで作る際、Get started with AWS Client VPNの手順どおり、サーバー証明書には--san=DNS:serverを付ける必要があります。これを忘れるとCertificate ... does not have a domainというエラーになるのですが、この失敗した証明書、aws acm list-certificatesデフォルト表示(ドメインを持つ証明書のみ)からは見えなくなります。全件確認するには--includes keyTypes=RSA_2048,...を明示する必要があり、地味に気づきにくいポイントでした。

2. macOSはVPNが配布したDNSサーバーを勝手には使ってくれない

Client VPNをスプリットトンネル構成にすると、VPNが配布するDNSサーバーをmacOSのシステムリゾルバが自動的に採用してくれません。/etc/resolver/にドメイン単位のSplit DNSを設定する必要があり、さらに厄介なことにnslookupdigはこの設定を無視するので、確認にはdscacheutilを使う必要があります。

sudo mkdir -p /etc/resolver
sudo tee /etc/resolver/amazonaws.com <<'EOF'
nameserver 10.0.0.2
EOF

dscacheutil -q host -a name bedrock-runtime.ap-northeast-1.amazonaws.com

3. VPCエンドポイントのセキュリティグループは、Client VPNのCIDRではなく「SNAT後のIP」で許可する

AWS Client VPNは、VPCへ通信を転送する際に送信元IPをClient VPNネットワークインターフェースのIPにSNATします。そのため、VPCエンドポイント側のセキュリティグループでClientCidrBlockを許可しても実際の送信元とは一致せず、接続がタイムアウトしてしまいます。正しくは、Client VPNエンドポイントに割り当てたセキュリティグループをソースとして参照します。

BedrockEndpointIngressFromClientVpn:
  Type: AWS::EC2::SecurityGroupIngress
  Properties:
    GroupId: !Ref BedrockEndpointSecurityGroup
    IpProtocol: tcp
    FromPort: 443
    ToPort: 443
    SourceSecurityGroupId: !Ref ClientVpnSecurityGroup

「設定は合っているはずなのに繋がらない」というときは、クライアント側(VPNやEDRエージェントなど)を疑いたくなるのですが、まずはVPCフローログでAWS側に本当にパケットが届いているかを確認するのが一番の近道でした。