+86 13541016684Mon. - Fri. 10:00-22:00

AWS S3如何配置自己的ssl证书和域名 CloudFront and SSL Certificate Manager

AWS S3如何配置自己的ssl证书和域名 CloudFront and SSL Certificate Manager

AWS S3如何配置自己的ssl证书和域名 CloudFront and SSL Certificate Manager

HTTPS for AWS CloudFront and AWS ELB

Wow, such easy, much free! A few simple steps on 1) How to obtain a certificate for your domain, and 2) how to use it on your CloudFront or Elastic Load Balancer.

(See 1.4 if it’s for a Load Balancer)

Quote CloudFront SSL Settings Page:

You can use certificates that you created in AWS Certificate Manager (ACM) in the US-East (N. Virginia) Region, or you can use certificates stored in the IAM certificate store.

1.1 Using AWS generated Certificate

If you don’t have a certificate (or if you do, but haven’t gotten too attached to it yet), this is the easy/recommended way – using AWS Certificate Manager:

  1. Go to AWS Certificate Manager in US East (North Virginia).
    • Request a certificate for your domain
  2. Wait… an email will arrive soon.
  3. Click the confirmation link in your e-mail and confirm that you know what’s happening
  4. Go to your CloudFront distribution > Select distribution > Distribution Settings > General > Edit
    • Make sure your domain name is in the “Alternate Domain Names (CNAMEs)” textbox.
    • Select “Custom SSL Certificate (example.com)”
    • Select the Certificate you got there.
  5. Wait… Changing a CloudFront distribution can take a while.
  6. Voilá! That’s it.

