Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using an existing API key with the Serverless Framework in AWS

In the serverless.yml file you can specify the name of an API key to use with functions in the deployed API. You list the API key name(s), and then mark the methods you wish to secure with it as private. For example:

provider:
  name: aws
  runtime: nodejs4.3
  cfLogs: true
  apiKeys:
    - MyAPIKey

Upon deploy, the framework generates the API key and assigns it to the functions. It generates the key even if one with the same name already exists in the environment.

Is there a way to specify an existing API key, rather than have the framework generate it? We really wish to keep generating the key separate from deployments.

like image 777
Mark Meuer Avatar asked Nov 14 '16 19:11

Mark Meuer


1 Answers

I know this is old, but I've had this problem recently and solved it, so I thought I'd put what I found here.

This answer is based on this forum post, which required a bit of context for me to get working: https://forum.serverless.com/t/using-an-existing-api-key/770

Using the resources section it is possible to add custom CloudFormation configs into your deployment. This includes adding in a custom usage plan with specific api keys enabled:

https://serverless.com/framework/docs/providers/aws/guide/resources/

The structure is roughly as follows, with explanations below:

resources:
  Resources:
    MyServiceUsagePlan:
      Type: "AWS::ApiGateway::UsagePlan"
      DependsOn: ApiGatewayRestApi
      Properties:
        UsagePlanName: ${self:service}-${self:provider.stage}-usagePlan
        Quota:
          Limit: 10000
          Offset: 0
          Period: DAY
        Throttle:
          BurstLimit: 20
          RateLimit: 10
        ApiStages:
          -
            ApiId:
              Ref: ApiGatewayRestApi
            Stage: ${self:provider.stage}

    MyServiceKey:
      Type: "AWS::ApiGateway::UsagePlanKey"
      DependsOn: MyServiceUsagePlan
      Properties :
        KeyId: ${file(./conf/${self:provider.stage}.yml):MyServiceKeyId}
        KeyType: API_KEY
        UsagePlanId:
          Ref: MyServiceUsagePlan

Each of these Resources are named after the key you give them. Serverless gives you the name of the serverless-generated Resource names in case you wish to overwrite parts of them or reference them. You can name them pretty much anything, though, as long as it matches CloudFormation naming requirements.

Serverless does add a few variables, though:

  • DependsOn: This means that the resource with References are by name. The serverless doc link above lists the standard naming conventions that are used in case you want to reference non-custom resources. For example, "ApiGatewayRestApi" is the standard api created by serverless in all deployments with http events.
  • Ref: A reference to another object in the stack. In the above example, it replaces the need to explicitly pass an ApiId or UsagePlanId (which will be generated or retrieved on stack creation). This means you can set up dependencies on things within your stack without needing to record Ids.
  • Quota and Throttle: optional. Leaving these out will avoid updating a referenced usage plan.

Additionally, some behaviour about usage plans and usage plan keys:

  • Usage plans, once generated once, will retain their UsagePlanId between deployments, even if you change the name of the plan (via UsagePlanName). My testing is that UsagePlanKeys created outside of the serverless deployment won't be removed on update, but I haven't tested this extensively enough to be 100% sure.
  • Usage plans can be created outside the scope of an API deployment and referenced in using the UsagePlanId variable.

You may be interested in creating your auth structure outside of any one api deployment and using CloudFormation's (via Serverless) Outputs service to get the ARN and/or ID of each of the resources you've created:

http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html

Outputs uses the same format as Resources and an example can be seen in the example aws serverless.yml. This will allow you to change the usage plans independent of the apis themselves and maintain that separately. You can save those outputs for use by your apis, using a javascript variable reference to add only the plans that should be enabled on a per-stage, per-api basis.

tl;dr - Use the resources structure to make raw CloudFormation configs.

  • Resources gives you the ability to reference existing keys, plans, and other Resources.
  • Outputs lets you, among other things, receive and save the identifiers of objects you may want to use across deployments.
  • Updating objects won't remove associations (that I have been able to see) made outside of the stack, so it is safe to add outside keys to usage plan you create this way.
like image 162
apathyman Avatar answered Oct 17 '22 09:10

apathyman