Amazon API Gateway de nível financeiro

Introdução

Este tutorial mostra como proteger AS APIs construídas em Portal da API da Amazon mais segura do que nunca, utilizando “tokens de acesso vinculados a certificados”.

Uma vez que um token de acesso tradicional do OAuth é vazado, um invasor pode acessar APIs com o token de acesso. Os tokens de acesso tradicionais são como uma passagem de trem que qualquer pessoa pode usar uma vez que é roubada.

A vulnerabilidade pode ser atenuada exigindo que o chamador de API apresente não apenas um token de acesso, mas também evidências que comprovem que o chamador de API é o titular legítimo do token de acesso. A evidência é chamada de “prova de posse”, que muitas vezes é encurtado para Pop. Os tokens de acesso que precisam de PoP em seu uso são como uma passagem de avião para voo internacional cujo procedimento de embarque exige que o passageiro apresente não apenas o bilhete, mas também seu passaporte.

RFC 8705, OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens, padronizou um mecanismo PoP. O mecanismo é chamado MTLS na comunidade OAuth, mas eu pessoalmente chamá-lo “vinculação de certificado” para evitar confusão. De qualquer forma, em suma, o mecanismo requer que o chamador de API apresente não apenas um token de acesso, mas também o mesmo Certificado X.509 como foi usado quando o token de acesso foi emitido a partir do ponto final do token. O diagrama abaixo ilustra o conceito de vinculação de certificado.


Certificate Binding

Você pode saber API de grau financeiro (FAPI). É uma especificação construída em cima de OAuth 2.0 e OpenID Connect para maior segurança da API. UK Open Banking adotou a FAPI como base do Perfil de Open Banking e agora outros países estão seguindo. O ponto que eu quero que você preste atenção aqui é que a FAPI requer vinculação de certificado como um componente técnico obrigatório.

A principal premissa para a vinculação cetificate é que as conexões entre APIs e aplicativos de clientes são estabelecidas usando TLS mútuo onde os aplicativos do cliente são necessários para apresentar seu X.509 certificado de cliente durante o aperto de mão TLS. Em 17 de setembro de 2020, a AWS finalmente anunciou em Introdução de autenticação TLS mútua para Amazon API Gateway que o Amazon API Gateway se tornou pronto para tls mútuo. O Amazon API Gateway abriu uma porta para a segurança da API de nível financeiro.

Papel do autorizador

Amazon API Gateway fornece um mecanismo chamado Autorizador Lambda pelo qual você pode implementar a lógica personalizada para a proteção da API. Um autorizador lambda que oferece proteção API baseada em OAuth extrai um token de acesso e um certificado de cliente de uma chamada de API e executa a seguinte validação.

  1. o token de acesso existe,
  2. o token de acesso não expirou,
  3. o token de acesso abrange os escopos necessários para acessar o recurso,
  4. o token de acesso não foi revogado, e
  5. o token de acesso está vinculado ao certificado do cliente. (vinculação de certificado)

Em seguida, o autorizador toma uma das seguintes ações com base no resultado da validação.

  • retornar uma política IAM que permite o acesso aos recursos.
  • retornar uma política do IAM que nega o acesso aos recursos.
  • lançar uma exceção com uma mensagem de erro 'Unauthorized' para dizer ao Amazon API Gateway para rejeitar o acesso ao recurso com código de status HTTP “401 não autorizado”.
  • lançar uma exceção com uma mensagem de erro diferente para dizer ao Amazon API Gateway para rejeitar o acesso ao recurso com código de status HTTP “500 Erro interno do servidor”.

Implementação do Autorizador

A implementação do autorizador lambda eu vou mostrar-lhe em breve delegados validação de token de acesso para AuthleteAPI de introspecção (/api/auth/introspection), para que a implementação do autorizador não contenha lógica complexa. O diagrama abaixo retrata a relação entre Amazon API Gateway, Lambda Authorizer e Authlete.


Amazon API Gateway, Lambda Authorizer and Authlete

Além disso, porque Authorizer classe em Biblioteca Python de Authlete faz quase todas as coisas necessárias, implementações podem ser muito pequenas. Na verdade, o código abaixo é um exemplo completo da implementação do autorizador Lambda que suporta a vinculação do certificado.

from authlete.aws.apigateway.authorizer import Authorizer

authorizer = Authorizer()

