JamesMatson
JamesMatson

Reputation: 2932

AWS APIGateway CloudFormation specify Api Key required for method?

I have the below CloudFormation template which creates my API Gateway (backed by Lambda). I want to enable API Keys as a requirement for one or more of these methods. I have successfully created API Keys, Usage Plans and the association between the two, but can't figure out how to actually enable the 'requires API Key' property for some of the methods. The documentation from AWS specifies an 'ApiKeyRequired' property as a part of the AWS::ApiGateway::Method component, but my CF template doesn't have or use this component? I'm unsure how to use it considering I've never required it before?

My template is below:

   "ServerlessRestApi": {
        "Type": "AWS::ApiGateway::RestApi",
        "Properties": {
            "Description":"This is a placeholder for the description of this web api",
            "ApiKeySourceType":"HEADER",
            "Body": {
                "info": {
                    "version": "1.0",
                    "title": {
                        "Ref": "AWS::StackName"
                    }
                },
                "paths": {
                    "/list/tables": {
                        "get": {
                            "x-amazon-apigateway-integration": {
                                "httpMethod": "POST",
                                "type": "aws_proxy",
                                "uri": {
                                    "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableList.Arn}/invocations"
                                }
                            },
                            "security": [
                                {
                                   "api_key": []
                                }
                             ],
                            "responses": {}
                        }
                    },
                    "/list/columns/{tableid}": {
                        "get": {
                            "x-amazon-apigateway-integration": {
                                "httpMethod": "POST",
                                "type": "aws_proxy",
                                "uri": {
                                    "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetColumnList.Arn}/invocations"
                                }
                            },
                            "responses": {}
                        }
                    },
                    "datagw/general/table/get/{tableid}": {
                        "get": {
                            "x-amazon-apigateway-integration": {
                                "httpMethod": "POST",
                                "type": "aws_proxy",
                                "uri": {
                                    "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableResponse.Arn}/invocations"
                                }
                            },
                            "responses": {}
                        }
                    },
                    "/": {
                        "get": {
                            "x-amazon-apigateway-integration": {
                                "httpMethod": "POST",
                                "type": "aws_proxy",
                                "uri": {
                                    "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Get.Arn}/invocations"
                                }
                            },
                            "responses": {}
                        }
                    },
                    "/tables/{tableid}/{columnid}": {
                        "get": {
                            "x-amazon-apigateway-integration": {
                                "httpMethod": "POST",
                                "type": "aws_proxy",
                                "uri": {
                                    "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableBasic.Arn}/invocations"
                                }
                            },
                            "responses": {}
                        }
                    },
                    "securityDefinitions": {
                        "type": "api_key",
                        "name": "x-api-key",
                        "in": "header"
                      }
                },
                "swagger": "2.0"
            }
        }
    },

Upvotes: 5

Views: 4933

Answers (5)

Sarthak Jain
Sarthak Jain

Reputation: 2096

Complete guide here. This guide provides a basic setup for enabling API keys for any API Gateway methods.

Use AWS::Serverless::Api for defining your API. It supports an Auth attribute which has an attribute named ApiKeyRequired. Set this to true.

Following code snippet from the above guide should do.

AuthApiGateway:
    Type: AWS::Serverless::Api
    Properties:
       StageName: Prod
       Auth:
           ApiKeyRequired: 'true' # This makes passing ApiKey mandatory
       DefinitionBody:
           swagger: '2.0'
           info: ...

Upvotes: 2

Ankit Jain
Ankit Jain

Reputation: 1

"security" : [{
                "myKey" : []
            }],

"myKey": {
            "type": "apiKey",
            "name": "x-api-key",
            "in": "header"
        },

Adding security element in body and myKey element in securityDefinitions worked for me.

Upvotes: 0

Jaffer
Jaffer

Reputation: 2968

Late to the party.

"x-amazon-apigateway-api-key-source" : "HEADER",

And

"securityDefinitions": {
    "<SOME_NAME>": {
        "type": "apiKey",
        "name": "x-api-key",
        "in": "header"
    }
 }

And

"security" : [{
    "<SOME_NAME>" : []
}]

