Template
Add Volcengine CDN certificate renewal runbook
This commit is contained in:
@@ -0,0 +1,34 @@
|
|||||||
|
# Intelligrow 对象存储证书
|
||||||
|
|
||||||
|
不要在本文档记录 AK/SK、私钥、证书包内容、cookie 或长期 token。
|
||||||
|
|
||||||
|
## 账号与工具
|
||||||
|
|
||||||
|
| 平台 | Profile / 账号 | 账号 ID | 用途 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 腾讯云 | 本机 `tccli` 默认配置 | `100040916199` | 申请和下载 TrustAsia DV 免费证书 |
|
||||||
|
| 火山引擎 | `ve ---profile intelligrow` | `2102414529` | Intelligrow TOS 源站 CDN 域名与证书中心 |
|
||||||
|
| 火山引擎 | `ve ---profile miaosi-lingchuang` | `2129210981` | 秒思领创账号,避免与 Intelligrow 混用 |
|
||||||
|
|
||||||
|
火山 AK/SK 放在仓库根目录 `.env` 中,使用账号前缀区分:
|
||||||
|
|
||||||
|
| 前缀 | 说明 |
|
||||||
|
| --- | --- |
|
||||||
|
| `INTELLIGROW_VOLCENGINE_*` | Intelligrow 火山账号 |
|
||||||
|
| `MIAOSILC_VOLCENGINE_*` | 秒思领创火山账号 |
|
||||||
|
|
||||||
|
## TOS/CDN 域名
|
||||||
|
|
||||||
|
| 域名 | 火山 CDN 源站 | 火山项目 | 服务类型 | 当前新证书来源 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| `douyin-video.tos.intelligrow.cn` | `douyin-video.tos-cn-beijing.volces.com` | `default` | `video` | 腾讯云 SSL 证书 `YDC7UTvD`,导入火山为 `cert-967de86ef95a4c37aa4d17f3196981f0` |
|
||||||
|
| `video-archive.tos.intelligrow.cn` | `miaosi-video-archive.tos-cn-beijing.volces.com` | `default` | `video` | 腾讯云 SSL 证书 `YLB5y62J`,导入火山为 `cert-a12b7ec544fc42ea9ae42d33173fd254` |
|
||||||
|
|
||||||
|
## 2026-07-03 维护记录
|
||||||
|
|
||||||
|
| 域名 | 原火山证书 | 新火山证书 | 新证书有效期 | 验证结果 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| `douyin-video.tos.intelligrow.cn` | `cert-3e7c789740704d7993b6d89dbb85076c` | `cert-967de86ef95a4c37aa4d17f3196981f0` | `2026-06-06 08:00:00` 到 `2026-09-04 07:59:59` | CDN `FullDeployed` / `online`,公网 TLS 握手返回新证书 |
|
||||||
|
| `video-archive.tos.intelligrow.cn` | `cert-9f7603a4b19141bb956b69f0da5deb91` | `cert-a12b7ec544fc42ea9ae42d33173fd254` | `2026-06-11 07:00:00` 到 `2026-09-09 06:59:59` | CDN `FullDeployed` / `online`,公网 TLS 握手返回新证书 |
|
||||||
|
|
||||||
|
如果需要回退,只能在旧证书仍未过期且仍存在于火山证书中心时,使用 `ve cdn BatchDeployCert` 重新绑定原火山证书 ID。
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
# 火山 TOS/CDN 证书续期 Runbook
|
||||||
|
|
||||||
|
适用于腾讯云 SSL 自动续期后,需要下载证书并同步到火山引擎证书中心,再绑定到火山 CDN 加速域名的场景。
|
||||||
|
|
||||||
|
## 安全边界
|
||||||
|
|
||||||
|
- 下载证书、上传证书、绑定 CDN 证书都是变更操作,执行前必须确认平台、账号、域名、证书 ID、影响、回退和验证方式。
|
||||||
|
- 不要在命令行参数、聊天、日志或仓库文件里输出私钥。
|
||||||
|
- 证书下载目录必须放在临时目录,完成后清理。
|
||||||
|
- 如果错误输出中出现 AK ID、token、私钥或证书私钥内容,后续回复不得复述具体值,并建议轮换对应凭据。
|
||||||
|
|
||||||
|
## 只读发现
|
||||||
|
|
||||||
|
确认腾讯云账号:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
tccli sts GetCallerIdentity
|
||||||
|
```
|
||||||
|
|
||||||
|
查询腾讯云证书:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
tccli ssl DescribeCertificates --Limit 100 --Offset 0 --SearchKey intelligrow.cn
|
||||||
|
```
|
||||||
|
|
||||||
|
确认火山账号:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
ve sts GetCallerIdentity ---profile intelligrow ---region cn-beijing
|
||||||
|
```
|
||||||
|
|
||||||
|
查询火山 CDN 域名和当前证书:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
ve cdn ListCdnDomains --PageSize 100 ---profile intelligrow ---region cn-beijing
|
||||||
|
ve cdn DescribeCdnConfig --Domain douyin-video.tos.intelligrow.cn ---profile intelligrow ---region cn-beijing
|
||||||
|
ve cdn DescribeCdnConfig --Domain video-archive.tos.intelligrow.cn ---profile intelligrow ---region cn-beijing
|
||||||
|
```
|
||||||
|
|
||||||
|
## 自动化执行
|
||||||
|
|
||||||
|
确认变更后,可用跨平台 Python 脚本执行单个域名的完整流程:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python scripts/update_volcengine_cdn_cert_from_tencent.py \
|
||||||
|
--domain douyin-video.tos.intelligrow.cn \
|
||||||
|
--tencent-certificate-id YDC7UTvD \
|
||||||
|
--volcengine-profile intelligrow \
|
||||||
|
--volcengine-profile-prefix INTELLIGROW
|
||||||
|
|
||||||
|
python scripts/update_volcengine_cdn_cert_from_tencent.py \
|
||||||
|
--domain video-archive.tos.intelligrow.cn \
|
||||||
|
--tencent-certificate-id YLB5y62J \
|
||||||
|
--volcengine-profile intelligrow \
|
||||||
|
--volcengine-profile-prefix INTELLIGROW
|
||||||
|
```
|
||||||
|
|
||||||
|
脚本行为:
|
||||||
|
|
||||||
|
- 使用 `tccli ssl DownloadCertificate` 下载腾讯云证书。
|
||||||
|
- 解包后使用 Nginx 证书链和私钥文件。
|
||||||
|
- 通过 `scripts/import_volcengine_certificate.py` 调用火山证书服务 `ImportCertificate`,避免把私钥放进 `ve` 命令行参数。
|
||||||
|
- 使用 `ve cdn BatchDeployCert` 绑定新证书。
|
||||||
|
- 查询 CDN 配置和域名下发状态。
|
||||||
|
- 默认删除临时证书目录;调试时可加 `--keep-temp`,但调试后必须手动清理。
|
||||||
|
|
||||||
|
## 手工验证
|
||||||
|
|
||||||
|
CDN 配置验证:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
ve cdn ListCdnDomains --Domain douyin-video.tos.intelligrow.cn --ExactMatch true ---profile intelligrow ---region cn-beijing
|
||||||
|
ve cdn DescribeCdnConfig --Domain douyin-video.tos.intelligrow.cn ---profile intelligrow ---region cn-beijing
|
||||||
|
```
|
||||||
|
|
||||||
|
公网 TLS 握手验证:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -c "import socket, ssl; d='douyin-video.tos.intelligrow.cn'; c=ssl.create_default_context(); s=c.wrap_socket(socket.create_connection((d,443), timeout=10), server_hostname=d); print(s.getpeercert()); s.close()"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 回退
|
||||||
|
|
||||||
|
如果新证书绑定后异常,且旧证书仍可用:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
ve cdn BatchDeployCert --Domain <domain> --CertId <old-volcengine-cert-id> ---profile intelligrow ---region cn-beijing
|
||||||
|
```
|
||||||
|
|
||||||
|
回退后重复 CDN 配置和公网 TLS 握手验证。
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Import a local certificate/key pair into Volcengine Certificate Service.
|
||||||
|
|
||||||
|
This script deliberately reads certificate material from files at runtime so
|
||||||
|
private keys do not need to appear in shell arguments.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import datetime as dt
|
||||||
|
import hashlib
|
||||||
|
import hmac
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import urllib.error
|
||||||
|
import urllib.request
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def read_dotenv(path: Path) -> dict[str, str]:
|
||||||
|
values: dict[str, str] = {}
|
||||||
|
for raw_line in path.read_text(encoding="utf-8").splitlines():
|
||||||
|
line = raw_line.strip()
|
||||||
|
if not line or line.startswith("#") or "=" not in line:
|
||||||
|
continue
|
||||||
|
name, value = line.split("=", 1)
|
||||||
|
value = value.strip()
|
||||||
|
if len(value) >= 2 and value[0] == value[-1] and value[0] in {"'", '"'}:
|
||||||
|
value = value[1:-1]
|
||||||
|
values[name.strip()] = value
|
||||||
|
return values
|
||||||
|
|
||||||
|
|
||||||
|
def sha256_hex(text: str) -> str:
|
||||||
|
return hashlib.sha256(text.encode("utf-8")).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def hmac_bytes(key: bytes, text: str) -> bytes:
|
||||||
|
return hmac.new(key, text.encode("utf-8"), hashlib.sha256).digest()
|
||||||
|
|
||||||
|
|
||||||
|
def hmac_hex(key: bytes, text: str) -> str:
|
||||||
|
return hmac.new(key, text.encode("utf-8"), hashlib.sha256).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def sign_headers(
|
||||||
|
*,
|
||||||
|
access_key: str,
|
||||||
|
secret_key: str,
|
||||||
|
region: str,
|
||||||
|
service: str,
|
||||||
|
host: str,
|
||||||
|
method: str,
|
||||||
|
uri: str,
|
||||||
|
query: str,
|
||||||
|
body: str,
|
||||||
|
) -> dict[str, str]:
|
||||||
|
payload_hash = sha256_hex(body)
|
||||||
|
now = dt.datetime.now(dt.UTC)
|
||||||
|
x_date = now.strftime("%Y%m%dT%H%M%SZ")
|
||||||
|
short_date = now.strftime("%Y%m%d")
|
||||||
|
|
||||||
|
canonical_headers = (
|
||||||
|
f"content-type:application/json\n"
|
||||||
|
f"host:{host}\n"
|
||||||
|
f"x-content-sha256:{payload_hash}\n"
|
||||||
|
f"x-date:{x_date}\n"
|
||||||
|
)
|
||||||
|
signed_headers = "content-type;host;x-content-sha256;x-date"
|
||||||
|
canonical_request = "\n".join(
|
||||||
|
[
|
||||||
|
method,
|
||||||
|
uri,
|
||||||
|
query,
|
||||||
|
canonical_headers,
|
||||||
|
signed_headers,
|
||||||
|
payload_hash,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
scope = f"{short_date}/{region}/{service}/request"
|
||||||
|
string_to_sign = "\n".join(
|
||||||
|
[
|
||||||
|
"HMAC-SHA256",
|
||||||
|
x_date,
|
||||||
|
scope,
|
||||||
|
sha256_hex(canonical_request),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Volcengine OpenAPI uses the raw SK as the first HMAC key for this API.
|
||||||
|
k_date = hmac_bytes(secret_key.encode("utf-8"), short_date)
|
||||||
|
k_region = hmac_bytes(k_date, region)
|
||||||
|
k_service = hmac_bytes(k_region, service)
|
||||||
|
k_signing = hmac_bytes(k_service, "request")
|
||||||
|
signature = hmac_hex(k_signing, string_to_sign)
|
||||||
|
|
||||||
|
authorization = (
|
||||||
|
f"HMAC-SHA256 Credential={access_key}/{scope}, "
|
||||||
|
f"SignedHeaders={signed_headers}, Signature={signature}"
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"Authorization": authorization,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Host": host,
|
||||||
|
"X-Content-Sha256": payload_hash,
|
||||||
|
"X-Date": x_date,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def import_certificate(args: argparse.Namespace) -> dict:
|
||||||
|
env = read_dotenv(Path(args.env_path))
|
||||||
|
access_key = env.get(f"{args.profile_prefix}_VOLCENGINE_ACCESS_KEY", "")
|
||||||
|
secret_key = env.get(f"{args.profile_prefix}_VOLCENGINE_SECRET_KEY", "")
|
||||||
|
if not access_key or not secret_key:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Missing {args.profile_prefix}_VOLCENGINE_ACCESS_KEY or "
|
||||||
|
f"{args.profile_prefix}_VOLCENGINE_SECRET_KEY in {args.env_path}"
|
||||||
|
)
|
||||||
|
|
||||||
|
certificate = Path(args.certificate_path).read_text(encoding="utf-8")
|
||||||
|
private_key = Path(args.private_key_path).read_text(encoding="utf-8")
|
||||||
|
body = json.dumps(
|
||||||
|
{
|
||||||
|
"CertificateInfo": {
|
||||||
|
"CertificateChain": certificate,
|
||||||
|
"PrivateKey": private_key,
|
||||||
|
},
|
||||||
|
"ProjectName": args.project_name,
|
||||||
|
"Repeatable": True,
|
||||||
|
"Tag": args.domain,
|
||||||
|
},
|
||||||
|
ensure_ascii=False,
|
||||||
|
separators=(",", ":"),
|
||||||
|
)
|
||||||
|
|
||||||
|
service = "certificate_service"
|
||||||
|
host = "open.volcengineapi.com"
|
||||||
|
query = "Action=ImportCertificate&Version=2024-10-01"
|
||||||
|
headers = sign_headers(
|
||||||
|
access_key=access_key,
|
||||||
|
secret_key=secret_key,
|
||||||
|
region=args.region,
|
||||||
|
service=service,
|
||||||
|
host=host,
|
||||||
|
method="POST",
|
||||||
|
uri="/",
|
||||||
|
query=query,
|
||||||
|
body=body,
|
||||||
|
)
|
||||||
|
|
||||||
|
request = urllib.request.Request(
|
||||||
|
f"https://{host}/?{query}",
|
||||||
|
data=body.encode("utf-8"),
|
||||||
|
headers=headers,
|
||||||
|
method="POST",
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(request, timeout=args.timeout) as response:
|
||||||
|
return json.loads(response.read().decode("utf-8"))
|
||||||
|
except urllib.error.HTTPError as exc:
|
||||||
|
# Do not print Authorization, AK, SK, certificate, or private key.
|
||||||
|
raise RuntimeError(f"Volcengine API request failed with HTTP status {exc.code}") from None
|
||||||
|
|
||||||
|
|
||||||
|
def build_parser() -> argparse.ArgumentParser:
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument("--domain", required=True)
|
||||||
|
parser.add_argument("--certificate-path", required=True)
|
||||||
|
parser.add_argument("--private-key-path", required=True)
|
||||||
|
parser.add_argument("--env-path", default=".env")
|
||||||
|
parser.add_argument("--profile-prefix", default="INTELLIGROW")
|
||||||
|
parser.add_argument("--region", default="cn-beijing")
|
||||||
|
parser.add_argument("--project-name", default="default")
|
||||||
|
parser.add_argument("--timeout", type=int, default=30)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv: list[str] | None = None) -> int:
|
||||||
|
parser = build_parser()
|
||||||
|
args = parser.parse_args(argv)
|
||||||
|
result = import_certificate(args)
|
||||||
|
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Download a Tencent Cloud SSL cert and deploy it to a Volcengine CDN domain."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import ssl
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import zipfile
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import import_volcengine_certificate
|
||||||
|
|
||||||
|
|
||||||
|
def run_json(command: list[str]) -> dict:
|
||||||
|
completed = subprocess.run(
|
||||||
|
command,
|
||||||
|
check=True,
|
||||||
|
text=True,
|
||||||
|
capture_output=True,
|
||||||
|
encoding="utf-8",
|
||||||
|
errors="replace",
|
||||||
|
)
|
||||||
|
return json.loads(completed.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
def run_passthrough(command: list[str]) -> None:
|
||||||
|
subprocess.run(command, check=True)
|
||||||
|
|
||||||
|
|
||||||
|
def find_tccli() -> str:
|
||||||
|
tccli = shutil.which("tccli")
|
||||||
|
if tccli:
|
||||||
|
return tccli
|
||||||
|
|
||||||
|
appdata = os.environ.get("APPDATA")
|
||||||
|
if appdata:
|
||||||
|
fallback = Path(appdata) / "Python" / "Python313" / "Scripts" / "tccli.exe"
|
||||||
|
if fallback.exists():
|
||||||
|
return str(fallback)
|
||||||
|
|
||||||
|
raise RuntimeError("tccli was not found in PATH or the Python313 user Scripts directory")
|
||||||
|
|
||||||
|
|
||||||
|
def first_pem_certificate(bundle_text: str) -> str:
|
||||||
|
begin = "-----BEGIN CERTIFICATE-----"
|
||||||
|
end = "-----END CERTIFICATE-----"
|
||||||
|
start = bundle_text.find(begin)
|
||||||
|
stop = bundle_text.find(end, start)
|
||||||
|
if start == -1 or stop == -1:
|
||||||
|
raise RuntimeError("No PEM certificate block found in bundle")
|
||||||
|
return bundle_text[start : stop + len(end)] + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def decode_leaf_certificate(bundle_path: Path) -> dict[str, str]:
|
||||||
|
leaf_text = first_pem_certificate(bundle_path.read_text(encoding="utf-8"))
|
||||||
|
with tempfile.NamedTemporaryFile("w", encoding="utf-8", suffix=".pem", delete=False) as handle:
|
||||||
|
handle.write(leaf_text)
|
||||||
|
leaf_path = handle.name
|
||||||
|
try:
|
||||||
|
decoded = ssl._ssl._test_decode_cert(leaf_path) # noqa: SLF001 - stdlib has no public equivalent.
|
||||||
|
finally:
|
||||||
|
Path(leaf_path).unlink(missing_ok=True)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"subject": "/".join("=".join(part) for row in decoded.get("subject", []) for part in row),
|
||||||
|
"not_before": decoded.get("notBefore", ""),
|
||||||
|
"not_after": decoded.get("notAfter", ""),
|
||||||
|
"serial_number": decoded.get("serialNumber", ""),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def download_tencent_certificate(tccli: str, cert_id: str, target_dir: Path) -> None:
|
||||||
|
result = run_json([tccli, "ssl", "DownloadCertificate", "--CertificateId", cert_id])
|
||||||
|
content = base64.b64decode(result["Content"])
|
||||||
|
zip_path = target_dir / f"{cert_id}.zip"
|
||||||
|
zip_path.write_bytes(content)
|
||||||
|
with zipfile.ZipFile(zip_path) as archive:
|
||||||
|
archive.extractall(target_dir)
|
||||||
|
zip_path.unlink()
|
||||||
|
|
||||||
|
|
||||||
|
def build_parser() -> argparse.ArgumentParser:
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument("--domain", required=True)
|
||||||
|
parser.add_argument("--tencent-certificate-id", required=True)
|
||||||
|
parser.add_argument("--volcengine-profile", default="intelligrow")
|
||||||
|
parser.add_argument("--volcengine-profile-prefix", default="INTELLIGROW")
|
||||||
|
parser.add_argument("--region", default="cn-beijing")
|
||||||
|
parser.add_argument("--project-name", default="default")
|
||||||
|
parser.add_argument("--env-path", default=".env")
|
||||||
|
parser.add_argument("--keep-temp", action="store_true")
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv: list[str] | None = None) -> int:
|
||||||
|
args = build_parser().parse_args(argv)
|
||||||
|
temp_root = Path(tempfile.mkdtemp(prefix="volc-cert-update-"))
|
||||||
|
try:
|
||||||
|
domain_dir = temp_root / args.domain
|
||||||
|
domain_dir.mkdir()
|
||||||
|
tccli = find_tccli()
|
||||||
|
|
||||||
|
print(f"Downloading Tencent Cloud certificate {args.tencent_certificate_id} for {args.domain}")
|
||||||
|
download_tencent_certificate(tccli, args.tencent_certificate_id, domain_dir)
|
||||||
|
|
||||||
|
certificate_path = domain_dir / "Nginx" / f"1_{args.domain}_bundle.crt"
|
||||||
|
private_key_path = domain_dir / "Nginx" / f"2_{args.domain}.key"
|
||||||
|
if not certificate_path.exists() or not private_key_path.exists():
|
||||||
|
raise RuntimeError(f"Expected Nginx certificate/key files were not found under {domain_dir}")
|
||||||
|
|
||||||
|
cert_info = decode_leaf_certificate(certificate_path)
|
||||||
|
print(json.dumps({"downloaded_certificate": cert_info}, ensure_ascii=False, indent=2))
|
||||||
|
|
||||||
|
import_args = argparse.Namespace(
|
||||||
|
domain=args.domain,
|
||||||
|
certificate_path=str(certificate_path),
|
||||||
|
private_key_path=str(private_key_path),
|
||||||
|
env_path=args.env_path,
|
||||||
|
profile_prefix=args.volcengine_profile_prefix,
|
||||||
|
region=args.region,
|
||||||
|
project_name=args.project_name,
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
import_result = import_volcengine_certificate.import_certificate(import_args)
|
||||||
|
volc_cert_id = import_result.get("Result", {}).get("InstanceId", "")
|
||||||
|
if not volc_cert_id:
|
||||||
|
raise RuntimeError("Volcengine ImportCertificate did not return Result.InstanceId")
|
||||||
|
|
||||||
|
print(json.dumps({"volcengine_certificate_id": volc_cert_id}, ensure_ascii=False, indent=2))
|
||||||
|
run_passthrough(
|
||||||
|
[
|
||||||
|
"ve",
|
||||||
|
"cdn",
|
||||||
|
"BatchDeployCert",
|
||||||
|
"--Domain",
|
||||||
|
args.domain,
|
||||||
|
"--CertId",
|
||||||
|
volc_cert_id,
|
||||||
|
"---profile",
|
||||||
|
args.volcengine_profile,
|
||||||
|
"---region",
|
||||||
|
args.region,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
run_passthrough(
|
||||||
|
[
|
||||||
|
"ve",
|
||||||
|
"cdn",
|
||||||
|
"DescribeCdnConfig",
|
||||||
|
"--Domain",
|
||||||
|
args.domain,
|
||||||
|
"---profile",
|
||||||
|
args.volcengine_profile,
|
||||||
|
"---region",
|
||||||
|
args.region,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
run_passthrough(
|
||||||
|
[
|
||||||
|
"ve",
|
||||||
|
"cdn",
|
||||||
|
"ListCdnDomains",
|
||||||
|
"--Domain",
|
||||||
|
args.domain,
|
||||||
|
"--ExactMatch",
|
||||||
|
"true",
|
||||||
|
"---profile",
|
||||||
|
args.volcengine_profile,
|
||||||
|
"---region",
|
||||||
|
args.region,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"domain": args.domain,
|
||||||
|
"tencent_certificate_id": args.tencent_certificate_id,
|
||||||
|
"volcengine_certificate_id": volc_cert_id,
|
||||||
|
"not_after": cert_info["not_after"],
|
||||||
|
"temp_directory": str(temp_root) if args.keep_temp else "",
|
||||||
|
},
|
||||||
|
ensure_ascii=False,
|
||||||
|
indent=2,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return 0
|
||||||
|
finally:
|
||||||
|
if args.keep_temp:
|
||||||
|
print(f"Kept temporary certificate directory: {temp_root}", file=sys.stderr)
|
||||||
|
else:
|
||||||
|
shutil.rmtree(temp_root, ignore_errors=True)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Reference in New Issue
Block a user