def lambda_handler(event, context):
    return authorizer.handle(event, context)

Escopos necessários para acesso a recursos

Em casos reais, no entanto, você precisará configurar qual recurso requer quais escopos. Isso pode ser alcançado por (1) dando uma função para Authorizer’s handle() método ou (2) fazendo uma subclasse de Authorizer e substituindo determine_scopes() método na subclasse.

Tanto a função quanto o método levam 4 argumentos conforme listado na tabela abaixo e são obrigados a retornar uma lista de nomes de escopo necessários para acessar o recurso.

Parametro Descrição
event O evento foi dado ao autorizador.
context O contexto dado ao autorizador.
method O método HTTP do acesso ao recurso.
path O caminho do recurso.

Dois exemplos abaixo têm o mesmo efeito afirmando que time:query escopo é necessário para acessar time recurso por HTTP GET método.

from authlete.aws.apigateway.authorizer import Authorizer

authorizer = Authorizer()

def determine_scopes(event, context, method, path):
    if method == 'GET' and path == 'time':
        return ['time:query']

    return None

def lambda_handler(event, context):
    return authorizer.handle(event, context, determine_scopes)
from authlete.aws.apigateway.authorizer import Authorizer

class CustomAuthorizer(Authorizer):
    def determine_scopes(self, event, context, method, path):
        if method == 'GET' and path == 'time':
            return ['time:query']

        return None

authorizer = CustomAuthorizer()

def lambda_handler(event, context):
    return authorizer.handle(event, context)

Política ou Exceção

Para estar em conformidade com as especificações relacionadas ao OAuth 2.0, um autorizador da Lambda tem que dizer ao Amazon API Gateway para devolver “401 não autorizados” ao chamador de API em alguns casos (por exemplo, quando o token de acesso apresentado expirou). De acordo com os documentos técnicos e programas de amostra da AWS, o autorizador tem que lançar uma exceção com uma mensagem 'Unauthorized' para alcançá-lo. No entanto, essa simples exceção deixa cair todas as informações valiosas sobre a resposta “não autorizada” e torna a depuração muito difícil.

Portanto, por padrão, em outras palavras, quando policy propriedade é True (padrão), Authorizer’s handle() método sempre retorna uma política IAM que representa “Permitir” ou “Negar” mesmo em casos de erro em que uma exceção com uma mensagem 'Unauthorized' deve ser jogado.

Se você quiser fazer Authorizer lançar uma exceção nos casos “Não autorizado” e “Erro do Servidor Interno”, definido False Para policy propriedade. Você pode alcançá-lo dando policy=False Para Authorizer‘construtor.

authorizer = Authorizer(policy=False)

Contexto na Política

Authorizer’s handle() método retorna um dict exemplo que representa uma política IAM. No dicionário, há context chave cujo valor é um dicionário. Authorizer incorpora algumas informações lá. A tabela abaixo mostra chaves que context dicionário pode conter.

Propriedade descrição
introspection_request String JSON que representa o pedido para a API de introspecção da Authlete.
introspection_response JSON string que representa a resposta da API de introspecção da Authlete.
introspection_exception String que representa uma exceção levantada durante a chamada para a API de introspecção da Authlete.
scope String de uma lista de escopos delimitados pelo espaço coberto pelo token de acesso apresentado.
client_id A ID do cliente do aplicativo do cliente ao qual o token de acesso foi emitido.
sub String que representa o assunto do proprietário do recurso que permitiu a emissão do token de acesso ao aplicativo do cliente.
exp A data de validade do token de acesso em segundos desde a época unix (1 de janeiro de 1970).
challenge O valor para WWW-Authenticate Cabeçalho HTTP em casos de erro.
action O valor de action na resposta da API de introspecção do Authlete.
resultMessage O valor de resultMessage na resposta da API de introspecção do Authlete.

Você pode adicionar entradas a context por substituir update_policy_context() método em uma subclasse de Authorizer. Tenha cuidado para não usar objeto JSON e matriz como valores em context. Trata-se de uma restrição técnica imposta pela AWS.

class CustomAuthorizer(Authorizer):
    def update_policy_context(self, event, context, request, response, exception, ctx):
        ctx.update({
            'my_key': 'my_value'
        })

Inscrições em context na apólice devolvida de um autorizador Lambda pode ser usado em outros lugares mais tarde. Ver Saída de um autorizador Lambda do Amazon API Gateway para detalhes.

