Skip to content

Commit

Permalink
Add Crosswalk API Gateway multi-language examples (#1122)
Browse files Browse the repository at this point in the history
* Draft TS API Gateway example

* Fix up example from testing

* First draft of python API gateway example

* Fix a bunch of python issues

* Fix provider errors

* Draft API Gateway Go example

* Fix bugs found in testing

* Add testing of Cognito token

* Implement Cognito testing

* Fix line break

* Fix lint errors

* Spike pure Go example

* Fix go handler setup

* Add copyright notices

* Move go lambdas into own file

- Remove unused TS import

* Remove lambdas suffix

* Draft API Key examples

* Outline swagger route

- Need to create lambda permission but depends on pulumi/pulumi-aws-apigateway#12

* Tidy up API Key examples

* Simplify swagger route example

- Remove need for manual lambda permission.

* Fix comments

* Add full-api swagger examples

* Enable Typescript API Key example

- Tested again pre-release of package.

* Add TS custom domain

* Draft Python and Go DNS setup

* Final tweaks & formatting in line with docs changes

- Add DNS testing to all READMEs

* Fix TS lint errors

* Upgrade to aws-apigateway v0.0.5

- Re-tested all examples work with fixed provider version.
- Fix missing regional provider in python DNS setup.
- Fix Go zone lookup and applies.
  • Loading branch information
danielrbradley committed Dec 9, 2021
1 parent a24d02f commit 5b1b42e
Show file tree
Hide file tree
Showing 31 changed files with 1,897 additions and 0 deletions.
9 changes: 9 additions & 0 deletions aws-apigateway-go-routes/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
all: build_authorizer build_handler

build_authorizer:
GOOS=linux GOARCH=amd64 go build -o ./bin/authorizer ./authorizer/handler.go
zip -j ./bin/authorizer.zip ./bin/authorizer

build_handler:
GOOS=linux GOARCH=amd64 go build -o ./bin/handler ./handler/handler.go
zip -j ./bin/handler.zip ./bin/handler
8 changes: 8 additions & 0 deletions aws-apigateway-go-routes/Pulumi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name: aws-apigateway-go-routes
runtime: go
description: Demonstration of API Gateway routes
template:
config:
aws:region:
description: The AWS region to deploy into
default: us-east-2
178 changes: 178 additions & 0 deletions aws-apigateway-go-routes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
[![Deploy](https://get.pulumi.com/new/button.svg)](https://app.pulumi.com/new)

# Routes in API Gateway

This example create an API Gateway which responds to requests using different sources:

1. Static files from a directory
2. Lambda Function
3. HTTP Proxy

When you're finished, you'll be familiar with how to configure routes in API Gateway using the RestAPI.

## Prerequisites

1. [Install Pulumi](https://www.pulumi.com/docs/get-started/install/)
2. [Configure AWS Credentials](https://www.pulumi.com/docs/intro/cloud-providers/aws/setup/)
3. [Install Go](https://www.pulumi.com/docs/intro/languages/go/)

## Deploy the App

### Step 1: Create a directory and cd into it

For Pulumi examples, we typically start by creating a directory and changing into it. Then, we create a new Pulumi project from a template. For example, `azure-javascript`.

1. Install prerequisites:

```bash
go install
```

2. Make Lambda handlers:

```bash
make
```

3. Create a new Pulumi stack:

```bash
pulumi stack init
```

4. Configure the AWS region to deploy into:

```bash
pulumi config set aws:region us-east-2
```

5. Deploy the Pulumi stack:

```bash
pulumi up
```

### Step 2: Test your API

Use the example CURL commands to test the API responses.

```bash
$ curl -w '\n' "$(pulumi stack output url)static"
<h1>Hello Pulumi!</h1>

$ curl -w '\n' "$(pulumi stack output url)lambda"
Hello, API Gateway!

$ python3 -m webbrowser "$(pulumi stack output url)proxy"
# Opens a page looking like Google in your browser

$ curl -w '\n' "$(pulumi stack output url)swagger"
{
"uuid": ...
}

$ curl -w '\n' -H "Authorization: HEADER.PAYLOAD.SIGNATURE" "$(pulumi stack output url)cognito-authorized"
{"message":"Unauthorized"}

$ curl -w '\n' -H "Authorization: goodToken" "$(pulumi stack output url)lambda-authorized"
Hello, API Gateway!

$ curl -w '\n' -H "Authorization: badToken" "$(pulumi stack output url)lambda-authorized"
{"message": "404 Not found" }

$ curl -w '\n' "$(pulumi stack output url)lambda-authorized" # No token
{"message":"Unauthorized"}

$ curl -w '\n' "$(pulumi stack output swagger-url)"
{
"uuid": ...
}

$ curl -w '\n' -H "x-api-key: $(pulumi stack output apiKeyValue --show-secrets)" "$(pulumi stack output url)key-authorized"
Hello, API Gateway!
```

Testing a valid Cognito token is a little more involved.

1. Create a random password

```bash
PASSWORD=$(curl -s https://www.passwordrandom.com/query?command=password&scheme=Llnn%23rrrrrrrrrr)
```

2. Create a user

```bash
aws cognito-idp sign-up --region $(pulumi config get aws:region) --client-id $(pulumi stack output user-pool-client-id) --username "[email protected]" --password "$PASSWORD"
```

3. Confirm the user's account

```bash
aws cognito-idp admin-confirm-sign-up --region $(pulumi config get aws:region) --user-pool-id $(pulumi stack output user-pool-id) --username "[email protected]"
```

4. Authenticate to create a new session:

```bash
TOKEN=$(aws cognito-idp admin-initiate-auth --region $(pulumi config get aws:region) --user-pool-id $(pulumi stack output user-pool-id) --client-id $(pulumi stack output user-pool-client-id) --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters "{\"USERNAME\":\"[email protected]\",\"PASSWORD\":\"$PASSWORD\"}")
```

5. Perform authenticated request

```bash
$ curl -w '\n' -H "Authorization: $(echo $TOKEN | jq '.AuthenticationResult.IdToken' -r)" "$(pulumi stack output url)cognito-authorized"
Hello, API Gateway!
```

Fetch and review the logs from the Lambda executions:

```bash
pulumi logs
```

### Set Up Custom DNS

Before you can set up a custom domain you must [register a domain name with Route 53](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/registrar.html).

Configure the stack with your custom DNS information:

```bash
pulumi config set domain subdomain.acmecorp.example
pulumi config set dns-zone acmecorp.example
```

Deploy your stack:

```bash
$ pulumi up
...
Type Name Plan
pulumi:pulumi:Stack aws-apigateway-ts-routes-dev
+ ├─ pulumi:providers:aws usEast1 create
+ ├─ aws:acm:Certificate ssl-cert create
+ ├─ aws:route53:Record ssl-cert-validation-dns-record create
+ ├─ aws:acm:CertificateValidation ssl-cert-validation create
+ ├─ aws:apigateway:DomainName api-domain-name create
+ ├─ aws:route53:Record api-dns create
+ └─ aws:apigateway:BasePathMapping api-domain-mapping create
```

Test your API is now available on your custom domain:

```bash
curl -w '\n' "$(pulumi stack output customUrl)static"
```

## Clean Up

Once you're finished experimenting, you can destroy your stack and remove it to avoid incurring any additional cost:

```bash
pulumi destroy
pulumi stack rm
```

## Summary

In this tutorial, you deployed an API with different route configurations. Now you can use these patterns to build real APIs which connect to other services.
33 changes: 33 additions & 0 deletions aws-apigateway-go-routes/authorizer/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2016-2021, Pulumi Corporation.
package main

import (
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)

func handler(request events.APIGatewayCustomAuthorizerRequestTypeRequest) (events.APIGatewayCustomAuthorizerResponse, error) {
var effect string
if request.Headers["Authorization"] == "goodToken" {
effect = "Allow"
} else {
effect = "Deny"
}
return events.APIGatewayCustomAuthorizerResponse{
PrincipalID: "my-user",
PolicyDocument: events.APIGatewayCustomAuthorizerPolicy{
Version: "2012-10-17",
Statement: []events.IAMPolicyStatement{
{
Action: []string{"execute-api:Invoke"},
Effect: effect,
Resource: []string{request.MethodArn},
},
},
},
}, nil
}

func main() {
lambda.Start(handler)
}
95 changes: 95 additions & 0 deletions aws-apigateway-go-routes/dns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright 2016-2021, Pulumi Corporation.
package main

import (
"github.com/pulumi/pulumi-aws/sdk/v4/go/aws"
"github.com/pulumi/pulumi-aws/sdk/v4/go/aws/acm"
"github.com/pulumi/pulumi-aws/sdk/v4/go/aws/apigateway"
"github.com/pulumi/pulumi-aws/sdk/v4/go/aws/route53"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func configureDns(ctx *pulumi.Context, domain string, zoneId string) (*apigateway.DomainName, error) {
// SSL Cert must be created in us-east-1 unrelated to where the API is deployed.
awsUsEast1, err := aws.NewProvider(ctx, "aws-provider-us-east-1", &aws.ProviderArgs{Region: pulumi.String("us-east-1")})
if err != nil {
return nil, err
}
// Request ACM certificate
sslCertificate, err := acm.NewCertificate(ctx,
"ssl-cert",
&acm.CertificateArgs{
DomainName: pulumi.String(domain),
ValidationMethod: pulumi.String("DNS"),
},
pulumi.Provider(awsUsEast1),
)
if err != nil {
return nil, err
}
domainValidationOption := sslCertificate.DomainValidationOptions.ApplyT(func(options []acm.CertificateDomainValidationOption) interface{} {
return options[0]
})
// Create DNS record to prove to ACM that we own the domain
sslCertificateValidationDnsRecord, err := route53.NewRecord(ctx,
"ssl-cert-validation-dns-record",
&route53.RecordArgs{
ZoneId: pulumi.String(zoneId),
Name: domainValidationOption.ApplyT(func(option interface{}) string {
return *option.(acm.CertificateDomainValidationOption).ResourceRecordName
}).(pulumi.StringOutput),
Type: domainValidationOption.ApplyT(func(option interface{}) string {
return *option.(acm.CertificateDomainValidationOption).ResourceRecordType
}).(pulumi.StringOutput),
Records: pulumi.StringArray{
domainValidationOption.ApplyT(func(option interface{}) string {
return *option.(acm.CertificateDomainValidationOption).ResourceRecordValue
}).(pulumi.StringOutput),
},
Ttl: pulumi.Int(10 * 60), // 10 minutes
},
)
if err != nil {
return nil, err
}
// Wait for the certificate validation to succeed
validatedSslCertificate, err := acm.NewCertificateValidation(ctx,
"ssl-cert-validation",
&acm.CertificateValidationArgs{
CertificateArn: sslCertificate.Arn,
ValidationRecordFqdns: pulumi.StringArray{sslCertificateValidationDnsRecord.Fqdn},
},
pulumi.Provider(awsUsEast1),
)
if err != nil {
return nil, err
}
// Configure API Gateway to be able to use domain name & certificate
apiDomainName, err := apigateway.NewDomainName(ctx, "api-domain-name",
&apigateway.DomainNameArgs{
CertificateArn: validatedSslCertificate.CertificateArn,
DomainName: pulumi.String(domain),
},
)
if err != nil {
return nil, err
}
// Create DNS record
_, err = route53.NewRecord(ctx, "api-dns",
&route53.RecordArgs{
ZoneId: pulumi.String(zoneId),
Type: pulumi.String("A"),
Name: pulumi.String(domain),
Aliases: route53.RecordAliasArray{
route53.RecordAliasArgs{
Name: apiDomainName.CloudfrontDomainName,
EvaluateTargetHealth: pulumi.Bool(false),
ZoneId: apiDomainName.CloudfrontZoneId,
},
},
})
if err != nil {
return nil, err
}
return apiDomainName, nil
}
10 changes: 10 additions & 0 deletions aws-apigateway-go-routes/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module github.com/pulumi/examples/aws-apigateway-go-routes

go 1.13

require (
github.com/aws/aws-lambda-go v1.27.0
github.com/pulumi/pulumi-aws-apigateway/sdk v0.0.5
github.com/pulumi/pulumi-aws/sdk/v4 v4.30.0
github.com/pulumi/pulumi/sdk/v3 v3.18.1
)
Loading

0 comments on commit 5b1b42e

Please sign in to comment.