1.2 Using your own certificate

  1. Acquire a certificate (via e.g. Let’s Encrypt)
  2. Upload that via the aws cli upload-server-certificate (Important: region must be eu-east-1 (N. Virginia for CloudFront)
    aws iam upload-server-certificate
       --path /cloudfront/test/
       --server-certificate-name myFirstCertificate
       --certificate-body file://<my-pub-key-file>
       --private-key file://<my-private-key>
       --certificate-chain file://<my-certificate-chain>

    Note how the path must start with cloudfront (required for that service only).

  3. Go to step 4 in the section 1.1. Your uploaded certificate should be found there.

1.3 Troubleshooting

If your Cloudfront is in front of an s3 bucket (fishsticks) and points to its website url (fishsticks.s3-website.eu-central-1.amazonaws.com), you can run into trouble.

The S3 website url doesn’t support https out of the box. You can fix this by setting The Origin Protocol Policy to HTTP Only (CloudFront > Distribution Settings > Origin > Edit), which will make traffic between your CloudFront and S3 bucket be http. If you’re uncomfortable with this, you can points to its regular bucket url (https://fishsticks.s3.amazonaws.com/), which do support https. If you do, remember to set default root object on your CloudFront.

1.4 For Elastic Load balancer

If you’re using your own certificate, do steps 1.2 above. Else, do steps 1.1. In both cases, you must request/upload them to the same region as your ELB.

Then, add your certificate to your ELB by following the steps in Add an HTTPS Listener using the Console guide on AWS.


 

Hosting on AWS S3, CloudFront and SSL Certificate Manager

With the AWS free tier you can store up to 5Gb of files and handle 20.000 GET requestson Amazon S3 each month for free. After the 12 months trial period the default Amazon S3 pricing kicks in …

Create an Amazon S3 Bucket

All you need to get started is an Amazon S3 bucket, enable static website hosting and define a required index document. This can be all be achieved using the aws command line interface, so let’s get started with creating a bucket for notify.heft.io with:

$ > aws s3api create-bucket \
--bucket notify.heft.io \
--region eu-west-1 \
--create-bucket-configuration LocationConstraint=eu-west-1

Now that we have created the S3 bucket to store all files, we need to enable the built-in Amazon S3 feature for hosting static websites and configure the default index document:

$ > aws s3 website s3://notify.heft.io/ \
--region eu-west-1 \
--index-document index.html

The first command already responded the public URL of the S3 bucket, in this case notify.heft.io.s3.amazonaws.com. But no worries, we will be able to access the files in this bucket with a custom domain using Amazon CloudFront in the end.

As we do not plan to store any confidential data in the Amazon S3 bucket, we can just enable general public read access to all objects stored in it:

$ > aws s3api put-bucket-policy \
--bucket notify.heft.io \
--region eu-west-1 \
--policy '{
      "Version": "2012-10-17",
      "Statement": [
          {
              "Sid": "Allow Public Access to All Objects",
              "Effect": "Allow",
              "Principal": "*",
              "Action": "s3:GetObject",
              "Resource": "arn:aws:s3:::notify.heft.io/*"
          }
      ]
  }'

After creating the bucket, enabling static web hosting and configuring the access permission it’s time upload the first content to the bucket. Let’s just create two simple files called index.html and error.html, put some content in it and upload them to the S3 bucket:

$ > echo "Index" > dist/index.html
$ > aws s3 cp --region eu-west-1 \
dist/index.html \
s3://notify.heft.io/index.html

$ > echo "Error" > dist/error.html
$ > aws s3 cp --region eu-west-1 \
dist/error.html \
s3://notify.heft.io/error.html

After both uploads have finished the files are available in the S3 bucket with the configured access pattern. You should be able to send a request to both of them and receive the stored content.

$ > curl http://notify.heft.io.s3.amazonaws.com/index.html
Index

$ > curl http://notify.heft.io.s3.amazonaws.com/error.html
Error

Now there is a basic setup to host a static website and you could just start with uploading files to Amazon S3. But the S3 bucket shall use a custom domain and not some URL ending with *.amazonaws.com, and have an SSL certificate for secure access to the content over HTTPS as well. You can be lucky, Amazon introduced free SSL certificates with the Amazon Certificate Manage just a couple of weeks ago.

Create an SSL Certificate

We need to request a certificate in ACM and Amazon will provide us with an identifier for the certificate which can be used to configure CloudFront to serve the files using HTTPS:

$ > aws acm request-certificate \
--domain-name notify.heft.io

{
    "CertificateArn": "arn:aws:acm:us-east-1:123456789123:certificate/…"
}

Write down that ARN, it will be needed for the CloudFront configuration. Amazon requires some kind of verification that you really own a domain, so we can trigger an verification email to admin@heft.io with the following command:

$ > aws acm resend-validation-email \
--certificate-arn "arn:aws:acm:us-east-1:198537873635:certificate/…" \
--domain notify.heft.io \
--validation-domain heft.io

Now check your inbox and click on approve in the mail Amazon did sent to your address. After approving the certificate we can use it with CloudFront; Other services like API Gateway will hopefully be added to the list of compatible services in the future.

Configure CloudFront

The configuration for CloudFront is more complex than the previous commands, but the JSON contains all settings for using a custom domain with SSL and have all HTTP requests redirected to HTTPS. Please check the Amazon CloudFront prices first. The free tier comens with 50 GB data transfer and 2,000,000 requests each month for one year.

$ > aws cloudfront create-distribution \
 --region=eu-west-1 \
 --distribution-config '{
    "CallerReference": "notify.heft.io",
    "Comment": "", 
    "CacheBehaviors": {
        "Quantity": 0
    }, 
    "Logging": {
        "Bucket": "", 
        "Prefix": "", 
        "Enabled": false, 
        "IncludeCookies": false
    }, 
    "WebACLId": "", 
    "Origins": {
        "Items": [
            {
                "OriginPath": "", 
                "CustomOriginConfig": {
                    "OriginProtocolPolicy": "http-only", 
                    "HTTPPort": 80, 
                    "OriginSslProtocols": {
                        "Items": [
                            "TLSv1", 
                            "TLSv1.1", 
                            "TLSv1.2"
                        ], 
                        "Quantity": 3
                    }, 
                    "HTTPSPort": 443
                }, 
                "CustomHeaders": {
                    "Quantity": 0
                }, 
                "Id": "notify.heft.io", 
                "DomainName": "notify.heft.io.s3-website-eu-west-1.amazonaws.com"
            }
        ], 
        "Quantity": 1
    }, 
    "DefaultRootObject": "", 
    "PriceClass": "PriceClass_All", 
    "Enabled": true, 
    "DefaultCacheBehavior": {
        "TrustedSigners": {
            "Enabled": false, 
            "Quantity": 0
        }, 
        "TargetOriginId": "notify.heft.io", 
        "ViewerProtocolPolicy": "redirect-to-https", 
        "ForwardedValues": {
            "Headers": {
                "Quantity": 0
            }, 
            "Cookies": {
                "Forward": "none"
            }, 
            "QueryString": false
        }, 
        "MaxTTL": 31536000, 
        "SmoothStreaming": false, 
        "DefaultTTL": 86400, 
        "AllowedMethods": {
            "Items": [
                "HEAD", 
                "GET"
            ], 
            "CachedMethods": {
                "Items": [
                    "HEAD", 
                    "GET"
                ], 
                "Quantity": 2
            }, 
            "Quantity": 2
        }, 
        "MinTTL": 0, 
        "Compress": false
    }, 
    "ViewerCertificate": {
        "SSLSupportMethod": "sni-only", 
        "ACMCertificateArn": "arn:aws:acm:us-east-1:123456789123:certificate/…", 
        "MinimumProtocolVersion": "TLSv1", 
        "Certificate": "arn:aws:acm:us-east-1:123456789123:certificate/…", 
        "CertificateSource": "acm"
    }, 
    "CustomErrorResponses": {
        "Quantity": 0
    }, 
    "Restrictions": {
        "GeoRestriction": {
            "RestrictionType": "none", 
            "Quantity": 0
        }
    }, 
    "Aliases": {
        "Items": [
            "notify.heft.io"
        ], 
        "Quantity": 1
    }
}'

