Coder Social home page Coder Social logo

amplify-education / serverless-domain-manager Goto Github PK

View Code? Open in Web Editor NEW
928.0 37.0 226.0 2.06 MB

Serverless plugin for managing custom domains with API Gateways.

License: MIT License

JavaScript 3.20% TypeScript 96.80%
serverless certificate lambda amazon-certificate-manager api-gateway route53 cloudformation

serverless-domain-manager's Introduction

serverless-domain-manager

serverless npm version MIT licensed Codacy Badge npm downloads

Create custom domain names that your lambda can deploy to with serverless. Allows for base path mapping when deploying and deletion of domain names.

About Amplify

Amplify builds innovative and compelling digital educational products that empower teachers and students across the country. We have a long history as the leading innovator in K-12 education - and have been described as the best tech company in education and the best education company in tech. While others try to shrink the learning experience into the technology, we use technology to expand what is possible in real classrooms with real students and teachers.

Learn more at https://www.amplify.com

Getting Started

Prerequisites

Make sure you have the following installed before starting:

The IAM role that is deploying the lambda might need the following permissions:

acm:ListCertificates                   *
acm:DescribeCertificate                *
apigateway:AddCertificateToDomain      /domainnames*
apigateway:RemoveCertificateFromDomain /domainnames*
apigateway:GET                         /domainnames*, /apis*, /restapis*
apigateway:DELETE                      /domainnames*, /apis*, /restapis*
apigateway:POST                        /domainnames*, /apis*, /restapis*
apigateway:PATCH                       /domainnames*, /apis*, /restapis*
cloudformation:GET                     *
cloudformation:ListStacks              *
cloudformation:DescribeStacks          *
cloudfront:UpdateDistribution          *
route53:ListHostedZones                *
route53:ChangeResourceRecordSets       hostedzone/{HostedZoneId}
route53:GetHostedZone                  *
route53:ListResourceRecordSets         *
iam:CreateServiceLinkedRole            arn:aws:iam::${AWS::AccountId}: role/aws-service-role/ops.apigateway.amazonaws.com/AWSServiceRoleForAPIGateway
s3:ListBucket                          *
s3:GetObject                           *

CloudFormation

Alternatively you can generate an least privileged IAM Managed Policy for deployment with this:

deployment policy cloudformation template

Installing

# From npm (recommended)
npm install serverless-domain-manager --save-dev

Then make the following edits to your serverless.yaml file:

Add the plugin.

plugins:
  - serverless-domain-manager

Add the plugin configuration (example for serverless.foo.com/api). For a single domain and API type the following structure can be used.

custom:
  customDomain:
    domainName: serverless.foo.com
    stage: ci
    basePath: api
    certificateName: '*.foo.com'
    createRoute53Record: true
    createRoute53IPv6Record: true
    endpointType: REGIONAL
    securityPolicy: tls_1_2
    apiType: rest
    autoDomain: false

Multiple API types mapped to different domains can also be supported with the following structure. The key is the API Gateway API type.

custom:
  customDomain:
    rest:
      domainName: rest.serverless.foo.com
      stage: ci
      basePath: api
      certificateName: '*.foo.com'
      createRoute53Record: true
      createRoute53IPv6Record: true
      endpointType: REGIONAL
      securityPolicy: tls_1_2
    http:
      domainName: http.serverless.foo.com
      stage: ci
      basePath: api
      certificateName: '*.foo.com'
      createRoute53Record: true
      createRoute53IPv6Record: true
      endpointType: REGIONAL
      securityPolicy: tls_1_2
    websocket:
      domainName: ws.serverless.foo.com
      stage: ci
      basePath: api
      certificateName: '*.foo.com'
      createRoute53Record: true
      createRoute53IPv6Record: true
      endpointType: REGIONAL
      securityPolicy: tls_1_2

Or for multiple domains

custom:
  customDomains:
    - http:
        domainName: http-api-${opt:RANDOM_STRING}.${env:TEST_DOMAIN}
        basePath: ''
        endpointType: REGIONAL
    - http:
        domainName: http-api-${opt:RANDOM_STRING}.${env:TEST_DOMAIN}.foo
        basePath: ''
        endpointType: REGIONAL

For multi-region deployments, a route53Params structure can be used to support latency or weighted routing policies

custom:
  customDomain:
    domainName: serverless.foo.com
    stage: ci
    basePath: api
    certificateName: '*.foo.com'
    createRoute53Record: true
    endpointType: REGIONAL
    securityPolicy: tls_1_2
    route53Params:
      routingPolicy: latency
Parameter Name Default Value Description
domainName (Required) The domain name to be created in API Gateway and Route53 (if enabled) for this API.
basePath (none) The base path that will prepend all API endpoints.
stage Value of --stage, or provider.stage (serverless will default to dev if unset) The stage to create the domain name for. This parameter allows you to specify a different stage for the domain name than the stage specified for the serverless deployment.
certificateName Closest match The name of a specific certificate from Certificate Manager to use with this API. If not specified, the closest match will be used (i.e. for a given domain name api.example.com, a certificate for api.example.com will take precedence over a *.example.com certificate).

