@zincapp/zn-vault-agent 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +701 -0
- package/deploy/logrotate.d/zn-vault-agent +14 -0
- package/deploy/systemd/zn-vault-agent.service +75 -0
- package/dist/commands/certs.d.ts +3 -0
- package/dist/commands/certs.d.ts.map +1 -0
- package/dist/commands/certs.js +369 -0
- package/dist/commands/certs.js.map +1 -0
- package/dist/commands/exec.d.ts +3 -0
- package/dist/commands/exec.d.ts.map +1 -0
- package/dist/commands/exec.js +193 -0
- package/dist/commands/exec.js.map +1 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +234 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/secrets.d.ts +3 -0
- package/dist/commands/secrets.d.ts.map +1 -0
- package/dist/commands/secrets.js +445 -0
- package/dist/commands/secrets.js.map +1 -0
- package/dist/commands/setup.d.ts +9 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +346 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/start.d.ts +3 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +113 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +85 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sync.d.ts +3 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +126 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api.d.ts +104 -0
- package/dist/lib/api.d.ts.map +1 -0
- package/dist/lib/api.js +338 -0
- package/dist/lib/api.js.map +1 -0
- package/dist/lib/config.d.ts +164 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +299 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/deployer.d.ts +22 -0
- package/dist/lib/deployer.d.ts.map +1 -0
- package/dist/lib/deployer.js +407 -0
- package/dist/lib/deployer.js.map +1 -0
- package/dist/lib/health.d.ts +68 -0
- package/dist/lib/health.d.ts.map +1 -0
- package/dist/lib/health.js +216 -0
- package/dist/lib/health.js.map +1 -0
- package/dist/lib/logger.d.ts +38 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +161 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/metrics.d.ts +50 -0
- package/dist/lib/metrics.d.ts.map +1 -0
- package/dist/lib/metrics.js +273 -0
- package/dist/lib/metrics.js.map +1 -0
- package/dist/lib/secret-deployer.d.ts +22 -0
- package/dist/lib/secret-deployer.d.ts.map +1 -0
- package/dist/lib/secret-deployer.js +201 -0
- package/dist/lib/secret-deployer.js.map +1 -0
- package/dist/lib/validation.d.ts +25 -0
- package/dist/lib/validation.d.ts.map +1 -0
- package/dist/lib/validation.js +257 -0
- package/dist/lib/validation.js.map +1 -0
- package/dist/lib/websocket.d.ts +74 -0
- package/dist/lib/websocket.d.ts.map +1 -0
- package/dist/lib/websocket.js +441 -0
- package/dist/lib/websocket.js.map +1 -0
- package/dist/services/api-key-renewal.d.ts +13 -0
- package/dist/services/api-key-renewal.d.ts.map +1 -0
- package/dist/services/api-key-renewal.js +204 -0
- package/dist/services/api-key-renewal.js.map +1 -0
- package/dist/services/npm-auto-update.d.ts +60 -0
- package/dist/services/npm-auto-update.d.ts.map +1 -0
- package/dist/services/npm-auto-update.js +245 -0
- package/dist/services/npm-auto-update.js.map +1 -0
- package/dist/types/update.d.ts +19 -0
- package/dist/types/update.d.ts.map +1 -0
- package/dist/types/update.js +7 -0
- package/dist/types/update.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
[Unit]
|
|
2
|
+
Description=ZN-Vault Certificate Agent
|
|
3
|
+
Documentation=https://github.com/zincapp/zn-vault
|
|
4
|
+
After=network-online.target
|
|
5
|
+
Wants=network-online.target
|
|
6
|
+
|
|
7
|
+
[Service]
|
|
8
|
+
Type=simple
|
|
9
|
+
User=zn-vault-agent
|
|
10
|
+
Group=zn-vault-agent
|
|
11
|
+
|
|
12
|
+
# Working directory
|
|
13
|
+
WorkingDirectory=/var/lib/zn-vault-agent
|
|
14
|
+
|
|
15
|
+
# Main executable
|
|
16
|
+
ExecStart=/usr/local/bin/zn-vault-agent start --health-port 9100
|
|
17
|
+
|
|
18
|
+
# Restart policy
|
|
19
|
+
Restart=always
|
|
20
|
+
RestartSec=5
|
|
21
|
+
StartLimitInterval=60
|
|
22
|
+
StartLimitBurst=5
|
|
23
|
+
|
|
24
|
+
# Environment
|
|
25
|
+
EnvironmentFile=/etc/zn-vault-agent/agent.env
|
|
26
|
+
EnvironmentFile=-/etc/zn-vault-agent/secrets.env
|
|
27
|
+
|
|
28
|
+
# Logging
|
|
29
|
+
StandardOutput=journal
|
|
30
|
+
StandardError=journal
|
|
31
|
+
SyslogIdentifier=zn-vault-agent
|
|
32
|
+
|
|
33
|
+
# Shutdown
|
|
34
|
+
TimeoutStopSec=30
|
|
35
|
+
KillMode=mixed
|
|
36
|
+
KillSignal=SIGTERM
|
|
37
|
+
|
|
38
|
+
# Security hardening
|
|
39
|
+
NoNewPrivileges=true
|
|
40
|
+
ProtectSystem=strict
|
|
41
|
+
ProtectHome=true
|
|
42
|
+
PrivateTmp=true
|
|
43
|
+
PrivateDevices=true
|
|
44
|
+
ProtectKernelTunables=true
|
|
45
|
+
ProtectKernelModules=true
|
|
46
|
+
ProtectControlGroups=true
|
|
47
|
+
RestrictNamespaces=true
|
|
48
|
+
RestrictRealtime=true
|
|
49
|
+
RestrictSUIDSGID=true
|
|
50
|
+
LockPersonality=true
|
|
51
|
+
|
|
52
|
+
# Allow writing certificates and logs
|
|
53
|
+
ReadWritePaths=/etc/ssl/znvault
|
|
54
|
+
ReadWritePaths=/var/lib/zn-vault-agent
|
|
55
|
+
ReadWritePaths=/var/log/zn-vault-agent
|
|
56
|
+
|
|
57
|
+
# Network access
|
|
58
|
+
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
|
|
59
|
+
|
|
60
|
+
# System call filter
|
|
61
|
+
SystemCallFilter=@system-service
|
|
62
|
+
SystemCallFilter=~@privileged @resources
|
|
63
|
+
SystemCallArchitectures=native
|
|
64
|
+
|
|
65
|
+
# Capabilities
|
|
66
|
+
CapabilityBoundingSet=
|
|
67
|
+
AmbientCapabilities=
|
|
68
|
+
|
|
69
|
+
# Resource limits
|
|
70
|
+
MemoryHigh=256M
|
|
71
|
+
MemoryMax=512M
|
|
72
|
+
LimitNOFILE=4096
|
|
73
|
+
|
|
74
|
+
[Install]
|
|
75
|
+
WantedBy=multi-user.target
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certs.d.ts","sourceRoot":"","sources":["../../src/commands/certs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAcpC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsY5D"}
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { addTarget, removeTarget, getTargets, isConfigured, } from '../lib/config.js';
|
|
5
|
+
import { listCertificates, getCertificate } from '../lib/api.js';
|
|
6
|
+
export function registerCertsCommands(program) {
|
|
7
|
+
// List available certificates in vault
|
|
8
|
+
program
|
|
9
|
+
.command('available')
|
|
10
|
+
.description('List certificates available in vault')
|
|
11
|
+
.option('--json', 'Output as JSON')
|
|
12
|
+
.addHelpText('after', `
|
|
13
|
+
Examples:
|
|
14
|
+
zn-vault-agent available # Human-readable list with status
|
|
15
|
+
zn-vault-agent available --json # JSON output for scripting
|
|
16
|
+
`)
|
|
17
|
+
.action(async (options) => {
|
|
18
|
+
if (!isConfigured()) {
|
|
19
|
+
console.error(chalk.red('Not configured. Run: zn-vault-agent login'));
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const spinner = ora('Fetching certificates...').start();
|
|
23
|
+
try {
|
|
24
|
+
const result = await listCertificates();
|
|
25
|
+
spinner.stop();
|
|
26
|
+
if (options.json) {
|
|
27
|
+
console.log(JSON.stringify(result.items, null, 2));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (result.items.length === 0) {
|
|
31
|
+
console.log('No certificates found in vault');
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
console.log();
|
|
35
|
+
console.log(chalk.bold('Available Certificates'));
|
|
36
|
+
console.log();
|
|
37
|
+
const targets = getTargets();
|
|
38
|
+
const configuredIds = new Set(targets.map(t => t.certId));
|
|
39
|
+
for (const cert of result.items) {
|
|
40
|
+
const configured = configuredIds.has(cert.id);
|
|
41
|
+
const status = configured ? chalk.green('✓ configured') : chalk.gray('not configured');
|
|
42
|
+
const expiry = cert.daysUntilExpiry < 30
|
|
43
|
+
? chalk.yellow(`${cert.daysUntilExpiry}d`)
|
|
44
|
+
: `${cert.daysUntilExpiry}d`;
|
|
45
|
+
console.log(` ${cert.id.substring(0, 8)} ${cert.alias.padEnd(25)} ${status}`);
|
|
46
|
+
console.log(` ${chalk.gray(cert.subjectCn)} (expires: ${expiry})`);
|
|
47
|
+
console.log();
|
|
48
|
+
}
|
|
49
|
+
console.log(`Total: ${result.total} certificate(s)`);
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
spinner.fail('Failed to fetch certificates');
|
|
53
|
+
console.error(chalk.red('Error:'), err instanceof Error ? err.message : String(err));
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
// Add a certificate target
|
|
58
|
+
program
|
|
59
|
+
.command('add')
|
|
60
|
+
.description('Add a certificate to sync')
|
|
61
|
+
.option('-c, --cert <id>', 'Certificate ID')
|
|
62
|
+
.option('-n, --name <name>', 'Local name for this certificate')
|
|
63
|
+
.option('--combined <path>', 'Path for combined cert+key file (HAProxy)')
|
|
64
|
+
.option('--cert-file <path>', 'Path for certificate file')
|
|
65
|
+
.option('--key-file <path>', 'Path for private key file')
|
|
66
|
+
.option('--chain-file <path>', 'Path for CA chain file')
|
|
67
|
+
.option('--fullchain-file <path>', 'Path for fullchain file')
|
|
68
|
+
.option('--owner <user:group>', 'File ownership (e.g., haproxy:haproxy)')
|
|
69
|
+
.option('--mode <mode>', 'File permissions (e.g., 0640)')
|
|
70
|
+
.option('--reload-cmd <cmd>', 'Command to reload service')
|
|
71
|
+
.option('--health-cmd <cmd>', 'Health check command after reload')
|
|
72
|
+
.addHelpText('after', `
|
|
73
|
+
Examples:
|
|
74
|
+
# Interactive mode (prompts for all options)
|
|
75
|
+
zn-vault-agent add
|
|
76
|
+
|
|
77
|
+
# HAProxy: combined cert+key file
|
|
78
|
+
zn-vault-agent add --cert $CERT_ID \\
|
|
79
|
+
--name haproxy-frontend \\
|
|
80
|
+
--combined /etc/haproxy/certs/frontend.pem \\
|
|
81
|
+
--owner haproxy:haproxy --mode 0640 \\
|
|
82
|
+
--reload-cmd "systemctl reload haproxy"
|
|
83
|
+
|
|
84
|
+
# Nginx: separate fullchain and key files
|
|
85
|
+
zn-vault-agent add --cert $CERT_ID \\
|
|
86
|
+
--name nginx-api \\
|
|
87
|
+
--fullchain-file /etc/nginx/ssl/api-fullchain.pem \\
|
|
88
|
+
--key-file /etc/nginx/ssl/api.key \\
|
|
89
|
+
--reload-cmd "nginx -t && systemctl reload nginx"
|
|
90
|
+
|
|
91
|
+
# With health check
|
|
92
|
+
zn-vault-agent add --cert $CERT_ID \\
|
|
93
|
+
--name app-server \\
|
|
94
|
+
--combined /etc/ssl/app.pem \\
|
|
95
|
+
--reload-cmd "systemctl restart app" \\
|
|
96
|
+
--health-cmd "curl -sf http://localhost:8080/health"
|
|
97
|
+
`)
|
|
98
|
+
.action(async (options) => {
|
|
99
|
+
if (!isConfigured()) {
|
|
100
|
+
console.error(chalk.red('Not configured. Run: zn-vault-agent login'));
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
// If cert ID not provided, show selection
|
|
104
|
+
let certId = options.cert;
|
|
105
|
+
let certAlias = '';
|
|
106
|
+
if (!certId) {
|
|
107
|
+
const spinner = ora('Fetching certificates...').start();
|
|
108
|
+
const result = await listCertificates();
|
|
109
|
+
spinner.stop();
|
|
110
|
+
if (result.items.length === 0) {
|
|
111
|
+
console.log('No certificates found in vault');
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
const { selectedCert } = await inquirer.prompt([
|
|
115
|
+
{
|
|
116
|
+
type: 'list',
|
|
117
|
+
name: 'selectedCert',
|
|
118
|
+
message: 'Select certificate to add:',
|
|
119
|
+
choices: result.items.map(c => ({
|
|
120
|
+
name: `${c.alias} (${c.subjectCn}) - expires in ${c.daysUntilExpiry}d`,
|
|
121
|
+
value: c.id,
|
|
122
|
+
})),
|
|
123
|
+
},
|
|
124
|
+
]);
|
|
125
|
+
certId = selectedCert;
|
|
126
|
+
certAlias = result.items.find(c => c.id === certId)?.alias || '';
|
|
127
|
+
}
|
|
128
|
+
// Get certificate details
|
|
129
|
+
const spinner = ora('Fetching certificate details...').start();
|
|
130
|
+
const cert = await getCertificate(certId);
|
|
131
|
+
spinner.stop();
|
|
132
|
+
console.log();
|
|
133
|
+
console.log(chalk.bold('Certificate:'), cert.alias);
|
|
134
|
+
console.log(chalk.gray(`Subject: ${cert.subjectCn}`));
|
|
135
|
+
console.log(chalk.gray(`Expires: ${cert.daysUntilExpiry} days`));
|
|
136
|
+
console.log();
|
|
137
|
+
// Gather output configuration
|
|
138
|
+
const answers = await inquirer.prompt([
|
|
139
|
+
{
|
|
140
|
+
type: 'input',
|
|
141
|
+
name: 'name',
|
|
142
|
+
message: 'Local name for this target:',
|
|
143
|
+
default: options.name || cert.alias.replace(/[^a-zA-Z0-9-_]/g, '-'),
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
type: 'list',
|
|
147
|
+
name: 'outputFormat',
|
|
148
|
+
message: 'Output format:',
|
|
149
|
+
choices: [
|
|
150
|
+
{ name: 'Combined (cert+key in one file) - for HAProxy', value: 'combined' },
|
|
151
|
+
{ name: 'Separate files (cert, key, chain)', value: 'separate' },
|
|
152
|
+
{ name: 'Custom', value: 'custom' },
|
|
153
|
+
],
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
type: 'input',
|
|
157
|
+
name: 'combined',
|
|
158
|
+
message: 'Combined file path:',
|
|
159
|
+
when: (ans) => ans.outputFormat === 'combined',
|
|
160
|
+
default: options.combined || `/etc/ssl/${cert.alias}.pem`,
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
type: 'input',
|
|
164
|
+
name: 'certFile',
|
|
165
|
+
message: 'Certificate file path:',
|
|
166
|
+
when: (ans) => ans.outputFormat === 'separate',
|
|
167
|
+
default: options.certFile || `/etc/ssl/certs/${cert.alias}.crt`,
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
type: 'input',
|
|
171
|
+
name: 'keyFile',
|
|
172
|
+
message: 'Private key file path:',
|
|
173
|
+
when: (ans) => ans.outputFormat === 'separate',
|
|
174
|
+
default: options.keyFile || `/etc/ssl/private/${cert.alias}.key`,
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
type: 'input',
|
|
178
|
+
name: 'chainFile',
|
|
179
|
+
message: 'CA chain file path (optional):',
|
|
180
|
+
when: (ans) => ans.outputFormat === 'separate',
|
|
181
|
+
default: options.chainFile || '',
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
type: 'input',
|
|
185
|
+
name: 'owner',
|
|
186
|
+
message: 'File ownership (user:group):',
|
|
187
|
+
default: options.owner || 'root:root',
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
type: 'input',
|
|
191
|
+
name: 'mode',
|
|
192
|
+
message: 'File permissions:',
|
|
193
|
+
default: options.mode || '0640',
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
type: 'input',
|
|
197
|
+
name: 'reloadCmd',
|
|
198
|
+
message: 'Reload command (run after cert update):',
|
|
199
|
+
default: options.reloadCmd || 'systemctl reload haproxy',
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
type: 'input',
|
|
203
|
+
name: 'healthCmd',
|
|
204
|
+
message: 'Health check command (optional):',
|
|
205
|
+
default: options.healthCmd || '',
|
|
206
|
+
},
|
|
207
|
+
]);
|
|
208
|
+
// Build target configuration
|
|
209
|
+
const target = {
|
|
210
|
+
certId,
|
|
211
|
+
name: answers.name,
|
|
212
|
+
outputs: {},
|
|
213
|
+
owner: answers.owner,
|
|
214
|
+
mode: answers.mode,
|
|
215
|
+
reloadCmd: answers.reloadCmd || undefined,
|
|
216
|
+
healthCheckCmd: answers.healthCmd || undefined,
|
|
217
|
+
};
|
|
218
|
+
if (answers.outputFormat === 'combined' || options.combined) {
|
|
219
|
+
target.outputs.combined = answers.combined || options.combined;
|
|
220
|
+
}
|
|
221
|
+
if (answers.certFile || options.certFile) {
|
|
222
|
+
target.outputs.cert = answers.certFile || options.certFile;
|
|
223
|
+
}
|
|
224
|
+
if (answers.keyFile || options.keyFile) {
|
|
225
|
+
target.outputs.key = answers.keyFile || options.keyFile;
|
|
226
|
+
}
|
|
227
|
+
if (answers.chainFile || options.chainFile) {
|
|
228
|
+
target.outputs.chain = answers.chainFile || options.chainFile;
|
|
229
|
+
}
|
|
230
|
+
if (options.fullchainFile) {
|
|
231
|
+
target.outputs.fullchain = options.fullchainFile;
|
|
232
|
+
}
|
|
233
|
+
// Handle custom output
|
|
234
|
+
if (answers.outputFormat === 'custom') {
|
|
235
|
+
const customAnswers = await inquirer.prompt([
|
|
236
|
+
{
|
|
237
|
+
type: 'input',
|
|
238
|
+
name: 'combined',
|
|
239
|
+
message: 'Combined file path (leave empty to skip):',
|
|
240
|
+
default: options.combined || '',
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
type: 'input',
|
|
244
|
+
name: 'cert',
|
|
245
|
+
message: 'Certificate file path (leave empty to skip):',
|
|
246
|
+
default: options.certFile || '',
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
type: 'input',
|
|
250
|
+
name: 'key',
|
|
251
|
+
message: 'Private key file path (leave empty to skip):',
|
|
252
|
+
default: options.keyFile || '',
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
type: 'input',
|
|
256
|
+
name: 'chain',
|
|
257
|
+
message: 'CA chain file path (leave empty to skip):',
|
|
258
|
+
default: options.chainFile || '',
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
type: 'input',
|
|
262
|
+
name: 'fullchain',
|
|
263
|
+
message: 'Fullchain file path (leave empty to skip):',
|
|
264
|
+
default: options.fullchainFile || '',
|
|
265
|
+
},
|
|
266
|
+
]);
|
|
267
|
+
if (customAnswers.combined)
|
|
268
|
+
target.outputs.combined = customAnswers.combined;
|
|
269
|
+
if (customAnswers.cert)
|
|
270
|
+
target.outputs.cert = customAnswers.cert;
|
|
271
|
+
if (customAnswers.key)
|
|
272
|
+
target.outputs.key = customAnswers.key;
|
|
273
|
+
if (customAnswers.chain)
|
|
274
|
+
target.outputs.chain = customAnswers.chain;
|
|
275
|
+
if (customAnswers.fullchain)
|
|
276
|
+
target.outputs.fullchain = customAnswers.fullchain;
|
|
277
|
+
}
|
|
278
|
+
// Save target
|
|
279
|
+
addTarget(target);
|
|
280
|
+
console.log();
|
|
281
|
+
console.log(chalk.green('✓') + ` Certificate target "${answers.name}" added`);
|
|
282
|
+
console.log();
|
|
283
|
+
console.log('Output files:');
|
|
284
|
+
for (const [type, path] of Object.entries(target.outputs)) {
|
|
285
|
+
if (path)
|
|
286
|
+
console.log(` ${type}: ${path}`);
|
|
287
|
+
}
|
|
288
|
+
console.log();
|
|
289
|
+
console.log('Run ' + chalk.cyan('zn-vault-agent sync') + ' to deploy now');
|
|
290
|
+
});
|
|
291
|
+
// List configured targets
|
|
292
|
+
program
|
|
293
|
+
.command('list')
|
|
294
|
+
.description('List configured certificate targets')
|
|
295
|
+
.option('--json', 'Output as JSON')
|
|
296
|
+
.addHelpText('after', `
|
|
297
|
+
Examples:
|
|
298
|
+
zn-vault-agent list # Human-readable list
|
|
299
|
+
zn-vault-agent list --json # JSON output for scripting
|
|
300
|
+
`)
|
|
301
|
+
.action(async (options) => {
|
|
302
|
+
const targets = getTargets();
|
|
303
|
+
if (options.json) {
|
|
304
|
+
console.log(JSON.stringify(targets, null, 2));
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (targets.length === 0) {
|
|
308
|
+
console.log('No certificate targets configured.');
|
|
309
|
+
console.log('Run ' + chalk.cyan('zn-vault-agent add') + ' to add one.');
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
console.log();
|
|
313
|
+
console.log(chalk.bold('Configured Certificate Targets'));
|
|
314
|
+
console.log();
|
|
315
|
+
for (const target of targets) {
|
|
316
|
+
const syncStatus = target.lastSync
|
|
317
|
+
? chalk.green(`synced ${new Date(target.lastSync).toLocaleString()}`)
|
|
318
|
+
: chalk.yellow('not synced');
|
|
319
|
+
console.log(` ${chalk.bold(target.name)}`);
|
|
320
|
+
console.log(` Certificate: ${target.certId.substring(0, 8)}...`);
|
|
321
|
+
console.log(` Status: ${syncStatus}`);
|
|
322
|
+
console.log(` Outputs:`);
|
|
323
|
+
for (const [type, path] of Object.entries(target.outputs)) {
|
|
324
|
+
if (path)
|
|
325
|
+
console.log(` ${type}: ${path}`);
|
|
326
|
+
}
|
|
327
|
+
if (target.reloadCmd) {
|
|
328
|
+
console.log(` Reload: ${target.reloadCmd}`);
|
|
329
|
+
}
|
|
330
|
+
console.log();
|
|
331
|
+
}
|
|
332
|
+
console.log(`Total: ${targets.length} target(s)`);
|
|
333
|
+
});
|
|
334
|
+
// Remove a target
|
|
335
|
+
program
|
|
336
|
+
.command('remove <name>')
|
|
337
|
+
.description('Remove a certificate target')
|
|
338
|
+
.option('-f, --force', 'Skip confirmation')
|
|
339
|
+
.addHelpText('after', `
|
|
340
|
+
Examples:
|
|
341
|
+
zn-vault-agent remove haproxy-frontend # Interactive confirmation
|
|
342
|
+
zn-vault-agent remove haproxy-frontend --force # Skip confirmation
|
|
343
|
+
`)
|
|
344
|
+
.action(async (name, options) => {
|
|
345
|
+
const targets = getTargets();
|
|
346
|
+
const target = targets.find(t => t.name === name || t.certId === name);
|
|
347
|
+
if (!target) {
|
|
348
|
+
console.error(chalk.red(`Target "${name}" not found`));
|
|
349
|
+
process.exit(1);
|
|
350
|
+
}
|
|
351
|
+
if (!options.force) {
|
|
352
|
+
const { confirm } = await inquirer.prompt([
|
|
353
|
+
{
|
|
354
|
+
type: 'confirm',
|
|
355
|
+
name: 'confirm',
|
|
356
|
+
message: `Remove target "${target.name}"?`,
|
|
357
|
+
default: false,
|
|
358
|
+
},
|
|
359
|
+
]);
|
|
360
|
+
if (!confirm) {
|
|
361
|
+
console.log('Cancelled');
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
removeTarget(name);
|
|
366
|
+
console.log(chalk.green('✓') + ` Target "${target.name}" removed`);
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
//# sourceMappingURL=certs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certs.js","sourceRoot":"","sources":["../../src/commands/certs.ts"],"names":[],"mappings":"AACA,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAEL,SAAS,EACT,YAAY,EACZ,UAAU,EACV,YAAY,GAEb,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEjE,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,uCAAuC;IACvC,OAAO;SACJ,OAAO,CAAC,WAAW,CAAC;SACpB,WAAW,CAAC,sCAAsC,CAAC;SACnD,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;SAClC,WAAW,CAAC,OAAO,EAAE;;;;CAIzB,CAAC;SACG,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACxB,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC,CAAC;YACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,OAAO,GAAG,GAAG,CAAC,0BAA0B,CAAC,CAAC,KAAK,EAAE,CAAC;QAExD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;YACxC,OAAO,CAAC,IAAI,EAAE,CAAC;YAEf,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;gBACjB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBACnD,OAAO;YACT,CAAC;YAED,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;gBAC9C,OAAO;YACT,CAAC;YAED,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC;YAClD,OAAO,CAAC,GAAG,EAAE,CAAC;YAEd,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;YAC7B,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;YAE1D,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBAChC,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC9C,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;gBACvF,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,GAAG,EAAE;oBACtC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,eAAe,GAAG,CAAC;oBAC1C,CAAC,CAAC,GAAG,IAAI,CAAC,eAAe,GAAG,CAAC;gBAE/B,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC;gBAChF,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,MAAM,GAAG,CAAC,CAAC;gBAC9E,OAAO,CAAC,GAAG,EAAE,CAAC;YAChB,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,UAAU,MAAM,CAAC,KAAK,iBAAiB,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;YAC7C,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YACrF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,2BAA2B;IAC3B,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,2BAA2B,CAAC;SACxC,MAAM,CAAC,iBAAiB,EAAE,gBAAgB,CAAC;SAC3C,MAAM,CAAC,mBAAmB,EAAE,iCAAiC,CAAC;SAC9D,MAAM,CAAC,mBAAmB,EAAE,2CAA2C,CAAC;SACxE,MAAM,CAAC,oBAAoB,EAAE,2BAA2B,CAAC;SACzD,MAAM,CAAC,mBAAmB,EAAE,2BAA2B,CAAC;SACxD,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,CAAC;SACvD,MAAM,CAAC,yBAAyB,EAAE,yBAAyB,CAAC;SAC5D,MAAM,CAAC,sBAAsB,EAAE,wCAAwC,CAAC;SACxE,MAAM,CAAC,eAAe,EAAE,+BAA+B,CAAC;SACxD,MAAM,CAAC,oBAAoB,EAAE,2BAA2B,CAAC;SACzD,MAAM,CAAC,oBAAoB,EAAE,mCAAmC,CAAC;SACjE,WAAW,CAAC,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;CAyBzB,CAAC;SACG,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACxB,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC,CAAC;YACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,0CAA0C;QAC1C,IAAI,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;QAC1B,IAAI,SAAS,GAAG,EAAE,CAAC;QAEnB,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,OAAO,GAAG,GAAG,CAAC,0BAA0B,CAAC,CAAC,KAAK,EAAE,CAAC;YACxD,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;YACxC,OAAO,CAAC,IAAI,EAAE,CAAC;YAEf,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;gBAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;gBAC7C;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,cAAc;oBACpB,OAAO,EAAE,4BAA4B;oBACrC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;wBAC9B,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,SAAS,kBAAkB,CAAC,CAAC,eAAe,GAAG;wBACtE,KAAK,EAAE,CAAC,CAAC,EAAE;qBACZ,CAAC,CAAC;iBACJ;aACF,CAAC,CAAC;YAEH,MAAM,GAAG,YAAY,CAAC;YACtB,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;QACnE,CAAC;QAED,0BAA0B;QAC1B,MAAM,OAAO,GAAG,GAAG,CAAC,iCAAiC,CAAC,CAAC,KAAK,EAAE,CAAC;QAC/D,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;QAC1C,OAAO,CAAC,IAAI,EAAE,CAAC;QAEf,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,eAAe,OAAO,CAAC,CAAC,CAAC;QACjE,OAAO,CAAC,GAAG,EAAE,CAAC;QAEd,8BAA8B;QAC9B,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;YACpC;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,6BAA6B;gBACtC,OAAO,EAAE,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC;aACpE;YACD;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,cAAc;gBACpB,OAAO,EAAE,gBAAgB;gBACzB,OAAO,EAAE;oBACP,EAAE,IAAI,EAAE,+CAA+C,EAAE,KAAK,EAAE,UAAU,EAAE;oBAC5E,EAAE,IAAI,EAAE,mCAAmC,EAAE,KAAK,EAAE,UAAU,EAAE;oBAChE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;iBACpC;aACF;YACD;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,qBAAqB;gBAC9B,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,KAAK,UAAU;gBAC9C,OAAO,EAAE,OAAO,CAAC,QAAQ,IAAI,YAAY,IAAI,CAAC,KAAK,MAAM;aAC1D;YACD;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,wBAAwB;gBACjC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,KAAK,UAAU;gBAC9C,OAAO,EAAE,OAAO,CAAC,QAAQ,IAAI,kBAAkB,IAAI,CAAC,KAAK,MAAM;aAChE;YACD;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,wBAAwB;gBACjC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,KAAK,UAAU;gBAC9C,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,oBAAoB,IAAI,CAAC,KAAK,MAAM;aACjE;YACD;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,gCAAgC;gBACzC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,KAAK,UAAU;gBAC9C,OAAO,EAAE,OAAO,CAAC,SAAS,IAAI,EAAE;aACjC;YACD;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,OAAO;gBACb,OAAO,EAAE,8BAA8B;gBACvC,OAAO,EAAE,OAAO,CAAC,KAAK,IAAI,WAAW;aACtC;YACD;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,mBAAmB;gBAC5B,OAAO,EAAE,OAAO,CAAC,IAAI,IAAI,MAAM;aAChC;YACD;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,yCAAyC;gBAClD,OAAO,EAAE,OAAO,CAAC,SAAS,IAAI,0BAA0B;aACzD;YACD;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,kCAAkC;gBAC3C,OAAO,EAAE,OAAO,CAAC,SAAS,IAAI,EAAE;aACjC;SACF,CAAC,CAAC;QAEH,6BAA6B;QAC7B,MAAM,MAAM,GAAe;YACzB,MAAM;YACN,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,OAAO,EAAE,EAAE;YACX,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,SAAS;YACzC,cAAc,EAAE,OAAO,CAAC,SAAS,IAAI,SAAS;SAC/C,CAAC;QAEF,IAAI,OAAO,CAAC,YAAY,KAAK,UAAU,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YAC5D,MAAM,CAAC,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;QACjE,CAAC;QACD,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACzC,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;QAC7D,CAAC;QACD,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACvC,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;QAC1D,CAAC;QACD,IAAI,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YAC3C,MAAM,CAAC,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,SAAS,CAAC;QAChE,CAAC;QACD,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;YAC1B,MAAM,CAAC,OAAO,CAAC,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC;QACnD,CAAC;QAED,uBAAuB;QACvB,IAAI,OAAO,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;YACtC,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;gBAC1C;oBACE,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,UAAU;oBAChB,OAAO,EAAE,2CAA2C;oBACpD,OAAO,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE;iBAChC;gBACD;oBACE,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE,8CAA8C;oBACvD,OAAO,EAAE,OAAO,CAAC,QAAQ,IAAI,EAAE;iBAChC;gBACD;oBACE,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,KAAK;oBACX,OAAO,EAAE,8CAA8C;oBACvD,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;iBAC/B;gBACD;oBACE,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,OAAO;oBACb,OAAO,EAAE,2CAA2C;oBACpD,OAAO,EAAE,OAAO,CAAC,SAAS,IAAI,EAAE;iBACjC;gBACD;oBACE,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,WAAW;oBACjB,OAAO,EAAE,4CAA4C;oBACrD,OAAO,EAAE,OAAO,CAAC,aAAa,IAAI,EAAE;iBACrC;aACF,CAAC,CAAC;YAEH,IAAI,aAAa,CAAC,QAAQ;gBAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC;YAC7E,IAAI,aAAa,CAAC,IAAI;gBAAE,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC;YACjE,IAAI,aAAa,CAAC,GAAG;gBAAE,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,aAAa,CAAC,GAAG,CAAC;YAC9D,IAAI,aAAa,CAAC,KAAK;gBAAE,MAAM,CAAC,OAAO,CAAC,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC;YACpE,IAAI,aAAa,CAAC,SAAS;gBAAE,MAAM,CAAC,OAAO,CAAC,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC;QAClF,CAAC;QAED,cAAc;QACd,SAAS,CAAC,MAAM,CAAC,CAAC;QAElB,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,wBAAwB,OAAO,CAAC,IAAI,SAAS,CAAC,CAAC;QAC9E,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAC7B,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1D,IAAI,IAAI;gBAAE,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,IAAI,EAAE,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,gBAAgB,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEL,0BAA0B;IAC1B,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,qCAAqC,CAAC;SAClD,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;SAClC,WAAW,CAAC,OAAO,EAAE;;;;CAIzB,CAAC;SACG,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;QAE7B,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC9C,OAAO;QACT,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;YAClD,OAAO,CAAC,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,cAAc,CAAC,CAAC;YACxE,OAAO;QACT,CAAC;QAED,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,EAAE,CAAC;QAEd,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ;gBAChC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC;gBACrE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YAE/B,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC5C,OAAO,CAAC,GAAG,CAAC,oBAAoB,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;YACpE,OAAO,CAAC,GAAG,CAAC,eAAe,UAAU,EAAE,CAAC,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAC5B,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC1D,IAAI,IAAI;oBAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,KAAK,IAAI,EAAE,CAAC,CAAC;YAClD,CAAC;YACD,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;gBACrB,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;YACjD,CAAC;YACD,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,UAAU,OAAO,CAAC,MAAM,YAAY,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEL,kBAAkB;IAClB,OAAO;SACJ,OAAO,CAAC,eAAe,CAAC;SACxB,WAAW,CAAC,6BAA6B,CAAC;SAC1C,MAAM,CAAC,aAAa,EAAE,mBAAmB,CAAC;SAC1C,WAAW,CAAC,OAAO,EAAE;;;;CAIzB,CAAC;SACG,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;QAC9B,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC;QAEvE,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,IAAI,aAAa,CAAC,CAAC,CAAC;YACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACnB,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;gBACxC;oBACE,IAAI,EAAE,SAAS;oBACf,IAAI,EAAE,SAAS;oBACf,OAAO,EAAE,kBAAkB,MAAM,CAAC,IAAI,IAAI;oBAC1C,OAAO,EAAE,KAAK;iBACf;aACF,CAAC,CAAC;YAEH,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;gBACzB,OAAO;YACT,CAAC;QACH,CAAC;QAED,YAAY,CAAC,IAAI,CAAC,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,YAAY,MAAM,CAAC,IAAI,WAAW,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/commands/exec.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoGpC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoH1D"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// Path: src/commands/exec.ts
|
|
2
|
+
// Exec mode - run a command with secrets as environment variables
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { spawn } from 'node:child_process';
|
|
5
|
+
import { isConfigured } from '../lib/config.js';
|
|
6
|
+
import { getSecret } from '../lib/api.js';
|
|
7
|
+
/**
|
|
8
|
+
* Parse secret mapping from CLI argument
|
|
9
|
+
* Formats:
|
|
10
|
+
* ENV_VAR=alias:secret/path -> entire secret as JSON
|
|
11
|
+
* ENV_VAR=alias:secret/path.key -> specific key from secret
|
|
12
|
+
* ENV_VAR=uuid -> entire secret as JSON
|
|
13
|
+
* ENV_VAR=uuid.key -> specific key from secret
|
|
14
|
+
*/
|
|
15
|
+
function parseSecretMapping(mapping) {
|
|
16
|
+
const eqIndex = mapping.indexOf('=');
|
|
17
|
+
if (eqIndex === -1) {
|
|
18
|
+
throw new Error(`Invalid mapping format: ${mapping}. Expected: ENV_VAR=secret-id[.key]`);
|
|
19
|
+
}
|
|
20
|
+
const envVar = mapping.substring(0, eqIndex);
|
|
21
|
+
let secretPath = mapping.substring(eqIndex + 1);
|
|
22
|
+
if (!envVar || !secretPath) {
|
|
23
|
+
throw new Error(`Invalid mapping format: ${mapping}. Expected: ENV_VAR=secret-id[.key]`);
|
|
24
|
+
}
|
|
25
|
+
// Check if there's a key after the secret ID
|
|
26
|
+
// For alias format: alias:path/to/secret.key
|
|
27
|
+
// For UUID format: uuid.key
|
|
28
|
+
let key;
|
|
29
|
+
if (secretPath.startsWith('alias:')) {
|
|
30
|
+
// Handle alias:path/to/secret.key
|
|
31
|
+
const lastDotIndex = secretPath.lastIndexOf('.');
|
|
32
|
+
if (lastDotIndex > secretPath.indexOf(':') + 1) {
|
|
33
|
+
// There's a dot after the alias prefix
|
|
34
|
+
const potentialKey = secretPath.substring(lastDotIndex + 1);
|
|
35
|
+
// Check if this looks like a key (not a file extension or path segment)
|
|
36
|
+
if (potentialKey && !potentialKey.includes('/')) {
|
|
37
|
+
key = potentialKey;
|
|
38
|
+
secretPath = secretPath.substring(0, lastDotIndex);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
// Handle uuid.key or uuid
|
|
44
|
+
const dotIndex = secretPath.indexOf('.');
|
|
45
|
+
if (dotIndex !== -1) {
|
|
46
|
+
key = secretPath.substring(dotIndex + 1);
|
|
47
|
+
secretPath = secretPath.substring(0, dotIndex);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
envVar,
|
|
52
|
+
secretId: secretPath,
|
|
53
|
+
key,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Fetch secrets and build environment variables
|
|
58
|
+
*/
|
|
59
|
+
async function buildSecretEnv(mappings) {
|
|
60
|
+
const env = {};
|
|
61
|
+
// Group by secretId to minimize API calls
|
|
62
|
+
const secretCache = new Map();
|
|
63
|
+
for (const mapping of mappings) {
|
|
64
|
+
let data = secretCache.get(mapping.secretId);
|
|
65
|
+
if (!data) {
|
|
66
|
+
const secret = await getSecret(mapping.secretId);
|
|
67
|
+
data = secret.data;
|
|
68
|
+
secretCache.set(mapping.secretId, data);
|
|
69
|
+
}
|
|
70
|
+
if (mapping.key) {
|
|
71
|
+
// Get specific key
|
|
72
|
+
const value = data[mapping.key];
|
|
73
|
+
if (value === undefined) {
|
|
74
|
+
throw new Error(`Key "${mapping.key}" not found in secret "${mapping.secretId}"`);
|
|
75
|
+
}
|
|
76
|
+
env[mapping.envVar] = typeof value === 'string' ? value : JSON.stringify(value);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Get entire secret as JSON
|
|
80
|
+
env[mapping.envVar] = JSON.stringify(data);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return env;
|
|
84
|
+
}
|
|
85
|
+
export function registerExecCommand(program) {
|
|
86
|
+
program
|
|
87
|
+
.command('exec')
|
|
88
|
+
.description('Run a command with secrets as environment variables')
|
|
89
|
+
.option('-s, --secret <mapping>', 'Secret mapping (ENV_VAR=secret-id[.key])', (val, acc) => {
|
|
90
|
+
acc.push(val);
|
|
91
|
+
return acc;
|
|
92
|
+
}, [])
|
|
93
|
+
.option('-o, --output <path>', 'Write secrets to env file instead of running command')
|
|
94
|
+
.option('--inherit', 'Inherit current environment variables (default: true)', true)
|
|
95
|
+
.option('--no-inherit', 'Do not inherit current environment variables')
|
|
96
|
+
.argument('[command...]', 'Command to execute')
|
|
97
|
+
.addHelpText('after', `
|
|
98
|
+
Examples:
|
|
99
|
+
# Run node with database password
|
|
100
|
+
zn-vault-agent exec -s DB_PASSWORD=alias:db/prod.password -- node server.js
|
|
101
|
+
|
|
102
|
+
# Multiple secrets
|
|
103
|
+
zn-vault-agent exec \\
|
|
104
|
+
-s DB_HOST=alias:db/prod.host \\
|
|
105
|
+
-s DB_PASSWORD=alias:db/prod.password \\
|
|
106
|
+
-s API_KEY=alias:api/key.value \\
|
|
107
|
+
-- ./start.sh
|
|
108
|
+
|
|
109
|
+
# Export to env file
|
|
110
|
+
zn-vault-agent exec \\
|
|
111
|
+
-s DB_PASSWORD=alias:db/prod.password \\
|
|
112
|
+
--output /tmp/secrets.env
|
|
113
|
+
|
|
114
|
+
# Get entire secret as JSON
|
|
115
|
+
zn-vault-agent exec -s CONFIG=alias:app/config -- node app.js
|
|
116
|
+
`)
|
|
117
|
+
.action(async (command, options) => {
|
|
118
|
+
if (!isConfigured()) {
|
|
119
|
+
console.error(chalk.red('Not configured. Run: zn-vault-agent login'));
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
if (options.secret.length === 0) {
|
|
123
|
+
console.error(chalk.red('At least one --secret mapping is required'));
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
// Parse mappings
|
|
127
|
+
let mappings;
|
|
128
|
+
try {
|
|
129
|
+
mappings = options.secret.map(parseSecretMapping);
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
console.error(chalk.red('Error:'), err instanceof Error ? err.message : String(err));
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
// Fetch secrets
|
|
136
|
+
let secretEnv;
|
|
137
|
+
try {
|
|
138
|
+
secretEnv = await buildSecretEnv(mappings);
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
console.error(chalk.red('Failed to fetch secrets:'), err instanceof Error ? err.message : String(err));
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
// If --output specified, write to file and exit
|
|
145
|
+
if (options.output) {
|
|
146
|
+
const fs = await import('node:fs');
|
|
147
|
+
const content = Object.entries(secretEnv)
|
|
148
|
+
.map(([k, v]) => `${k}="${v.replace(/"/g, '\\"')}"`)
|
|
149
|
+
.join('\n') + '\n';
|
|
150
|
+
fs.writeFileSync(options.output, content, { mode: 0o600 });
|
|
151
|
+
console.log(chalk.green('✓') + ` Secrets written to ${options.output}`);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
// Must have a command to run
|
|
155
|
+
if (command.length === 0) {
|
|
156
|
+
console.error(chalk.red('No command specified. Provide a command after --'));
|
|
157
|
+
console.error('Example: zn-vault-agent exec -s VAR=secret -- ./my-command');
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
// Build environment
|
|
161
|
+
const env = options.inherit
|
|
162
|
+
? { ...process.env, ...secretEnv }
|
|
163
|
+
: secretEnv;
|
|
164
|
+
// Run the command
|
|
165
|
+
const [cmd, ...args] = command;
|
|
166
|
+
const child = spawn(cmd, args, {
|
|
167
|
+
env,
|
|
168
|
+
stdio: 'inherit',
|
|
169
|
+
shell: process.platform === 'win32',
|
|
170
|
+
});
|
|
171
|
+
// Forward signals to child
|
|
172
|
+
const signals = ['SIGINT', 'SIGTERM', 'SIGHUP'];
|
|
173
|
+
for (const signal of signals) {
|
|
174
|
+
process.on(signal, () => {
|
|
175
|
+
child.kill(signal);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
// Exit with child's exit code
|
|
179
|
+
child.on('exit', (code, signal) => {
|
|
180
|
+
if (signal) {
|
|
181
|
+
process.kill(process.pid, signal);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
process.exit(code ?? 0);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
child.on('error', (err) => {
|
|
188
|
+
console.error(chalk.red('Failed to start command:'), err.message);
|
|
189
|
+
process.exit(1);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=exec.js.map
|