Ganchos

Authorizer classe oferece seguintes métodos de gancho para implementações de subclasse. Substitua-os conforme necessário.

Método descrição
determine_scopes() determina os escopos necessários para o acesso ao recurso.
update_policy_context() Atualizações context que deve ser incorporado na política.
on_enter() é chamado quando handle() método começa.
on_introspection_error() é chamada quando a chamada para API de introspecção Authlete falhou.
on_introspection() é chamada depois que a API de introspecção Authlete foi bem sucedida.
on_allow() é chamado quando uma política permitir é gerada.
on_deny() é chamado quando uma política de Nega é gerada.
on_unauthorized() é chamado quando uma exceção para “Não Autorizado” é lançada.
on_internal_server_error() é chamado quando uma exceção para “Erro do servidor interno” é lançada.

Configuração do autorizador

Carga de eventos Lambda

A coisa mais importante na criação de um autorizador Lambda é escolha “Solicitar” para o Payload do Evento Lambda. Caso contrário, o autorizador não pode acessar informações sobre o certificado do cliente. Isso significa que o autorizador não pode verificar se o token de acesso está vinculado ao certificado do cliente.


Create Authorizer

Ver Entrada para um autorizador Lambda do Amazon API Gateway para detalhes sobre como a escolha do tipo de carga de carga de eventos Lambda altera a entrada para o autorizador.

Variáveis ambientais

Se uma instância de AuthleteApi não é dado, Authorizer‘construtor internamente cria um chamando AuthleteApiImpl(AuthleteEnvConfiguration()) e usa a instância para acessar APIs Authlete. Porque AuthleteEnvConfiguração usado lá assume que a configuração Authlete está disponível através de variáveis de ambiente, as seguintes variáveis de ambiente precisam ser definidas para a função Lambda que é usada como a implementação do seu autorizador Lambda.

Variável de Ambiente Descrição
AUTHLETE_BASE_URL A URL base do servidor Authlete.
AUTHLETE_SERVICE_APIKEY A chave API atribuída ao seu serviço.
AUTHLETE_SERVICE_APISECRET O segredo da API atribuído ao seu serviço.


Lambda function environment variables

Timeout

Recomenda-se aumentar o valor do tempo limite da função Lambda a partir do valor padrão, pois a chamada para a API de introspecção da Authlete pode levar mais tempo dependendo de várias condições.


Lambda function timeout

Embalagem autorizador

Como criar e carregar um pacote ZIP da função Lambda é explicado em Atualização de uma função com dependências adicionais em Pacote de implantação AWS Lambda em Python.

Abaixo está um exemplo que cria e carrega um arquivo ZIP do autorizador Lambda com o authlete pacote.

~$ mkdir authorizer
~$ cd authorizer
~/authorizer$ vi lambda_function.py
~/authorizer$ pip install --target ./package authlete
~/authorizer$ (cd package; zip -r9 ../function.zip .)
~/authorizer$ zip -g function.zip lambda_function.py
~/authorizer$ aws lambda update-function-code --function-name authorizer --zip-file fileb://function.zip

Teste

Os testes podem ser a parte mais difícil neste tutorial, pois existem muitos passos para configurar o ambiente de teste ilustrado abaixo.


Components to test certificate binding

Vamos dar os seguintes passos um por um juntos.

  1. Prepare um servidor de autorização que suporta vinculação de certificados.
  2. Prepare um certificado de servidor para o servidor de autorização.
  3. Configurar um proxy reverso para TLS mútuo no ponto final do token do servidor de autorização.
  4. Prepare um aplicativo do cliente que está configurado para vinculação de certificado.
  5. Prepare um certificado de cliente para a aplicação do cliente.
  6. Configurar um domínio personalizado para Amazon API Gateway.
  7. Obter um token de acesso vinculado a certificados.
  8. Acesse um recurso (faça uma chamada de API).

Servidor de Autorização

Vamos usar java-oauth-servidor como servidor de autorização. É uma implementação amostra de servidor de autorização escrito em Java que usa o Authlete como um serviço backend.

$ git clone https://github.com/authlete/java-oauth-server
$ cd java-oauth-server
$ vi authlete.properties
$ docker-compose up

As linhas de comando acima iniciarão um servidor de autorização (java-oauth-server) em sua máquina local em http://localhost:8080.