Note: Edge-optimized endpoints require that the certificate be located in us-east-1 to be used with the CloudFront distribution.
certificateArn (none) The arn of a specific certificate from Certificate Manager to use with this API.
createRoute53Record true Toggles whether or not the plugin will create A Alias and AAAA Alias records in Route53 mapping the domainName to the generated distribution domain name. If false, does not create a record.
createRoute53IPv6Record true Toggles whether or not the plugin will create an AAAA Alias record in Route53 mapping the domainName to the generated distribution domain name. If false, does not create a record.
route53Profile (none) Profile to use for accessing Route53 resources when Route53 records are in a different account
route53Region (none) Region to send Route53 services requests to (only applicable if also using route53Profile option)
endpointType EDGE Defines the endpoint type, accepts REGIONAL or EDGE.
apiType rest Defines the api type, accepts rest, http or websocket.
tlsTruststoreUri undefined An Amazon S3 url that specifies the truststore for mutual TLS authentication, for example s3://bucket-name/key-name. The truststore can contain certificates from public or private certificate authorities. Be aware mutual TLS is only available for regional APIs.
tlsTruststoreVersion undefined The version of the S3 object that contains your truststore. To specify a version, you must have versioning enabled for the S3 bucket.
hostedZoneId If hostedZoneId is set the route53 record set will be created in the matching zone, otherwise the hosted zone will be figured out from the domainName (hosted zone with matching domain).
hostedZonePrivate If hostedZonePrivate is set to true then only private hosted zones will be used for route 53 records. If it is set to false then only public hosted zones will be used for route53 records. Setting this parameter is specially useful if you have multiple hosted zones with the same domain name (e.g. a public and a private one). If records need to be set in both private and public hosted zones use splitHorizonDns parameter.
splitHorizonDns false When hostedZoneId and hostedZonePrivate are not set, setting this to true creates route53 records in both private and public hosted zones with matching domain.
enabled true Sometimes there are stages for which is not desired to have custom domain names. This flag allows the developer to disable the plugin for such cases. Accepts either boolean or string values and defaults to true for backwards compatibility.
securityPolicy tls_1_2 The security policy to apply to the custom domain name. Accepts tls_1_0 or tls_1_2
allowPathMatching false When updating an existing api mapping this will match on the basePath instead of the API ID to find existing mappings for an update.
autoDomain false Toggles whether or not the plugin will run create_domain/delete_domain as part of sls deploy/remove so that multiple commands are not required.
autoDomainWaitFor 120 How long to wait for create_domain to finish before starting deployment if domain does not exist immediately.
route53Params A set of options to customize Route 53 record creation. If left empty, A and AAAA records with simple routing will be created. If createRoute53Record is false, anything passed here will be ignored.
route53Params:
  routingPolicy
simple Defines the Route 53 routing policy, accepts simple, latency or weighted.
route53Params:
  weight
200 Sets the weight for weighted routing. Ignored for simple and latency routing.
route53Params:
  setIdentifier
A unique identifier for records in a set of Route 53 records with the same domain name. Only relevant for latency and weighted routing. Defaults to the regional endpoint if not provided.
route53Params:
  healthCheckId
An optional id for a Route 53 health check. If it is failing, Route 53 will stop routing to it. Only relevant for latency and weighted routing. If it is not provided, no health check will be associated with the record.
preserveExternalPathMappings false When autoDomain is set to true, and a deployment is removed, setting this to true checks for additional API Gateway base path mappings before automatically deleting the domain, and avoids doing so if they exist.

Running

To create the custom domain:

serverless create_domain

To deploy with the custom domain:

serverless deploy

To remove the created custom domain:

serverless delete_domain

How it works

Creating the custom domain takes advantage of Amazon's Certificate Manager to assign a certificate to the given domain name. Based on already created certificate names, the plugin will search for the certificate that resembles the custom domain's name the most and assign the ARN to that domain name. The plugin then creates the proper A Alias and AAAA Alias records for the domain through Route 53. Once the domain name is set it takes up to 40 minutes before it is initialized. After the certificate is initialized, sls deploy will create the base path mapping and assign the lambda to the custom domain name through CloudFront. All resources are created independent of CloudFormation. However, deploying will also output the domain name and distribution domain name to the CloudFormation stack outputs under the keys DomainName and DistributionDomainName, respectively.

Behavior Change in Version 3

In version 3, we decided to create/update/delete all resources through the API. Previously, only the basepath mapping was managed through CloudFormation. We moved away from creating anything through the stack for two reasons.

  1. It seemed cleaner to have all resources be created in the same fashion, rather than just having one created elsewhere. Since multiple CloudFormation stacks can't create the same custom domain, we decided to have everything be done through the API.

  2. We ran into issues such as #57 where the CloudFormation wasn't always being applied.

However, we still add the domain name and distribution domain name to the CloudFormation outputs, preserving the functionality requested in #43 implemented in #47.

Running Tests

To run unit tests:

npm test

To run integration tests, set an environment variable TEST_DOMAIN to the domain you will be testing for (i.e. example.com if creating a domain for api.example.com). And ROUTE53_PROFILE for creating route53 record in one AWS account and deploy in another. Then,

export TEST_DOMAIN=example.com
export ROUTE53_PROFILE=default
export TLS_TRUSTSTORE_URI=s3://bucket-name/key-name
export TLS_TRUSTSTORE_VERSION=default

npm run build
npm run integration-test

All tests should pass. All unit tests should pass before merging. Integration tests will take an extremely long time, as DNS records have to propogate for the resources created - therefore, integration tests will not be run on every commit.

If there is an error update the node_modules inside the serverless-domain-manager folder:

npm install

Writing Integration Tests

Unit tests are found in test/unit-tests. Integration tests are found in test/integration-tests. Each folder in tests/integration-tests contains the serverless-domain-manager configuration being tested. To create a new integration test, create a new folder for the handler.js and serverless.yml with the same naming convention and update deploy.test.ts or create a separate one with the test.ts ending.

Changing API Types

AWS API Gateway has three different API types: REST, HTTP, and WebSocket. Special steps need to be taken when migrating from one api type to another. A common migration will be from a REST API to an HTTP API given the potential cost savings. Below are the steps required to change from REST to HTTP. A similar process can be applied for other API type migrations.

REST to HTTP

  1. Confirm the Domain name is a Regional domain name. Edge domains are not supported by AWS for HTTP APIs. See this guide for migrating an edge-optimized custom domain name to regional.
  2. Wait for all DNS changes to take effect/propagate and ensure all traffic is being routed to the regional domain name before proceeding.
  3. Make sure you have setup new or modified existing routes to use httpApi event in your serverless.yml file.
  4. Make the following changes to the customDomain properties in the serverless.yml confg:
    endpointType: REGIONAL
    apiType: http
    allowPathMatching: true # Only for one deploy
  5. Run sls deploy
  6. Remove the allowPathMatching option, it should only be used once when migrating a base path from one API type to another.

NOTE: Always test this process in a lower level staging or development environment before performing it in production.

Known Issues

  • (5/23/2017) CloudFormation does not support changing the base path from empty to something or vice a versa. You must run sls remove to remove the base path mapping.
  • (1/17/2018) The create_domain command provided by this plugin does not currently update an existing Custom Domain's configuration. Instead, it only supports updating the Route 53 record pointing to the Custom Domain. For example, one must delete and recreate a Custom Domain to migrate it from regional to edge or vice versa, or to modify the certificate.
  • (8/22/2018) Creating a custom domain creates a CloudFront Distribution behind the scenes for fronting your API Gateway. This CloudFront Distribution is managed by AWS and cannot be viewed/managed by you. This is not a bug, but a quirk of how the Custom Domain feature works in API Gateway.
  • (2/12/2019) Users who upgraded from 2.x.x to version 3.0.4 (now unpublished) and then reverted back to 2.x.x will be unable to deploy because of a bug that will be fixed in 3.1.0. The workaround is to delete the basepath mapping manually, which will let them successfully revert back to 2.x.x.
  • (1/20/2022) Using route53Profile option requires having hosted zone for the domain in this profile and ACM certificate in the main profile (where functions are deployed).
  • (2/13/2024) ACM certificate must exist in the us-east-1 for the EDGE endpoint type. https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-edge-optimized-custom-domain-name.html

Responsible Disclosure

If you have any security issue to report, contact project maintainers privately. You can reach us at [email protected]

Contributing

We welcome pull requests! For your pull request to be accepted smoothly, we suggest that you:

  1. For any sizable change, first open a GitHub issue to discuss your idea.
  2. Create a pull request. Explain why you want to make the change and what it’s for. We’ll try to answer any PR’s promptly.

serverless-domain-manager's People

Contributors

alexfedin avatar aoskotsky-amplify avatar bryan-hunter avatar clintadams-sg avatar codyseibert avatar conradkurth avatar dariuscox avatar davidrosson avatar drexler avatar ethanherbertson avatar exocom avatar jconstance-amplify avatar jerep6 avatar jscattergood avatar lmorchard avatar majones-amplify avatar medikoo avatar mscharp avatar mscifo avatar raducoti avatar rddimon avatar revmischa avatar sampsasaarela avatar sidgonuts avatar spaideri avatar sromic avatar tehnrd avatar tomsaleeba avatar tylerhendrickson avatar wongjonathan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

serverless-domain-manager's Issues

Include custom domain in stack output

Hi, I just received an issue for my serverless-stack-output plugin to include the custom domain in the stack output. I think this is something you can easily add to the CloudFormation Outputs. My plugin takes all the stack output and writes it to a file or passes it to a function handler afterwards …

Domain is created in the wrong region

I have a serverless app that I am deploying to us-west-2. My ACM certificate is in us-east-1 like it should be.

However, when I run sls create-domain, it successfully makes the domain in us-east-1:

Serverless: 'api.example.app' was created/updated. New domains may take up to 40 minutes to be initialized.

When I run sls deploy, it fails since it cannot find the domain in us-west-2:

 Error --------------------------------------------------
 
  Error: Could not set up basepath mapping. Try running sls create_domain first.
Error: Error: 'api.example.app' could not be found in API Gateway.
NotFoundException: Invalid domain name identifier specified
 
     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.

Files

serverless.yml

# ...
custom:
   customDomain:
     domainName: api${self:provider.variables.apiDomainName}
     basePath: ''
     stage: ${self:provider.stage}
     createRoute53Record: true
# ...

Possible Solution?

Perhaps when the API Gateway object gets created, a region can be passed to it that is set from the custom section in the yml file?

this.apigateway = new AWS.APIGateway({ region: customRegion || 'us-east-1' });

Select specific hosted zone

Configuration option to set a specific Route53 hosted zone id.