So a possible working solution could be

              "Body": {
                    "swagger": "2.0",
                    "info": {
                        "version": "2017-01-27T21:44:58Z",
                        "title": {"Ref": "AWS::StackName"}
                    },
                    "basePath": "/bbd",
                    "x-amazon-apigateway-api-key-source" : "HEADER",
                    "schemes": [
                        "https"
                    ],
                    "paths": {
                        "/{proxy+}": {
                            "x-amazon-apigateway-any-method": {
                                "produces": [
                                    "application/json"
                                ],
                                "parameters": [
                                    {
                                        "name": "proxy",
                                        "in": "path",
                                        "required": true,
                                        "type": "string"
                                    }
                                ],
                                "security" : [{
                                    "bbd" : []
                                }],
                                "responses": {},
                                "x-amazon-apigateway-integration": {
                                    "responses": {
                                        "default": {
                                            "statusCode": "200"
                                        }
                                    },
                                    "uri": "<URL>",
                                    "passthroughBehavior": "when_no_match",
                                    "httpMethod": "POST",
                                    "cacheNamespace": "xh7gp9",
                                    "cacheKeyParameters": [
                                        "method.request.path.proxy"
                                    ],
                                    "contentHandling": "CONVERT_TO_TEXT",
                                    "type": "aws_proxy"
                                }
                            }
                        }
                    },
                    "securityDefinitions": {
                        "bbd": {
                            "type": "apiKey",
                            "name": "x-api-key",
                            "in": "header"
                        }
                    }
                }

Upvotes: 1

John Iwasz
John Iwasz

Reputation: 151

I ran into the same issue and resolved it by abandoning the use of the Body property in the AWS::ApiGateway::RestApi using:

 "ServerlessRestApi": {
        "Type": "AWS::ApiGateway::RestApi",
        "DependsOn": "AspNetCoreFunction",
        "Properties": {
           "Description":"My Api Gateway",
            "ApiKeySourceType" : "HEADER",      
            "EndpointConfiguration" : {  "Types" : [ "REGIONAL" ]}
        }
    },

Then, I created a proxy resource. In your case, you would create a resource for each of your paths. Where I have, "{proxy+}", you would have "/list/tables."

"ProxyResource": {
    "Type": "AWS::ApiGateway::Resource",
    "Properties": {
        "RestApiId": {
            "Ref": "ServerlessRestApi"
        },
        "ParentId": {
            "Fn::GetAtt": [
                "ServerlessRestApi",
                "RootResourceId"
            ]
        },
        "PathPart": "{proxy+}"
    }
},

Finally, I was able to define an AWS::ApiGateway::Method then enforce usage an API key:

"CoreApiPostMethod":
  {
    "Type": "AWS::ApiGateway::Method",
     "DependsOn" : ["AspNetCoreFunction", "ServerlessRestApi"],
    "Properties":
    {
     "AuthorizationType" :"NONE",
      "OperationName" : "My API Post Request",

     "ApiKeyRequired" : true,
            "ResourceId": { "Ref": "ProxyResource"  },
    "RestApiId": {
      "Ref": "ServerlessRestApi"
    },
     "HttpMethod" : "POST",
      "Integration" : {  
       "ConnectionType" :  "INTERNET",
          "IntegrationHttpMethod" : "POST",
       "Type" : "AWS_PROXY",
        "Uri" : {
                          "Fn::Sub":"arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AspNetCoreFunction.Arn}/invocations"
                }
      }        
    }

  },

And then follow the same pattern for the other HTTP methods. It's more verbose than the original configuration, but it does give you more control over the method configuration.

Upvotes: 2

A.Khan
A.Khan

Reputation: 4002

I think adding security under each path and then securityDefinitions under paths would work.

"paths": {
  "/list/tables": {
     "get": {
        "x-amazon-apigateway-integration": {
           "httpMethod": "POST",
           "type": "aws_proxy",
           "uri": {
              "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015- 
               03-31/functions/${GetTableList.Arn}/invocations"
           }
        },
        "security": [
           {
              "api_key": []
           }
        ]
     }
  }
},
"securityDefinitions": {
  "type": "api_key",
  "name": "x-api-key",
  "in": "header"
}

Upvotes: 2

Related Questions