【問題】
プライベートサブネットのインスタンスがECRからDockerイメージをプライベート接続でpullしたい。
インターネットゲートウェイ、NATゲートウェイを使用せずに外部接続無しで実現するにはどのようにするか。
【答え】
2019年1月のAWS Private linkのサポートによりこの問題は解決された。
その方法を投稿する。
#AWS Private Linkとは
AWSサービスへのアクセスをプライベートに接続できる高可用性、高スケールラブルなNWサービス。
Private Link Endpointを設定するとVPC内でプライベートIP付きのENIが作成される。
AWS PrivateLinkサポートにより、パブリック or プライベート 関わらずインスタンスはECRからプライベートな接続でイメージをダウンロードすることができる。
もちろん、NATゲートウェイやインターネットゲートウェイは必要ない。
不必要なアウトバウンド向け通信をブロックしたい時などのにも使用でき、セキュリティ強化となる。
Fargate使用においても、タスクにパブリックIPをアサインすることなくDocker imageをpullできる。
今回、AWS PrivateLinkの作成は複数に渡る。
###1.AWS PrivateLink endpoints for ECR.
インスタンスはECRと接続でき、Docker manifestファイルをダウンロードできる。
###2.Gateway VPC endpoint for Amazon S3.
インスタンスはプライベートなS3バケットに接続でき、そこに配置されたDocker レイヤーファイルをダウンロードできる
※Docker imageはManifestファイル(JSON形式)とレイヤーファイル(tar.gz形式)から構成される
以降、Docker imageファイル、Docker manifestファイル、Docker レイヤーファイルと記述する
Docker imageファイル = (Docker manifestファイル + Docker レイヤーファイル)
###3.AWS PrivateLink endpoints for ECS.
インスタンスはECS用のVPCエンドポイントの作成時に使用する3つのドメイン(telemetryとecsコントロールプレーンのagentサービス)と接続可能となる。
- com.amazonaws.region.ecs-agent
- com.amazonaws.region.ecs-telemetry
- com.amazonaws.region.ecs
##ECR接続用のPrivateLink endpointを作成する
ECRとの接続は2つのエンドポイントが必要
- com.amazonaws.region.ecr.api
- com.amazonaws.region.ecr.dkr
region は使用リージョンに置き換える。(ap-northeast-1 など)
VPCのマネジメントコンソール左メニューよりエンドポイントを作成する。
次に、PrivateLinkを配置するVPCとサブネットを決める。
ECSクラスターを実行するVPCと同じ場所に配置することを確認すること。
大規模障害を考慮し、リスト表示される全てのAZとサブネットを選択する。
ただし、ネットワークのニーズに応じて、各アベイラビリティーゾーンのプライベートサブネットでのみ
AWS PrivateLinkエンドポイントを有効にすることできる。
次に、Enable Private DNS Nameを有効にする。
Route53などで設定したプライベートホストゾーンを設定している方は、ECRのデフォルトのドメイン(https://api.ecr.region.amazonaws.com) を使用してリソースにアクセス可能。
エンドポイントのプライベートホストネームや、プライベートIPv4アドレスを使用する必要は無く、自動的に名前解決してアクセスできる。
プライベートホストゾーンを設定している、かつ2019年1月24日以降にリリースされたSDKを使用する場合のコマンド例
aws ecr describe-repositories
プライベートホストゾーンを設定していない場合のコマンド例
aws --endpoint-url https://VPC_Endpoint_ID.api.ecr.region.vpce.amazonaws.com ecr describe-repositories
プライベートホストゾーンで com.amazonaws.region.ecr.api を設定している、かつ2019年1月24日以前にリリースされたSDK、もしくはaws cliコマンドを使用する場合はエンドポイントを特定すること。
aws --endpoint-url https://api.ecr.region.amazonaws.com
最後に、エンドポイント自体にセキュリティーグループを設定する。
セキュリティーグループはエンドポイントに接続するプライベートサブネットのインバウンド通信(ポート443)を許可すること。
もしくはクラスターのオートスケーリンググループに対して許可する場合もあるし、全てのインスタンスからの接続を許可することもできる。
Create Endpointを選択する。作成したエンドポイントが表示される。
##Gateway VPC endpoint for Amazon S3を作成する
次はGateway VPC endpoint for Amazon S3を作成する。
え?なぜS3へのアクセスが必要なのか?
それはECRはDockerレイヤーファイルをS3に保管するから。
インスタンスがECRからDokcer manifestファイルを取得し、S3から(イメージの実体である)Docker レイヤーファイルをダウンロードする。
ちなみに、Docker レイヤーファイルの保管ARNは以下
arn:aws:s3:::prod-region-starport-layer-bucket/*
ECRを使用するにあたり、S3に対して設定する最小限のアクセスは以下
{
"Statement": [
{
"Sid": "Access-to-specific-bucket-only",
"Principal": "*",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Effect": "Allow",
"Resource": ["arn:aws:s3:::prod-region-starport-layer-bucket/*"]
}
]
}
S3はゲートウェイと呼ばれる少々違ったタイプのエンドポイントを使用する。
もしプログラムがS3を使いまくるような設計なら、S3ゲートウェイ追加時には気をつけるべし。
S3ゲートウェイがアタッチされる際、接続中のS3とアプリのコネクションが一時的に中断されるからだ。
例えば頻繁にDockerをデプロイする場合など。
その場合は新しくVPCを作成してS3ゲートウェイを作成するのがベスト。
そして、ECSクラスターとコンテナをそのVPCに統合して頂きたい。
AWSサービスのリストからcom.amazonaws.region.s3を選択し、ECSクラスタが所属するVPCを選択してS3ゲートウェイエンドポイントを追加する。
Gateway endpointはサブネットのVPCルートテーブルにアタッチされる。
それぞれの「S3ゲートウェイが配置されるべきサブネットに関連したルートテーブル」を選択する。
Gateway endpointはセキュリティグループを使用する代わりに「IAM policy document」を使用する。
これはサービスへのアクセスを制限する為のものだ。
このポリシーはIAMポリシーと似ているが、アプリケーションのデフォルトIAMロールを置き換えるものではない。
ゲートウェイを通しての利用可能なAWSサービスをより詳細に制限する目的なだけだ。
デフォルトであるフルアクセスを使用しても構わない。
Createを選択してGateway endpointをVPCにアタッチしよう。
サブネットのルートテーブルを見てみると、S3 Gatewayがある。
S3からECR Docker レイヤーイメージがダウンロードされる際は常に使用されることだろう。
##AWS PrivateLink interface endpoint for ECSを作る
ECRからのDockerイメージダウンロードに加え、EC2インスタンスはECSのオーケストレーションの指示を受ける為、ECSとも接続しなければならない。
ECSは次の3つのendpointを必要とする
- com.amazonaws.region.ecs-agent
- com.amazonaws.region.ecs-telemetry
- com.amazonaws.region.ecs
先ほどのECRと同じやり方でこの3つのエンドポイントを作成しよう。
それぞれのエンドポイントをアタッチし、サブネットとセキュリティグループを設定しよう。
エンドポイントが作成され、VPCにアタッチされた後、もう1ステップある。
ECSエージェントがバージョン1.25.1以上であることを確認する。
※詳しくはinstructions for upgrading the ECS agent 参照
正しいバージョンでECSエージェントが実行されていれば、VPCで実行中のECSエージェントすべてを再起動しよう。
ECSエージェントとECSバックエンドとの接続はソケットコネクションで接続され続けており、VPCエンドポイントは既存のコネクションに対して接続を中断しない。
リスタートしない限り、エンドポイントとの新規接続ではなく既存のコネクションを使い続ける。
コンテナアプリに影響無くエージェントを再起動するために、SSHでクラスターのEC2に接続して次のコマンドを実行してほしい。
sudo docker restart ecs-agent
このコマンドはホスト上の他のコンテナに影響を与えることなく、ECSエージェントを再起動できる。
ちなみに、エンドポイントを通してECSにアクセスしているわけだが、このアクセスコントロールは現在サポートされておらず、フルアクセスでの接続となる。
###※尚、Fargate使用においては
以下2つのエンドポイントのみで良い。
com.amazonaws.region.ecr.dkr
com.amazonaws.region.s3
#蓋を開けてみるとCloudWatchのエンドポイントも必要との苦情が多数
2019/05/08追記
【原因】
英語版の公式サイトには記載あり、日本語版には無い。以上。
#まとめ
このサポートの対応前は、EC2インスタンスがDockerイメージをECRからダウンロードしたりECSへアクセスするにはインターネットゲートウェイを使う必要があった。
パブリックIPを持ったパブリックサブネット所属のインスタンスは直接インターネットゲートウェイからプライベートサブネットのインスタンスはNATゲートウェイを使用してアクセスしなければならなかった。
(ちなみにNATゲートウェイはその後、インターネットゲートウェイを通過してECRやECSにアクセスする)
AWSは爆速で新機能がリリースされて改善されていくので、ついていくのが大変だ。
これからもAWS関連の記事を書いていくので、振り落とされないように一緒に頑張ろう。
参考:
https://docs.aws.amazon.com/AmazonECS/latest/developerguide/vpc-endpoints.html
https://aws.amazon.com/jp/blogs/compute/setting-up-aws-privatelink-for-amazon-ecs-and-amazon-ecr/
最後まで読んでいただきありがとうございました。
少しでもお役にたちましたらいいねをよろしくお願いします。
#宣伝
このたび個人で「会員制コミュニティ付きのAWS初学者を導く体系的な動画学習サービス」
AWS CloudTechをリリースしました。
こちらがご案内動画です。
https://www.youtube.com/watch?v=PppZnHGaChI&feature=youtu.be
無料コースもご用意しておりますので、よろしければ試してみて下さいね!