前言
前不久,阿里云通知笔者 CDN 的 SSL 证书快到期了,于是笔者就打算新申请一张 1 年的 SSL 证书。
对于免费领取的 SSL 证书,签发后的证书有效期统一变更为 3 个月
结果发现,现在免费的证书只有 3 个月了,跟 Let’s Encrypt 提供的 90 天免费证书一样了。
既然如此,为什么不直接使用 Let’s Encrypt 提供的免费证书呢?
在之前,由于 Let’s Encrypt 只提供最长 90 天的免费证书,为了省点事,选择了阿里云的 1 年期免费证书。
关于 Let’s Encrypt 为什么只提供 90 天的免费证书,详见:Why ninety-day lifetimes for certificates?
最重要的是 Let’s Encrypt 完全免费!
经过一通研究,笔者发现可以通过调用阿里云 OpenAPI 来实现自动化更新 SSL 证书,在此记录一下使用方式。
什么是阿里云 OpenAPI
OpenAPI 是指开放应用程序编程接口(Open Application Programming Interface)的简称。阿里云 OpenAPI 为开发者提供了一系列开放的应用程序接口,使您可以通过这些应用程序接口来方便的管理云上资源、数据和服务等内容。
详见:什么是 OpenAPI
总之,我们可以通过阿里云提供的 OpenAPI,来调用阿里云上的一系列接口,从而管理对应的资源和服务。
获取 AccessKey
在一切开始之前,需要先获取到 AccessKeyId 和 AccessKeySecret。
如果你现在点击 左上角的 AccessKey
管理的话,就会发现,阿里云提示你使用 子用户 AccessKey
在这里,出于安全起见,十分建议使用子用户 AccessKey!
可以前往 子用户管理 页面进行创建。
创建用户的时候记得选上 OpenAPI 调用访问
。
详见:创建 RAM 用户
记得及时保存 AccessKey ID
和 AccessKey Secret
,关掉之后就看不见了。
创建完子用户后还需要给子用户授权。
由于目前只需要管理 CDN,因此这里只给子用户授权 CDN 相关的权限即可。
因为还需要写入域名证书,故需要拿到写入权限,不要选择 只读
权限。
如何使用 OpenAPI 管理 CDN
在调用 OpenAPI 之前,显然需要先知道这个 API 是干什么的,有哪些入参,返回值又是什么样的。
查看 API 文档
所幸,阿里云提供了完善的 API 文档。
详见:阿里云 API 文档
经过一番搜索,就可以看到需要的 API 了。
DescribeDomainCertificateInfo - 查询域名证书信息
和 SetCdnDomainSSLCertificate - 设置CDN域名证书
。一个用于查看当前域名的证书信息,另一个用于设置证书。
查看 API 代码调用示例
点击右上方的 去调用
即可调试相关接口。
在输入输入参数
后,即可点击左侧的 SDK 示例
查看具体的代码。
由于笔者比较喜欢用 TypeScript,所以此处的例子是用 TypeScript 实现的。
读者朋友也可以使用自己喜欢的编程语言进行调用。
阿里云提供了包括 Java、TypeScript、Go、PHP、Python 等多种语言的 SDK,可以选一个喜欢的进行使用。
基于同样的原理,也可以获取到 SetCdnDomainSSLCertificate
的代码逻辑。
封装 API 调用
参考阿里云给出的例子后,稍加改动,就得到了以下代码。
import Cdn20180510, * as $Cdn20180510 from '@alicloud/cdn20180510'
import * as $OpenApi from '@alicloud/openapi-client'
import * as $Util from '@alicloud/tea-util'
export default class Client {
/**
* 使用AK&SK初始化账号Client
* @return Client
* @throws Exception
*/
static createClient(): Cdn20180510 {
// 工程代码泄露可能会导致 AccessKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考。
// 建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378664.html。
const config = new $OpenApi.Config({
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
accessKeyId: process.env['ALIBABA_CLOUD_ACCESS_KEY_ID'],
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
accessKeySecret: process.env['ALIBABA_CLOUD_ACCESS_KEY_SECRET'],
})
// Endpoint 请参考 https://api.aliyun.com/product/Cdn
config.endpoint = 'cdn.aliyuncs.com'
return new Cdn20180510(config)
}
// 查询域名的证书
static async describeDomainCertificateInfoWithOptions(domainName: string) {
const client = Client.createClient()
const describeDomainCertificateInfoRequest = new $Cdn20180510.DescribeDomainCertificateInfoRequest({
domainName,
})
const runtime = new $Util.RuntimeOptions({})
try {
// 复制代码运行请自行打印 API 的返回值
return (await client.describeDomainCertificateInfoWithOptions(describeDomainCertificateInfoRequest, runtime)).body
} catch (error) {
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
// 错误 message
console.error(error?.message)
// 诊断地址
console.error(error?.data?.['Recommend'])
}
}
/**
* 设置域名证书
*
* @author CaoMeiYouRen
* @date 2024-05-22
* @static
* @param domainName 域名
* @param certName 证书名称
* @param SSLPub 证书内容
* @param SSLPri 私钥内容
*/
static async setCdnDomainSSLCertificateWithOptions(domainName: string, certName: string, SSLPub: string, SSLPri: string) {
const client = Client.createClient()
const setCdnDomainSSLCertificateRequest = new $Cdn20180510.SetCdnDomainSSLCertificateRequest({
domainName,
certName,
certType: 'upload',
SSLProtocol: 'on',
SSLPub,
SSLPri,
})
const runtime = new $Util.RuntimeOptions({})
try {
// 复制代码运行请自行打印 API 的返回值
return (await client.setCdnDomainSSLCertificateWithOptions(setCdnDomainSSLCertificateRequest, runtime)).body
} catch (error) {
// 此处仅做打印展示,请谨慎对待异常处理,在工程项目中切勿直接忽略异常。
console.error(error?.message)
// 诊断地址
console.error(error?.data?.['Recommend'])
}
}
}
这里通过设置 ALIBABA_CLOUD_ACCESS_KEY_ID
和 ALIBABA_CLOUD_ACCESS_KEY_SECRET
两个环境变量来进行调用 API,相对安全。
如果需要更安全的方式,可以考虑通过 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378664.html。
实现自动更新 SSL 证书逻辑
最后,再添加一些判断逻辑进去,就是实现了自动更新 SSL 证书,这里是在过期时间小于 31 天的时候就更新证书。
import path from 'path'
import dotenv from 'dotenv'
import dayjs from 'dayjs'
import fs from 'fs-extra'
import CdnClient from './apis/cdn' // './apis/cdn' 文件就是上面的示例。
dotenv.config({ path: ['.env.local', '.env'] })
// 更新 CDN 证书
async function updateCdnCertificate(domainName: string) {
// 域名证书位置
const CDN_SSL_DIR_PATH = process.env.CDN_SSL_DIR_PATH
const certificateInfo = await CdnClient.describeDomainCertificateInfoWithOptions(domainName)
const days = dayjs(certificateInfo.certInfos.certInfo[0].certExpireTime).diff(dayjs(), 'days')
console.log(`域名 NULL 还有 NULL 天过期`)
if (days < 31) { // 如果小于 31 天,更新证书
console.log(`域名 NULL 的证书即将过期,正在更新中`)
const certName = `NULL-${dayjs().format('YYYY-MM-DD')}`
// 此处假定是 Let’s Encrypt 提供的域名证书,公钥是 fullchain.pem,私钥是 privkey.pem。其他类型的证书也类似
const SSLPub = await fs.readFile(path.join(CDN_SSL_DIR_PATH, 'fullchain.pem'), 'utf-8')
const SSLPri = await fs.readFile(path.join(CDN_SSL_DIR_PATH, 'privkey.pem'), 'utf-8')
const certificateResponseBody = await CdnClient.setCdnDomainSSLCertificateWithOptions(domainName, certName, SSLPub, SSLPri)
console.log(JSON.stringify(certificateResponseBody))
console.log
return
}
console.log(`域名 NULL 的证书还未过期,跳过更新`)
}
updateDcdnCertificate('example.com')
最后,把这份代码设置为定时任务,每天执行一遍,即可实现自动更新 SSL 证书!
总结
除了更新 CDN 证书外,阿里云 OpenAPI 自然也可以更新 DCDN 域名证书、管理 DNS 解析、管理图床、管理 WAF 等。
总之,只要是阿里云上提供的服务,基本上都能通过阿里云 OpenAPI 来管理。对自动化来说,是极大的利好。
不过,需要注意的是,也要保管好 AccessKey ID
和 AccessKey Secret
,以免泄露,从而造成损失。
- 本文链接: https://wp.cmyr.ltd/archives/how-to-manage-cdn-through-alibaba-cloud-openapi
- 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
欢迎关注我的其它发布渠道
发表回复
要发表评论,您必须先登录。