🗝︎
[ECS] EnvoyをエッジプロキシとしてAWSサービスへ接続する方法(2)
概要
ECSで起動したEnvoyコンテナをエッジプロキシとして使用しAWSサービスへアクセスする方法を整理します
この記事ではCognitoで取得したアクセストークンの検証をします
前回の記事の環境を使用します
コンテナの作成
サンプルコードはこちらにあります
Port10000がS3サービスのリスナー
Port10001がApi Gatewayサービスのリスナーです
S3の設定を抜粋します
JwtAuthenticationフィルターで署名, 有効期限, issを検証し、"payload_in_metadata: jwt-payload"にてDynamicMetadataに情報を保存します
この情報を参照し、Luaフィルターでclient_id, scopeを検証します
- envoy設定
http_filters:
- name: envoy.filters.http.jwt_authn
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
providers:
cognito:
issuer: "${JWT_ISSUER}"
forward_payload_header: jwt-payload
payload_in_metadata: jwt-payload
remote_jwks:
http_uri:
uri: "${JWT_JWK_URI}"
cluster: jwks
timeout: 5s
cache_duration: 600s
rules:
- match:
prefix: '/'
requires:
provider_name: cognito
- name: envoy.filters.http.lua
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
inline_code: |
-- Called on the request path.
function envoy_on_request(request_handle)
-- Do something.
local jwt_tokenuse = request_handle:streamInfo():dynamicMetadata():get('envoy.filters.http.jwt_authn')['jwt-payload']['token_use']
local jwt_client = request_handle:streamInfo():dynamicMetadata():get('envoy.filters.http.jwt_authn')['jwt-payload']['client_id']
local jwt_scope = request_handle:streamInfo():dynamicMetadata():get('envoy.filters.http.jwt_authn')['jwt-payload']['scope']
if jwt_tokenuse == nil or jwt_tokenuse ~= 'access' then
request_handle:respond({[':status'] = '401'}, 'unauthorized_tokenuse_error')
end
if jwt_client == nil or jwt_client ~= '"${JWT_CLIENT}"' then
request_handle:respond({[':status'] = '401'}, 'unauthorized_client_error')
end
if jwt_scope == nil or jwt_scope ~= 's3/access' then
request_handle:respond({[':status'] = '401'}, 'unauthorized_scope_error')
end
end
JwtAuthenticationフィルタが検証する内容
フィルタが検証する内容は次のコードで実装されています
Cognitoが推奨する検証項目は次のリンク先に記載されています
Filterが検証する項目
- kidがjwkに存在するかどうか
- algの一致
- 署名検証
- issuer
- exp (有効期限)
ユーザが追加で検証すべき項目
- token_use
- scope
- client_id
コンテナの実行
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
export JWT_ISSUER=https://cognito-idp.ap-northeast-1.amazonaws.com/userpoolid
export JWT_CLIENT=client_id
export JWT_JWK_URI=https://cognito-idp.ap-northeast-1.amazonaws.com/userpoolid/.well-known/jwks.json
export JWT_ISSUER_HOST=cognito-idp.ap-northeast-1.amazonaws.com
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 -e JWT_ISSUER=$JWT_ISSUER -e JWT_CLIENT=$JWT_CLIENT -e JWT_JWK_URI=$JWT_JWK_URI -e JWT_ISSUER_HOST=$JWT_ISSUER_HOST envoy:v1
別のシェルで接続確認をします
curl -H 'Authorization: Bearer accesstoken_string' http://localhost:10000/test.txt
curl -H 'Authorization: Bearer accesstoken_string' -H 'Content-type: application/json' -d '{"Name": "Jone"}' http://localhost:10001/proxy-test
後続記事ではSSL設定について記載します
Discussion