Welcome to Knowledge Base!

KB at your finger tips

This is one stop global knowledge base where you can learn about all the products, solutions and support features.

Categories
All

Cloud-AWS

Identify API key usage with API Gateway

How can I identify the usage associated with an API key for API Gateway?

Last updated: 2022-08-12

How can I get the usage associated with an API key for Amazon API Gateway?

Resolution

Follow these instructions to get the API key usage using either the AWS Management Console or the AWS Command Line Interface (AWS CLI).

Note: If you receive errors when running AWS CLI commands, make sure that you’re using the most recent version of the AWS CLI.

Use the AWS Management Console

  1. Open the API Gateway console.
  2. In the navigation pane, choose APIs .
  3. Choose your API, and then choose Usage Plans .
  4. Choose your Usage Plan .
  5. Choose Actions , and then choose Export Usage Data .
  6. Choose the export From and To date range.
  7. For Export as , choose JSON or CSV , and then choose Export .

For more information, see Create, configure, and test usage plans with the API Gateway console.

Use the AWS CLI

You can use the AWS CLI command get-usage to get the usage data of a usage plan in a date range similar to the following:

aws apigateway get-usage --usage-plan-id <usage-plan-id> --start-date "20xx-xx-xx" --end-date "20xx-xx-xx" --key-id <api-key-id>

Note: The usage date range can't exceed 90 days.

For more information, see Create, configure, and test usage plans using the API Gateway CLI and REST API.


Best practices for API keys and usage plans

Did this article help?

Submit feedback

Do you need billing or technical support?

Contact AWS Support

Fix authorization HTTP 403 errors from API Gateway Lambda authorizers

Why is my API Gateway proxy resource with a Lambda authorizer that has caching activated returning HTTP 403 "User is not authorized to access this resource" errors?

Last updated: 2022-08-17

My Amazon API Gateway proxy resource with an AWS Lambda authorizer that has caching activated returns the following HTTP 403 error message: "User is not authorized to access this resource". Why is this happening, and how do I resolve the error?

Short description

Note: API Gateway can return 403 User is not authorized to access this resource errors for a variety of reasons. This article addresses 403 errors related to API Gateway proxy resources with a Lambda authorizer that has caching activated only. For information on troubleshooting other types of 403 errors, see How do I troubleshoot HTTP 403 errors from API Gateway?

A Lambda authorizer's output returns an AWS Identity and Access Management (IAM) policy to API Gateway. The IAM policy includes an explicit API Gateway API "Resource" element that's in the following format:

"arn:aws:execute-api:<region>:<account>:<API_id>/<stage>/<http-method>/[<resource-path-name>/[<child-resources-path>]"

When Authorization Caching is activated on a Lambda authorizer, the returned IAM policy is cached. The cached IAM policy is then applied to any additional API requests made within the cache's specified time-to-live (TTL) period.

If the API has a proxy resource with a greedy path variable of {proxy+} , the first authorization succeeds. Any additional API requests made to a different path within the cache's TTL period fail and return the following error:

"message": "User is not authorized to access this resource"

The additional requests fail, because the paths don't match the explicit API Gateway API "Resource" element defined in the cached IAM policy.

To resolve the issue, you can modify the Lambda authorizer function's code to return a wildcard ( */* ) resource in the output instead. For more information, see Resources and conditions for Lambda actions.

Note : To activate authorizer caching, your authorizer must return a policy that is applicable to all methods across an API Gateway. The Lambda authorizer function's code must return a wildcard (*/*) resource in the output to allow all resources. The cache policy expects the same resource path cached, unless you made the same request twice on the same resource-path.

Resolution

Note: Modify the example Lambda authorizer function code snippets in this article to fit your use case.

In the following example setups, the Lambda functions extract the API Gateway's id value from the method's Amazon Resource Name (ARN) ( "event.methodArn" ). Then, the functions define a wildcard "Resource" variable by combining the method ARN's paths with the API's id value and a wildcard ( */* ).

Example token-based Lambda authorizer function code that returns a wildcard "Resource" variable

exports.handler =  function(event, context, callback) {
    var token = event.authorizationToken;
    var tmp = event.methodArn.split(':');
    var apiGatewayArnTmp = tmp[5].split('/');
    
    // Create wildcard resource
    var resource = tmp[0] + ":" + tmp[1] + ":" + tmp[2] + ":" + tmp[3] + ":" + tmp[4] + ":" + apiGatewayArnTmp[0] + '/*/*'; 
    switch (token) {
        case 'allow':
            callback(null, generatePolicy('user', 'Allow', resource));
            break;
        case 'deny':
            callback(null, generatePolicy('user', 'Deny', resource));
            break;
        case 'unauthorized':
            callback("Unauthorized");   // Return a 401 Unauthorized response
            break;
        default:
            callback("Error: Invalid token"); // Return a 500 Invalid token response
    }
};
// Help function to generate an IAM policy
var generatePolicy = function(principalId, effect, resource) {
    var authResponse = {};
    
    authResponse.principalId = principalId;
    if (effect && resource) {
        var policyDocument = {};
        policyDocument.Version = '2012-10-17'; 
        policyDocument.Statement = [];
        var statementOne = {};
        statementOne.Action = 'execute-api:Invoke'; 
        statementOne.Effect = effect;
        statementOne.Resource = resource;
        policyDocument.Statement[0] = statementOne;
        authResponse.policyDocument = policyDocument;
    }
    
    // Optional output with custom properties of the String, Number or Boolean type.
    authResponse.context = {
        "stringKey": "stringval",
        "numberKey": 123,
        "booleanKey": true
    };
    return authResponse;
}

