理系学生日記

おまえはいつまで学生気分なのか

Claude CodeをBedrock連携させた時のネットワーク疎通要件検証

Claude Code、便利ですよね。課金した。コードの自動生成やリファクタリング、ちょっとした調査まで、開発現場での「もう一人の自分」として頼りになる存在です。でも、企業や組織の“境界型ネットワーク”、つまり外部との通信を厳しく制限している環境で使う場合、ネットワーク疎通要件が気になる人も多いのではないでしょうか。

公式ドキュメントに書かれていること

Anthropic公式のセキュリティ要件ページには、Claude Codeが必要とするネットワーク疎通先として

  • api.anthropic.com
  • statsig.anthropic.com
  • sentry.io

の3つが明記されています。これらはAnthropicのクラウドサービスと連携する場合の話。ファイアウォールでこれらのドメインを許可リストに追加すれば、Claude Codeの基本的な機能は動作するでしょう。

ここで一つ疑問が湧きます。Claude CodeはAWS Bedrock経由でも利用できますが、その場合のネットワーク要件はどうなるのでしょう? api.anthropic.comなどのAnthropicのAPIサーバーへのアクセスは発生するのでしょうか。どのドメインに対して穴を開ける必要があるのでしょうか。これを確かめてみました。

確認方法

確認方法としては、みんな大好きパケットキャプチャを使います。Claude Codeをインストールした Docker コンテナを用意し、以下の2パターンでネットワーク通信をキャプチャします。

  1. Anthropic連携モード:公式ドキュメント通りに設定し、AnthropicのAPIサーバーへの通信を確認
  2. Bedrock連携モード:AWSのBedrock経由でClaude Codeを利用し、どのエンドポイントにアクセスしているかを確認

どうせ通信はHTTPSなのでパケット通信の内容を覗くのは面倒です。ここでは、Client HelloのServer Name Indication (SNI)を使って、どのドメインにアクセスしているかを確認します。

なお、今回検証した Claude Codeのバージョンは

claude -v
1.0.24 (Claude Code)

です。

事前準備

雑に、次のようなDockerfileを用意して、Claude Codeをインストールしたコンテナを作成します。

FROM node:24-slim

# Claude Codeのインストール
RUN npm install -g @anthropic-ai/claude-code

