[ECS] EnvoyをエッジプロキシとしてAWSサービスへ接続する方法(2)


概要

ECSで起動したEnvoyコンテナをエッジプロキシとして使用しAWSサービスへアクセスする方法を整理します
この記事ではCognitoで取得したアクセストークンの検証をします

前回の記事の環境を使用します

コンテナの作成

サンプルコードはこちらにあります

https://github.com/tubame0505/envoy_aws_request_signing_sample/tree/main/docker_jwt

Port10000がS3サービスのリスナー
Port10001がApi Gatewayサービスのリスナーです

S3の設定を抜粋します
JwtAuthenticationフィルターで署名, 有効期限, issを検証し、"payload_in_metadata: jwt-payload"にてDynamicMetadataに情報を保存します
この情報を参照し、Luaフィルターでclient_id, scopeを検証します

https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/jwt_authn_filter
https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/lua_filter

  • 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_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_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

コンテナの実行

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設定について記載します

関連記事

参考リンク