申请 SSL 证书上传并部署证书到 CDN 服务流程

这篇文章将介绍我的博客部署 SSL 服务的方法,包括自动化申请 SSL 证书并将证书应用到网站,以及上传并部署证书到 CDN 服务(也就是给网站使用的静态资源也加上 SSL)。

需求与整体设计

对于不同架构的服务和不同需求,部署 SSL 证书的方式也不一样。这里简单介绍下我的网站的技术架构和预期效果以及部署 SSL 的技术方案。

项目整体架构

我的网站域名托管在 DNS Pod,后端服务和前端内容则放在了腾讯云 CVM 上。体积较大的静态资源存储在腾讯云 COS 上并配置 CDN 以进行加速。

预期实现的效果

本着省(kou)钱(men)的原则,我打算用 Let’ s encrypt 提供的免费 SSL 证书服务;但是这个证书有效期很短,只有三个月,需要频繁地换发证书,所以我希望整个证书的签发流程和部署流程是全自动化的,最好是可以定时执行、完全摆脱人工干预的。

因为我想要部署的是一个站群,可能会有多个域名,所以我需要申请一个通配符证书。

CDN 服务也需要部署 SSL 证书,这个证书可以和网站本身共用同一个。所以我希望在为网站签发证书之后,同步为 CDN 部署上去。

SSL 部署流程

没有什么是比 CVM 更适合折腾了,如果有,那也只能是实体机。申请签发 SSL 证书的,显然应该是 CVM 机器。

CVM 完成网站本身证书的签发和部署之后,通过调用 CDN 的 API 来实现证书在 CDN 的部署。

流程实现

整个流程基本上分为三个步骤:SSL 证书的申请、本地部署和 CDN 部署。

SSL 证书的申请

Let’s encrypt 推荐了若干种用于申请证书及部署的客户端,其中 acme.sh 符合我几乎全部的要求。

因为 Let’s encrypt 对于通配符证书要求使用 DNS 验证所有权,而 acme.sh 支持配置 DNS API 进行证书自动化签发;我想偷懒完成定时全自动化签发,而 acme.sh 会在证书签发完成后自动部署并添加证书过期前自动重新申请的定时任务;我希望在证书签发和部署在服务器之后再部署一份到 CDN 上,而 acme.sh 支持自定义部署后执行的 ssh,可以让我自己编写部署到 CDN 的脚本。

需要通过 DNS 验证签发证书,你需要在服务区的环境变量中保存 DNS API 的 ID 和密钥。这里我以 DNS Pod 为例,使用其他 DNS 服务的可以参考 acme.sh 官网文档。

首先需要获取 DNS Pod 的 API ID 和密钥,可以在DNS Pod 管理控制台生成和获取。之后,在 CVM 中键入如下命令,把 DNS Pod 的 API ID 和密钥添加到环境变量:

export DPI_Id="你的 DNS Pod API ID"
export DPI_Key="你的 DNS Pod API Key"

之后,安装 acme.sh 到系统中:

curl  https://get.acme.sh | sh -s email=你的邮箱

安装完成之后,用如下命令签发:

acme.sh --issue -d 你的域名.cn -d *.你的域名.cn --dns dns_dp

这里 -d 参数后面接的是域名,一个证书可以包含若干个域名,也可以包含通配符域名。而 --dns dns_dp 表示使用 DNS 进行域名所有权验证,并且使用的是 DNS Pod 的 API;如果使用的是其他的 DNS 服务,可以看它的官方文档。

SSL 证书的部署

证书签发完成后,可以继续使用 acme.sh 完成部署。部署的工作也会被加入定时任务,到期重新签发之后自动部署。

acme.sh --install-cert -d 你的域名.cn --cert-file /存放/证书/文件/的/绝对路径 --key-file /存放/Key/文件/的/绝对路径 --fullchain-file /存放/完整证书链/文件/的/绝对路径 --reloadcmd "部署证书完成后需要执行的命令"

如果你的证书有多个域名,这里 -d 后只需要填写签发时输入的第一个。存放证书和 Key 的路径按需填写,Nginx 也需要做相应配置:

ssl_certificate /存放/完整证书链/文件/的/绝对路径;
ssl_certificate_key /存放/Key/文件/的/绝对路径;

因为我的 Nginx 配置用的是完整证书链而非单一的证书,所以 --cert-file /存放/证书/文件/的/绝对路径 这个参数是可以不要的。

我需要在重新部署 SSL 证书后重启 Nginx 服务器,所以需要执行的命令有 service nginx restart;因为我需要再把这个证书部署到 CDN 上,所以还需要 python3 /某个路径/deploy.py。综上,这个参数应该填成这样:--reloadcmd "service nginx restart; python3 /某个路径/deploy.py"

