修正 Pingora 证书副本归属

拆分 TLS 证书同步脚本的 target owner 与服务用户。

目标证书默认保持 root:genarrative,服务用户只做可读性复核。

更新证书同步测试,覆盖显式 target-user 的本机 apply 场景。
This commit is contained in:
2026-06-17 22:44:10 +08:00
parent 057522fc2e
commit 764f3609d0
2 changed files with 16 additions and 3 deletions
+3
View File
@@ -67,6 +67,7 @@ function assertApplyCopiesToPrivateTarget() {
const result = runSync(fixture, ['--apply'], {
serviceUser: `#${process.getuid?.() ?? 0}`,
serviceGroup: `#${process.getgid?.() ?? 0}`,
targetUser: `#${process.getuid?.() ?? 0}`,
});
assertStatus(result, 0, 'apply 应复制证书到目标目录。');
assertFileContent(fixture.targetCert, 'fixture fullchain\n');
@@ -215,6 +216,8 @@ function runSync(fixture, args = [], options = {}) {
options.serviceUser || `#${process.getuid?.() ?? 0}`,
'--service-group',
options.serviceGroup || `#${process.getgid?.() ?? 0}`,
'--target-user',
options.targetUser || `#${process.getuid?.() ?? 0}`,
'--json',
...args,
]);
+13 -3
View File
@@ -21,6 +21,7 @@ import { userInfo } from 'node:os';
const DEFAULT_SERVICE_USER = 'genarrative';
const DEFAULT_SERVICE_GROUP = 'genarrative';
const DEFAULT_TARGET_USER = 'root';
const DEFAULT_DIRECTORY_MODE = '0750';
const DEFAULT_FILE_MODE = '0640';
@@ -50,7 +51,8 @@ Options:
--target-dir <path> Pingora 私有 TLS 目录,例如 /etc/genarrative/pingora-tls/<host>。
--service-user <user|uid> 目标服务用户,默认 genarrative。
--service-group <group|gid>
目标服务组,默认 genarrative。
目标文件组,默认 genarrative。
--target-user <user|uid> 目标文件 owner,默认 root。
--directory-mode <mode> 目标目录权限,默认 0750。
--file-mode <mode> 证书和私钥权限,默认 0640。
--apply 执行复制;默认只做 dry-run 校验。
@@ -74,6 +76,9 @@ function parseArgs(argv) {
serviceGroup:
process.env.GENARRATIVE_PINGORA_TLS_CERT_SYNC_SERVICE_GROUP ||
DEFAULT_SERVICE_GROUP,
targetUser:
process.env.GENARRATIVE_PINGORA_TLS_CERT_SYNC_TARGET_USER ||
DEFAULT_TARGET_USER,
directoryMode:
process.env.GENARRATIVE_PINGORA_TLS_CERT_SYNC_DIRECTORY_MODE ||
DEFAULT_DIRECTORY_MODE,
@@ -111,6 +116,9 @@ function parseArgs(argv) {
case '--service-group':
result.serviceGroup = requireValue(argv, ++index, arg);
break;
case '--target-user':
result.targetUser = requireValue(argv, ++index, arg);
break;
case '--directory-mode':
result.directoryMode = requireValue(argv, ++index, arg);
break;
@@ -136,6 +144,7 @@ function parseArgs(argv) {
validateSafeAbsoluteDirectoryPath(result.targetDir, '--target-dir');
validateIdentity(result.serviceUser, '--service-user');
validateIdentity(result.serviceGroup, '--service-group');
validateIdentity(result.targetUser, '--target-user');
result.directoryModeNumber = parseMode(
result.directoryMode,
'--directory-mode',
@@ -226,7 +235,7 @@ function run() {
const certTarget = path.join(config.targetDir, 'fullchain.pem');
const keyTarget = path.join(config.targetDir, 'privkey.pem');
const owner = config.apply
? resolveOwner(config.serviceUser, config.serviceGroup)
? resolveOwner(config.targetUser, config.serviceGroup)
: { uid: null, gid: null };
assertNoSymlinkAncestors(config.targetDir, '--target-dir');
@@ -240,10 +249,11 @@ function run() {
mode: config.apply ? 'apply' : 'dry-run',
target: {
directory: config.targetDir,
user: config.serviceUser,
user: config.targetUser,
group: config.serviceGroup,
uid: owner.uid,
gid: owner.gid,
serviceUser: config.serviceUser,
directoryMode: formatMode(config.directoryModeNumber),
fileMode: formatMode(config.fileModeNumber),
},