Why:

  • in the company I work for we have two hosted zone ids with the same domain (one is public and the other is private)
  • because of the current hostedzoneid resolve strategy (#getHostedZoneId method) the DNS record set was being created in the "wrong hosted zone" (I had to create one in the public zone but it was being created in the private one)

Solution:

  • make the plugin accept a hostedZoneId configuration option
  • if the value is set use it, otherwise fallback to the current strategy

Example configuration:

plugins:
  - serverless-domain-manager
custom:
  customDomain:
    domainName: awesome-endpoint-${opt:stage}.mydomain.com
    basePath: ''
    stage: ${opt:stage}
    createRoute53Record: true
    certificateName: '*.mydomain.com'
    hostedZoneId: 1AM4N1D

PS: for my case I already forked the repo and implemented the proposed solution. It is currently being used in our production environment

No base path mapping is being set

Hello,

First, thanks for your great work on this! It makes a custom domain much easier.

I'm having a problem I can't figure out. No matter what I put into basePath and stage, no path mapping are showing in the API Gateway custom domain configuration in AWS (and so all requests to the custom domain get 403s).

My configuration is:

custom:
  customDomain:
    domainName: sub.domain.com
    certificateName: domain.com
    basePath: ''
    stage: production
    createRoute53Record: true

The custom domain and route53 dns record properly get made. The only thing is the "base path mappings" are totally blank. I tried putting anything into basePath, such as 'test', but still nothing. If I manually create it in AWS then everything works properly but obviously I don't want to have to do that.

I'm sorry if I'm missing something obvious and this isn't urgent. But let me know how I can help debug. And thanks again for sharing this with the community!

Serverless package should not require AWS credentials

As a Serverless developer, I want to run serverless package without specifying AWS credentials, so I don't have to configure my cloud secrets in my build system, which is independent from my deployment system.

Since serverless create_domain is a separate step, creating the domain can be easily separated from creating and deploying the package. In our case, we created the domain once manually, and our CI system runs only serverless package to build and test the package, before our CD system installs it with serverless deploy. The serverless package step has nothing to do with our cloud infrastructure, so it should not need credentials to access it. It was working fine with serverless-domain-manager up until to version 1.1.18, but from 1.1.19 even the serverless package step requires AWS credentials, otherwise the getDomain call fails, and the "Cannot find specified domain name..." error is displayed.

Thank you for creating and maintaining this package.

Support for wildcard certificates

Even though I have a wildcard cert in ACM, it seems that this will not attempt to use it when available. Simply gives the generic error Error: Could not find the certificate sub.yourdomain.com sub.yourdomain.com was not created in API Gateway. even though I have a *.yourdomain.com active in ACM.

Cannot find AWS::ApiGateway::Deployment Try running sls create_domain first

I have multiple serverless projects - one dedicated to setting up infrastucture with others addressing various services.

The infrastructure project is responsible for creating a custom domain with the following config:

  customDomain:
    domainName: ${file(./serverless.env.yml):${self:custom.stage}.API_DOMAIN}
    stage: ${self:custom.stage}
    certificateName: ${file(./serverless.env.yml):${self:custom.stage}.ACM_CERTIFICATE_NAME}
    createRoute53Record: true

After running sls create_domain --stage staging the custom domain is created fine.

But when I then try to deploy the project (which creates some lambdas along with a number of CloudFormation resources) I'm getting the following error:

Error --------------------------------------------------

  Error: Cannot find AWS::ApiGateway::Deployment Try running sls create_domain first.

     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.

  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Forums:        forum.serverless.com
     Chat:          gitter.im/serverless/serverless

  Your Environment Information -----------------------------
     OS:                     darwin
     Node Version:           7.10.1
     Serverless Version:     1.23.0

Any ideas?

Version number bump should not be part of pull request

I submitted a new pull request yesterday #25 and PR merge job is failing because I did not bump the version number.

I don't think the version number bump should be part of the PR since there is no way to synchronise version numbers across pull requests. For example now there is one open PR which has bumped version number so should I assume that PR is merged before mine. What if that or my pull request gets discarded?

Please consider maintaining version numbers your self as part of your release process.

BadRequestException: The domain name you provided is already associated with an existing CloudFront distribution.

lorzwingzero:~/workspace $ SLS_DEBUG=* serverless create_domain                                                                                                                                                                   
Serverless: Load command run
Serverless: Load command config
Serverless: Load command config:credentials
Serverless: Load command create
Serverless: Load command install
Serverless: Load command package
Serverless: Load command deploy
Serverless: Load command deploy:function
Serverless: Load command deploy:list
Serverless: Load command deploy:list:functions
Serverless: Load command invoke
Serverless: Load command invoke:local
Serverless: Load command info
Serverless: Load command logs
Serverless: Load command login
Serverless: Load command logout
Serverless: Load command metrics
Serverless: Load command print
Serverless: Load command remove
Serverless: Load command rollback
Serverless: Load command rollback:function
Serverless: Load command slstats
Serverless: Load command plugin
Serverless: Load command plugin
Serverless: Load command plugin:install
Serverless: Load command plugin
Serverless: Load command plugin:uninstall
Serverless: Load command plugin
Serverless: Load command plugin:list
Serverless: Load command plugin
Serverless: Load command plugin:search
Serverless: Load command emit
Serverless: Load command config
Serverless: Load command config:credentials
Serverless: Load command rollback
Serverless: Load command rollback:function
Serverless: Load command create_domain
Serverless: Load command delete_domain
Serverless: Invoke create_domain
 
  Error --------------------------------------------------
 
  BadRequestException: The domain name you provided is already associated with an existing CloudFront distribution. 
Remove the domain name from the existing CloudFront distribution or use a different domain name. 
If you own this domain name and are not using it on an existing CloudFront distribution, please contact support. redditapi.XXXXXX.com was not created in API Gateway.
 
     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.
 
  Stack Trace --------------------------------------------
 
Error: BadRequestException: The domain name you provided is already associated with an existing CloudFront distribution. 
Remove the domain name from the existing CloudFront distribution or use a different domain name. 
If you own this domain name and are not using it on an existing CloudFront distribution, please contact support. redditapi.XXXXXX.com was not created in API Gateway.
    at createDomainName.catch (/home/ubuntu/workspace/node_modules/serverless-domain-manager/index.js:59:15)
    at <anonymous>
    at process._tickDomainCallback (internal/process/next_tick.js:228:7)
From previous event:
    at PluginManager.invoke (/home/ubuntu/workspace/node_modules/serverless/lib/classes/PluginManager.js:366:22)
    at PluginManager.run (/home/ubuntu/workspace/node_modules/serverless/lib/classes/PluginManager.js:397:17)
    at variables.populateService.then (/home/ubuntu/workspace/node_modules/serverless/lib/Serverless.js:104:33)
    at runCallback (timers.js:800:20)
    at tryOnImmediate (timers.js:762:5)
    at processImmediate [as _immediateCallback] (timers.js:733:5)
From previous event:
    at Serverless.run (/home/ubuntu/workspace/node_modules/serverless/lib/Serverless.js:91:74)
    at serverless.init.then (/home/ubuntu/workspace/node_modules/serverless/bin/serverless:42:50)
    at <anonymous>
 
  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Forums:        forum.serverless.com
     Chat:          gitter.im/serverless/serverless
 
  Your Environment Information -----------------------------
     OS:                     linux
     Node Version:           9.2.0
     Serverless Version:     1.24.1
 
lorzwingzero:~/workspace $ aws --region=us-east-1 apigateway get-domain-names
{
    "items": []
}

image

My AWS User has AdministratorAccess policy.

Versions from package.json

    "serverless": "^1.24.1",
    "serverless-domain-manager": "^1.1.20"

Serverless config

custom:
  customDomain:
    domainName: redditapi.XXXXXX.com
    basePath: 'reddit'
    certificateName: 'XXXXXX.com'
    stage: 'prod'
    createRoute53Record: true

It's true that "XXXXXXX.com" A record is an ALIAS to a cloudfront service. But I don't see why that matters as I can do all this manually through the AWS console.

Better parameter descriptions

We should make a table with descriptions of each parameter and default values. Its not very clear in the readme which ones are optional and what they are used for.

Certificate is in use (after sls delete_domain)

I need to create a new SLS Cert (to add a subdomain) but sls delete_domain doesn't seem to remove all required entries:

E.g., I'm getting the following error when trying to remove the cert (NOTE, before sls delete_domain, I was getting 2 errors, so something definitely DID happen).

Certificate is in use
The certificate XXX.com (XXX) is in use (associated with other AWS resources) and cannot be deleted. Disassociate the certificate from each resource in the list and try again.

Associated resources
arn:aws:cloudfront:XXX

Don't fail if domain already exists.

The sls create_domain command will fail if the custom domain already exists. We could make it handle this better and continue to the next steps like creating Route53 records if the domain already exists.

domainName fails if in quotes.

It's pretty normal in yml files to quote strings, but the following fails.

  customDomain:
    domainName: "www.example.com"

with:

Error: Cannot find specified domain name www.example.com. Domain manager summary logging failed.

Ouch (this was hard to find) ;).

