pulumi / pulumi-aws-apigateway

Apache License 2.0
12 stars 5 forks source link

Easier support for APIs SSL and custom domains #35

Open joeduffy opened 5 years ago

joeduffy commented 5 years ago

After quite a bit of spelunking, I figured out how to assign a custom domain name, with SSL support, for an awsx.apigateway.API. This is nice because it not only gives me a custom domain over HTTPS, but also eliminates the ugly trailing /stage part of the URL.

It was not easy although in hindsight all of the pieces make perfect sense:

import * as aws from "@pulumi/aws";
import * as awsx from "@pulumi/awsx";
import * as pulumi from "@pulumi/pulumi";

// Fetch our custom domain from configuration. To configure this, run:
//
//     $ pulumi config set domain <your.domain.com>
//
const domain = new pulumi.Config().require("domain");

// Serve our web's static and dynamic endpoints through API Gateway.
const web = new awsx.apigateway.API("web", {
    routes: [{
        path: "/",
        localPath: "./static",
    }],
});

// Create a DNS zone for our custom domain.
const webDnsZone = new aws.route53.Zone("webDnsZone", {
    name: domain,
});

// Provision an SSL certificate to enable SSL -- ensuring to do so in us-east-1.
const awsUsEast1 = new aws.Provider("usEast1", { region: "us-east-1" });
const sslCert = new aws.acm.Certificate("sslCert", {
    domainName: domain,
    validationMethod: "DNS",
}, { provider: awsUsEast1 });

// Create the necessary DNS records for ACM to validate ownership, and wait for it.
const sslCertValidationRecord = new aws.route53.Record("sslCertValidationRecord", {
    zoneId: webDnsZone.id,
    name: sslCert.domainValidationOptions[0].resourceRecordName,
    type: sslCert.domainValidationOptions[0].resourceRecordType,
    records: [ sslCert.domainValidationOptions[0].resourceRecordValue ],
    ttl: 10 * 60 /* 10 minutes */,
});
const sslCertValidationIssued = new aws.acm.CertificateValidation("sslCertValidationIssued", {
    certificateArn: sslCert.arn,
    validationRecordFqdns: [ sslCertValidationRecord.fqdn ],
}, { provider: awsUsEast1 });

// Configure an edge-optimized domain for our API Gateway, leveraging . This will configure
// a Cloudfront CDN distribution behind the scenes and serve our API Gateway at a custom
// domain name over SSL.
const webDomain = new aws.apigateway.DomainName("webCdn", {
    certificateArn: sslCertValidationIssued.certificateArn,
    domainName: domain,
});
const webDomainMapping = new aws.apigateway.BasePathMapping("webDomainMapping", {
    restApi: web.restAPI,
    stageName: web.stage.stageName,
    domainName: webDomain.id,
});

// Now, create an A record for our domain that directs to the allocated CloudFront distribution.
const webDnsRecord = new aws.route53.Record("webDnsRecord", {
    name: webDomain.domainName,
    type: "A",
    zoneId: webDnsZone.id,
    aliases: [{
        evaluateTargetHealth: true,
        name: webDomain.cloudfrontDomainName,
        zoneId: webDomain.cloudfrontZoneId,
    }],
}, { dependsOn: sslCertValidationIssued });

export const url = `https://${domain}`;
export const dnsNameServers = webDnsZone.nameServers;

I honestly just wanted to write something like this:

const web = new awsx.apigateway.API("web", {
    domain: new pulumi.Config().require("domain"),
    routes: [{
        path: "/",
        localPath: "./static",
    }],
});

However, I realize why papering over too many details -- including SSL certificate creation, domain creation, and so on -- is dangerous. It could be that we simply need a blog and example for this. But I do think it's worth pondering what we could/should do here.

Ilchuk-Mihail commented 5 years ago

Hello,

If I use this kind of stuff with domain, ssl , cert validation stuff ... It takes much more time for deployments: For example: (correct me if I'm wrong) First time , we have approximately 10 minutes. If we have domain external domain provider, we should do manual step to setup NS record on the domain provider map to hosted zone NS records. And it takes much more time, before domain dns propagated. Sometimes script can throw timeout error.

All next times, I see next items after pulumi up :

 -   ├─ aws:acm:CertificateValidation     certificateValidation          delete
 -   ├─ aws:route53:Record                domainName-validation  delete
 -   ├─ aws:acm:Certificate               certificate                    delete
 -   └─ pulumi:providers:aws              east                           delete

Every time, script try to delete this items, and simple updates takes about 5, 10 minutes. Why script try delete it every time?

I use this exmaple https://github.com/pulumi/examples/tree/master/aws-ts-static-website

But with some changes: cointainer app , Fargate service .