プロキシに阻まれながらAWS CLIをEC2インスタンスから動かしたときの話 

# この記事の概要
プロキシがある環境下でAWS CLIをEC2インスタンスから使う方法を書きます。
その中でハマったポイントがあったのですが、ハマったことにより知見が深まったのでQiitaに投稿します。
主に**AWS CLI周り**の話と**Squid**の話となります。

使ったツール・プロダクト等は以下です。

* Squid(Windows版)
* AWS CLI
* Direct Connect
* IAM
* EC2
* S3（あまり本題には出てきませんが）


# 背景
弊社には他の多くの会社さんと同様、インターネットへ接続するためのプロキシ（通称「社内プロキシ」）が存在しています。
そんな弊社に所属する私は業務上の事情でAWS CLIでS3上の操作を行う必要が出てきました。
しかし、先日開発用端末を変えたことにより、その端末にAWS CLIがインストールされていないのです。
セキュリティの観点からアクセスキーは発行したくないし、端末にAWS CLIをインストールする以外の方法を検討しました。
そこで、IAMロールをEC2インスタンスにアタッチすることでアクセスキーを発行することなく認証させる方法を知っていたということもあり、この方法を採用しました。
しかも、AWSにはAWS CLIがプリインストールされたAmazon Linuxのイメージが公式で提供されており、これを使えば準備が楽そう…。
AWS CLIを使うには社内プロキシを突破してインターネットへ出る必要がありますが、まあSquidを活用した多段プロキシ構成で切り抜けれるだろうと思い作業を開始しました。

構成・通信の概略を示すと次の通りです。（あくまで概略です。）
![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214621/f70b4fec-a97d-512e-21bc-8236ce62e919.png)


AWS CLI自体にはそこそこ慣れているつもりで楽に準備ができるのではと思ったが、その思い上がり故に落とし穴に引っかかる私でありました…。

# ハマりポイント その1 AWS CLIを使うには`no_proxy=169.254.169.254`が必要
AWS CLIがプリインストールされたEC2インスタンスにIAMロールを付与して…。
インスタンスが起動したらプロキシ設定して…。

```
$ export http_proxy=http://(SquidのホストIP):(Squidで開けているport)
$ export https_proxy=http://(SquidのホストIP):(Squidで開けているport)
$ export no_proxy=localhost,127.0.0.1
```
いざ`aws s3 ls`！

```
$ aws s3 ls
Unable to locate credentials. You can configure credentials by running "aws configure".
```
ん？ちゃんとIAMロール付けてるんですが…。

```
$ aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key                <not set>             None    None
secret_key                <not set>             None    None
    region           ap-northeast-1      config-file    ~/.aws/config
```
一旦ターミナルを落として一呼吸。
もう一度AWS CLIの設定を確認。

```
$ aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ********************         iam-role    
secret_key     ********************         iam-role    
    region           ap-northeast-1      config-file    ~/.aws/config
```
ターミナルを落とした…、まさか！`export`コマンドで環境変数をいじったことが影響しているのだろうか？

```
$ export hoge=fuga
$ aws configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                <not set>             None    None
access_key     ********************         iam-role    
secret_key     ********************         iam-role    
    region           ap-northeast-1      config-file    ~/.aws/config
```
変わらない…。
ということはプロキシの影響か…、しかしAWS CLIってインターネットへの接続が必要だよな…。

調べてみたところ`169.254.169.254`へのアクセスをプロキシ経由で行わないように設定する必要があるようです。
唐突に謎のIPアドレスが出てきたぞ！？と思ったのですが、`169.254.169.254`へはインスタンスメタデータを取得するためにアクセスするらしいです。
インスタンスメタデータというのは、その動いているインスタンスに関するデータで、実行中のインスタンスを設定または管理するために使用されるものとのことでした。
そして、インスタンスメタデータへのアクセスはそのインスタンス内からのみアクセスが許可されているということだそうです。
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-instance-metadata.html

ということで、no_proxy設定を追加。

```
$ export no_proxy=localhost,127.0.0.1,169.254.169.254
```

# ハマりポイント その2 SquidでSSL通信をするには`never_direct allow CONNECT`の設定が必要
今度こそ`aws s3 ls`！
…レスポンスが返ってこない。
`curl http://www.google.com`はレスポンスが返ってくる。
AWS CLIはhttps通信らしいので、
`curl https://www.google.com`を実行すると…、あれ？返ってこない。

Squidのログを見ると503で弾きましたというログが残っている…。
開けてるポートの問題か？もしかして社内プロキシに弾かれて503になっている？
色々想像しましたが、SquidのデフォルトではSSL通信を直接接続しようとするらしいです。

~~私のググり力が欠如しており~~この辺りの情報がやや少なく、この情報にたどり着くまで紆余曲折を経たのですが、結局この設定をSquidに入れれば解決でした。

```squid.conf
never_direct allow CONNECT
```

# 結局どのような手順で設定するか
## Windows端末にSquidをインストール
* squid.diladele.comからWindows用インストーラをダウンロード・インストール

※Squid for Windowsはそれなりに実績もあり信頼はできるのですが、squid-cache.orgによる公式の提供はLinux版のみのようなので、あくまで自己責任でのご利用をお願いいたします。

* Squidを起動
* 右下のSquidのアイコンをクリックして`Open Squid Configuration`をクリック
* 以下の設定を変更

```squid.conf
(略)
# Squid normally listens to port 3128
http_port (競合しない任意のport番号) # ←わざわざ変えなくても結構ですが念の為
(略)
dns_nameservers (社内でご利用のDNSサーバのIPアドレス)
(略)
```
* 以下の設定を末尾に追加

```squid.conf
cache_peer (社外へ出るためのプロキシのホスト名もしくはIPアドレス) parent (社外へ出るためのプロキシのport番号) 0 no-query no-netdb-exchange no-digest login=(社外へ出るためのプロキシのID):(社外へ出るためのプロキシのPassword) default
cache deny all

never_direct allow all
never_direct allow CONNECT # ←今回のハマりポイント2
```
* 設定ファイルを保存
* 右下のSquidのアイコンをクリックして`Stop Squid Service` → `Start Squid Service`で再起動

## IAMロール付きEC2インスタンス作成
（簡易な記述ですみません…。）

* EC2インスタンス用のIAMロールを適切なポリシーを付与して作成
* AWS CLIがプリインストールされているイメージからEC2インスタンスを作成
* EC2インスタンスにIAMロールをアタッチ

## EC2インスタンス側での設定
* EC2インスタンスにSSH接続
* プロキシ設定を実施

```
$ export http_proxy=http://(SquidをインストールしたWindows端末のIP):(Squidで開けているport)
$ export https_proxy=http://(SquidをインストールしたWindows端末のIP):(Squidで開けているport)
$ export no_proxy=localhost,127.0.0.1,169.254.169.254 # ←今回のハマりポイント1
```

# 最後に
AWS CLIの話とSquidの話をしましたが、設定にしてみたらこんな少しの設定の話です。
でもそんな少しの設定でも色々な学びがあるんだなあと痛感しました。
あと、Squidは使い終わったらこまめにOFFにするようにしましょう。念の為。
気になったところやうまく行かない点などあれば是非コメント下さい。