5

I have a .NET solution that uses a SAM template to generate cloudformation to deploy the stack. I am expecting the deployment - once complete - to have API Key Required = true on at least one of the methods. However after deployment, the keys and usage plans are created, but in the console the api key required is still set to false?

See below:

enter image description here

My SAM template:

    "ServerlessRestApi": {
        "Type": "AWS::ApiGateway::RestApi",
        "Properties": {
            "Description":"This is a placeholder for the description of this web api",
            "Body": {
                "info": {
                    "version": "1.0",
                    "title": {
                        "Ref": "AWS::StackName"
                    }
                },
                "x-amazon-apigateway-api-key-source": "HEADER",
                "paths": {
                    "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": {}
                        },
                        "security":[
                                    {
                                        "api_key":[]
                                    }
                                ]},
                                "securityDefinitions":{
                                    "api_key":{
                                        "type":"apiKey",
                                        "name":"x-api-key",
                                        "in":"header"
                                }
                    },
                    "/": {
                        "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": {}
                        }
                    }
                },
                "swagger": "2.0"
            }
        }
    },

I am not that familiar with swagger definitions, I know only the basics of SAM and CloudFormation. What am I missing here? I have reviewed other answers on stack overflow and believe I've copied the configuration correctly.

When I check the generated CloudFormation, my entries regarding x-api-key are not even present in the template?

  "ServerlessRestApi": {
        "Type": "AWS::ApiGateway::RestApi",
        "Properties": {
            "Body": {
                "info": {
                    "version": "1.0",
                    "title": {
                        "Ref": "AWS::StackName"
                    }
                },
                "paths": {
                    "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": {}
                        }
                    },
                    "/datagw/general/webhook/ccnotify": {
                        "post": {
                            "x-amazon-apigateway-integration": {
                                "httpMethod": "POST",
                                "type": "aws_proxy",
                                "uri": {
                                    "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PostClickCollectNotification.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": {}
                        }
                    },
                    "/datagw/general/post/sohupdate": {
                        "post": {
                            "x-amazon-apigateway-integration": {
                                "httpMethod": "POST",
                                "type": "aws_proxy",
                                "uri": {
                                    "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PostClickCollectStockUpdate.Arn}/invocations"
                                }
                            },
                            "responses": {}
                        }
                    }
                },
                "swagger": "2.0"
            }
        }
    },

EDIT: This is what I have worked up to, but still API key required is not set to true in the API once the deployment has completed.

"ServerlessRestApi": {
    "Type": "AWS::ApiGateway::RestApi",
    "Properties": {
        "Description":"InSite Web API Version 2.0.0.0",
        "Body": {
            "swagger": "2.0",
            "info": {
                "version": "1.0",
                "title": {
                    "Ref": "AWS::StackName"
                }
            },
            "x-amazon-apigateway-api-key-source" : "HEADER",
            "schemes":["https"],
            "paths": {
                "tables/query/{tableid}": {
                    "get": {
                        "x-amazon-apigateway-integration": {
                            "httpMethod": "GET",
                            "type": "aws_proxy",
                            "uri": {
                                "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableResponse.Arn}/invocations"
                            }
                        },
                        "responses": {},
                            "security": [
                            {
                                "api_key": []
                            }
                        ]
                    }
                },
                "/products/update/": {
                    "post": {
                        "x-amazon-apigateway-integration": {
                            "httpMethod": "POST",
                            "type": "aws_proxy",
                            "uri": {
                                "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PostClickCollectStockUpdate.Arn}/invocations"
                            }
                        },
                        "responses": {}
                    }
                },
                "/": {
                    "get": {
                        "x-amazon-apigateway-integration": {
                            "httpMethod": "GET",
                            "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": "GET",
                            "type": "aws_proxy",
                            "uri": {
                                "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableBasic.Arn}/invocations"
                            }
                        },
                        "responses": {}
                    }
                }
            },
            "securityDefinitions": {
                "api_key": {
                    "type": "apiKey",
                    "name": "x-api-key",
                    "in": "header"
                }
            }
        }
    }
},
JamesMatson
  • 2,522
  • 2
  • 37
  • 86
  • [AWS::ApiGateway::RestApi docs](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html) – Pat Myron Sep 04 '19 at 00:58
  • [Amazon API Gateway OpenAPI Definition example](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-as-s3-proxy-export-swagger-with-extensions.html) – Pat Myron Sep 04 '19 at 01:07
  • [more Amazon API Gateway OpenAPI Definition examples](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-authorizer.html) – Pat Myron Sep 04 '19 at 01:08

2 Answers2

0

I think you are missing the "securityDefinitions":

  Body:
    swagger: "2.0"
      ...
      ...
    securityDefinitions:
      sigv4:
        type: "apiKey"
        name: "x-api-key"
        in: "header"
        x-amazon-apigateway-authorizer:
          type: token