Example request parameter-based Lambda authorizer function code that returns a wildcard "Resource" variable

exports.handler = function(event, context, callback) {        
   
    // Retrieve request parameters from the Lambda function input:
    var headers = event.headers;
    var queryStringParameters = event.queryStringParameters;
    var pathParameters = event.pathParameters;
    var stageVariables = event.stageVariables;
        
    // Parse the input for the parameter values
    var tmp = event.methodArn.split(':');
    var apiGatewayArnTmp = tmp[5].split('/');

    // Create wildcard resource
    var resource = tmp[0] + ":" + tmp[1] + ":" + tmp[2] + ":" + tmp[3] + ":" + tmp[4] + ":" + apiGatewayArnTmp[0] + '/*/*'; 
    console.log("resource: " + resource);
    // if (apiGatewayArnTmp[3]) {
    //     resource += apiGatewayArnTmp[3];
    // }
        
    // Perform authorization to return the Allow policy for correct parameters and 
    // the 'Unauthorized' error, otherwise.
    var authResponse = {};
    var condition = {};
    condition.IpAddress = {};
     
    
    if (headers.headerauth1 === "headerValue1"
        && queryStringParameters.QueryString1 === "queryValue1"
        && stageVariables.StageVar1 === "stageValue1") {
        callback(null, generateAllow('me', resource));
    }  else {
        callback("Unauthorized");
    }
}
     
// Help function to generate an IAM policy
var generatePolicy = function(principalId, effect, resource) {
    // Required output:
    console.log("Resource in generatePolicy(): " + resource);
    var authResponse = {};
    authResponse.principalId = principalId;
    if (effect && resource) {
        var policyDocument = {};
        policyDocument.Version = '2012-10-17'; // default version
        policyDocument.Statement = [];
        var statementOne = {};
        statementOne.Action = 'execute-api:Invoke'; // default action
        statementOne.Effect = effect;
        statementOne.Resource = resource;
        console.log("***Resource*** " + resource);
        policyDocument.Statement[0] = statementOne;
        console.log("***Generated Policy*** ");
        console.log(policyDocument);
        authResponse.policyDocument = policyDocument;
    }
    // Optional output with custom properties of the String, Number or Boolean type.
    authResponse.context = {
        "stringKey": "stringval",
        "numberKey": 123,
        "booleanKey": true
    };
    
    return authResponse;
}
     
var generateAllow = function(principalId, resource) {
    return generatePolicy(principalId, 'Allow', resource);
}
     
var generateDeny = function(principalId, resource) {
    return generatePolicy(principalId, 'Deny', resource);
}

For more information on how to edit Lambda function code, see Deploying Lambda functions defined as .zip file archives.


Edit code using the console editor

Did this article help?

Submit feedback

Do you need billing or technical support?

Contact AWS Support
Read article

Resolve mutual TLS 403 Forbidden errors from API Gateway

How do I troubleshoot HTTP 403 Forbidden errors from an API Gateway custom domain name that requires mutual TLS?

Last updated: 2021-12-08

My Amazon API Gateway custom domain name that has mutual Transport Layer Security (TLS) authentication activated returns HTTP 403 Forbidden errors. Why is this happening, and how do I troubleshoot the issue?

Short description

Note: API Gateway can return 403 Forbidden errors for a variety of reasons. This article addresses 403 Forbidden errors related to mutual TLS only. For information on troubleshooting other types of 403 Forbidden errors, see How do I troubleshoot HTTP 403 Forbidden errors from API Gateway?

To invoke an API Gateway API using a custom domain name that requires mutual TLS, clients must present a trusted certificate in the API request. When a client attempts to invoke the API, API Gateway looks for the client certificate's issuer in your truststore.

If any of the following conditions occur, then API Gateway fails the TLS connection and returns a 403 status code:

  • API Gateway can't find the issuer of the client certificate in your truststore.
  • The client certificate is using an insecure signature algorithm.
  • The client certificate is self signed.