Em seguida, faça login Console do proprietário de serviço e configurar o serviço correspondente ao servidor de autorização para que ele possa suportar a vinculação do certificado.


Service Configuration for Certificate Binding

Certificado do servidor

Crie uma chave privada e, em seguida, um certificado auto-assinado para o servidor de autorização.

$ openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256    > server_private_key.pem
$ openssl req -x509 -key server_private_key.pem -subj /CN=localhost > server_certificate.pem

Note que openssl comando usado neste tutorial é OpenSSL’s. Porque openssl comando instalado no macOS é LibraSSL desde High Sierra, você tem que instalar OpenSSL’s openssl para tentar linhas de comando neste tutorial como eles são.

$ /usr/bin/openssl version -a
LibreSSL 2.6.5
......
$ brew install openssl
$ /usr/local/opt/openssl/bin/openssl version -a
OpenSSL 1.1.1g  21 Apr 2020
......

Proxy reverso

Como o servidor java-oauth em si não protege seus pontos finais pelo TLS, um proxy reverso precisa ser colocado na frente do java-oauth-server para aceitar conexões TLS. Abaixo está um exemplo de arquivo de configuração que configura Nginx como um proxy reverso.

events {}
http {
  server {
    # Accept TLS connections at port 8443.
    listen 8443 ssl;

    # Server certificate in PEM format
    ssl_certificate /path/to/server_certificate.pem;

    # Servicer private key in PEM format
    ssl_certificate_key /path/to/server_private_key.pem;

    # Enable mutual TLS. 'optional_no_ca' requests a client certificate but
    # does not require it to be signed by a trusted CA certificate. This is
    # enough for this tutorial. See the document of ngx_http_ssl_module for
    # details: http://nginx.org/en/docs/http/ngx_http_ssl_module.html
    ssl_verify_client optional_no_ca;

    # Pass the client certificate in the mutual TLS connection to the proxied
    # server (java-oauth-server) as the value of 'X-Ssl-Cert' HTTP header.
    # The proxied server has to be able to recognize the HTTP header, and
    # java-oauth-server does recognize it. To be exact, authlete-java-jaxrs
    # library used by java-oauth-server recognizes it.
    proxy_set_header X-Ssl-Cert $ssl_client_escaped_cert;

    # Pass requests that Nginx receives at 'https://localhost:8443/token' to
    # 'http://localhost:8080/api/token' ('/api/token' of java-oauth-server).
    # Note that TLS is terminated here.
    location = /token {
      proxy_pass http://localhost:8080/api/token;
    }
  }
}

Esta configuração faz com que o Nginx seja executado em https://localhost:8443 e encaminhar pedidos para /token Para http://localhost:8080/api/token.

Se o nome do arquivo de configuração for nginx.conf, Nginx pode ser iniciado digitando o comando abaixo.

$ nginx -c $PWD/nginx.conf

Quando quiser parar o Nginx, digite isto:

$ nginx -s stop

Aplicativo do cliente

Login Console de desenvolvedores e alterar a configuração de um aplicativo cliente que você vai usar para testes para habilitar a vinculação do certificado.


Client Configuration for Certificate Binding

Certificado do Cliente

Crie uma chave privada e, em seguida, um certificado auto-assinado para a solicitação do cliente.

$ openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 > client_private_key.pem
$ openssl req -x509 -key client_private_key.pem -subj /CN=client.example.com > client_certificate.pem

Crie mais um par de chaves privadas e certificado para usar para testes posteriormente. Certifique-se de especificar um valor diferente para o nome comum (para /CN=), porque a configuração de domínio personalizada do Amazon API Gateway, que cobriremos na próxima seção, rejeita um arquivo truststore que contém certificados com o mesmo assunto.

$ openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 > client_private_key_2.pem
$ openssl req -x509 -key client_private_key_2.pem -subj /CN=client2.example.com > client_certificate_2.pem

Domínio personalizado

Para habilitar TLS mútuo no Amazon API Gateway, no momento desta escrita, você tem que atribuir um domínio personalizado (por exemplo, api.example.com) para sua API.

O console Web do Amazon API Gateway fornece o menu “Nomes de domínio personalizados”. Para configurar um domínio personalizado lá sem problemas, é melhor preparar os seguintes itens com antecedência.

  1. Certificado do servidor para o domínio personalizado
  2. Loja de Confiança, um arquivo contendo certificados de clientes confiáveis em formato PEM