部署到 CDN

腾讯云 SSL 和 CDN 提供了 Python SDK,所以可以很方便地写一个把证书部署到 CDN 的脚本。

第一步当然是装 SDK:

pip install tencentcloud-sdk-python

先读取 SSL 证书文件:

full_chain_path = "/存放/完整证书链/文件/的/绝对路径"
private_key_path = "/存放/Key/文件/的/绝对路径"

with open(full_chain_path, “r”) as full_chain_file:
with open(private_key_path, “r”) as private_key_file:
# 进行后面的操作

之后是对腾讯云 API 的操作,你需要获取 APP ID 和 Key,需要从控制台生成。

每次部署完新证书后,我都要删除旧的证书。所以,在上传证书以及部署之前,先保存一个旧证书的列表,以便完成操作之后逐个删除。

from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk
from tencentcloud.ssl.v20191205 import ssl_client, models as ssl_models

# 腾讯云 APP ID 和 Key
secret_id = “你的 APP ID”
secret_key = “你的 APP Key”

ssl_api_address = “ssl.tencentcloudapi.com”
cdn_api_address = “cdn.tencentcloudapi.com”

# 初始化认证
cred = credential.Credential(secret_id, secret_key)
# 初始化客户端
ssl_http_profile = HttpProfile()
ssl_http_profile.endpoint = ssl_api_address
ssl_client_profile = ClientProfile()
ssl_client_profile.httpProfile = ssl_http_profile
ssl_client_instance = ssl_client.SslClient(cred, “”, ssl_client_profile)
# 获取证书列表
req = ssl_models.DescribeCertificatesRequest()
req.from_json_string(json.dumps({}))
resp = ssl_client_instance.DescribeCertificates(req)
certificates = json.loads(resp.to_json_string())[‘Certificates’]

之后是上传证书以及部署到 CDN:

# 将证书上传到腾讯云并获取证书ID
import json, time
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.ssl.v20191205 import ssl_client, models as ssl_models
from tencentcloud.cdn.v20180606 import cdn_client, models as cdn_models

# 腾讯云 APP ID 和 Key
secret_id = “你的 APP ID”
secret_key = “你的 APP Key”

ssl_api_address = “ssl.tencentcloudapi.com”
cdn_api_address = “cdn.tencentcloudapi.com”

# 当天日期,用于证书命名
today = time.strftime(“%Y-%m-%d”, time.localtime())

req = ssl_models.UploadCertificateRequest()
params = {
# 之前打开的证书链文件
“CertificatePublicKey”: full_chain,
# 证书 Key 文件
“CertificatePrivateKey”: private_key,
# 证书命名
“Alias”: today
}
req.from_json_string(json.dumps(params))
resp = ssl_client_instance.UploadCertificate(req)
cert_id = json.loads(resp.to_json_string())[‘CertificateId’]
# 重新初始化客户端
cdn_http_profile = HttpProfile()
cdn_http_profile.endpoint = cdn_api_address
cdn_client_profile = ClientProfile()
cdn_client_profile.httpProfile = cdn_http_profile
cdn_client_instance = cdn_client.CdnClient(cred, “”, cdn_client_profile)
# 将新证书部署到CDN
req = cdn_models.UpdateDomainConfigRequest()
params = {
“Domain”: “你的 CDN 域名”,
“Https”: {
“Switch”: “on”,
“Http2”: “on”,
“CertInfo”: {
“CertId”: cert_id
}
}
}
req.from_json_string(json.dumps(params))
resp = cdn_client_instance.UpdateDomainConfig(req)

因为证书的上传和部署需要一定的时间,这里我们延迟一分钟删除原有证书:

import json, time
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.ssl.v20191205 import ssl_client, models as ssl_models
from tencentcloud.cdn.v20180606 import cdn_client, models as cdn_models

# 腾讯云 APP ID 和 Key
secret_id = “你的 APP ID”
secret_key = “你的 APP Key”

ssl_api_address = “ssl.tencentcloudapi.com”
cdn_api_address = “cdn.tencentcloudapi.com”

time.sleep(60)
for certificate in certificates:
cert_id = certificate[‘CertificateId’]
req = ssl_models.DeleteCertificateRequest()
params = {
“CertificateId”: cert_id
}
req.from_json_string(json.dumps(params))
resp = ssl_client_instance.DeleteCertificate(req)

最后,加一个 trycatch 就是完整代码了:

import json, time
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.ssl.v20191205 import ssl_client, models as ssl_models
from tencentcloud.cdn.v20180606 import cdn_client, models as cdn_models

