你提到指南中提到预计会有3个文件,其中包括一个“DigiCertCA.crt”文件;听起来这是针对DigiCert作为您的证书提供商编写的,而不是GoDaddy。
证书
首先,为了确保“f6f65901b1708ae5.crt”包含您请求的证书(并消除任何疑虑),您可以将“server.csr”文件(即证书签名请求)中的数据(例如通用名称(CN)、DNS主题备用名称(SANs)等)与“f6f65901b1708ae5.crt”文件中的数据进行比较。
$ openssl req -noout -text < server.csr
这应该显示关于CSR文件中您域名的详细信息的易读文本。与此相比较:
$ openssl x509 -noout -text < f6f65901b1708ae5.crt
这应该显示类似于易于阅读的文本,其中包含更多的细节/字段。但它们应该大致符合您的期望。请注意,如果您看到类似于以下内容的错误:
注意:
51299:error:0906D06C:PEM routines:PEM_read_bio:no start line:/SourceCache/OpenSSL098/OpenSSL098-52.40.1/src/crypto/pem/pem_lib.c:648:Expecting: TRUSTED CERTIFICATE
那么它建议您的"f6f65901b1708ae5.crt"文件是DER格式,而不是PEM格式。如果不是,则您已经拥有了PEM文件,这是AWS ELBs所期望的。如果您有一个DER格式的证书,可以使用以下方法轻松转换为PEM格式:
$ openssl x509 -in f6f65901b1708ae5.crt -inform DER -out f6f65901b1708ae5.pem -outform PEM
我只是想要详尽说明这一部分。
假设我们现在知道"f6f65901b1708ae5.crt"包含您域名的PEM格式证书,我们已经准备好处理“证书链”部分了。
我查看了GoDaddy的在线证书存储库,看看您提到的"gd_bundle-g2-g1.crt"文件是否存在,并且确实存在。(这些文件可以公开使用,因为它们包含的是供任何人/每个人使用的公共证书。)查看gd_bundle-g2-g1.crt文件,我发现它包含多个证书。这很重要。
看,一个“证书链”是一个文件列表,提供了从你拥有的“f6f65901b1708ae5.crt”证书到受信任的根GoDaddy CA证书的“信任路径”(或“链”)。每个证书都有一个“主题”(它是谁颁发给的)和一个“发行者”(谁颁发的)。这意味着你可以向“后”走,从你的证书到发行者的证书,再到那个证书的发行者的证书,以此类推。这个向后走就是“证书链”。
“gd_bundle-g2-g1.crt”文件包含多个证书的事实意味着该文件包含你需要的证书链。这也意味着你不想这样做:
$ openssl x509 -inform PEM -in gd_bundle-g2-g1.crt > aws_public.pem
因为
openssl x509
只读取指定文件中的第一个证书,而你需要所有证书。
鉴于上述情况,您可能只需要以下内容(确保您的私钥格式为PEM):
$ openssl rsa -in server.key -text > aws_private.pem
接下来,我们假设"f6f65901b1708ae5.crt"已经是PEM格式(如果不是,您知道如何在上面进行转换),而且我们知道"gd_bundle-g2-g1.crt"已经是PEM格式,因此我们现在可以将它们上传到AWS ELB。
AWS ELB
要上传证书和密钥以供ELB使用,请使用以下内容:
$ aws iam upload-server-certificate \
--server-certificate-name redmatterapp_com2 \
--certificate-body file://f6f65901b1708ae5.crt \
--private-key file://aws_private.pem \
--certificate-chain file://gd_bundle-g2-g1.crt \
--path /cloudfront/redmatterapp_com/
请注意,我使用了不同的
--server-certificate-name
,只是为了确保它不会覆盖或冲突您现有的配置。建议您在名称中包含上传证书的日期(或更好的是到期日期),作为提示,告诉未来的自己这个证书是何时添加的,例如“redmatterapp_com-2016-02-18”。
还要注意,如果您
不使用CloudFront,则不应使用
--path
选项。如果您曾经使用CloudFront然后将其删除,我强烈建议您再次执行上述
aws iam upload-server-certificate
命令,只需使用不同的
--server-certificate-name
并且没有
--path
选项(并删除先前的名称)。这可能意味着重新配置任何现有的ELB HTTPS侦听器以使用新的证书名称,但这可能是必要的,因为该
--path
影响SSL处理。
完成上述步骤后,使用 AWS 控制台,您应该能够配置 AWS ELB,在“侦听器”选项卡下点击“编辑”,添加一个名为“https”的侦听器。当添加任何支持 SSL 的侦听器时,您将看到“SSL 证书”列/选项卡下出现一个“更改”链接。点击“更改”,选择“现有证书”按钮。在“证书名称”下拉菜单下,您应该会看到您上面使用的“--server-certificate-name”字符串/标签的条目。选择该条目,然后点击“保存”。现在,对于 AWS ELB 上的该侦听器,连接应该已经正确地配置为浏览器信任的 SSL/TLS 连接。
因此,HTTPS 侦听器配置如下:
- 负载均衡器协议:HTTPS
- 负载均衡器端口:443
- 实例协议:HTTP
- 实例端口:80
- 密码:(默认策略)
- SSL 证书:(
--server-certificate-name
名称)
请注意,您不希望将端口443用作实例端口;如果这样做,那么就意味着您想要从ELB到实例的HTTPS,这通常是不需要的。 (一些安全站点需要此操作,但这是一个不同的主题/存储。)因此,上述配置使ELB处理SSL终止;对于实例上的Node.js服务器,它只会在端口80上接收普通HTTP请求:
client ---> HTTP ---> ELB port 80 ---> HTTP ---> server port 80
client ---> HTTPS --> ELB port 443 --> HTTP ---> server port 80
如果您的服务器需要知道原始请求是HTTP还是HTTPS,请查找AWS ELB将自动添加到请求中的
X-Forwarded-For
(和其他请求标头)
链接。
现在,一旦您配置好ELB,验证其是否正常工作是一个好步骤。首先,您可以使用
openssl s_client
来验证SSL握手是否正常:
$ openssl s_client -connect example.com:443
CONNECTED(00000003)
depth=3 /C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
verify error:num=19:self signed certificate in certificate chain
verify return:0
---
Certificate chain
0 s:/OU=Domain Control Validated/CN=redmatterapp.com
i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certs.godaddy.com/repository//CN=Go Daddy Secure Certificate Authority - G2
1 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certs.godaddy.com/repository//CN=Go Daddy Secure Certificate Authority - G2
i:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./CN=Go Daddy Root Certificate Authority - G2
2 s:/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./CN=Go Daddy Root Certificate Authority - G2
i:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
3 s:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
i:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
---
Server certificate
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
subject=/OU=Domain Control Validated/CN=example.com
issuer=/C=US/ST=Arizona/L=Scottsdale/O=GoDaddy.com, Inc./OU=http://certs.godaddy.com/repository//CN=Go Daddy Secure Certificate Authority - G2
---
No client certificate CA names sent
---
SSL handshake has read 4929 bytes and written 456 bytes
---
New, TLSv1/SSLv3, Cipher is AES128-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : AES128-SHA
...
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
以上显示我们成功完成了SSL握手,您可以看到它显示了带有GoDaddy名称的证书链;“服务器证书”部分应与您加载的“f6f65901b1708ae5.crt” PEM文件匹配。
HTTPS和DNS
现在来测试HTTPS部分;为此,我喜欢使用curl,如下所示:
$ curl -kv https://example.com/
-v
选项会显示更多信息,特别是证书是否与DNS名称匹配;-k
告诉curl
忽略任何证书不匹配或有问题的情况,这样我们就可以看到有关事物的详细信息。
这就需要进行一些额外的配置。如果您在curl
命令(或浏览器)中使用自动生成的ELB DNS名称,则很可能会看到安全警告/问题。为什么?因为HTTPS的一部分是验证您在URL中使用的DNS名称是否与服务器证书中的域名/主机名匹配,可以作为证书中的公共名称(CN),也可以作为DNS主题备用名称(SAN)之一。而您可能没有在向GoDaddy提交证书签名请求(CSR)时包含ELB DNS名称。
这意味着下一步是配置指向AWS ELB名称的DNS CNAME记录,例如:
www.example.com CNAME to aws-elb-1.elb.amazonaws.com
如果您正在使用AWS进行DNS,则可以使用例如Route 53来执行此操作。然后,您可以重试您的curl命令(或浏览器)。
curl -kv https://www.example.com/
另一个需要注意的重要事项(您可以从curl -v输出中看到)是观察
Host
请求头的内容。一些HTTP服务器(即在后端实例上运行的服务器)对那里的值非常挑剔;他们希望
Host
头与其配置中的某些内容匹配,如果不匹配,则可能拒绝请求。
另一个常见的陷阱是:
如果您从ELB收到此响应,则通常意味着您的后端服务器未响应或未能响应ELB健康检查。请仔细检查用于ELB健康检查的端口和路径/ URL是否正确,并且任何防火墙或AWS安全组是否允许ELB与您的实例进行连接。
因此,现在您应该拥有将端口80(HTTP)和端口443(HTTPS)转发到后端实例的ELB。并且您在DNS中为“www.example.com”设置了指向该ELB名称的CNAME记录。还剩下什么?
HTTP重定向
我强烈建议配置您的HTTP服务器,始终将重定向到相同URL的HTTPS等效版本。为什么?
为了保护客户端和服务器之间的数据安全,现在预期使用SSL/TLS。事实上,越来越多的浏览器自动首选HTTPS,并且只会勉强使用HTTP作为备选方案。像Chrome(以及其他浏览器)这样的浏览器希望尽可能避免此HTTP回退,因此他们引入了机制,例如HTTP Strict Transport Security:让您的网站告诉浏览器仅对该网站使用HTTPS,永不使用HTTP。此外,这也是一个更好的营销故事。实际上,如果您不使用HTTPS,则可以预期从客户/用户那里得到负面反应。
使用HTTPS保护您网站的所有流量还可以防止他人使用其DNS名称和ELB。您为“www.example.com”设置了指向“aws-elb-1.elb.amazonaws.com”的CNAME记录。但是,如果我还为“www.evilco.com”创建自己的CNAME,该CNAME也指向相同的“aws-elb-1.elb.amazonaws.com”会怎样呢?访问“www.evilco.com”的人将看到
您的网站,并认为它是我的!
通过强制所有网站流量都使用HTTPS,您可以强制所有HTTPS客户端
验证服务器(即您的“f6f65901b1708ae5.crt”文件)提供的证书是否包含与客户端在其URL中使用的域名
匹配的公共名称(CN)或DNS主题备用名称(SAN)。显然,您的证书不包含“www.evilco.com”的CN或DNS SAN,因此该验证过程将失败,用户会发现有可疑之处。但是,如果您也允许HTTP流量,则可能会发生这种现象,而您查看网站日志时将永远不会知道!
附言
我个人没有使用过AWS证书管理器或CloudFront(因此无法对它们发表评论),但我已经多次使用上述过程,为多个域名的多个证书提供服务。
希望这可以帮到你!