この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
AWSチームのすずきです。
先日、2016年8月9日のアップデートにより、CloudFormation が、AWSのサーバ証明書発行サービスACM(AWS Certificate Manager)に対応し、 無料のサーバ証明書の作成と、ELB、CloudFrontへのサーバ証明書の組み込みを、CloudFormationで実施する事が可能になりました。
今回、その内容について紹介させていただきます。
ACM サーバ証明書の作成
以下のCloudFormationテンプレートを利用して、サーバ証明書を作成します。
JSONテンプレート
- acm-test.json
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "ACM test 2016-08-09",
"Parameters": {
"DomainName": {
"Description": "FQDN of the certificate being requested.",
"Type": "String",
"Default": ""
},
"ValidationDomain": {
"Description": "The domain to which validation email is sent.",
"Type": "String",
"Default": ""
}
},
"Resources": {
"ACMCertificate": {
"Type": "AWS::CertificateManager::Certificate",
"Properties": {
"DomainName": { "Fn::Join" : [ "", [ "*.", { "Ref" : "DomainName"} ]]},
"SubjectAlternativeNames": [{ "Ref": "DomainName" }],
"DomainValidationOptions": [{
"DomainName": { "Fn::Join" : [ "", [ "*.", { "Ref" : "DomainName"} ]]},
"ValidationDomain": { "Ref": "ValidationDomain" }
}]
}
}
}
}
CloudFormation操作
テンプレート指定
- ACM設定用のJSONテンプレートを指定します
パラメータ指定
スタック名
- 任意の名称とします
DomainName
- 発行するサーバ証明書のドメイン(FQDN)を指定します。
- コモンネームは「*.DomainName」、ワイルドカード証明書とします。
- ZoneApex、ホスト名省略したアドレスにも対応する証明書とするため、SAN(SubjectAlternativeNames)指定を行います。
ValidationDomain
- メールによるドメイン認証対象となるFQDNを指定します
- 通常「DomainName」と同一の値を指定します
- 証明書の発行対象がサブドメインの場合、親ドメインの指定も可能です
オプション
- 今回は利用しません
確認
ACM ステータス確認
- CloudFromationで作成したサーバ証明書、Statusは「Pending validation」承認待ちである事を確認します
- 承認メールの通知先は、Detailed statusで確認する事が可能です
メール承認
- ドメイン管理者宛に届くメールのリンクより、承認画面を開きます
- ブラウザを開き、承認操作実施します
- ACMのStatus 「Issued」となった事を確認します。
CloudFormation 確認
- CloudFromation 、タイムアウトする前にドメイン承認が実施されると、「CreateComplete」となります。
ELB利用
- ACMで作成した証明書のARNは、「"Ref":リソース名」で取得可能です
- ELBのリスナー設定、SSLCertificateIdに、ACMで作成した証明書のARNを指定して利用します
テンプレート抜粋
"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
"Properties": {
"Listeners": [
{
"InstancePort": "80",
"LoadBalancerPort": "443",
"Protocol": "HTTPS",
"InstanceProtocol": "HTTP",
"SSLCertificateId": { "Ref" : "ACMCertificate" }
}
]
}
CloudFront利用
- CloudFrontはバージニア(us-east-1)で作成したACM証明書を利用します。
- ACMの証明書作成するCloudFormationはバージニアでの実行が必要です。
- AcmCertificateArn にACMで作成した証明書のARNを指定して利用します。
- CloudFrontのSSLは、追加費用不要なSNI(sni-only)を指定します。
テンプレート抜粋
"Type": "AWS::CloudFront::Distribution",
"Properties": {
"DistributionConfig": {
"ViewerCertificate": {
"SslSupportMethod": "sni-only",
"AcmCertificateArn": { "Ref": "ACMCertificate"}
}
}
}
まとめ
今回のCloudFromationのアップデート以前、ELB、CloudFrontにACMで発行した サーバ証明書を利用するためには、AWSコンソール、CLIによる手動操作が必須、 作業ミスや、CloudFomationをUpdateStackで更新する際の干渉などにも注意が必要でした。
ACMを利用して、サーバ証明書の有効期限や鍵の管理をAWSに任せる事で、 従来の証明書と比較し、管理、運用に費やす工数も大幅に抑制する事が可能です。 今回のCloudFormationのアップデートにより、更に使いやすくなったACM、ぜひご活用ください。
また、現在ACMのドメイン認証はメールのみ、DNSのTXTレコードなどによる認証が待たれますが、 現在の方式でも、SESのメール受信とLambdaの組み合わせで自動化ができそう。 こちら成功したら、改めて紹介させて頂きたいと思います。
テンプレート例
- Route53、Alias、CNAMEなどのDNSレコード設定は別途必要です
ELB用
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "ACM ELB test 2016-08-09",
"Metadata" : {
"AWS::CloudFormation::Interface" : {
"ParameterGroups" : [
{
"Label" : { "default": "ACM Configuration" },
"Parameters" : [ "DomainName", "ValidationDomain" ]
},
{
"Label" : { "default" : "ELB Configuration" },
"Parameters" : [ "DummyElbSubnet" ]
}
],
"ParameterLabels" : {
"DomainName" : { "default" : "Domain Name" },
"ValidationDomain" : { "default" : "Validation Domain Name" }
}
}
},
"Parameters": {
"DomainName": {
"Description": "FQDN of the certificate being requested.",
"Type": "String",
"Default": ""
},
"ValidationDomain": {
"Description": "The domain to which validation email is sent.",
"Type": "String",
"Default": ""
},
"DummyElbSubnets" : {
"Description" : "VPC subnets List (ELB)",
"Type" : "List<AWS::EC2::Subnet::Id>"
}
},
"Resources": {
"ACMCertificate": {
"Type": "AWS::CertificateManager::Certificate",
"Properties": {
"DomainName": { "Fn::Join" : [ "", [ "*.", { "Ref" : "DomainName"} ]]},
"SubjectAlternativeNames": [{ "Ref": "DomainName" }],
"DomainValidationOptions": [{
"DomainName": { "Fn::Join" : [ "", [ "*.", { "Ref" : "DomainName"} ]]},
"ValidationDomain": { "Ref": "ValidationDomain" }
}]
}
},
"DummyElb": {
"DependsOn" : "ACMCertificate",
"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
"Properties": {
"Subnets": { "Ref" : "DummyElbSubnets" },
"Listeners": [
{
"InstancePort": "80",
"LoadBalancerPort": "443",
"Protocol": "HTTPS",
"InstanceProtocol": "HTTP",
"SSLCertificateId": { "Ref" : "ACMCertificate" }
}
],
"Instances": []
}
}
},
"Outputs": {
"ACMCertificate": {
"Description": "ACMCertificate ARN",
"Value": { "Ref": "ACMCertificate" }
}
}
}
CloudFront
- バージニア(us-east-1)で実行
- OriginDomainNameには、CloudFrontのカスタムオリジンとするFQDNを指定します。
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "ACM CloudFront test 2016-08-09",
"Metadata": {
"AWS::CloudFormation::Interface": {
"ParameterGroups": [
{
"Label": { "default": "ACM Configuration" },
"Parameters": [ "DomainName", "ValidationDomain" ]
},
{
"Label": { "default": "CloudFront Configuration" },
"Parameters": [ "OriginDomainName" ]
}
],
"ParameterLabels": {
"DomainName": { "default": "Domain Name" },
"ValidationDomain": { "default": "Validation Domain Name" },
"OriginDomainName": { "default": "Origin Domain Name" }
}
}
},
"Parameters": {
"DomainName": {
"Description": "FQDN of the certificate being requested.",
"Type": "String",
"Default": ""
},
"ValidationDomain": {
"Description": "The domain to which validation email is sent.",
"Type": "String",
"Default": ""
},
"OriginDomainName": {
"Description": "Origin information to specify a custom origin.",
"Type": "String",
"Default": ""
}
},
"Resources": {
"ACMCertificate": {
"Type": "AWS::CertificateManager::Certificate",
"Properties": {
"DomainName": {
"Ref": "DomainName"
},
"DomainValidationOptions": [
{
"DomainName": { "Ref": "DomainName" },
"ValidationDomain": { "Ref": "ValidationDomain" }
}
]
}
},
"DummyCloudFrontDistribution": {
"DependsOn" : "ACMCertificate",
"Type": "AWS::CloudFront::Distribution",
"Properties": {
"DistributionConfig": {
"Origins": [
{
"DomainName": { "Ref": "OriginDomainName" },
"Id": "DeliveryOrigin",
"CustomOriginConfig": {
"HTTPPort": "80",
"HTTPSPort": "443",
"OriginProtocolPolicy": "http-only"
}
}
],
"Enabled": "true",
"Comment": { "Ref": "AWS::StackId" },
"Aliases": [{ "Ref": "DomainName"}],
"DefaultCacheBehavior": {
"TargetOriginId": "DeliveryOrigin",
"SmoothStreaming": "false",
"ForwardedValues": {
"QueryString": "false",
"Cookies": { "Forward": "all" }
},
"ViewerProtocolPolicy": "allow-all"
},
"ViewerCertificate": {
"SslSupportMethod": "sni-only",
"AcmCertificateArn": { "Ref": "ACMCertificate"}
}
}
}
}
},
"Outputs": {
"ACMCertificate": {
"Description": "ACMCertificate ARN",
"Value": { "Ref": "ACMCertificate" }
}
}
}