# 腾讯云 APP ID 和 Key
secret_id = “你的 APP ID”
secret_key = “你的 APP Key”

full_chain_path = “/存放/完整证书链/文件/的/绝对路径”
private_key_path = “/存放/Key/文件/的/绝对路径”

ssl_api_address = “ssl.tencentcloudapi.com”
cdn_api_address = “cdn.tencentcloudapi.com”

with open(full_chain_path, “r”) as full_chain_file:
with open(private_key_path, “r”) as private_key_file:
full_chain = full_chain_file.read()
private_key = private_key_file.read()
# 当天日期,用于证书命名
today = time.strftime(“%Y-%m-%d”, time.localtime())
try:
# 初始化认证
cred = credential.Credential(secret_id, secret_key)
# 初始化客户端
ssl_http_profile = HttpProfile()
ssl_http_profile.endpoint = ssl_api_address
ssl_client_profile = ClientProfile()
ssl_client_profile.httpProfile = ssl_http_profile
ssl_client_instance = ssl_client.SslClient(cred, “”, ssl_client_profile)
# 获取证书列表
req = ssl_models.DescribeCertificatesRequest()
req.from_json_string(json.dumps({}))
resp = ssl_client_instance.DescribeCertificates(req)
certificates = json.loads(resp.to_json_string())[‘Certificates’]
# 将证书上传到腾讯云并获取证书ID
req = ssl_models.UploadCertificateRequest()
params = {
“CertificatePublicKey”: full_chain,
“CertificatePrivateKey”: private_key,
“Alias”: today
}
req.from_json_string(json.dumps(params))
resp = ssl_client_instance.UploadCertificate(req)
cert_id = json.loads(resp.to_json_string())[‘CertificateId’]
# 重新初始化客户端
cdn_http_profile = HttpProfile()
cdn_http_profile.endpoint = cdn_api_address
cdn_client_profile = ClientProfile()
cdn_client_profile.httpProfile = cdn_http_profile
cdn_client_instance = cdn_client.CdnClient(cred, “”, cdn_client_profile)
# 将新证书部署到CDN
req = cdn_models.UpdateDomainConfigRequest()
params = {
“Domain”: “你的 CDN 域名”,
“Https”: {
“Switch”: “on”,
“Http2”: “on”,
“CertInfo”: {
“CertId”: cert_id
}
}
}
req.from_json_string(json.dumps(params))
resp = cdn_client_instance.UpdateDomainConfig(req)
# 延迟一分钟后删除原有证书
time.sleep(60)
for certificate in certificates:
cert_id = certificate[‘CertificateId’]
req = ssl_models.DeleteCertificateRequest()
params = {
“CertificateId”: cert_id
}
req.from_json_string(json.dumps(params))
resp = ssl_client_instance.DeleteCertificate(req)
except TencentCloudSDKException as err:
# 对异常进行处

在 acme.sh 签发证书后,执行这个 Python 脚本,就可以把 CVM 上申请的证书部署到 CDN 服务使用了

 

原创文章,作者:速盾高防cdn,如若转载,请注明出处:https://www.sudun.com/ask/93535.html

(0)
速盾高防cdn's avatar速盾高防cdn
上一篇 2024年7月12日 下午2:44
下一篇 2024年7月17日 下午3:20

相关推荐

  • cdn托管有哪些公司,cdn托管服务提供商

    标题:CDN托管有哪些公司 首段:在当今数字化时代,网站速度和性能对于在线业务至关重要。而内容分发网络(CDN)是一种有效的解决方案,可以加速网站内容的传输,提升用户体验。本文将探…

    2024年5月11日
    0
  • 网络协议驱动互联网

    在分布式系统中,数据通过各种网络协议在网络中传输。作为应用程序开发者,这往往在问题出现之前似乎是一个黑盒子。 在本文中,我们将解释常见网络协议的工作原理,它们在分布式系统中的应用以…

    CDN资讯 2024年4月14日
    0
  • 高防cdn边缘计算

    高防CDN的边缘计算是指利用分布在全球各地的边缘节点(Edge Nodes)来执行计算任务和处理请求,以提高网络性能和响应速度。以下是关于高防CDN边缘计算的一些关键特点和功能: …

    CDN资讯 2024年2月18日
    0
  • cdn加速是什么?cdn加速原理详解

    在今日的世界中,互联网已经与人们的生活密不可分,诸如电商、门户网站、直播、游戏等互联网业务都有着广泛的受众。而在这些服务的背后,都离不开一个重要的角色:CDN。 互联网上的大部分业…

    2024年3月29日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注