Merge branch 'v2-dev' of https://github.com/certd/certd into v2-dev

This commit is contained in:
xiaojunnuo
2026-07-08 11:51:35 +08:00
35 changed files with 357 additions and 72 deletions
+9
View File
@@ -3,6 +3,15 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.42.2](https://github.com/certd/certd/compare/v1.42.1...v1.42.2) (2026-07-07)
### Bug Fixes
* 修复火山视频点播源站选择不到自定义源站的bug ([0071bcb](https://github.com/certd/certd/commit/0071bcb0e4dd108c86d7ca01820a9f6e6960e440))
* 修复企业模式下弹出邮箱绑定提醒的问题 ([8d9dad9](https://github.com/certd/certd/commit/8d9dad9c82f6f2fd3ab3040068946a33f37145b1))
* 修复AsiaIsp CDN证书重复情况下部署失败的问题 ([c3d6db3](https://github.com/certd/certd/commit/c3d6db3f1ef2f1c897b7989521fe8809dffaded1))
* 修复cname用阿里云校验时报找不到runtimeDepsService的错误 ([072edd7](https://github.com/certd/certd/commit/072edd7affee424ab3411f4d41d338f084d7cac6))
## [1.42.1](https://github.com/certd/certd/compare/v1.42.0...v1.42.1) (2026-07-06)
### Bug Fixes
+9
View File
@@ -3,6 +3,15 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.42.2](https://github.com/certd/certd/compare/v1.42.1...v1.42.2) (2026-07-07)
### Bug Fixes
* 修复火山视频点播源站选择不到自定义源站的bug ([0071bcb](https://github.com/certd/certd/commit/0071bcb0e4dd108c86d7ca01820a9f6e6960e440))
* 修复企业模式下弹出邮箱绑定提醒的问题 ([8d9dad9](https://github.com/certd/certd/commit/8d9dad9c82f6f2fd3ab3040068946a33f37145b1))
* 修复AsiaIsp CDN证书重复情况下部署失败的问题 ([c3d6db3](https://github.com/certd/certd/commit/c3d6db3f1ef2f1c897b7989521fe8809dffaded1))
* 修复cname用阿里云校验时报找不到runtimeDepsService的错误 ([072edd7](https://github.com/certd/certd/commit/072edd7affee424ab3411f4d41d338f084d7cac6))
## [1.42.1](https://github.com/certd/certd/compare/v1.42.0...v1.42.1) (2026-07-06)
### Bug Fixes
+1 -1
View File
@@ -9,5 +9,5 @@
}
},
"npmClient": "pnpm",
"version": "1.42.1"
"version": "1.42.2"
}
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.42.2](https://github.com/publishlab/node-acme-client/compare/v1.42.1...v1.42.2) (2026-07-07)
**Note:** Version bump only for package @certd/acme-client
## [1.42.1](https://github.com/publishlab/node-acme-client/compare/v1.42.0...v1.42.1) (2026-07-06)
**Note:** Version bump only for package @certd/acme-client
+2 -2
View File
@@ -3,7 +3,7 @@
"description": "Simple and unopinionated ACME client",
"private": false,
"author": "nmorsman",
"version": "1.42.1",
"version": "1.42.2",
"type": "module",
"module": "./dist/index.js",
"main": "./dist/index.js",
@@ -18,7 +18,7 @@
"types"
],
"dependencies": {
"@certd/basic": "^1.42.1",
"@certd/basic": "^1.42.2",
"@peculiar/x509": "^1.11.0",
"asn1js": "^3.0.5",
"axios": "^1.9.0",
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.42.2](https://github.com/certd/certd/compare/v1.42.1...v1.42.2) (2026-07-07)
**Note:** Version bump only for package @certd/basic
## [1.42.1](https://github.com/certd/certd/compare/v1.42.0...v1.42.1) (2026-07-06)
**Note:** Version bump only for package @certd/basic
+1 -1
View File
@@ -1 +1 @@
00:18
19:56
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/basic",
"private": false,
"version": "1.42.1",
"version": "1.42.2",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.42.2](https://github.com/certd/certd/compare/v1.42.1...v1.42.2) (2026-07-07)
**Note:** Version bump only for package @certd/pipeline
## [1.42.1](https://github.com/certd/certd/compare/v1.42.0...v1.42.1) (2026-07-06)
**Note:** Version bump only for package @certd/pipeline
+3 -3
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/pipeline",
"private": false,
"version": "1.42.1",
"version": "1.42.2",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -21,8 +21,8 @@
"lint": "eslint --fix"
},
"dependencies": {
"@certd/basic": "^1.42.1",
"@certd/plus-core": "^1.42.1",
"@certd/basic": "^1.42.2",
"@certd/plus-core": "^1.42.2",
"dayjs": "^1.11.7",
"lodash-es": "^4.17.21",
"reflect-metadata": "^0.2.2"
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.42.2](https://github.com/certd/certd/compare/v1.42.1...v1.42.2) (2026-07-07)
**Note:** Version bump only for package @certd/lib-huawei
## [1.42.1](https://github.com/certd/certd/compare/v1.42.0...v1.42.1) (2026-07-06)
**Note:** Version bump only for package @certd/lib-huawei
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/lib-huawei",
"private": false,
"version": "1.42.1",
"version": "1.42.2",
"main": "./dist/bundle.js",
"module": "./dist/bundle.js",
"types": "./dist/d/index.d.ts",
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.42.2](https://github.com/certd/certd/compare/v1.42.1...v1.42.2) (2026-07-07)
**Note:** Version bump only for package @certd/lib-iframe
## [1.42.1](https://github.com/certd/certd/compare/v1.42.0...v1.42.1) (2026-07-06)
**Note:** Version bump only for package @certd/lib-iframe
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/lib-iframe",
"private": false,
"version": "1.42.1",
"version": "1.42.2",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.42.2](https://github.com/certd/certd/compare/v1.42.1...v1.42.2) (2026-07-07)
**Note:** Version bump only for package @certd/jdcloud
## [1.42.1](https://github.com/certd/certd/compare/v1.42.0...v1.42.1) (2026-07-06)
**Note:** Version bump only for package @certd/jdcloud
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/jdcloud",
"version": "1.42.1",
"version": "1.42.2",
"description": "jdcloud openApi sdk",
"main": "./dist/bundle.js",
"module": "./dist/bundle.js",
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.42.2](https://github.com/certd/certd/compare/v1.42.1...v1.42.2) (2026-07-07)
**Note:** Version bump only for package @certd/lib-k8s
## [1.42.1](https://github.com/certd/certd/compare/v1.42.0...v1.42.1) (2026-07-06)
**Note:** Version bump only for package @certd/lib-k8s
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/lib-k8s",
"private": false,
"version": "1.42.1",
"version": "1.42.2",
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -21,7 +21,7 @@
"lint": "eslint --fix"
},
"dependencies": {
"@certd/basic": "^1.42.1",
"@certd/basic": "^1.42.2",
"@kubernetes/client-node": "0.21.0"
},
"devDependencies": {
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.42.2](https://github.com/certd/certd/compare/v1.42.1...v1.42.2) (2026-07-07)
**Note:** Version bump only for package @certd/lib-server
## [1.42.1](https://github.com/certd/certd/compare/v1.42.0...v1.42.1) (2026-07-06)
**Note:** Version bump only for package @certd/lib-server
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/lib-server",
"version": "1.42.1",
"version": "1.42.2",
"description": "midway with flyway, sql upgrade way ",
"private": false,
"type": "module",
@@ -29,11 +29,11 @@
],
"license": "AGPL",
"dependencies": {
"@certd/acme-client": "^1.42.1",
"@certd/basic": "^1.42.1",
"@certd/pipeline": "^1.42.1",
"@certd/plugin-lib": "^1.42.1",
"@certd/plus-core": "^1.42.1",
"@certd/acme-client": "^1.42.2",
"@certd/basic": "^1.42.2",
"@certd/pipeline": "^1.42.2",
"@certd/plugin-lib": "^1.42.2",
"@certd/plus-core": "^1.42.2",
"@midwayjs/cache": "3.14.0",
"@midwayjs/core": "3.20.11",
"@midwayjs/i18n": "3.20.13",
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.42.2](https://github.com/certd/certd/compare/v1.42.1...v1.42.2) (2026-07-07)
**Note:** Version bump only for package @certd/midway-flyway-js
## [1.42.1](https://github.com/certd/certd/compare/v1.42.0...v1.42.1) (2026-07-06)
**Note:** Version bump only for package @certd/midway-flyway-js
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/midway-flyway-js",
"version": "1.42.1",
"version": "1.42.2",
"description": "midway with flyway, sql upgrade way ",
"private": false,
"type": "module",
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.42.2](https://github.com/certd/certd/compare/v1.42.1...v1.42.2) (2026-07-07)
**Note:** Version bump only for package @certd/plugin-cert
## [1.42.1](https://github.com/certd/certd/compare/v1.42.0...v1.42.1) (2026-07-06)
**Note:** Version bump only for package @certd/plugin-cert
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-cert",
"private": false,
"version": "1.42.1",
"version": "1.42.2",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -20,7 +20,7 @@
"lint": "eslint --fix"
},
"dependencies": {
"@certd/plugin-lib": "^1.42.1"
"@certd/plugin-lib": "^1.42.2"
},
"devDependencies": {
"@types/chai": "^4.3.12",
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.42.2](https://github.com/certd/certd/compare/v1.42.1...v1.42.2) (2026-07-07)
**Note:** Version bump only for package @certd/plugin-lib
## [1.42.1](https://github.com/certd/certd/compare/v1.42.0...v1.42.1) (2026-07-06)
### Performance Improvements
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@certd/plugin-lib",
"private": false,
"version": "1.42.1",
"version": "1.42.2",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -17,9 +17,9 @@
"lint": "eslint --fix"
},
"dependencies": {
"@certd/acme-client": "^1.42.1",
"@certd/basic": "^1.42.1",
"@certd/pipeline": "^1.42.1",
"@certd/acme-client": "^1.42.2",
"@certd/basic": "^1.42.2",
"@certd/pipeline": "^1.42.2",
"dayjs": "^1.11.7",
"jszip": "^3.10.1",
"lodash-es": "^4.17.21",
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.42.2](https://github.com/certd/certd/compare/v1.42.1...v1.42.2) (2026-07-07)
### Bug Fixes
* 修复企业模式下弹出邮箱绑定提醒的问题 ([8d9dad9](https://github.com/certd/certd/commit/8d9dad9c82f6f2fd3ab3040068946a33f37145b1))
## [1.42.1](https://github.com/certd/certd/compare/v1.42.0...v1.42.1) (2026-07-06)
### Bug Fixes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/ui-client",
"version": "1.42.1",
"version": "1.42.2",
"private": true,
"scripts": {
"dev": "vite --open",
@@ -105,8 +105,8 @@
"zod-defaults": "^0.1.3"
},
"devDependencies": {
"@certd/lib-iframe": "^1.42.1",
"@certd/pipeline": "^1.42.1",
"@certd/lib-iframe": "^1.42.2",
"@certd/pipeline": "^1.42.2",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3",
"@types/chai": "^4.3.12",
+9
View File
@@ -3,6 +3,15 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.42.2](https://github.com/certd/certd/compare/v1.42.1...v1.42.2) (2026-07-07)
### Bug Fixes
* 修复火山视频点播源站选择不到自定义源站的bug ([0071bcb](https://github.com/certd/certd/commit/0071bcb0e4dd108c86d7ca01820a9f6e6960e440))
* 修复企业模式下弹出邮箱绑定提醒的问题 ([8d9dad9](https://github.com/certd/certd/commit/8d9dad9c82f6f2fd3ab3040068946a33f37145b1))
* 修复AsiaIsp CDN证书重复情况下部署失败的问题 ([c3d6db3](https://github.com/certd/certd/commit/c3d6db3f1ef2f1c897b7989521fe8809dffaded1))
* 修复cname用阿里云校验时报找不到runtimeDepsService的错误 ([072edd7](https://github.com/certd/certd/commit/072edd7affee424ab3411f4d41d338f084d7cac6))
## [1.42.1](https://github.com/certd/certd/compare/v1.42.0...v1.42.1) (2026-07-06)
### Bug Fixes
@@ -102,6 +102,7 @@ input:
sourceStationType:
title: 源站类型
helper: 选择源站类型
value: 1
component:
name: a-select
vModel: value
@@ -110,7 +111,6 @@ input:
label: 点播源站
- value: 2
label: 自定义源站
value: 1
helper: 注意:封面加速域名不支持自定义源站
required: false
order: 0
+14 -14
View File
@@ -1,6 +1,6 @@
{
"name": "@certd/ui-server",
"version": "1.42.1",
"version": "1.42.2",
"description": "fast-server base midway",
"private": true,
"type": "module",
@@ -41,20 +41,20 @@
"lint1": "eslint --fix"
},
"dependencies": {
"@certd/acme-client": "^1.42.1",
"@certd/basic": "^1.42.1",
"@certd/commercial-core": "^1.42.1",
"@certd/acme-client": "^1.42.2",
"@certd/basic": "^1.42.2",
"@certd/commercial-core": "^1.42.2",
"@certd/cv4pve-api-javascript": "^8.4.2",
"@certd/jdcloud": "^1.42.1",
"@certd/lib-huawei": "^1.42.1",
"@certd/lib-k8s": "^1.42.1",
"@certd/lib-server": "^1.42.1",
"@certd/midway-flyway-js": "^1.42.1",
"@certd/pipeline": "^1.42.1",
"@certd/plugin-cert": "^1.42.1",
"@certd/plugin-lib": "^1.42.1",
"@certd/plugin-plus": "^1.42.1",
"@certd/plus-core": "^1.42.1",
"@certd/jdcloud": "^1.42.2",
"@certd/lib-huawei": "^1.42.2",
"@certd/lib-k8s": "^1.42.2",
"@certd/lib-server": "^1.42.2",
"@certd/midway-flyway-js": "^1.42.2",
"@certd/pipeline": "^1.42.2",
"@certd/plugin-cert": "^1.42.2",
"@certd/plugin-lib": "^1.42.2",
"@certd/plugin-plus": "^1.42.2",
"@certd/plus-core": "^1.42.2",
"@koa/cors": "^5.0.0",
"@midwayjs/bootstrap": "3.20.11",
"@midwayjs/cache": "3.14.0",
@@ -1,21 +1,107 @@
// 导入所需的 SDK 模块
import { AwsCNAccess } from "../access.js";
import { CertInfo } from "@certd/plugin-cert";
import { ILogger } from "@certd/basic";
type AwsIAMClientOptions = { access: AwsCNAccess; region: string };
type AwsIAMClientOptions = { access: AwsCNAccess; region: string; logger?: ILogger };
// IAM ListServerCertificates 返回的证书元信息(仅保留本插件用到的字段)
export type ServerCertificateMetadata = {
ServerCertificateName?: string;
ServerCertificateId?: string;
Expiration?: Date | string;
};
/**
* PEM
* 使 lookbehind -----END CERTIFICATE-----
* PEMAWS MalformedCertificate
*/
export function splitCertAndChain(crt: string): { cert: string; chain: string } {
const pemBlocks = crt.split(/(?<=-----END CERTIFICATE-----)/);
const cert = pemBlocks[0].trim();
const chain = pemBlocks.slice(1).join("").trim();
return { cert, chain };
}
/**
* IAM "本次被替换掉"
* distribution
* / IAM
*
* - ServerCertificateId targetCertIds CloudFront
* - excludeCertId
* ServerCertificateName
*/
export function pickReplacedCertNames(params: { metadataList: ServerCertificateMetadata[]; targetCertIds: Set<string> | string[]; excludeCertId?: string }): string[] {
const { metadataList, targetCertIds, excludeCertId } = params;
const targetIdSet = targetCertIds instanceof Set ? targetCertIds : new Set(targetCertIds);
const names = new Set<string>();
for (const metadata of metadataList) {
const certId = metadata.ServerCertificateId;
const certName = metadata.ServerCertificateName;
if (!certId || !certName) {
continue;
}
if (!targetIdSet.has(certId)) {
continue;
}
if (excludeCertId && certId === excludeCertId) {
continue;
}
names.add(certName);
}
return [...names];
}
// CloudFront ViewerCertificate 字段(仅保留本插件用到的字段)
export type ViewerCertificate = {
CloudFrontDefaultCertificate?: boolean;
ACMCertificateArn?: string;
IAMCertificateId?: string;
Certificate?: string;
CertificateSource?: string;
SSLSupportMethod?: string;
MinimumProtocolVersion?: string;
};
/**
* ViewerCertificate 使 IAM
* - CloudFront ACMCertificateArnIAMCertificateIdCloudFrontDefaultCertificate
* IAM CloudFrontDefaultCertificate false ACMCertificateArn
* - Certificate/CertificateSource AWS ACM
* - SSLSupportMethod sni-onlyAWS CloudFront SNI vipIP
* 沿 vip "The parameter ViewerCertificate with the specified SSL support method isn't available in this region"
* - MinimumProtocolVersion 沿
*/
export function buildIamViewerCertificate(params: { oldViewerCertificate?: ViewerCertificate; certId: string }): ViewerCertificate {
const { oldViewerCertificate, certId } = params;
const old = oldViewerCertificate || {};
return {
CloudFrontDefaultCertificate: false,
IAMCertificateId: certId,
SSLSupportMethod: "sni-only",
MinimumProtocolVersion: old.MinimumProtocolVersion || "TLSv1.2_2021",
};
}
export class AwsIAMClient {
options: AwsIAMClientOptions;
access: AwsCNAccess;
region: string;
logger?: ILogger;
constructor(options: AwsIAMClientOptions) {
this.options = options;
this.access = options.access;
this.region = options.region;
this.logger = options.logger;
}
async importCertificate(certInfo: CertInfo, certName: string) {
// 创建 IAM 客户端
const { IAMClient, UploadServerCertificateCommand } = await this.access.importRuntime("@aws-sdk/client-iam");
// 统一创建 IAM 客户端,供上传/查询/删除复用
private async createIamClient() {
const iamModule = await this.access.importRuntime("@aws-sdk/client-iam");
const { IAMClient } = iamModule;
const iamClient = new IAMClient({
region: this.region, // 替换为您的 AWS 区域
credentials: {
@@ -23,20 +109,99 @@ export class AwsIAMClient {
secretAccessKey: this.access.secretAccessKey,
},
});
return { iamClient, iamModule };
}
const cert = certInfo.crt.split("-----END CERTIFICATE-----")[0] + "-----END CERTIFICATE-----";
const chain = certInfo.crt.split("-----END CERTIFICATE-----\n")[1];
async importCertificate(certInfo: CertInfo, certName: string) {
const { iamClient, iamModule } = await this.createIamClient();
const { UploadServerCertificateCommand } = iamModule;
const { cert, chain } = splitCertAndChain(certInfo.crt);
// 构建上传参数
const command = new UploadServerCertificateCommand({
Path: "/cloudfront/",
ServerCertificateName: certName,
CertificateBody: cert,
PrivateKey: certInfo.key,
CertificateChain: chain,
CertificateChain: chain || undefined,
});
const data = await iamClient.send(command);
console.log("Upload successful:", data);
// 返回证书 ID
return data.ServerCertificateMetadata.ServerCertificateId;
try {
const data = await iamClient.send(command);
// 返回证书 ID
return data.ServerCertificateMetadata.ServerCertificateId;
} catch (err) {
const message = err.message || String(err);
const requestId = err.$metadata?.requestId || err.requestId;
console.error(`IAM 调用失败: ${message}, requestId: ${requestId}`);
throw err;
}
}
// 拉取 /cloudfront/ path 下的全部 server certificate 元信息(处理分页)
async listCloudFrontServerCertificates(): Promise<ServerCertificateMetadata[]> {
const { iamClient, iamModule } = await this.createIamClient();
const { ListServerCertificatesCommand } = iamModule;
const metadataList: ServerCertificateMetadata[] = [];
let marker: string | undefined = undefined;
do {
const command = new ListServerCertificatesCommand({
PathPrefix: "/cloudfront/",
Marker: marker,
});
const data: any = await iamClient.send(command);
const pageList: ServerCertificateMetadata[] = data.ServerCertificateMetadataList || [];
metadataList.push(...pageList);
marker = data.IsTruncated ? data.Marker : undefined;
} while (marker);
return metadataList;
}
// 按名称删除 IAM server certificate
async deleteServerCertificate(serverCertificateName: string) {
const { iamClient, iamModule } = await this.createIamClient();
const { DeleteServerCertificateCommand } = iamModule;
const command = new DeleteServerCertificateCommand({
ServerCertificateName: serverCertificateName,
});
await iamClient.send(command);
}
/**
*
* distribution IAM
* CloudFront DeleteConflict
*
*/
async deleteReplacedCerts(params: { oldCertIds: Set<string> | string[]; newCertId?: string }) {
const { oldCertIds, newCertId } = params;
const targetIdSet = oldCertIds instanceof Set ? oldCertIds : new Set(oldCertIds);
if (targetIdSet.size === 0) {
return;
}
const metadataList = await this.listCloudFrontServerCertificates();
const replacedCertNames = pickReplacedCertNames({
metadataList,
targetCertIds: targetIdSet,
excludeCertId: newCertId,
});
if (replacedCertNames.length === 0) {
this.logger?.info("没有需要清理的旧证书");
return;
}
for (const certName of replacedCertNames) {
try {
await this.deleteServerCertificate(certName);
this.logger?.info(`已删除被替换的旧证书: ${certName}`);
} catch (err: any) {
const message = err?.message || String(err);
this.logger?.warn(`删除旧证书失败(可能仍被其他分配引用),已跳过: ${certName}, 原因: ${message}`);
}
}
}
}
@@ -1,7 +1,7 @@
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
import { AwsCNAccess } from "../access.js";
import { AwsIAMClient } from "../libs/aws-iam-client.js";
import { AwsIAMClient, buildIamViewerCertificate } from "../libs/aws-iam-client.js";
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib";
import { AwsCNRegions } from "../constants.js";
@@ -77,10 +77,19 @@ export class AwsCNDeployToCloudFront extends AbstractTaskPlugin {
async execute(): Promise<void> {
const access = await this.getAccess<AwsCNAccess>(this.accessId);
const iamClient = new AwsIAMClient({
access,
region: this.region,
logger: this.logger,
});
// 本次是否真正上传了新证书(cert 为字符串时表示直接使用已有证书ID,不涉及替换过期旧证书)
const uploadedNewCert = typeof this.cert !== "string";
let certId = this.cert as string;
if (typeof this.cert !== "string") {
if (uploadedNewCert) {
//先上传
certId = await this.uploadToIAM(access, this.cert);
certId = await this.uploadToIAM(iamClient, this.cert as CertInfo);
}
//部署到CloudFront
@@ -93,6 +102,9 @@ export class AwsCNDeployToCloudFront extends AbstractTaskPlugin {
},
});
// 记录每个分配部署前引用的旧 IAM 证书ID,部署完成后清理其中已过期的
const oldCertIds = new Set<string>();
// update-distribution
for (const distributionId of this.distributionIds) {
// get-distribution-config
@@ -100,30 +112,61 @@ export class AwsCNDeployToCloudFront extends AbstractTaskPlugin {
Id: distributionId,
});
const configData = await cloudFrontClient.send(getDistributionConfigCommand);
const configData: any = await this.sendCloudFrontCommand(() => cloudFrontClient.send(getDistributionConfigCommand), `获取CloudFront配置(${distributionId})`);
const oldViewerCertificate = configData.DistributionConfig?.ViewerCertificate;
const oldCertId = oldViewerCertificate?.IAMCertificateId;
if (oldCertId) {
oldCertIds.add(oldCertId);
}
// 使用干净的 IAM ViewerCertificate,避免与旧的 ACM/默认证书字段冲突导致 InvalidViewerCertificate
const viewerCertificate = buildIamViewerCertificate({ oldViewerCertificate, certId });
const updateDistributionCommand = new UpdateDistributionCommand({
DistributionConfig: {
...configData.DistributionConfig,
ViewerCertificate: {
...configData.DistributionConfig.ViewerCertificate,
IAMCertificateId: certId,
},
ViewerCertificate: viewerCertificate,
},
Id: distributionId,
IfMatch: configData.ETag,
});
await cloudFrontClient.send(updateDistributionCommand);
await this.sendCloudFrontCommand(() => cloudFrontClient.send(updateDistributionCommand), `更新CloudFront证书(${distributionId})`);
this.logger.info(`部署${distributionId}完成:`);
}
this.logger.info("部署完成");
// 仅当本次上传了新证书时,清理被替换掉的旧证书(无论是否过期);清理失败不影响部署结果
if (uploadedNewCert) {
try {
await iamClient.deleteReplacedCerts({ oldCertIds, newCertId: certId });
} catch (err: any) {
this.logger.warn(`清理旧证书失败,已忽略: ${err?.message || err}`);
}
}
}
private async uploadToIAM(access: AwsCNAccess, cert: CertInfo) {
const acmClient = new AwsIAMClient({
access,
region: this.region,
});
const awsCertID = await acmClient.importCertificate(cert, this.appendTimeSuffix(this.certName));
/**
* CloudFront
* AWS AccessDenied / not authorized
* IAM CloudFront IAM 便 AWS
*/
private async sendCloudFrontCommand<T>(action: () => Promise<T>, actionDesc: string): Promise<T> {
try {
return await action();
} catch (err: any) {
const message = err?.message || String(err);
const isAuthError = err?.name === "AccessDenied" || /not authorized to perform|no identity-based policy/i.test(message);
if (isAuthError) {
const requiredPermissions = ["cloudfront:ListDistributions", "cloudfront:GetDistributionConfig", "cloudfront:UpdateDistribution", "iam:UploadServerCertificate"].join("、");
throw new Error(`${actionDesc}失败:AWS 账号权限不足,请为该 IAM 用户附加 CloudFront 部署所需权限(${requiredPermissions})。原始错误:${message}`);
}
throw err;
}
}
private async uploadToIAM(iamClient: AwsIAMClient, cert: CertInfo) {
const awsCertID = await iamClient.importCertificate(cert, this.appendTimeSuffix(this.certName));
this.logger.info("证书上传成功,id=", awsCertID);
return awsCertID;
}
+1 -1
View File
@@ -1 +1 @@
00:21
20:04
+1 -1
View File
@@ -1 +1 @@
00:35
21:20