skip to Main Content

I am confused to how to create a certificate for the apex domain, which will also work with subdomain.

I have created a basic website deployment CDK Construct and have been trying to fix it so it works for both www.example.com subdomain and example.com but I haven’t been able to do that.
With the current setup, www.example.com works but when I visit example.com it issues the following error:

This site can’t provide a secure connection
example.com sent an
invalid response. ERR_SSL_PROTOCOL_ERROR

My guess is an issue with certificate creation but I am not sure. Here is the partial CDK code, showing the zone, cloudFormation, certificate and route53 setup.

    const siteDomain = "example.com"

    const zone = route53.HostedZone.fromLookup(this, "Zone", {
      domainName: siteDomain,
    });


    // TLS certificate
    const certificateArn = new acm.DnsValidatedCertificate(
      this,
      "SiteCertificate",
      {
        domainName: "*." + siteDomain,
        hostedZone: zone,
        region: "us-east-1", // Cloudfront only checks this region for certificates.
      }
    ).certificateArn;

    // Specifies you want viewers to use HTTPS & TLS v1.1 to request your objects
    const viewerCertificate = cloudfront.ViewerCertificate.fromAcmCertificate(
      {
        certificateArn: certificateArn,
        env: {
          region: Aws.REGION,
          account: Aws.ACCOUNT_ID,
        },
        node: this.node,
        stack: parent,
        metricDaysToExpiry: () => ...
      },
      {
        sslMethod: cloudfront.SSLMethod.SNI,
        securityPolicy: cloudfront.SecurityPolicyProtocol.TLS_V1_1_2016,
        aliases: ["*." + siteDomain],
      }
    );


    // CloudFront distribution
    const distribution = new cloudfront.CloudFrontWebDistribution(
      this,
      "SiteDistribution",
      {
        viewerCertificate,
        originConfigs: [
          {
            s3OriginSource: {
              ...
            },
            behaviors: [
              {
                ...
              },
            ],
          },
        ],
      }
    );

    // Route53 alias record for the CloudFront distribution
    const siteRecord = new route53.ARecord(this, "SiteAliasRecord", {
      recordName: siteDomain,
      target: route53.RecordTarget.fromAlias(
        new targets.CloudFrontTarget(distribution)
      ),
      zone,
    });

    new route53.CnameRecord(this, "SiteWWWAliasRecord", {
       recordName: "www." + siteDomain,
       domainName: siteDomain,
       zone,
    });


    // deploy/copy the website built website to s3 bucket
    this.deploy = new s3Deployment.BucketDeployment(
      this,
      CONSTRUCT_NAMES.bucket.deployment,
      {
        sources: [...],
        destinationBucket: this.websiteBucket,
        distribution,
        distributionPaths: ["/*"],
      }
    );
  }
}

After a successful deployment, when I visit the full domain www.example.com it shows the page but without the www subdomain the certificate issues an error. An ideas on how to fix this? I have to somehow set a correct certificate root domain value instead of a wildcard. Here is the route53 output after running the command:

enter image description here

2

Answers


  1. Mhh try more like my working bits:

        const cloudFrontOAI = new cloudfront.OriginAccessIdentity(this, 'OAI');
    siteBucket.grantRead(cloudFrontOAI.grantPrincipal);
    
    const hostedZone = route53.HostedZone.fromLookup(this, 'Zone', {
      domainName: props.domainName,
    });
    
    const certificate = new certificatemanager.DnsValidatedCertificate(
      this,
      'certificate',
      {
        domainName: `${props.recordName === '' ? '' : props.recordName + '.'}${
          props.domainName
        }`,
        subjectAlternativeNames: props.alternativeRecordName
          ? [`${props.alternativeRecordName}.${props.domainName}`]
          : undefined,
        hostedZone,
        region: 'us-east-1',
      },
    );
    
    const distribution = new cloudfront.CloudFrontWebDistribution(
      this,
      'Distribution',
      {
        enableIpV6: false,
        originConfigs: [
          {
            s3OriginSource: {
              s3BucketSource: siteBucket,
              originAccessIdentity: cloudFrontOAI,
            },
            behaviors: [{ isDefaultBehavior: true }],
          },
        ],
        errorConfigurations: [
          {
            errorCode: 404,
            responseCode: 404,
            responsePagePath: '/index.html',
          },
        ],
        viewerCertificate: cloudfront.ViewerCertificate.fromAcmCertificate(
          certificate,
          {
            aliases: props.alternativeRecordName
              ? [
                  `${props.recordName === '' ? '' : props.recordName + '.'}${
                    props.domainName
                  }`,
                  `${props.alternativeRecordName}.${props.domainName}`,
                ]
              : [
                  `${props.recordName === '' ? '' : props.recordName + '.'}${
                    props.domainName
                  }`,
                ],
          },
        ),
      },
    );
    
    Login or Signup to reply.
  2. Try using the newer Distribution construct rather than the older CloudFrontWebDistribution construct. From the docs:

    The CloudFrontWebDistribution construct is the original construct written for working with CloudFront distributions. Users are encouraged to use the newer Distribution instead, as it has a simpler interface and receives new features faster.

    You also need to make sure you add both domain names to your distribution if you want to be able to access it via both URLs. See below example, disregard the OAI portion if you don’t need it:

    const siteDomain = "example.com";
    
    const zone = route53.HostedZone.fromLookup(this, "Zone", {
      domainName: siteDomain,
    });
    
    const certificate = new acm.DnsValidatedCertificate(
      this,
      "SiteCertificate",
      {
        domainName: siteDomain,
        subjectAlternativeNames: ["*." + siteDomain],
        hostedZone: zone,
        region: "us-east-1", // Cloudfront only checks this region for certificates.
      }
    );
    
    const oai = new cloudfront.OriginAccessIdentity(this, "SiteOai");
    this.websiteBucket.grantRead(oai);
    
    const distribution = new cloudfront.Distribution(
      this, 
      "SiteDistribution", 
      {
        certificate,
        defaultBehavior: {
          origin: new origins.S3Origin(this.websiteBucket, {
            originAccessIdentity: oai
          }),
          ...
        },
        domainNames: [siteDomain, "www." + siteDomain],
        ...
      }
    );
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search