Certificado de servidor para domínio personalizado

Um certificado de servidor para um domínio personalizado para o Amazon API Gateway deve estar sob gerenciamento de Gerente de Certificados AWS (ACM). Você pode importar certificados existentes ou criar novos em Console ACM. No entanto, os certificados importados não podem ser usados para domínios personalizados para o Amazon API Gateway quando o TLS mútuo estiver ativado. Então, crie um novo lá.

Loja de Confiança

Quando você configurar tls mútuo, você será solicitado a inserir a localização de um arquivo que contém certificados de cliente confiáveis. O arquivo é chamado “loja de confiança”. A implementação do Amazon API Gateway mutual TLS verifica se o certificado de cliente apresentado durante o aperto de mão TLS está incluído na loja de confiança. Se não for incluído, o Amazon API Gateway rejeita a conexão sem invocar um autorizador Lambda.

Truststore é um arquivo de texto listando certificados de clientes em formato PEM como abaixo.

-----BEGIN CERTIFICATE-----
<Certificate contents>
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
<Certificate contents>
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
<Certificate contents>
-----END CERTIFICATE-----
...

Uma loja de confiança para este tutorial pode ser criada digitando os comandos abaixo.

$ cat client_certificate.pem   >  truststore.pem
$ cat client_certificate_2.pem >> truststore.pem

A loja de confiança precisa ser carregada para S3 para que o Amazon API Gateway possa se referir a ele.

$ aws s3 cp truststore.pem s3://{your-s3-bucket}

Os passos acima são descritos em Configuração de autenticação TLS mútua para uma API REST. Consulte o documento para obter detalhes.

Configuração personalizada do domínio

Agora você está pronto para registrar um domínio personalizado no Amazon API Gateway.

Habilitar Autenticação mútua de TLS na caixa “Detalhes do domínio” e um campo para Truststore URI aparecerá. Insira o S3 URI da sua loja de confiança no campo.


Custom Domain Details

Em seguida, selecione o certificado de servidor para o domínio personalizado na caixa “Configuração de ponto final”.


Custom Domain Endpoint Configuration

Depois de registrar um domínio personalizado, você pode configurar como mapear “API” e “Stage” para “Path” sob o domínio personalizado. Na captura de tela abaixo, API “Exemplo” dev palco é mapeado para o caminho do domínio personalizado dev.


Configure API mappings

Roteamento

O passo final para a configuração personalizada de domínio é adicionar um registro CNAME ao seu servidor DNS para que o domínio personalizado possa ser roteado para “nome de domínio API Gateway”.


API Gateway domain name

Token de acesso vinculado a certificados

Fizemos toda a preparação. Vamos pegar um. token de acesso vinculado a certificados pelo fluxo de código de autorização.

Solicitação de Autorização

No fluxo de código de autorização, o primeiro passo é enviar um solicitação de autorização para o endpoint de autorização do servidor de autorização através de um navegador web. Neste tutorial, o ponto final de autorização é http://localhost:8080/api/authorization hospedado no java-oauth-server. Substituir ${CLIENT_ID} na URL abaixo que representa uma solicitação de autorização com a ID do cliente real do seu aplicativo cliente e, em seguida, acessar a URL com o seu navegador web.

http://localhost:8080/api/authorization?response_type=code&client_id=${CLIENT_ID}&scope=profile+email&state=123

Seu navegador da Web exibirá um página de autorização gerado pelo servidor de autorização. Vai parecer lá embaixo.


Authorization page in authorization code flow

A página tem campos de entrada para ID de login e senha. Entrada john e john lá e pressione o botão “Autorizar”, e seu navegador da Web será redirecionado para o ponto final de redirecionamento do aplicativo do seu cliente.

Se você não mudou redirecionar URI do seu aplicativo cliente a partir do valor padrão, a URL do ponto final de redirecionamento é https://{authlete-server}/api/mock/redirection/{service-api-key}.

A URL do ponto final de redirecionamento que você pode ver na barra de endereço do seu navegador contém code parâmetro de resposta como abaixo.

https://{authlete-server}/api/mock/redirection/{service-api-key}?state=123&code=RwRq2Lp0bJVMiLPKAFz4qB1hxieBD1X5HKuv8EPkJeM