If Amazon CloudWatch logging is activated for your API, then an error message that indicates the cause of the error appears in your execution logs.

Important: If the API request doesn't produce any CloudWatch Logs after logging is activated, then the 403 Forbidden error isn't related to mutual TLS.

For REST APIs

If you set up Amazon CloudWatch logging for your REST API, then one of the following error messages also appears in your execution logs:

  • Access denied. Reason: Could not find issuer for certificate
  • Access denied. Reason: Client cert using an insecure Signature Algorithm
  • Access denied. Reason: self signed certificate

For HTTP APIs

HTTP APIs don't support execution logging. To troubleshoot 403 Forbidden errors returned by a custom domain name that requires mutual TLS and invokes an HTTP API, you must do the following:

1.    Create a new API mapping for your custom domain name that invokes a REST API for testing only.
Note: If you don't have a REST API available for testing, then use the example PetStore REST API. Then, deploy the example API to a new stage and create a new API mapping for it that uses your custom domain name.

2.    Follow the instructions in the Resolution section of this article using the new API mapping that you created to your REST API.

3.    After the error is identified and resolved, reroute the API mapping for your custom domain name back to your HTTP API.

Resolution

Confirm the cause of the error

1.    If you haven't already, turn on CloudWatch logging for your REST API. Make sure that you configure execution and access logging.

Note: When configuring access logging for this use case, it's a best practice to use the following $context variables. These variables do two things:

  • They tell API Gateway to generate CloudWatch Logs when your custom domain name that requires mutual TLS returns a 403 Forbidden error.
  • They make it easier to identify the caller that tried to invoke your API when you review your CloudWatch Logs.

Recommended $context variables for CloudWatch access logging that will allow API Gateway to generate execution and access logs

{ "accountId":"$context.accountId", "apiId":"$context.apiId", "domainName":"$context.domainName", "domainPrefix":"$context.domainPrefix", "error.message":"$context.error.message", "error.responseType":"$context.error.responseType", "extendedRequestId":"$context.extendedRequestId", "httpMethod":"$context.httpMethod", "identity.sourceIp":"$context.identity.sourceIp", "identity.clientCert.clientCertPem":"$context.identity.clientCert.clientCertPem", "identity.clientCert.subjectDN":"$context.identity.clientCert.subjectDN", "identity.clientCert.issuerDN":"$context.identity.clientCert.issuerDN", "identity.clientCert.serialNumber":"$context.identity.clientCert.serialNumber", "identity.clientCert.validity.notBefore":"$context.identity.clientCert.validity.notBefore", "identity.clientCert.validity.notAfter":"$context.identity.clientCert.validity.notAfter", "identity.userAgent":"$context.identity.userAgent", "path":"$context.path", "protocol":"$context.protocol", "requestId":"$context.requestId", "requestTime":"$context.requestTime", "requestTimeEpoch":"$context.requestTimeEpoch", "resourceId":"$context.resourceId", "resourcePath":"$context.resourcePath", "stage":"$context.stage", "responseLatency":"$context.responseLatency", "responseLength":"$context.responseLength", "status":"$context.status" }

2.    Identify what's causing the 403 Forbidden errors by viewing your REST API's execution logs in CloudWatch. If a 403 Forbidden error related to mutual TLS is logged, then an error message similar to the following example appears.

Example CloudWatch Logs error message for when a custom domain name that requires mutual TLS returns a 403 Forbidden error

Extended Request Id: {extendedRequestId} 
Access denied. Reason: {reason} 
ForbiddenException Forbidden: {requestId}

To resolve "Access denied. Reason: Could not find issuer for certificate" errors

Verify that the issuer of the client certificate in the API request is included in the custom domain name's truststore

The issuer of the client certificate ( client.pem ) in the API request must be included in your custom domain name's truststore. The issuer must also be included as part of the certificate bundle ( bundle.pem ) in Amazon Simple Storage Service (Amazon S3).

To verify if the issuer of the client certificate is included in the required truststore, run the following OpenSSL command:

$ openssl verify -CAfile bundle.pem client.pem

-or-

If the certificate bundle contains intermediate certificate authorities, then run the following OpenSSL command:

$ openssl verify -CAfile rootCA.pem -untrusted intCA.pem client.pem

The command returns an OK response if the issuer of the client certificate in the API request is included in the required truststore.

The command returns the following error if the issuer of the client certificate isn't included in the required truststore: "error X at Y depth lookup: unable to get local issuer certificate"

Verify that all of the client certificates in your custom domain name's truststore are valid

If one of the client certificate's in your custom domain name's truststore isn't valid, then some clients might not be able to access your API.

To verify whether all of the client certificates in your truststore are valid, do the following:

1.    Open the API Gateway console.

2.    In the left navigation pane, choose Custom domain names . Then, choose your custom domain name that requires mutual TLS.

