Skip to main content

TCP/443は通るのにAWS CLIはタイムアウトする――Windows EC2のプロキシ設定を切り分けた話

■  目次 

    1. 発生した事象:AWS CLIでS3へファイルをアップロードするとタイムアウトする
    2. AWS側には問題が見つからなかった
    3. TCP/443の成功は「AWS CLIも同じ経路を通る」という意味ではない
    4. 同じEC2でも、実行ユーザーを変えると結果が変わった
    5. Windowsのプロキシ設定は1か所ではない
    6. 永続設定を変えずに、NO_PROXYで対照試験をした
    7. 正常なEC2との差分比較で解消した
    8. 他プロジェクトへの展開を想定した調査手順
    9. まとめ
    10. 参考資料

 

■ 発生した事象:AWS CLIでS3へファイルをアップロードするとタイムアウトする

Windows EC2上のローカルユーザーでAWS CLIを実行し、S3バケットへファイルをアップロードしようとしたところ、接続タイムアウトが発生しました。

ところが、同じEC2からS3エンドポイントへのTCP/443接続は成功しました。Security GroupとNetwork ACLにも、原因となる制限は見つかりませんでした。

「ネットワークは通っているのに、なぜAWS CLIだけ失敗するのか」

今回つまずいたのはAWS側の経路ではなく、Windowsのユーザーごとに適用されるプロキシ設定でした。この記事では設定に永続的な変更を加えず、原因を切り分けた過程と、その後の解消確認までをまとめます。

※実案件をもとにしていますが、識別情報や構成値は一般化・匿名化しています。

実際のエラー出力は次のとおりです。

Connect timeout on endpoint URL:
https://example-bucket.s3.ap-northeast-1.amazonaws.com/

実行したコマンドは以下の1行だけです。

aws s3 cp C:\path\to\sample.txt s3://example-bucket/

同じ用途の別EC2ではファイル授受ができていました。問題のEC2を再起動しても、接続タイムアウトは解消しませんでした。

ここだけを見るとS3への経路や権限に問題があるように見えます。しかし、調査で判明した直接の原因はIAMでもS3バケットポリシーでもありませんでした。

 

■ AWS側には問題が見つからなかった

まずEC2からS3までのAWS側構成を確認しました。

  • S3 Gateway Endpointはavailable
  • 対象サブネットのルートテーブルにS3 Prefix ListからGateway Endpointへの有効なルートがある
  • Security GroupのアウトバウンドでTCP/443が許可されている
  • Network ACLの送信・戻り通信が許可されている
  • VPC Endpoint Policyによる拒否がない
  • S3バケットとEC2のリージョンが一致している
  • DNSでS3エンドポイントを名前解決できる
  • EC2のIAMロールを使って認証情報を取得できる

権限不足なら通常はAccessDeniedなどの応答が返るはずです。今回はS3からエラー応答が返る前に接続そのものがタイムアウトしています。

AWS側の構成だけを確認していても、原因は特定できませんでした。

 

■ TCP/443の成功は「AWS CLIも同じ経路を通る」という意味ではない

対象EC2でS3エンドポイントへのTCP接続を確認しました。