Unresolved resource dependencies [ApiGatewayRestApi] error

Hi,

I am getting the following error while trying to provision a custom domain using the plugin.

Template format error: Unresolved resource dependencies [ApiGatewayRestApi] in the Resources block of the template

Let me state at the beginning though that I faced this issue with shared-api branch of the serverless framework and not with the master release. So I can understand if you guys don't want to have a look at this right now and I will try to use the AWS CLI instead.

However, I would appreciate any thoughts or suggestions in the interim. I have added the stack trace and yaml files in the below thread.

serverless/serverless#3934 (comment)

Error 403 after changing to a domain

Hi,

I was able to create the domain, certificate and deploy everything.
But now when I try to call the new url from the application I get a HTTP 403 error.
It was working before without the custom domain.

I'm using aws_iam as the authorizer.

And if I use the api gateway url it works again.

Any guesses what could be the problem?

Thanks!

Missing permission in docs: POST to basepathmappings

I found that my deployment user needs permission to execute apigateway:POST to /domainnames/*/basepathmappings.

CloudFormation (I've tested something specific to my environment, but roughly equivalent to this):

- Effect: Allow
  Action:
    - apigateway:POST
  Resource: !Sub arn:aws:apigateway:${AWS::Region}::/domainnames/*/basepathmappings

Domain exists and doesn't exist at the same time

I'm having some trouble setting up a new domain. I'm just following the example in the docs but it doesn't seem to work:

$ serverless create_domain
  Error: Record set for my.domain already exists. my.domain was not created.
$ serverless delete_domain
  Error: Record set for my.domain does not exist and cannot be deleted. my.domain was not deleted.
$ serverless create_domain
  BadRequestException: The domain name you provided is already associated with an existing CloudFront distribution. 