O valor de code parâmetro de resposta é o código de autorização que foi emitido do servidor de autorização para o aplicativo do seu cliente. O código de autorização é necessário quando o aplicativo do cliente faz uma solicitação de token.

Solicitação de token

Depois de obter um código de autorização, o aplicativo do cliente envia um solicitação de token para o ponto final token do servidor de autorização. Neste tutorial, o ponto final do token é https://localhost:8443/token hospedado em Nginx.

Uma solicitação de token pode ser feita por curl comando em um terminal shell. Abaixo está um exemplo de solicitação de token. Não se esqueça de substituir $CLIENT_ID e $CODE com o ID do cliente real e o código de autorização real antes de digitar.

$ curl -k --key client_private_key.pem --cert client_certificate.pem https://localhost:8443/token -d grant_type=authorization_code -d client_id=$CLIENT_ID -d code=$CODE
Argumento Descrição
-k não verifique o certificado do servidor. Como este tutorial usa um certificado de servidor auto-assinado, essa opção é necessária.
--key client_private_key.pem especifica a chave privada do cliente.
--cert client_certificate.pem especifica o certificado do cliente.
https://localhost:8443/token A URL do ponto final do token.
-d grant_type=authorization_code indica que o fluxo é o fluxo de código de autorização.
-d client_id=$CLIENT_ID especifica o ID do cliente. $CLIENT_ID com a ID do cliente real do seu aplicativo de cliente.
-d code=$CODE especifica o código de autorização. Substituir $CODE com o código de autorização real.

O ponto aqui é que é necessário passar a chave privada do cliente e certificado para curl comando usando --key opção e --cert opção porque o ponto final do token requer TLS mútuo (ou seja, requer um certificado de cliente durante o aperto de mão TLS). O token de acesso emitido a partir do ponto final do token será vinculado ao certificado do cliente usado na solicitação de token.

Quando uma solicitação de token é bem sucedida, o ponto final do token retorna JSON que inclui access_token propriedade como abaixo.

{
  "access_token":  "b5qgqkXpzObRyceBqKeGPDCT9NX9GGXSt_oSYBSj7GQ",
  "refresh_token": "1iSpvpeznTzwdUJzwRbt-abqE4znWn_yhN5PbBKV9zw",
  "scope":         "email profile",
  "token_type":    "Bearer",
  "expires_in":    86400
}

O valor do access_token propriedade é o token de acesso emitido. O aplicativo do cliente usa o token de acesso quando faz chamadas de API.

Acesso a recursos (chamada de API)

Finalmente, ficamos prontos para acessar recursos (APIs) no Amazon API Gateway, que são protegidos por tokens de acesso vinculados a certificados.

Primeiro, acesse um recurso com o token de acesso e o certificado de cliente certo. Substituir ${ACCESS_TOKEN}, ${CUSTOM_DOMAIN} e ${RESOURCE} no exemplo abaixo com valores reais de vocês. Se todas as coisas foram configuradas corretamente, você pode obter o recurso com sucesso sem ser bloqueado.

$ curl --key client_private_key.pem --cert client_certificate.pem -H "Authorization: Bearer ${ACCESS_TOKEN}" https://${CUSTOM_DOMAIN}/${RESOURCE}

Em seguida, acesse o recurso com o mesmo token de acesso e um certificado de cliente errado (client_certificate_2.pem neste tutorial).

$ curl --key client_private_key_2.pem --cert client_certificate_2.pem -H "Authorization: Bearer ${ACCESS_TOKEN}" https://${CUSTOM_DOMAIN}/${RESOURCE}

Você receberá a seguinte resposta de erro.

{"Message":"User is not authorized to access this resource with an explicit deny"}

Isso inidique que o Amazon API Gateway rejeitou o acesso aos recursos. O ponto mais importante aqui é que o acesso ao recurso foi rejeitado embora o token de acesso fosse legítimo e foi porque o certificado de cliente apresentado em conjunto não era o legítimo vinculado ao token de acesso. Isso é vinculação de certificado.

Parabéns!

Você completou este tutorial e agora pode proteger suas APIs no Amazon API Gateway com mais segurança do que nunca antes de utilizar a vinculação de certificados (RFC 8705)!

Entre em contato conosco se você precisar de apoio. Você é sempre bem-vindo!