# パケットキャプチャ用のtcpdump、
# ネットワーク情報確認用のiproute2をインストール
RUN apt-get update && apt-get install -y tcpdump iproute2 && rm -rf /var/lib/apt/lists/*

これを用いてDockerイメージをビルドします。

docker build -t claudecode .

Anthropic連携モードの確認

公式ドキュメント通りにAnthropicのAPIサーバーを利用するモードで、ネットワーク通信をキャプチャします。

claude code実行用のコンテナを起動します。

docker run -v $(pwd)/pcap:/pcap -it --rm claudecode /bin/tcsh

root@32c7c97e4476:/#

起動したコンテナに対して、さらにパケットキャプチャを開始します。

docker exec -it 32c7c97e4476 tcpdump -i eth0 -s0 -w /pcap/container_traffic.pcap

その後、コンテナ上でClaudeのAuthentication Codeを用いてログインし、Claude Codeにhelloと呼びかけます。

> helloHello! How can I help you today?

以上でClaude Codeを実行した際のネットワーク通信が /pcap/container_traffic.pcap に保存されます。実際にどのドメインにアクセスしているかを確認するため、tshark を使ってパケットキャプチャを解析します。

tshark -r container_traffic.pcap \
       -Y "ip.src == 172.17.0.0/16 and tls.handshake.extensions_server_name" \
       -T fields \
       -e tcp.dstport\
       -e tls.handshake.extensions_server_name \
    | sort | uniq
443 api.anthropic.com
443 console.anthropic.com
443 o1158394.ingest.us.sentry.io
443 raw.githubusercontent.com
443 registry.npmjs.org
443 statsig.anthropic.com
443 www.google.com

www.google.comraw.githubusercontent.comregistry.npmjs.orgなど、AnthropicのAPIサーバー以外にもアクセスが発生していることがわかりますが、Authentication Codeの認証に至る前に Claude Code がブラウザ起動を試行しているので、そのためかもしれません。 総じて言えば、だいたいネットワーク疎通要件の通りな感じはありますね。

Bedrock連携モードの確認

次に、AWSのBedrock経由でClaude Codeを利用するモードで、ネットワーク通信をキャプチャします。こちらは、AWSのBedrockサービスを利用するための設定が必要です。

先ほどのDockerイメージを使って、Bedrock連携モードでコンテナを起動します。ここでは、AWSの認証情報をホストの ~/.aws/credentials からコンテナにマウントしています。その上で、Bedrockのエンドポイントを指定して、Claude Codeを実行します。

docker run -v $(pwd)/pcap:/pcap -v $HOME/.aws/credentials:/root/.aws/credentials:ro -it --rm claudecode /bin/tcsh

root@7f28a0f9ba49:/# CLAUDE_CODE_USE_BEDROCK=1 ANTHROPIC_MODEL='apac.anthropic.claude-3-7-sonnet-20250219-v1:0' AWS_REGION='ap-northeast-1' claude 

この状態で、再度パケットキャプチャを開始し、bedrock_traffic.pcapに保存しました。先ほどと同様のコマンドで、どのドメインにアクセスしているかを確認します。

tshark -r container_traffic.pcap \
       -Y "ip.src == 172.17.0.0/16 and tls.handshake.extensions_server_name" \
       -T fields \
       -e tcp.dstport\
       -e tls.handshake.extensions_server_name \
    | sort | uniq
443 bedrock-runtime.ap-northeast-1.amazonaws.com
443 bedrock.ap-northeast-1.amazonaws.com
443 raw.githubusercontent.com
443 registry.npmjs.org

なるほど、anthropic.com や sentry.io へのアクセスは発生していません。AWSのBedrockサービスを通じて、直接AnthropicのAPIサーバーにアクセスする必要はないようです。 Bedrock連携モードを使う前提で言えば、特段これらドメインへのアクセスを許可する必要はなさそうですね。

githubusercontent.com や npmjs.org へのアクセスは?

ただし、raw.githubusercontent.comregistry.npmjs.org へのアクセスは発生していますが、これは Claude Code の利用に必須なのでしょうか?

この確認のために、Firewallで raw.githubusercontent.comregistry.npmjs.org へのアクセスをブロックしてみます。次のようなスクリプトを init-firewall.sh として作成しました。 実際には、これはClaude Code公式が提供しているファイアウォール設定スクリプトをベースにカスタマイズしたものです。 (実行のためには、上で示したDockerfileにて、iptables ipset dnsutils curl をインストールするよう修正しDockerイメージを再ビルドしておく必要があります。)

#!/bin/bash
set -euo pipefail  # Exit on error, undefined vars, and pipeline failures
IFS=$'\n\t'       # Stricter word splitting

# Flush existing rules and delete existing ipsets
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
ipset destroy allowed-domains 2>/dev/null || true

# First allow DNS and localhost before any restrictions
# Allow outbound DNS
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
# Allow inbound DNS responses
iptables -A INPUT -p udp --sport 53 -j ACCEPT
# Allow outbound SSH
iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT
# Allow inbound SSH responses
iptables -A INPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
# Allow localhost
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# Create ipset with CIDR support
ipset create allowed-domains hash:net

# Resolve and add other allowed domains
for domain in \
    "bedrock.ap-northeast-1.amazonaws.com" \
    "bedrock-runtime.ap-northeast-1.amazonaws.com"; do
    echo "Resolving $domain..."
    ips=$(dig +short A "$domain")
    if [ -z "$ips" ]; then
        echo "ERROR: Failed to resolve $domain"
        exit 1
    fi
    
    while read -r ip; do
        if [[ ! "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
            echo "ERROR: Invalid IP from DNS for $domain: $ip"
            exit 1
        fi
        echo "Adding $ip for $domain"
        ipset add allowed-domains "$ip"
    done < <(echo "$ips")
done

# Get host IP from default route
HOST_IP=$(ip route | grep default | cut -d" " -f3)
if [ -z "$HOST_IP" ]; then
    echo "ERROR: Failed to detect host IP"
    exit 1
fi

HOST_NETWORK=$(echo "$HOST_IP" | sed "s/\.[0-9]*$/.0\/24/")
echo "Host network detected as: $HOST_NETWORK"

# Set up remaining iptables rules
iptables -A INPUT -s "$HOST_NETWORK" -j ACCEPT
iptables -A OUTPUT -d "$HOST_NETWORK" -j ACCEPT

# Set default policies to DROP first
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

# First allow established connections for already approved traffic
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Then allow only specific outbound traffic to allowed domains
iptables -A OUTPUT -m set --match-set allowed-domains dst -j ACCEPT

echo "Firewall configuration complete"
echo "Verifying firewall rules..."
if curl --connect-timeout 5 https://example.com >/dev/null 2>&1; then
    echo "ERROR: Firewall verification failed - was able to reach https://example.com"
    exit 1
else
    echo "Firewall verification passed - unable to reach https://example.com as expected"
fi

このスクリプトをDockerコンテナ内で実行してClaude Codeが実行できれば、raw.githubusercontent.comregistry.npmjs.org へのアクセスは必須ではないと判断できます。 --cap-add=NET_ADMIN が必要なことに注意して、以下のようにコンテナを起動します。

docker run --cap-add=NET_ADMIN -v $(pwd)/pcap:/pcap -v $HOME/.aws/credentials:/root/.aws/credentials:ro -v $(pwd)/init-firewall.sh:/tmp/init-firewall.sh:ro -it --rm claudecode /bin/tcsh
root@0d13e44141fa:/#

ではまず、両ドメインに対して疎通が取れることを確認した上で、ファイアウォール設定スクリプトを実行します。

# 両ドメインに対して疎通が取れることを確認
root@06edb0431dab:/# curl -m 2 registry.npmjs.org
root@06edb0431dab:/# curl -m 2 raw.githubusercontent.com
# ファイアウォール設定スクリプトを実行
root@06edb0431dab:/# /tmp/init-firewall.sh
Resolving bedrock.ap-northeast-1.amazonaws.com...
Adding 54.64.23.202 for bedrock.ap-northeast-1.amazonaws.com
Adding 35.79.34.234 for bedrock.ap-northeast-1.amazonaws.com
Adding 54.238.138.9 for bedrock.ap-northeast-1.amazonaws.com
Resolving bedrock-runtime.ap-northeast-1.amazonaws.com...
Adding 3.114.250.252 for bedrock-runtime.ap-northeast-1.amazonaws.com
Adding 35.73.171.187 for bedrock-runtime.ap-northeast-1.amazonaws.com
Adding 54.248.89.255 for bedrock-runtime.ap-northeast-1.amazonaws.com
Host network detected as: 172.17.0.0/24
Firewall configuration complete
Verifying firewall rules...
Firewall verification passed - unable to reach https://example.com as expected

これでファイアウォール設定が完了しました。疎通確認のため、再度 registry.npmjs.orgraw.githubusercontent.com にアクセスしてみます。

root@06edb0431dab:/# curl -m 2 registry.npmjs.org
curl: (28) Connection timed out after 2000 milliseconds
root@06edb0431dab:/# curl -m 2 raw.githubusercontent.com
curl: (28) Connection timed out after 2000 milliseconds

想定通りアクセスできなくなりました。では、Claude Codeを実行してみます。

root@06edb0431dab:/# CLAUDE_CODE_USE_BEDROCK=1 ANTHROPIC_MODEL='apac.anthropic.claude-3-7-sonnet-20250219-v1:0' AWS_REGION='ap-northeast-1' claude
(略)
> hello world

● Hello! How can I help you today?

無事にClaude Codeが動作しました。raw.githubusercontent.comregistry.npmjs.org へのアクセスは必須ではないようです。

まとめ

今回の検証から、Claude CodeをAWSのBedrock経由で利用する場合、AnthropicのAPIサーバー(api.anthropic.comなど)やsentry.ioへのアクセスは不要であり、必要なネットワーク疎通先はAWSのBedrockエンドポイント(bedrock.ap-northeast-1.amazonaws.comなど)のみで十分であることがわかりました。エンドポイントは、利用するリージョン等で変化するので注意してね。

公式ドキュメントではAnthropic側のAPIサーバーへの許可が前提ですが、Bedrock経由ならAWSの管理下で完結できるため、セキュリティポリシーや運用負荷の観点でも現場にフィットしやすいでしょう。

一方で、今後Claude CodeやBedrockの仕様が変わる可能性もゼロではありません。新しいバージョンや追加機能のリリース時には、再度ネットワーク要件を見直すことをおすすめします。

init-firewall.shの差分

diff -u init-firewall.sh.orig init-firewall.sh
--- init-firewall.sh.orig 2025-06-15 08:02:55
+++ init-firewall.sh 2025-06-15 08:05:50
@@ -27,36 +27,10 @@
 # Create ipset with CIDR support
 ipset create allowed-domains hash:net

-# Fetch GitHub meta information and aggregate + add their IP ranges
-echo "Fetching GitHub IP ranges..."
-gh_ranges=$(curl -s https://api.github.com/meta)
-if [ -z "$gh_ranges" ]; then
-    echo "ERROR: Failed to fetch GitHub IP ranges"
-    exit 1
-fi
-
-if ! echo "$gh_ranges" | jq -e '.web and .api and .git' >/dev/null; then
-    echo "ERROR: GitHub API response missing required fields"
-    exit 1
-fi
-
-echo "Processing GitHub IPs..."
-while read -r cidr; do
-    if [[ ! "$cidr" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]]; then
-        echo "ERROR: Invalid CIDR range from GitHub meta: $cidr"
-        exit 1
-    fi
-    echo "Adding GitHub range $cidr"
-    ipset add allowed-domains "$cidr"
-done < <(echo "$gh_ranges" | jq -r '(.web + .api + .git)[]' | aggregate -q)
-
 # Resolve and add other allowed domains
 for domain in \
-    "registry.npmjs.org" \
-    "api.anthropic.com" \
-    "sentry.io" \
-    "statsig.anthropic.com" \
-    "statsig.com"; do
+    "bedrock.ap-northeast-1.amazonaws.com" \
+    "bedrock-runtime.ap-northeast-1.amazonaws.com"; do
     echo "Resolving $domain..."
     ips=$(dig +short A "$domain")
     if [ -z "$ips" ]; then
@@ -108,11 +82,3 @@
 else
     echo "Firewall verification passed - unable to reach https://example.com as expected"
 fi
-
-# Verify GitHub API access
-if ! curl --connect-timeout 5 https://api.github.com/zen >/dev/null 2>&1; then
-    echo "ERROR: Firewall verification failed - unable to reach https://api.github.com"
-    exit 1
-else
-    echo "Firewall verification passed - able to reach https://api.github.com as expected"
-fi