AWS CLIの基本より前のネットワーク通信の話

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

このブログは、サーバーワークス Advent Calendar 2023 の 24日目のエントリーです。

エンタープライズクラウド部の三好です。

明日はクリスマスなわけですが、サンタさんの皆様は贈り物を確保されましたでしょうか?

AWSエンジニアは普段 AWS CLI (など)によってAWSさんのサービスエンドポイント経由で 願い を捧げることにより 贈り物(AWSリソースやその情報)を得ているので、本日はAWS CLI が我々の願いを叶える通信の流れを見ていきたいと思います。

概要-AWS CLI の通信の流れ

AWS CLI だからと言って特別に通常のWebサイトへのアクセスなどと異なることはありません。 基本的には以下の流れです。

  1. AWSサービスのエンドポイント名をDNSなどによって名前解決する。
  2. https でサービスエンドポイントに通信を行う。

aws s3 ls を例にざっくり以下の通りにクリスマス的に図示してみました。

aws cli のネットワーク通信のイメージ ver. Happy Holidays

1. AWSサービスのエンドポイント名をDNSなどによって名前解決する

AWSでは基本的にサービスごとに各サービスのエンドポイント名が提供されているのでここにお願い事をすることになります。 例えば、東京リージョンのS3/EC2に関するお願い事は以下のエンドポイントにお願いします。

  • s3.ap-northeast-1.amazonaws.com
  • ec2.ap-northeast-1.amazonaws.com

AWS CLI のざっくりした挙動の理解としては2番目のサブコマンドによりサービス(つまりサービスエンドポイント)を指定して、3番目以下のサブコマンドと引数によりお願い事を指定をします。

aws s3 ls # S3のサービスエンドポイントに設定や環境変数で指定しているAWSアカウント/リージョンのバケットの一覧を教えてくれと頼む
aws ec2 describe-instances # EC2のサービスエンドポイントに設定や環境変数で指定しているAWSアカウント/リージョンのEC2の一覧を取得してくれと頼む

エンドポイント名自体はAWS CLI自身で前もってわかっていますが、エンドポイント名そのものだけでは直接お願いごとの手紙を送ることはできません。 なぜなら、インターネットという配送の仕組みでは、荷物の宛名はエンドポイント名のような名前ではなく、特定の数字で記述されたインターネット上の住所(IPアドレス)を宛名にする必要があるからです。

なのでエンドポイント名をIPアドレスに変換する仕組みが必要なわけですが、これがDNSによる名前解決になります。 なぜかサンタさんの住所を知っている家族のように、DNSサーバもサービスエンドポイントの正確な住所を教えてくれます1。 AWS CLI ではこの名前解決に関しても、普段使っているWebブラウザ同様暗黙的にやってくれています。

もし、AWS CLI で通信関係のトラブルがあったときは、DNSサーバに対してエンドポイント名が名前解決できる状態かも含めて確認するといいと思います。

おまけ

AWS CLI のオプションである --endpoint-url については名前解決の挙動に影響を与えるオプションです。 利用するサービスのエンドポイント名で名前解決されるIPアドレスではなく、--endpoint-url で指定したFQDNのIPアドレスや IPアドレスに対して、通信をおこなうようになります。

これは例えばDirect Connect やVPN でオンプレミス環境と繋がっているときに、インターネットを介してS3のインターフェースエンドポイントに通信するのではなく、オンプレミス側から通信可能なVPCインターフェースエンドポイントを経由してS3のエンドポイントに通信するときに利用するオプションです。

ざっくりいうと --endpoint-url vpcインターフェースのendpoint名 とすることで、標準的に利用するインターネットに公開されている住所ではなく、サンタさんへの別ルートの住所を指定できるということになります。

2. https でサービスエンドポイントに通信を行う

DNSで名前解決が完了したら、あとはサンタさんのいる住所に向かってお願い事の手紙を送る&プレゼントを受け取るだけです。 プレゼントをちゃんともらうには本人である証明(アクセストークン/シークレットトークンなどのクレデンシャル)とプレゼントをもらえるに値する良い子か(IAMロール/ポリシーなどの権限)という話はありますが、大筋は概要のところに書いた絵のようになります。

3. strace によるシステムコールの確認

1, 2 の挙動は普段AWS CLI を使っていてなんとなく意識されていたかと思いますが 実際にそうなのか確認する方法があります。

strace というコマンド/プログラムがありOSがどういったことをやっているのか追跡できるコマンドがあります。 Amazon Linux 2023 には標準的にはインストールされていないので以下のようにインストールします。

dnf install strace

strace の後に解析したいコマンドをつけると、OSがコマンドを実行するために何をやったのかが標準エラー出力に出力されます。 本番で動いているサーバのプログラムに対して実行すると性能劣化する恐れがあるので基本的にはやめましょう。

strace aws s3 ls

私の環境では24327行ほど出力されたので、今回のブログと関係するところだけ抜粋します。

execve("/usr/bin/aws", ["aws", "s3", "ls"], 16進数 /* 20 vars */) = 0
~~中略~~
connect(4, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("172.31.0.2")}, 16) = 0
~~中略~~
connect(4, {sa_family=AF_INET, sin_port=htons(443), sin_addr=inet_addr("xxx.xxx.xxx.xxx")}, 16) = 0
~~中略~~
connect(4, {sa_family=AF_INET, sin_port=htons(443), sin_addr=inet_addr("xxx.xxx.x.xxx")}, 16) = 0
~~中略~~

execveという行が一番最初にあり、/usr/bin/aws を実行します。 その後色々あってconnectという命令で外部に接続を試みようとしていることがわかります。 172.31.0.2 への53番ポートへの接続はRoute 53 Resolver への名前解決で、 xxx.xxx.xxx.xxx はS3のエンドポイントへのHTTPS通信となっています。

ここには詳細を書きませんが、strace によってpythonの処理系やその他のライブラリが利用されている様を見ることができます2。 ここまでのトラブルシューティングは滅多にないかもしれませんが、OS側でどんな処理をしているのか時々興味を持つことは重要かなと考えています。

AWSの観点では普段はシステムコール等は意識しないかもしれませんが、コンテナのランタイムセキュリティなどの文脈でOSイベントの監視やeBPFの利用など盛んになってきているので来年はこの辺も学んでいきたいなと思っています。

syscalls(2) - Linux manual page

あとがき

最近はサンタさんを騙るに偽物が多いので、プレゼント発送前に私がちゃんとしたサンタですよと証明する証明書(サーバ証明書)を送ってきたり普段AWS CLIを利用する分にはあまり意識していないですが、サンタさんにお願いするにしてもお願いごとのフォーマットがあるなど色々と書こうとしたのですが、技術的な裏取とクリスマスの例えにするのが難しいなと感じました。精進します。


  1. DNSはちゃんと理屈があるので大人の皆さんは覚えましょう。
  2. AWS CLI 自体はPythonで書かれている。