Remove the domain name from the existing CloudFront distribution or use a different domain name. 
If you own this domain name and are not using it on an existing CloudFront distribution, please contact support. my.domain was not created.
$ aws cloudfront --region us-east-1 list-distributions
<nothing>

My serverless.yml is pretty much the 'hello world' example, with this in the custom section:

custom:
  customDomain:
    domainName: my.domain
    basePath: ''
    stage: ${self:provider.stage}
    createRoute53Record: true

I haven't used the domain before now so it can't be in use. I can sls deploy and everything seems to work:

...
Serverless Domain Manager Summary
Domain Name
  my.domain
Distribution Domain Name
  xxx.cloudfront.net

But I can't connect to the domain because I get a not-found error (which is because the domain isn't listed in Route53.)

Any ideas what's gone wrong?

Could not find hosted zone

I verified vdesaiaws.net is present in Route53 domain.

C:\Vishal\autodomainapimapping>sls create_domain
Serverless: 'vdesaiaws.net' was created/updated. New domains may take up to 40 minutes to be initialized.

Error --------------------------------------------------

Error: 'vdesaiaws.net' was not created in Route53.
Error: Error: Could not find hosted zone 'net'

Multiple domain support

Would you be interested in a pull request that adds support for multiple domains (per stage).

That is I would like www.example.com and example.com to point to the same aws lambda.

Unless this is already possible?

Add support for multiple domain names

For example, to create one sub-domain per stage:

custom:
  customDomain:
    - domainName: dev.example.com
      basePath: ''
      stage: dev
      createRoute53Record: true
    - domainName: qa.example.com
      basePath: ''
      stage: qa
      createRoute53Record: true

Testing if sls create_domain worked

How do you know if sls create_domain worked? I understand it takes 40mins, but what has actually changed on the AWS dashboard? (e.g., either the API Gateway or Route 53)?

Feature Request: Allow multiple services to use the same basePath

I'd like to allow multiple services to use the same basePath.

For example I would like all my services to be versioned. So all services that are v1 would share the v1 prefix. All that were v2 would have the v2 prefix, and so on. Then I would like to specify the service they want to access. Eg domain.com/v1/someServiceName. I would prefer not to use subdomains to solve the problem.

For example instead of domain.com/houses and domain.com/cars, I would like domain.com/v2/houses and domain.com/v2/cars. Users could also access the older versions of the service code. Eg domain.com/v1/houses.

If I set the basePath for two services to the same thing (ex v2) then the second deployment will overwrite the first, or the second deployment attempt will give me the 'base path already exists for this domain name' error. I've also read through the docs and didn't find anything that worked.

Either way, thanks for the awesome plugin!

Does not support HTTP proxy

serverless-domain-manager does not support using it behind eg. a corporate firewall over an HTTP proxy by ignoring http_proxy and/or HTTPS_PROXY environment variables.

It would automatically pick them up, if the AWS resources inside the plugin would be acquired through the serverless object instead of recreating them from scratch. I believe this would also make some code in the plugin obsolete that handles updating the user's credentials.

The following patch adds HTTP proxy functionality by inheriting it from serverless:

--- a/index.js
+++ b/index.js
@@ -1,6 +1,6 @@
 'use strict';

-const AWS = require('aws-sdk');
+// const AWS = require('aws-sdk');
 const chalk = require('chalk');
 const DomainResponse = require('./DomainResponse');

