[ECS] EnvoyをエッジプロキシとしてAWSサービスへ接続する方法(1)
概要
ECSで起動したEnvoyコンテナをエッジプロキシとして使用しAWSサービスへアクセスする方法を整理します
コンテナに割り当てたIAMロールを使用してAWSサービスへ接続します
設定はV3 APIを使用します
なお、Emvoy初心者のため設定が一部おかしい可能性があります
テスト環境
テスト対象として
S3オブジェクトのGET/PUT
API Gatewayへの接続の確認をします
S3
samplebktenvoytestという名前のバケットを作成しました
読み出しテスト用にtest.txtというファイルをアップロードしました
https://samplebktenvoytest.s3.ap-northeast-1.amazonaws.com/test.txt
でアクセスできますが、認証が必要です
Lambda関数の作成
プロキシからアクセスするためのLambda関数を作成します
関数名: proxy-test
ランタイム: Node.js 14.x
アーキテクチャ x86_64
index.jsを次のように変更します
入力データをログに記録し、そのまま返す関数です。
console.log('Loading function');
exports.handler = async (event, context) => {
let body = event.body;
let headers = event.headers;
let pathparams = event.pathParameters;
let queryparams = event.queryStringParameters;
let statusCode = '200';
console.log(body);
console.log(headers);
console.log(pathparams);
console.log(queryparams);
return {
statusCode,
body,
headers,
};
};
API Gateway
今作成したLambda関数へ接続するAPI Gatewayを作成します
HTTP APIでproxy-test-apiというAPIを作成します
ルートはパスパラメータ有りと無しの2種類作成しました
ステージはデフォルト設定です
IAM認証によるアクセス制限をかけておきます。
https://apigwid.execute-api.ap-northeast-1.amazonaws.com/proxy-test
https://apigwid.execute-api.ap-northeast-1.amazonaws.com/proxy-test/foo/bar
でアクセスできますが、認証が必要です
コンテナの作成
サンプルコードはこちらにあります
Port10000がS3サービスのリスナー
Port10001がApi Gatewayサービスのリスナーです
パスで切り替えたかったのですが署名のフィルターがうまく動作しませんでしたので個別のリスナーとしています
S3の設定を抜粋します
AWS Request Signingフィルターを使用して署名を生成します
service_nameにはサービスURIのリージョンの前にある箇所を記載します
s3は"s3"、Api Gatewayは"execute-api"です
AWSリクエスト署名は環境変数 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEYが設定されていればこの値から、無ければコンテナに割り当てられた実行ロールから生成されます。
- envoy設定
static_resources:
listeners:
- name: listener_s3
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 10000
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: AUTO
scheme_header_transformation:
scheme_to_overwrite: https
stat_prefix: ingress_http
route_config:
name: s3_route
virtual_hosts:
- name: s3_web
domains: ['*']
routes:
- match:
prefix: '/'
route:
cluster: s3
http_filters:
- name: envoy.filters.http.aws_request_signing
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.aws_request_signing.v3.AwsRequestSigning
service_name: s3
region: "${AWS_REGION}"
use_unsigned_payload: true
host_rewrite: "${AWS_S3_ENDPOINT}"
- name: envoy.filters.http.router
clusters:
- name: s3
connect_timeout: 30s
type: LOGICAL_DNS
# Comment out the following line to test on v6 networks
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: s3
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: "${AWS_S3_ENDPOINT}"
port_value: 443
transport_socket:
name: envoy.transport_sockets.tls
コンテナの実行
ECSを使わずローカルで起動して動作確認ができます
export AWS_ACCESS_KEY_ID=xxxxxx
export AWS_SECRET_ACCESS_KEY=xxxxxx
export AWS_S3_ENDPOINT=samplebktenvoytest.s3.ap-northeast-1.amazonaws.com
export AWS_APIGW_ENDPOINT=apigwid.execute-api.ap-northeast-1.amazonaws.com
export AWS_REGION=ap-northeast-1
docker build -t envoy:v1 .
docker run --rm --name envoy -p 9901:9901 -p 10000:10000 -p 10001:10001 -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY -e AWS_S3_ENDPOINT=$AWS_S3_ENDPOINT -e AWS_REGION=$AWS_REGION -e AWS_APIGW_ENDPOINT=$AWS_APIGW_ENDPOINT envoy:v1
別のシェルで接続確認をします
curl http://localhost:10000/test.txt
echo "This is test2 file." > test2.txt
curl -X PUT --data-binary @test2.txt http://localhost:10000/test2.txt
curl -H 'Content-type: application/json' -d '{"Name": "Jone"}' http://localhost:10001/proxy-test
curl -H 'Content-type: application/json' -d '{"Name": "Jone"}' http://localhost:10001/proxy-test/param1/param2
curl -H 'Content-type: application/json' -d '{"Name": "Jone"}' 'http://localhost:10001/proxy-test/param1/param2?qparam1=abc&qparam2=def'
認証情報はEnvoyが生成するためURIのみで接続できます
Lambdaのログを確認すると、API Gatewayへ渡したパスパラメータ、クエリパラメータが記録されていました
ECSで起動する場合は、環境変数AWS_S3_ENDPOINT, AWS_APIGW_ENDPOINT, AWS_REGIONだけ設定すればよいです
後続記事ではCognitoを使用したアクセス制限、SSL設定について記載します
Discussion