Test-NetConnection `
example-bucket.s3.ap-northeast-1.amazonaws.com `
-Port 443 `
-InformationLevel Detailed

TCP接続は成功しました。

RemotePort : 443
TcpTestSucceeded : True

それでも直後に実行したAWS CLIはタイムアウトしました。

この結果から言えるのは、「EC2からS3エンドポイントへ直接TCP/443で到達できる」ということまでです。AWS CLIが実際に同じ経路を選ぶことまでは保証しません。

この食い違いをきっかけに、調査対象をAWS側の構成からOS側の設定へ広げました。

次の図は、事象が発生していたユーザーでAWS CLIを実行した場合の通信経路です。試験前は、このユーザーにプロキシ関連の環境変数は定義されていませんでした。

設定されていたプロキシの接続先ポートはTCP/80です。図の左側は試験前の状態、右側は同一EC2・同一ユーザーで対象S3ホストを一時的にNO_PROXYへ指定した場合を示しています。

S3ホストのプロキシ除外有無によるAWS CLIの通信経路

図1:S3ホストのプロキシ除外有無によるAWS CLIの通信経路

疎通確認の成功とアプリケーション通信の成功は別物です。

 

■ 同じEC2でも、実行ユーザーを変えると結果が変わった

調査用のSession Managerユーザーでは次のコマンドが成功しました。

aws s3api head-bucket --bucket example-bucket --region ap-northeast-1

一方、事象が発生していたローカルユーザーで同じコマンドを実行すると、タイムアウトが再現しました。

EC2、IAMロール、AWS CLI、リージョン、アクセス先は同じです。異なるのはWindowsの実行ユーザーでした。

「EC2単位」ではなく「ユーザー単位」で設定を確認する必要があります。

 

■ Windowsのプロキシ設定は1か所ではない

Windows上のプロキシ設定を確認するときに注意したいのは、設定レイヤーが複数あることです。


● 環境変数

AWS CLIの公式ドキュメントでは、プロキシ利用時の設定としてHTTP_PROXY、HTTPS_PROXY、NO_PROXYが案内されています。

set | findstr /I "PROXY"

事象が発生していたユーザーには、これらの環境変数が定義されていませんでした。


● WinHTTPプロキシ

次にWinHTTPの設定を確認しました。

netsh winhttp show proxy

プロキシサーバーとバイパス一覧が表示されました。ここでWinHTTPの設定だけを見て終えると、もう一つの設定を見落とします。

netsh winhttp reset proxyが操作するWinHTTPプロキシとWindows のユーザー別 Internet Settingsは同じものではありません。

 


● Windows のユーザー別 Internet Settings

事象が発生していたユーザーで、次のレジストリキーを読み取りました。

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings

HKCUは現在ログインしているユーザーの設定です。次のコマンドは値を参照するだけで設定を変更しません。

reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyEnable
reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyServer
reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyOverride

確認するとユーザー別プロキシが有効でした。確認時点では、対象EC2から設定されていたプロキシへのTCP/80接続を確立できませんでした。また、S3のホストはバイパス対象に含まれていませんでした。

これで「直接TCP/443は成功するのにAWS CLIだけがタイムアウトする」という食い違いを説明できます。

 

■ 永続設定を変えずに、NO_PROXYで対照試験をした

原因候補は見つかりました。しかし、本番系のEC2でいきなりレジストリやプロキシ設定を変更するわけにはいきません。

そこで新しく起動するPowerShellプロセスの中だけにNO_PROXYを設定しました。その状態で同じAWS CLIコマンドを実行しました。

powershell -NoProfile -Command "$env:NO_PROXY='example-bucket.s3.ap-northeast-1.amazonaws.com,169.254.169.254'; aws s3api head-bucket --bucket example-bucket --region ap-northeast-1"

(169.254.169.254は、EC2インスタンスメタデータサービス(IMDS)のIPアドレスです。IAMロールの認証情報取得がプロキシの影響を受けないよう、NO_PROXYに含めています。)

結果は成功でした。

{
"BucketArn": "arn:aws:s3:::example-bucket",
"BucketRegion": "ap-northeast-1",
"AccessPointAlias": false
}

EC2、ユーザー、AWS CLI、IAMロールは同一です。S3ホストをプロキシ経由から除外した場合だけ成功しました。

PowerShellの子プロセスが終了したあとに、元のコマンドプロンプトで確認しました。NO_PROXYは未定義のままでした。

set NO_PROXY

環境変数 NO_PROXY が定義されていません

この試験で確認したのはS3 APIのHeadBucketが成功することです。ファイルアップロードの成功やPutObject権限まで確認したわけではありません。この線引きも調査結果を共有するときには重要でした。

 

■ 正常なEC2との差分比較で解消した

調査結果を共有したあと、環境の管理者がS3とのファイル授受に成功している別EC2とユーザー別設定を比較しました。

問題のEC2だけにProxyServerとProxyOverrideが残っていました。管理者の判断で正常なEC2と同じ設定にそろえたところ、S3とのファイル授受に成功しました。

一時的なNO_PROXY試験は原因を絞るためのものです。最終的な恒久対応は、その環境のネットワークポリシーと正常系の標準設定を確認したうえで管理者が決める必要があります。

今回の事象はAWS側の構成を変更せずに解消しました。

 

■ 他プロジェクトへの展開を想定した調査手順

同様に「TCP接続は成功するがAWS CLIはタイムアウトする」という事象が発生した場合は、次の順番で確認すると切り分けやすくなります。


● 1.エラーの種類を分ける

  • AccessDeniedなのか
  • 名前解決エラーなのか
  • TLSエラーなのか
  • 接続タイムアウトなのか

接続タイムアウトならIAMだけでなく通信経路を疑います。


● 2.AWS側の静的構成を確認する

  • ルートテーブル
  • VPC EndpointとEndpoint Policy
  • Security Group
  • Network ACL
  • DNS
  • バケットのリージョン

S3 Gateway Endpointを使う場合は、対象サブネットのルートテーブルにS3 Prefix List向けのルートがあるか確認します。


● 3.直接TCP接続とAWS CLIを同じ端末で比較する

TCP/443の成功だけで「ネットワークに問題なし」と結論づけず、AWS CLIの結果と並べます。


● 4.事象発生時と同じユーザーで再現する

管理用ユーザーだけで成功しても利用者の問題が解消したとは限りません。ユーザーごとの設定差を確認します。


● 5.プロキシ設定をレイヤー別に確認する

  • HTTP_PROXY、HTTPS_PROXY、NO_PROXY
  • netsh winhttp show proxy
  • HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings

どこか1か所だけを見て「プロキシ設定なし」と判断しないことが大切です。


● 6.一時設定で対照試験をする

本番環境では、まず子プロセスや現在のセッションだけに限定した設定で仮説を検証します。検証が成功しても、永続的な設定変更は管理方針や影響範囲を確認してから行います。


● 7.正常な同種サーバーと比較する

正常系があるなら原因を絞り込む有力な手掛かりとなります。OS設定、実行ユーザー、環境変数、レジストリ、AWS CLIの認証元をそろえて差分を確認します。

 

■ まとめ

最初はS3 Gateway Endpointかルートテーブルを疑いました。AWS CLIのエラーにS3のURLが表示されていたからです。

しかし、エラーに表示された接続先と実際にプロセスが選んだ通信経路は同じとは限りませんでした。

原因を絞れた決め手は三つです。

  1. TCP/443とAWS CLIを別の試験として扱ったこと
  2. EC2単位ではなく、実行ユーザー単位で結果を比較したこと
  3. 永続設定を変えずに、NO_PROXYで対照試験をしたこと

疎通確認が成功しても、アプリケーションが同じ経路を使うとは限りません。AWS CLIだけが失敗する場合は、AWS側の構成に加えてOSや実行ユーザーごとのプロキシ設定も確認対象になります。

今回の調査で得た最も実践的な教訓は、通信経路をEC2単位で捉えず、実行ユーザーとプロセスの単位まで追うことでした。

 

■ 参考資料