You can find here some more examples: https://docs.aws.amazon.com/apigateway/latest/developerguide/api-as-s3-proxy-export-swagger-with-extensions.html

P. Str
  • 580
  • 1
  • 5
  • 18
  • I added this to the SAM template but it changes nothing? "swagger": "2.0", "securityDefinitions": { "sigv4": { "type": "apiKey", "name": "x-api-key", "in": "header", "x-amazon-apigateway-authorizer": { "type": "token" } } } } } – JamesMatson Sep 01 '19 at 23:18
0

So first off, if you are using the SAM framework, then why not try the serverless API (AWS::Serverless::Api) which has an Auth object where you can turn on ApiKeyRequired.

https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessapi

"ServerlessRestApi": {
    "Type": "AWS::Serverless::Api",
    "Properties": {
        "Description":"InSite Web API Version 2.0.0.0",
        "Auth": {
            "ApiKeyRequired": "true"
        },
        "DefinitionBody": {
            "swagger": "2.0",
            "info": {
                "version": "1.0",
                "title": {
                    "Ref": "AWS::StackName"
                }
            },
            "x-amazon-apigateway-api-key-source" : "HEADER",
            "schemes":["https"],
            "paths": {
                "tables/query/{tableid}": {
                    "get": {
                        "x-amazon-apigateway-integration": {
                            "httpMethod": "GET",
                            "type": "aws_proxy",
                            "uri": {
                                "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableResponse.Arn}/invocations"
                            }
                        },
                        "responses": {},
                            "security": [
                            {
                                "api_key": []
                            }
                        ]
                    }
                },
                "/products/update/": {
                    "post": {
                     "x-amazon-apigateway-integration": {
                            "httpMethod": "POST",
                            "type": "aws_proxy",
                            "uri": {
                                "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PostClickCollectStockUpdate.Arn}/invocations"
                            }
                        },
                        "responses": {}
                    }
                },
                "/": {
                    "get": {
                        "x-amazon-apigateway-integration": {
                            "httpMethod": "GET",
                            "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": "GET",
                            "type": "aws_proxy",
                            "uri": {
                                "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableBasic.Arn}/invocations"
                            }
                        },
                        "responses": {}
                    }
                }
            },
            "securityDefinitions": {
                "api_key": {
                    "type": "apiKey",
                    "name": "x-api-key",
                    "in": "header"
                }
            }
        }
    }
},

If for some reason you cannot use the serverless, you might be trying to overload the RestApi (which is fine, but you lose some of the other fine grain options). For full disclosure I do not work with API gateway in this way (I use the serverless transform) so this is all from reading the documentation and not from experiance.

I would try creating a bare bones AWS::ApiGateway::RestApi and then attach an AWS::ApiGateway::Method to the RestApi by reference it though RestApiId.

[1] https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-method.html

J.A. Simmons V
  • 176
  • 1
  • 8
  • Thanks J.A, is it suitable enough that I can do a straight replace of AWS::ApiGateway::RestApi with AWS::Serverless::Api? and keep the rest of the template as-is? – JamesMatson Sep 09 '19 at 03:07
  • @JamesMatson It looks like all you have to change is the Body => DefinitionBody and then AWS::ApiGateway::RestApi => AWS::Serverless::Api I am assuming that you are not modifying the API through other calls elsewhere. Updated answer with code block that should hopefully work for you. – J.A. Simmons V Sep 09 '19 at 03:14
  • Thank you so much. This worked! Visual Studio throws up errors about the serverless template since I changed the values, but if I deploy via AWS toolkit for Visual Studio, the API creates fine and api key required is set to true. I've been looking for this solution FOREVER, so thankyou kindly :) – JamesMatson Sep 09 '19 at 04:01
  • Glad to help. :) – J.A. Simmons V Sep 09 '19 at 04:06
  • Spoke to soon. I must have manually updated api key required = true via the console or something. I set them all to false and redeployed the api, and they're still all set to false :( Ah well. – JamesMatson Sep 09 '19 at 04:20
  • 1
    @JamesMatson I do not know if "ApiKeyRequired" is a ChangeSet triggering option or not. I would test it out by deploying it in a new stack to confirm if my solution is correct or not. It might just be where that specific option will not kick off the ChangeSet by itself. (I have had that happen to me so many times before with minor changes like this). Does Cloudformation [detect it as a drift](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-drift.html#drift-status-codes)? – J.A. Simmons V Sep 09 '19 at 04:41
  • I'll give that a shot J.A and see what happens - thanks again for the advice and apologies for continuing to hassle you, this has been the bane of my existence for ages now! – JamesMatson Sep 09 '19 at 04:46
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/199161/discussion-between-j-a-simmons-v-and-jamesmatson). – J.A. Simmons V Sep 09 '19 at 04:48