3.    In the Details section, see whether there's the following error message: There is an invalid certificate in your truststore bundle .

4.    If you see the error message, then you must decode the certificates in your truststore to identify which certificate produced the warning.
Note: The following OpenSSL command displays the contents of a certificate, including its subject:

$ openssl x509 -in certificate.crt -text -noout

5.    Update or remove the certificates that produced the warning. Then, upload a new truststore to Amazon S3.

For more information, see Troubleshooting certificate warnings.

Note: API Gateway accepts client certificates signed directly by the root certificate authority or any other intermediate if their certificate chain is preserved. To validate client certificates signed by the last intermediate certificate authority only, use a request parameter-based AWS Lambda authorizer. You can use your custom validation algorithm at the Lambda function level by accepting the client certificate as input from the API request.

To resolve "Access denied. Reason: Client cert using an insecure Signature Algorithm" errors

Verify that your truststore text file uses a supported hashing algorithm

API Gateway supports the following hashing algorithms in the truststore:

  • SHA-256 or stronger
  • RSA-2048 or stronger
  • ECDSA-256 or stronger

To verify if your truststore text file uses a supported hashing algorithm or not, then run the following OpenSSL command:

$ openssl x509 -in client.crt -text -noout | grep 'Signature Algorithm'

The command response returns your truststore's signature algorithm.

For more information, see Configuring your truststore.

To resolve "Access denied. Reason: self signed certificate" errors

Verify that the self-signed client certificate in the API request isn't altered or corrupted

The following must match exactly:

  • The modulus of the private key ( private.key ) used to sign the self-signed certificate within the truststore in S3 ( bundle.crt or bundle.pem ).
  • The modulus from the client's certificate passed in the API request ( client.crt ).

To compare the two modulus, run the following OpenSSL commands:

$ openssl rsa -noout -modulus -in private.key
$ openssl x509 -noout -modulus -in bundle.crt
$ openssl x509 -noout -modulus -in client.crt

Note: To produce a shorter hash value for easier comparison, you can PIPE- ing the output modulus into a cryptographic hash function. For example: openssl sha1 .

$ openssl [operation] -noout -modulus -in [data] | openssl sha1

Valid command output examples

2143831a73a8bb28467860df18550c696c03fbcb
2143831a73a8bb28467860df18550c696c03fbcb
2143831a73a8bb28467860df18550c696c03fbcb

To confirm data integrity, verify that there wasn't any data modification at the content level by running the following diff command:

$ diff client.crt bundle.crt

For more information, see Configuring your truststore.


Did this article help?

Submit feedback

Do you need billing or technical support?

Contact AWS Support
Read article

Select Amazon API Gateway Cache capacity to avoid hitting a rate limit

How do I select the best Amazon API Gateway Cache capacity to avoid hitting a rate limit?

Last updated: 2021-11-18

My API Gateway is rate limiting and I want to prevent throttling. How can I select the best API Gateway Cache capacity for my workload?

Short description

Amazon API Gateway throttles requests to your API to prevent it from being overwhelmed by too many requests. Turn on API caching to reduce the number of calls made to your endpoint.

There are multiple API Gateway Cache sizes available. To select the appropriate cache size, run a load test on your API and then review the Amazon CloudWatch metrics.

Resolution

Turn on API Gateway caching

Turn on Amazon API Gateway caching for your API stage. The cache capacity depends on the size of your responses and workload.

Note : Cache capacity affects the CPU, memory, and network bandwidth of the cache instance. As a result, cache capacity can affect the performance of your cache.

After creating your cache, run a load test to determine if the cache size is high enough to prevent throttling.

Run a load test

Run a load test on your API. You can use AWS Distributed Load Testing to simulate the load test.

Run the load test for at least 10 minutes and mirror your production traffic. When the load test is running, monitor related CloudWatch metrics using the steps in the following section.

Monitor API metrics in CloudWatch

  1. Open the CloudWatch console.
  2. In the navigation pane, select Metrics.
  3. Choose the ApiGateway metric.
  4. Monitor Latency , 4XXError , 5XXError , CacheHitCount, and CacheMissCount metrics for the API that you are load testing against.
  5. If you see an increase in Latency , 4XXError , 5XXError or CacheMissCount with a CacheHitCount decrease, then resize your API Gateway cache to a larger capacity.
  6. If you see an increase in CacheHitCount and no corresponding increase in CacheMissCount , then resize your API Gateway cache to a smaller capacity.
  7. After any changes to your cache's capacity, run the load test again until there are no sudden increases or decreases.

Amazon API Gateway pricing

Turn on API caching to enhance responsiveness

Amazon API Gateway dimensions and metrics

Did this article help?

Submit feedback

Do you need billing or technical support?

Contact AWS Support
Read article