Amazon needs some time to distribute our CloudFront setup, but after a few minutes you can access the S3 bucket with a *.cloudfront.netsubdomain.

Use Route53 for DNS

To have Amazon answer requests for the custom notify.heft.iodomain and use the previously created SSL certificate we need to add a RecordSet to the Route53 configuration. The following aws API request depends on an already configured HostedZone in Route53 and creates a subdomain pointing to the CloudFront address:

$ > aws route53 change-resource-record-sets \
--hosted-zone-id Z5ADD5OALD2PL \
--change-batch '{
  "Changes": [
    {
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "notify.heft.io.",
				"Type": "A",
        "AliasTarget": {
          "HostedZoneId": "Z5ADD5OALD2PL",
          "DNSName": "dt4egtm72vk4z.cloudfront.net.",
          "EvaluateTargetHealth": false
        }
      }
    }
  ]
}'

Now Amazon Route53 knows how to handle requests to the custom domain notify.heft.io and to respond with the CloudFront distribution of the uploaded content from the S3 bucket. Together with the certificate from Amazon Certificate Manager this is a neat setup to host a static website using HTTPS without any maintenance.

As we are all setup now you can finally send requests to notify.heft.io which will resond with our uploaded files:

$ > curl https://notify.heft.io/
Index

$ > curl https://notify.heft.io/error.html
Error

Always remember to invalidate the CloudFront cache after uploading changes to a S3 bucket! Of course Amazon supports cache invalidation using the aws command line interface, so you can easily integrate it in your deploy flow:

$ > aws cloudfront create-invalidation \
--distribution-id A3ER1GOP2FROL
--paths '/*'

Make sure to check out the heft.io repository on GitHub to see how this works when using a .travis.yml configuration for Travis CI