如何使用Cloud Formation为CloudFront分配配置ACM证书

时间:2016-03-10 10:42:46

标签: amazon-web-services ssl ssl-certificate amazon-cloudfront amazon-cloudformation

我正在尝试使用Cloud Formation在我的CloudFrontDistribution中设置证书。

我的证书已通过证书管理器发出。它已被批准,我已经验证证书可以通过CloudFront控制台直接手动配置。

在我的CloudFormation模板中,我尝试在IamCertificateId属性中使用与证书关联的 Identifier ARN 值:

"ViewerCertificate" : {
  "IamCertificateId" : "********",
  "SslSupportMethod": "sni-only"
}

但是在这两种情况下我都收到以下错误:

The specified SSL certificate doesn't exist, isn't valid, or doesn't include a valid certificate chain.

阅读DistributionConfig Complex Type的文档,看起来有一个'ACMCertificateArn'属性,但这似乎不适用于CloudFormation。

任何帮助都将不胜感激。

5 个答案:

答案 0 :(得分:14)

(更新:自Aug 9 2016起,AWS CloudFormation现在使用AcmCertificateArn属性支持ACM,因此不再需要下面描述的自定义资源。)

虽然AWS :: CloudFront :: Distribution资源尚未更新以支持ACMCertificateArn属性,但目前可以使用custom CloudFormation resource直接使用AWS API实现所需的功能。资源已更新。

请参阅Ryan S. Brown的帖子CloudFormation To Build A CDN With (Free) Custom SSL,其中描述了他将ACM证书与CloudFront分配相关联的Custom::CloudFrontAcmAssociation资源的实现。该代码位于ryansb/acm-certs-cloudformation

要使用它,您需要通过AWS Lambda函数提供CloudFormation资源的实现。 Ryan的实现已发布到公共S3存储桶,因此您可以在CloudFormation模板中直接引用它以进行测试,如下所示:

"AcmAssociationFunction": {
  "Type": "AWS::Lambda::Function",
  "Properties": {
    "Handler": "cloudfront_associator.handler",
    "MemorySize": 128,
    "Runtime": "python2.7",
    "Code": {
      "S3Bucket": "demos.serverlesscode.com",
      "S3Key": "acm-certificate-resource-functions.zip"
    },
    "Role": {"Fn::GetAtt": ["ExecRole", "Arn"]},
    "Timeout": 300
  }
},

Lambda::Function资源依赖于IAM服务角色和相关策略来委派必需的权限到lambda函数(上面的ExecRole引用),所以你也需要添加它: / p>

"ExecRolePolicies": {
  "Type": "AWS::IAM::Policy",
  "Properties": {
    "PolicyName": "ExecRolePolicy",
    "PolicyDocument": {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Action": [
            "acm:*",
            "cloudfront:List*",
            "cloudfront:Get*",
            "cloudfront:UpdateDistribution"
          ],
          "Resource": [ "*" ],
          "Effect": "Allow"
        },
        {
          "Action": [ "logs:*" ],
          "Resource": "arn:aws:logs:*:*:*",
          "Effect": "Allow"
        }
      ]
    },
    "Roles": [{"Ref": "ExecRole"}]
  }
},
"ExecRole": {
  "Type": "AWS::IAM::Role",
  "Properties": {
    "AssumeRolePolicyDocument": {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Action": ["sts:AssumeRole"],
          "Effect": "Allow",
          "Principal": {"Service": ["lambda.amazonaws.com"]}
        }
      ]
    }
  }
},

使用lambda函数,最后添加Custom::CloudFrontAcmAssociation资源,提供分发ID,证书ARN和自定义资源lambda函数的ARN:

"DistributionCertificateSetting": {
  "Type": "Custom::CloudFrontAcmAssociation",
  "Properties": {
    "DistributionId": {
      "Ref": "SiteCDN"
    },
    "CertificateArn": {
      "Ref": "AcmCertificate"
    },
    "ServiceToken": {
      "Fn::GetAtt": [
        "AcmAssociationFunction",
        "Arn"
      ]
    }
  }
},

tldr:将上面的所有代码复制到您的CloudFormation模板中,设置相应的SiteCDNAcmCertificate属性(或使用硬编码值编辑模板),您应该有自定义资源解决方法直到亚马逊更新官方CloudFront资源。

答案 1 :(得分:9)

Cloudformation添加了此属性,但未记录。您可以轻松使用:

"ViewerCertificate": {
            "SslSupportMethod": "sni-only",
            "AcmCertificateArn": "CERTIFICATE_ARN"
}

请注意,证书必须在us-east-1区域创建,否则将不被接受。

答案 2 :(得分:2)

我有一个正确创建的证书(公钥2048位),上传了完整链。更具挑战性的是在其他AWS服务(公共ELB)中使用证书时没有问题。

我也正确地传递了证书ID(我也尝试过使用ARN,但这不正确)。

在我的情况下,问题是证书是用"路径":" /"创建的。在我使用" Path":" / cloudfront /"上传新证书(使用不同的名称)之后,一切都正常运行。

  aws iam upload-server-certificate \
    --server-certificate-name cert_cf \
    --certificate-body file://cert.crt \
    --private-key file://cert.key \
    --certificate-chain file://chain.pem \
    --path /cloudfront/

答案 3 :(得分:0)

我现在使用的另一种有效方法是,只要不颁发证书,就使用默认证书创建堆栈(受this post启发)

看起来像

"Conditions": {
    "HasAcmCertificate": {
        "Fn::Equals": [
            {
                "Ref": "CloudfrontCertificateArn"
            },
            "NOT_ISSUED"
        ]
    }
},

...

"Cloudfront": {
    "Properties": {
        "DistributionConfig": {

            ...

            "ViewerCertificate": {
                "AcmCertificateArn": {
                    "Fn::If": [
                        "HasAcmCertificate",
                        {
                            "Ref": "AWS::NoValue"
                        },
                        {
                            "Ref": "CloudfrontCertificateArn"
                        }
                    ]
                },
                "CloudFrontDefaultCertificate": {
                    "Fn::If": [
                        "HasAcmCertificate",
                        true,
                        {
                            "Ref": "AWS::NoValue"
                        }
                    ]
                },
                "SslSupportMethod": {
                    "Fn::If": [
                        "HasAcmCertificate",
                        {
                            "Ref": "AWS::NoValue"
                        },
                        "sni-only"
                    ]
                }
            }
        }
    },
    "Type": "AWS::CloudFront::Distribution"
},

答案 4 :(得分:-2)

花了几天时间,但在AWS支持的帮助下找到答案。

以下信息:

"ViewerCertificate" : {
  "IamCertificateId" : "********",
  "SslSupportMethod": "sni-only"
}

使用CLI" aws iam list-server-certificates":

{
    "ServerCertificateId": "ASCAXXXXXXXXXXXXXX", 
    "ServerCertificateName": "devops.XXXXXXX.com", 
    "Expiration": "2017-03-10T15:00:33Z", 
    "Path": "/cloudfront/", 
    "Arn": "arn:aws:iam::XXXXXXXXXXX:server-certificate/cloudfront/devops.XXXXXXXXXXX.com", 
    "UploadDate": "2016-03-14T16:13:59Z"
}, 

一旦我发现我添加了一个带有ServerCertificateId的变量cloudfront.CloudFrontCertificateId并将其输入ViewerCertificate:

"ViewerCertificate" : {
  "IamCertificateId" : {{ cloudfront.CloudFrontCertificateId }},
  "SslSupportMethod": "sni-only"
}