@@ -48,9 +48,8 @@ class ServerlessCustomDomain {
     if (!this.initialized) {
       // Sets the credentials for AWS resources.
       const awsCreds = this.serverless.providers.aws.getCredentials();
-      AWS.config.update(awsCreds);
-      this.apigateway = new AWS.APIGateway();
-      this.route53 = new AWS.Route53();
+      this.apigateway = new this.serverless.providers.aws.sdk.APIGateway();
+      this.route53 = new this.serverless.providers.aws.sdk.Route53();
       this.setGivenDomainName(this.serverless.service.custom.customDomain.domainName);
       this.setEndpointType(this.serverless.service.custom.customDomain.endpointType);
       this.setAcmRegion();
@@ -285,7 +284,7 @@ class ServerlessCustomDomain {
    * Obtains the certification arn
    */
   getCertArn() {
-    const acm = new AWS.ACM({
+    const acm = new this.serverless.providers.aws.sdk.ACM({
       region: this.acmRegion,
     });

I am not a user of this plugin, so please review carefully:)

Feature request: create domain in Route 53; provision and validate ACM certs

This is me wondering aloud whether the following could be possible. (It would be pretty slick if so.)

If I'm going to create a domain in Route 53 for use with API Gateway, and I need an ACM cert to accomplish the process, could this plugin:

  1. Create the DNS record (whether A or CNAME or ALIAS or whatever) in Route 53; and
  2. Create the cert; and
  3. Validate the cert with DNS validation (i.e. add the needed CNAME to complete validation); and
  4. Then do the rest of the awesomeness it already does

?

If so, this would remove the only two manual steps in the process of configuring a custom domain. I'm not sure this would work for every use case - for instance, once the record type is changed in #70, I'm not sure this will work for zone apex records, since (if I understand correctly) they may take longer to provision than CNAME records for subdomains. But it's pretty slick for automated configuration of subdomains.

The details of DNS is not my strongest area, so I'm sure I'm overlooking things here. Wanted to float the idea and see what y'all thought. Thanks for reading!

devDependencies

Hello!

Is there any reason serverless-domain-manager should be installed without --save-dev? When I installed it according to the README it increased my deployment bundle by 5+ Mb, though I believe the plugin is used strictly w/ the CLI, not during execution of my function, correct?

Could not find the certificate

Hi,

Your plugin is looking great, but I can't use it...
I have a wildcard certificate for my doamin
*.mydomain.com - i used the tag name to named it (mydomaincom) .
I used this configuration:

custom:
stage: ${opt:stage, self:provider.stage}
domains:
prod: service.mydomain.com
dev: devService.cryptovan.io

customDomain:
basePath: "api"
domainName: ${self:custom.domains.${self:custom.stage}}
certificateName: mydomaincom
stage: "${self:custom.stage}"
createRoute53Record: true

And i'm keep getting the error:
Error: Could not find the certificate mydomaincom

I don't think it a premisions problem (i set AdministratorAccess and AWSCertificateManagerReadOnly)

Thanks

Does not seem to work with Java-based projects

Just tried the plugin with the default project layout created by sls create --template aws-java-maven and it does not seem to work:

  • ACM cert was properly created (manually).
  • create_domain successfully manages to create the entry in both Route 53 and API Gateway, where I also manually confirmed ACM cert was properly bound after 20' or so.
  • deploy produces:
Serverless: Packaging service...
  Error --------------------------------------------------
  Error: Could not set up basepath mapping. Try running sls create_domain first.
Error: Cannot find AWS::ApiGateway::Deployment

Trying to debug a little further, the problem seems to be in getDeploymentId where it iterates over the keys of compiledCloudFormationTemplate.Resources looking for AWS::ApiGateway::Deployment (and it can't find any). Some extra debug output in getDeploymentId:

console.log("cloudTemplate=", cloudTemplate);
console.log("cloudTemplate keys=", Object.keys(cloudTemplate.Resources));

=>

cloudTemplate= { AWSTemplateFormatVersion: '2010-09-09',
  Description: 'The AWS CloudFormation template for this Serverless application',
  Resources:
   { ServerlessDeploymentBucket: { Type: 'AWS::S3::Bucket', Properties: [Object] },
     HelloLogGroup: { Type: 'AWS::Logs::LogGroup', Properties: [Object] },
     IamRoleLambdaExecution: { Type: 'AWS::IAM::Role', Properties: [Object] },
     HelloLambdaFunction:
      { Type: 'AWS::Lambda::Function',
        Properties: [Object],
        DependsOn: [Object] } },
  Outputs: { ServerlessDeploymentBucketName: { Value: [Object] } } }

cloudTemplate keys= [ 'ServerlessDeploymentBucket',
  'HelloLogGroup',
  'IamRoleLambdaExecution',
  'HelloLambdaFunction' ]

Is this a known issue or I am doing something wrong here?

Missing CloudFront Distribution/Missing Authentication Token Issue

For context, I'm currently following this tutorial on setting up API Gateway with custom domains: https://serverless.com/blog/serverless-api-gateway-domain/

I got to the following step: sls create_domain
But for some reason, the CloudFront distribution isn't showing up under the CloudFront Management Console. However, when I curl the distribution or do an nslookup, it's present and responding back.

It looks like everything was mapped correctly through API Gateway and through Route53 (which shows the new custom domain and the CloudFront distribution, ironically), however, when I try to hit the new endpoint with my newly hosted custom domain, I get the following error message:

{
    "message": "Missing Authentication Token"
}

I don't have any authentication tokens or any authentication set on my endpoint on API Gateway, so I'm not sure what I'm missing and why the CloudFront distribution isn't showing up in CloudFront. Any ideas/feedback?

Edit: If it makes a difference, I've waited over two hours after running sls create_domain.

Thank you!

Great plugin

Just a shout out of the great work you have done here 👏

use domain manager without route 53

it would be cool of you can use the domain manager WITHOUT ROUTE 53

we own our own domain and dont want to move DNS onto amazon

when i try to use the plugin its just failing because the route 53 is failing to lookup domains

possible option to SKIP the route 53 stuff/code ?

How to specify a blank basepath across multiple services (serverless.yml files)?

First off, thank you for building this module - it makes life a lot easier.

I have my api broken up into individually deployable services, each with its own serverless.yml. In my users service, for example, I setup the serverless-domain-manager plugin and everything works great (I am able to POST to api.mydomain.com/users, for example).

The relevant code looks like so:

customDomain: domainName: ${self:custom.domains.${self:custom.stage}} basePath: '' stage: ${self:custom.stage} certificateName: "*.mydomain.com" createRoute53Record: false

and

functions: post: handler: functions/users.post events: - http: path: users method: POST private: true

The problem is that when I go to my next service (separate directory, separate serverless.yml) ,and setup the customDomain section (which looks exactly like the above from users service), and then sls deploy, I get an error that the basePath is already in use (I would like to be able to GET to api.mydomain.com/profiles, for example).

So I tried removing the basePath from my second service and that gave me "Error: Could not set up basepath mapping. Try running sls create_domain first." upon sls deploy.

What I would like to be able to do is use the same basepath ("") in all services, but have the http path for the individual functions to be dynamic. I have read elsewhere that in order to do this, I would need to specify different basePaths in each serverless.yml ("users" and "profiles" in the case of my example above), but then that leaves me with routes like /users/users or /profiles/profiles, which are not what I want....unless the events-http-path can be set to "/", which is not something I have attempted yet.

Any advice would be greatly appreciated.

Can't delete or create domain?

I'm getting the error on sls create_domain

Error --------------------------------------------------

Error: Record set for mydomain.com already exists. mydomain.com was not created.

I get another error when I try sls delete_domain

Error --------------------------------------------------

Error: Record set for mydomain.com does not exist and cannot be deleted. mydomain.com was not deleted.

So is it created or not created?? I am so confused by these error messages.

How does this preserve cloudformation state across deploys?

I've looked at your code and there is something that is confusing me.

You've created a command that will allow you to setup a new domain. Effectively, this is dynamically altering the compiled cloudformation template to create new route53 recordsets among other things. This logic is only run on serverless create_domain, and it is not run on serverless deploy (based on your code).

At the end of the day, the original serverless.yml file is still the same (except for some configuration parameters). And, on a serverless deploy, there doesn't seem to be anything that is somehow reconstructing your modifications to the cloudformation template that were made when running serverless create_domain.

So, my question is how is it possible that if you do a serverless deploy, the dynamic (and non-persisting?) changes to the cloudformation template are somehow "remembered"? If they were not, then a serverless deploy would result in the recordsets etc. being removed again, because the "new" cloudformation template would not have them, while the uploaded cloudformation stack on AWS would.

Or is this what setupBasePathMapping is doing? This seems unlikely, because it does not re-create all resources, e.g. the route53 recordsets are not added to the cloudformation template here.

I hope my case is clear. I'm looking into creating a similar plugin for the automatic requesting of certificates and would like to learn from this plugin, so any help is much appreciated.

impact of stage parameter

Sorry for posting a question here - not sure where else to ask it.

Can you clarify what impact the stage parameter has? clear it doesn't influence the domain name or url in any way.

If I have a different subdomain for each stage (dev.api.domain.name, prod.api.domain.name) should i just add multiple customDomain sections?

When I run sls create-domain will it only create for the stage I've specified?

Thanks :-)

Could not find hosted zone 'email'

Hi there,

Trying to set up a domain with the TLD .email and am having issues.

Have tried creating a Route53 hosted zone manually through the AWS console, but still get the same result. Would appreciate any help.

  Error --------------------------------------------------
 
  Error: 'mydomain.email' was not created in Route53.
Error: Error: Could not find hosted zone 'email'
 
     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.
 
  Stack Trace --------------------------------------------
 
Error: Error: 'mydomain.email' was not created in Route53.
Error: Error: Could not find hosted zone 'email'
    at changeResourceRecordSet.catch (/home/sam/emailapp/node_modules/serverless-domain-manager/index.js:63:17)
    at <anonymous>
    at process._tickDomainCallback (internal/process/next_tick.js:228:7)

Error when creating domain: could not find Route53 hosted zone

I'm trying to create a custom domain which uses a wildcard certificate in ACM. However, everytime I run serverless create_domain I get the following error message:

Serverless: dev-api.mycompany.io was created/updated. New domains may take up to 40 minutes to be initialized.
(node:19556) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Error: Error: Could not find hosted zone. Unable to retrieve Route53 hosted zone id. dev-api.mycompany.io was not created in Route53.

Below is my serverless yaml configuration for the custom domain (company name redacted):

customDomain:
    basePath: "mypath"
    domainName: dev-api.mycompany.io
    stage: dev
    certificateName: "*.mycompany.io"
    createRoute53Record: true

I've also tried running serverless delete_domain, which also gives me the same error about not being able to find the Route53 hosted zone id.

Can anyone shed some light on this?

Could not find the certificate

Running sls create_domain fails with:

Error: Could not find the certificate api.example.com api.example.com was not created.

I also tried providing the certificate ARN in the certificateName field, no luck.

Could you give me some guidance?

can't seem to get severless-domain-manager working.

I am following this guide here https://serverless.com/blog/serverless-api-gateway-domain/ to set up a custom domain name for Lambda & API Gateway.

I get the following error

Serverless: ‘api_mydomain_com’ was created/updated. New domains may take up to 40 minutes to be initialized.

Error --------------------------------------------------

Error: ‘api_mydomain_com’ was not created in Route53.
MissingRequiredParameter: Missing required key ‘Value’ in params.ChangeBatch.Changes[0].ResourceRecordSet.ResourceRecords[0]

I have an issued certificate with aws certificate manager for my domain

Thanks

pathmapping - Invalid stage identifier specified.

Hi, at first thanks for this plugin. It solves many problems I else had. But I sometimes run into an issue:

Serverless: Operation failed!

  Serverless Error ---------------------------------------

  An error occurred: pathmapping - Invalid stage identifier specified.

  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Forums:        forum.serverless.com
     Chat:          gitter.im/serverless/serverless

  Your Environment Information -----------------------------
     OS:                     darwin
     Node Version:           8.9.1
     Serverless Version:     1.24.1

It seems as if there's a dependency with the stage missing when it tries to create the base-path mapping, eg. a race condition probably.

Running with custom domain code commented out once and than again with everything configured as before, everything works fine.

I have to say, that I also use serverless-plugin-stage-variables as plugin. Perhaps this breaks it. I'm new into serverless and could help by providing more input, but I'm not sure, where to look further.

Any clues?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.