@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
package/README.md
ADDED
|
@@ -0,0 +1,701 @@
|
|
|
1
|
+
# ZN-Vault Certificate Agent
|
|
2
|
+
|
|
3
|
+
Real-time certificate distribution agent for ZN-Vault. Automatically syncs TLS certificates from your vault to target servers with zero-downtime deployments.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
### Certificate Sync
|
|
8
|
+
- **Real-time updates**: WebSocket connection for instant certificate rotation
|
|
9
|
+
- **Fallback polling**: Periodic sync when WebSocket is unavailable
|
|
10
|
+
- **Atomic deployments**: Uses temp files and rename for safe updates
|
|
11
|
+
- **Automatic rollback**: Reverts on reload or health check failure
|
|
12
|
+
- **Multiple output formats**: Combined (HAProxy), separate cert/key/chain, fullchain (Nginx)
|
|
13
|
+
|
|
14
|
+
### Secret Sync
|
|
15
|
+
- **File output formats**: `.env`, JSON, YAML, raw value, or custom templates
|
|
16
|
+
- **Automatic sync**: Keep local secret files in sync with vault
|
|
17
|
+
- **Reload hooks**: Run commands after secrets are updated
|
|
18
|
+
|
|
19
|
+
### Exec Mode
|
|
20
|
+
- **Zero-config injection**: Run any command with secrets as environment variables
|
|
21
|
+
- **No file writes**: Secrets exist only in process memory
|
|
22
|
+
- **Signal forwarding**: Graceful shutdown of child processes
|
|
23
|
+
|
|
24
|
+
### General
|
|
25
|
+
- **Prometheus metrics**: Full observability via `/metrics` endpoint
|
|
26
|
+
- **Graceful shutdown**: Completes in-flight deployments before exit
|
|
27
|
+
- **Structured logging**: JSON logs with sensitive field redaction
|
|
28
|
+
- **Auto-updates**: Automatic npm-based updates with graceful restarts
|
|
29
|
+
- **API key auto-renewal**: Automatic rotation before expiry
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
### Option A: npm Install (Recommended)
|
|
34
|
+
|
|
35
|
+
The fastest way to install on Linux servers:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Install globally via npm
|
|
39
|
+
npm install -g @zincapp/zn-vault-agent
|
|
40
|
+
|
|
41
|
+
# Setup systemd service (as root)
|
|
42
|
+
sudo zn-vault-agent setup
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Requirements:** Node.js 18+ must be installed.
|
|
46
|
+
|
|
47
|
+
**What `setup` does:**
|
|
48
|
+
|
|
49
|
+
1. Creates `zn-vault-agent` system user/group
|
|
50
|
+
2. Creates directories: `/etc/zn-vault-agent/`, `/var/lib/zn-vault-agent/`, `/var/log/zn-vault-agent/`
|
|
51
|
+
3. Installs systemd service (enabled but not started)
|
|
52
|
+
4. Creates config template at `/etc/zn-vault-agent/agent.env`
|
|
53
|
+
|
|
54
|
+
**Install specific version or channel:**
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm install -g @zincapp/zn-vault-agent@1.3.0 # Specific version
|
|
58
|
+
npm install -g @zincapp/zn-vault-agent@beta # Beta channel
|
|
59
|
+
npm install -g @zincapp/zn-vault-agent@next # Development
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
After installation, configure and start:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# 1. Configure the agent
|
|
66
|
+
zn-vault-agent login --url https://vault.example.com \
|
|
67
|
+
--tenant my-tenant --api-key znv_abc123...
|
|
68
|
+
|
|
69
|
+
# 2. Add certificate to sync
|
|
70
|
+
zn-vault-agent certs add <cert-id> \
|
|
71
|
+
--name "haproxy-frontend" \
|
|
72
|
+
--combined /etc/haproxy/certs/frontend.pem \
|
|
73
|
+
--reload "systemctl reload haproxy"
|
|
74
|
+
|
|
75
|
+
# 3. Start service
|
|
76
|
+
sudo systemctl start zn-vault-agent
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Option B: Using znvault CLI
|
|
80
|
+
|
|
81
|
+
If you already have the `znvault` CLI installed:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Configure CLI (if not already done)
|
|
85
|
+
znvault config set url https://vault.example.com
|
|
86
|
+
znvault login -u admin -p 'password'
|
|
87
|
+
|
|
88
|
+
# Initialize agent config (uses CLI credentials)
|
|
89
|
+
znvault agent init
|
|
90
|
+
|
|
91
|
+
# Add a certificate to sync
|
|
92
|
+
znvault agent add <cert-id> \
|
|
93
|
+
--name "haproxy-frontend" \
|
|
94
|
+
--combined /etc/haproxy/certs/frontend.pem \
|
|
95
|
+
--reload "systemctl reload haproxy"
|
|
96
|
+
|
|
97
|
+
# Test sync (one-time)
|
|
98
|
+
znvault agent sync
|
|
99
|
+
|
|
100
|
+
# Start the daemon
|
|
101
|
+
znvault agent start
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Option C: Build from Source
|
|
105
|
+
|
|
106
|
+
For development or customization:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Build from source
|
|
110
|
+
cd zn-vault-agent
|
|
111
|
+
npm install
|
|
112
|
+
npm run build
|
|
113
|
+
|
|
114
|
+
# Install system-wide (as root)
|
|
115
|
+
sudo ./deploy/install.sh
|
|
116
|
+
|
|
117
|
+
# Configure
|
|
118
|
+
sudo vim /etc/zn-vault-agent/config.json
|
|
119
|
+
|
|
120
|
+
# Start
|
|
121
|
+
zn-vault-agent start --health-port 9100
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Authentication
|
|
125
|
+
|
|
126
|
+
The agent supports two authentication methods. **API key authentication is strongly recommended** for production deployments.
|
|
127
|
+
|
|
128
|
+
### API Key Authentication (Recommended)
|
|
129
|
+
|
|
130
|
+
API keys are more secure than passwords because:
|
|
131
|
+
- They can be scoped to only the permissions the agent needs
|
|
132
|
+
- They can be restricted by IP address
|
|
133
|
+
- They don't require storing user passwords
|
|
134
|
+
- They can be rotated independently of user credentials
|
|
135
|
+
|
|
136
|
+
#### Required Permissions
|
|
137
|
+
|
|
138
|
+
The agent needs only **two permissions** to function:
|
|
139
|
+
|
|
140
|
+
| Permission | Description |
|
|
141
|
+
|------------|-------------|
|
|
142
|
+
| `certificate:read:metadata` | View certificate metadata (expiry, fingerprint) |
|
|
143
|
+
| `certificate:read:value` | Decrypt and download certificate data |
|
|
144
|
+
|
|
145
|
+
#### Creating an API Key
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# 1. Login to vault as admin
|
|
149
|
+
TOKEN=$(curl -sk -X POST https://vault.example.com/auth/login \
|
|
150
|
+
-H "Content-Type: application/json" \
|
|
151
|
+
-d '{"username":"admin","password":"..."}' | jq -r '.accessToken')
|
|
152
|
+
|
|
153
|
+
# 2. Create a limited-scope API key for the agent
|
|
154
|
+
curl -sk -X POST https://vault.example.com/auth/api-keys \
|
|
155
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
156
|
+
-H "Content-Type: application/json" \
|
|
157
|
+
-d '{
|
|
158
|
+
"name": "cert-agent-prod-server1",
|
|
159
|
+
"expiresInDays": 365,
|
|
160
|
+
"scope": "limited",
|
|
161
|
+
"allowedPermissions": [
|
|
162
|
+
"certificate:read:metadata",
|
|
163
|
+
"certificate:read:value"
|
|
164
|
+
],
|
|
165
|
+
"ipAllowlist": ["10.0.0.0/8"]
|
|
166
|
+
}'
|
|
167
|
+
|
|
168
|
+
# Response includes the API key (shown only once!)
|
|
169
|
+
# {
|
|
170
|
+
# "key": "znv_abc123...",
|
|
171
|
+
# "message": "⚠️ Save this key - it will not be shown again!"
|
|
172
|
+
# }
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
#### Via Dashboard
|
|
176
|
+
|
|
177
|
+
In the ZN-Vault dashboard:
|
|
178
|
+
1. Navigate to **Settings** → **API Keys**
|
|
179
|
+
2. Click **Create API Key**
|
|
180
|
+
3. Set name: `cert-agent-<hostname>`
|
|
181
|
+
4. Set scope: **Limited**
|
|
182
|
+
5. Select permissions: `certificate:read:metadata`, `certificate:read:value`
|
|
183
|
+
6. Add IP allowlist if desired
|
|
184
|
+
7. Set expiration (max 365 days recommended)
|
|
185
|
+
8. **Save the key immediately** - it won't be shown again!
|
|
186
|
+
|
|
187
|
+
#### Security Best Practices
|
|
188
|
+
|
|
189
|
+
1. **Use limited scope**: Only grant the two required permissions
|
|
190
|
+
2. **Add IP allowlist**: Restrict to your server's IP or network CIDR
|
|
191
|
+
3. **Set expiration**: Use 365 days max, the agent will auto-renew
|
|
192
|
+
4. **One key per server**: Create unique keys for each agent instance
|
|
193
|
+
5. **Store securely**: Use `secrets.env` with `0600` permissions
|
|
194
|
+
|
|
195
|
+
#### Automatic API Key Renewal
|
|
196
|
+
|
|
197
|
+
The agent automatically renews API keys before they expire:
|
|
198
|
+
|
|
199
|
+
- **Check frequency**: Every 24 hours
|
|
200
|
+
- **Renewal threshold**: 30 days before expiry
|
|
201
|
+
- **What happens**:
|
|
202
|
+
1. Agent checks key expiration via `GET /auth/api-keys/self`
|
|
203
|
+
2. If expiring within 30 days, calls `POST /auth/api-keys/self/rotate`
|
|
204
|
+
3. New key is saved atomically to config file
|
|
205
|
+
4. Old key is immediately invalidated
|
|
206
|
+
|
|
207
|
+
**Log output during renewal:**
|
|
208
|
+
```
|
|
209
|
+
{"level":"info","msg":"API key status","expiresInDays":25,"isExpiringSoon":true}
|
|
210
|
+
{"level":"info","msg":"API key expiring soon, initiating rotation"}
|
|
211
|
+
{"level":"info","msg":"API key rotated successfully","newPrefix":"znv_abc1"}
|
|
212
|
+
{"level":"info","msg":"Config file updated with new API key"}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Note**: The renewal service only runs when the daemon is active. For environments where the daemon runs intermittently, consider checking key status via `znvault agent status` and rotating manually if needed.
|
|
216
|
+
|
|
217
|
+
### Password Authentication (Development Only)
|
|
218
|
+
|
|
219
|
+
Password auth stores credentials in the config file. **Not recommended for production.**
|
|
220
|
+
|
|
221
|
+
```json
|
|
222
|
+
{
|
|
223
|
+
"auth": {
|
|
224
|
+
"username": "agent-user",
|
|
225
|
+
"password": "..."
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Connection Modes
|
|
231
|
+
|
|
232
|
+
The agent supports two connection modes. **WebSocket is recommended** for production deployments.
|
|
233
|
+
|
|
234
|
+
### WebSocket Mode (Recommended)
|
|
235
|
+
|
|
236
|
+
WebSocket provides real-time push notifications when certificates or secrets are rotated:
|
|
237
|
+
|
|
238
|
+
```json
|
|
239
|
+
{
|
|
240
|
+
"websocket": true,
|
|
241
|
+
"pollInterval": 3600
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**Benefits:**
|
|
246
|
+
- **Instant updates**: Receives certificate/secret changes immediately
|
|
247
|
+
- **Lower latency**: No waiting for poll interval
|
|
248
|
+
- **Efficient**: Single persistent connection vs repeated HTTP requests
|
|
249
|
+
- **Disconnect alerts**: Server monitors connection health and can alert on disconnect
|
|
250
|
+
|
|
251
|
+
**When WebSocket is unavailable**, the agent falls back to polling automatically.
|
|
252
|
+
|
|
253
|
+
### Polling Mode
|
|
254
|
+
|
|
255
|
+
Polling periodically checks for updates via HTTP requests:
|
|
256
|
+
|
|
257
|
+
```json
|
|
258
|
+
{
|
|
259
|
+
"pollInterval": 3600
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Use polling when:
|
|
264
|
+
- WebSocket connections are blocked by firewall
|
|
265
|
+
- Updates are infrequent and immediate sync isn't critical
|
|
266
|
+
- Minimizing persistent connections is required
|
|
267
|
+
|
|
268
|
+
### Recommended Configuration
|
|
269
|
+
|
|
270
|
+
For most deployments, enable both WebSocket and polling as fallback:
|
|
271
|
+
|
|
272
|
+
```json
|
|
273
|
+
{
|
|
274
|
+
"vaultUrl": "https://vault.example.com",
|
|
275
|
+
"tenantId": "my-tenant",
|
|
276
|
+
"auth": {
|
|
277
|
+
"apiKey": "znv_abc123..."
|
|
278
|
+
},
|
|
279
|
+
"websocket": true,
|
|
280
|
+
"pollInterval": 3600,
|
|
281
|
+
"targets": [...]
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Configuration
|
|
286
|
+
|
|
287
|
+
Both `znvault agent` CLI and the standalone daemon share the same config file.
|
|
288
|
+
|
|
289
|
+
### Config File Locations
|
|
290
|
+
|
|
291
|
+
| Context | Location |
|
|
292
|
+
|---------|----------|
|
|
293
|
+
| System (root) | `/etc/zn-vault-agent/config.json` |
|
|
294
|
+
| User | `~/.config/zn-vault-agent/config.json` |
|
|
295
|
+
|
|
296
|
+
### Config Format
|
|
297
|
+
|
|
298
|
+
```json
|
|
299
|
+
{
|
|
300
|
+
"vaultUrl": "https://vault.example.com",
|
|
301
|
+
"tenantId": "my-tenant",
|
|
302
|
+
"auth": {
|
|
303
|
+
"apiKey": "znv_abc123..."
|
|
304
|
+
},
|
|
305
|
+
"targets": [
|
|
306
|
+
{
|
|
307
|
+
"certId": "uuid-of-certificate",
|
|
308
|
+
"name": "haproxy-frontend",
|
|
309
|
+
"outputs": {
|
|
310
|
+
"combined": "/etc/haproxy/certs/frontend.pem"
|
|
311
|
+
},
|
|
312
|
+
"owner": "haproxy:haproxy",
|
|
313
|
+
"mode": "0640",
|
|
314
|
+
"reloadCmd": "systemctl reload haproxy",
|
|
315
|
+
"healthCheckCmd": "curl -sf http://localhost:8080/health"
|
|
316
|
+
}
|
|
317
|
+
],
|
|
318
|
+
"pollInterval": 3600,
|
|
319
|
+
"insecure": false
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Environment Variables
|
|
324
|
+
|
|
325
|
+
Environment variables override config file values:
|
|
326
|
+
|
|
327
|
+
| Variable | Description |
|
|
328
|
+
|----------|-------------|
|
|
329
|
+
| `ZNVAULT_URL` | Vault server URL |
|
|
330
|
+
| `ZNVAULT_TENANT_ID` | Tenant ID |
|
|
331
|
+
| `ZNVAULT_API_KEY` | API key (preferred) |
|
|
332
|
+
| `ZNVAULT_USERNAME` | Username for password auth |
|
|
333
|
+
| `ZNVAULT_PASSWORD` | Password for password auth |
|
|
334
|
+
| `ZNVAULT_INSECURE` | Skip TLS verification (`true`/`false`) |
|
|
335
|
+
| `ZNVAULT_AGENT_CONFIG_DIR` | Custom config directory |
|
|
336
|
+
| `LOG_LEVEL` | Log level: `trace`, `debug`, `info`, `warn`, `error` |
|
|
337
|
+
| `LOG_FILE` | Optional log file path |
|
|
338
|
+
|
|
339
|
+
### Output Formats
|
|
340
|
+
|
|
341
|
+
| Output | Description | Use Case |
|
|
342
|
+
|--------|-------------|----------|
|
|
343
|
+
| `combined` | cert + key + chain | HAProxy |
|
|
344
|
+
| `cert` | Certificate only | General |
|
|
345
|
+
| `key` | Private key only | General |
|
|
346
|
+
| `chain` | CA chain certificates | General |
|
|
347
|
+
| `fullchain` | cert + chain | Nginx |
|
|
348
|
+
|
|
349
|
+
## Commands
|
|
350
|
+
|
|
351
|
+
### Standalone Agent (`zn-vault-agent`)
|
|
352
|
+
|
|
353
|
+
| Command | Description |
|
|
354
|
+
|---------|-------------|
|
|
355
|
+
| `start` | Start the daemon |
|
|
356
|
+
| `login` | Configure vault credentials |
|
|
357
|
+
| `add <cert-id>` | Add a certificate to sync |
|
|
358
|
+
| `remove <cert-id>` | Remove a certificate |
|
|
359
|
+
| `list` | List configured certificates |
|
|
360
|
+
| `sync` | Manual one-time sync |
|
|
361
|
+
| `status` | Show sync status |
|
|
362
|
+
| `secret add <id>` | Add a secret to sync |
|
|
363
|
+
| `secret remove <name>` | Remove a secret target |
|
|
364
|
+
| `secret list` | List configured secrets |
|
|
365
|
+
| `secret sync` | Sync all secrets |
|
|
366
|
+
| `exec` | Run command with secrets as env vars |
|
|
367
|
+
| `setup` | Install systemd service (requires root) |
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
zn-vault-agent start [options]
|
|
371
|
+
|
|
372
|
+
Options:
|
|
373
|
+
-v, --verbose Enable debug logging
|
|
374
|
+
--health-port <port> Enable health/metrics HTTP server
|
|
375
|
+
--validate Validate config before starting
|
|
376
|
+
--auto-update Enable automatic updates
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
## Secret Sync
|
|
380
|
+
|
|
381
|
+
Sync secrets from vault to local files in various formats.
|
|
382
|
+
|
|
383
|
+
> **Note**: Requires a user with `secret:read:value` permission. Admin users cannot decrypt secrets (separation of duties). See [GUIDE.md](docs/GUIDE.md#required-permissions) for role setup.
|
|
384
|
+
|
|
385
|
+
### Add a Secret Target
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
# Sync to .env file
|
|
389
|
+
zn-vault-agent secret add alias:db/credentials \
|
|
390
|
+
--format env \
|
|
391
|
+
--output /etc/myapp/secrets.env \
|
|
392
|
+
--reload "systemctl restart myapp"
|
|
393
|
+
|
|
394
|
+
# Sync to JSON file
|
|
395
|
+
zn-vault-agent secret add alias:app/config \
|
|
396
|
+
--format json \
|
|
397
|
+
--output /etc/myapp/config.json
|
|
398
|
+
|
|
399
|
+
# Extract single value
|
|
400
|
+
zn-vault-agent secret add alias:api/key \
|
|
401
|
+
--format raw \
|
|
402
|
+
--key apiKey \
|
|
403
|
+
--output /etc/myapp/api-key.txt
|
|
404
|
+
|
|
405
|
+
# Use template
|
|
406
|
+
zn-vault-agent secret add alias:db/prod \
|
|
407
|
+
--format template \
|
|
408
|
+
--template /etc/myapp/config.tmpl \
|
|
409
|
+
--output /etc/myapp/config.yml
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Output Formats
|
|
413
|
+
|
|
414
|
+
| Format | Description | Example Output |
|
|
415
|
+
|--------|-------------|----------------|
|
|
416
|
+
| `env` | Environment file | `DB_HOST="localhost"` |
|
|
417
|
+
| `json` | JSON object | `{"host": "localhost"}` |
|
|
418
|
+
| `yaml` | YAML document | `host: localhost` |
|
|
419
|
+
| `raw` | Single value (requires `--key`) | `localhost` |
|
|
420
|
+
| `template` | Custom template with `{{ key }}` placeholders | (based on template) |
|
|
421
|
+
|
|
422
|
+
### Sync Secrets
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
# Sync all configured secrets
|
|
426
|
+
zn-vault-agent secret sync
|
|
427
|
+
|
|
428
|
+
# Sync specific target
|
|
429
|
+
zn-vault-agent secret sync --name db-credentials
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Exec Mode
|
|
433
|
+
|
|
434
|
+
Run any command with secrets injected as environment variables. Secrets never touch disk.
|
|
435
|
+
|
|
436
|
+
> **Note**: Same permission requirements as Secret Sync - requires `secret:read:value` permission.
|
|
437
|
+
|
|
438
|
+
### Basic Usage
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
# Single secret
|
|
442
|
+
zn-vault-agent exec \
|
|
443
|
+
-s DB_PASSWORD=alias:db/prod.password \
|
|
444
|
+
-- node server.js
|
|
445
|
+
|
|
446
|
+
# Multiple secrets
|
|
447
|
+
zn-vault-agent exec \
|
|
448
|
+
-s DB_HOST=alias:db/prod.host \
|
|
449
|
+
-s DB_PASSWORD=alias:db/prod.password \
|
|
450
|
+
-s API_KEY=alias:api/key.value \
|
|
451
|
+
-- ./start.sh
|
|
452
|
+
|
|
453
|
+
# Entire secret as JSON
|
|
454
|
+
zn-vault-agent exec \
|
|
455
|
+
-s CONFIG=alias:app/config \
|
|
456
|
+
-- node -e "console.log(JSON.parse(process.env.CONFIG))"
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### Mapping Format
|
|
460
|
+
|
|
461
|
+
```
|
|
462
|
+
ENV_VAR=secret-id[.key]
|
|
463
|
+
|
|
464
|
+
Examples:
|
|
465
|
+
DB_PASS=alias:db/credentials.password # Specific key
|
|
466
|
+
DB_PASS=abc123.password # UUID with key
|
|
467
|
+
CONFIG=alias:app/config # Entire secret as JSON
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### Export to File
|
|
471
|
+
|
|
472
|
+
```bash
|
|
473
|
+
# Write secrets to env file (without running a command)
|
|
474
|
+
zn-vault-agent exec \
|
|
475
|
+
-s DB_PASSWORD=alias:db/prod.password \
|
|
476
|
+
-o /tmp/secrets.env
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
### CLI Commands (`znvault agent`)
|
|
480
|
+
|
|
481
|
+
The CLI provides the same configuration commands:
|
|
482
|
+
|
|
483
|
+
| Command | Description |
|
|
484
|
+
|---------|-------------|
|
|
485
|
+
| `znvault agent init` | Initialize agent config (uses CLI credentials) |
|
|
486
|
+
| `znvault agent add <cert-id>` | Add a certificate to sync |
|
|
487
|
+
| `znvault agent remove <id-or-name>` | Remove a certificate |
|
|
488
|
+
| `znvault agent list` | List configured certificates |
|
|
489
|
+
| `znvault agent sync` | One-time sync (for testing) |
|
|
490
|
+
| `znvault agent start` | Start the daemon (invokes `zn-vault-agent`) |
|
|
491
|
+
| `znvault agent status` | Show sync status |
|
|
492
|
+
|
|
493
|
+
## Health & Metrics
|
|
494
|
+
|
|
495
|
+
When started with `--health-port`, the agent exposes:
|
|
496
|
+
|
|
497
|
+
| Endpoint | Description |
|
|
498
|
+
|----------|-------------|
|
|
499
|
+
| `/health` | JSON health status |
|
|
500
|
+
| `/ready` | Readiness probe (Kubernetes) |
|
|
501
|
+
| `/live` | Liveness probe |
|
|
502
|
+
| `/metrics` | Prometheus metrics |
|
|
503
|
+
|
|
504
|
+
### Prometheus Metrics
|
|
505
|
+
|
|
506
|
+
```
|
|
507
|
+
# Counters
|
|
508
|
+
znvault_agent_sync_total{status,cert_name}
|
|
509
|
+
znvault_agent_sync_failures_total{cert_name,reason}
|
|
510
|
+
znvault_agent_websocket_reconnects_total
|
|
511
|
+
znvault_agent_api_requests_total{method,status}
|
|
512
|
+
|
|
513
|
+
# Gauges
|
|
514
|
+
znvault_agent_connected
|
|
515
|
+
znvault_agent_certs_tracked
|
|
516
|
+
znvault_agent_last_sync_timestamp{cert_name}
|
|
517
|
+
znvault_agent_cert_expiry_days{cert_id,cert_name}
|
|
518
|
+
|
|
519
|
+
# Histograms
|
|
520
|
+
znvault_agent_sync_duration_seconds{cert_name}
|
|
521
|
+
znvault_agent_api_request_duration_seconds{method}
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
## Systemd Installation
|
|
525
|
+
|
|
526
|
+
```bash
|
|
527
|
+
# Install via npm
|
|
528
|
+
npm install -g @zincapp/zn-vault-agent
|
|
529
|
+
|
|
530
|
+
# Setup systemd (as root)
|
|
531
|
+
sudo zn-vault-agent setup
|
|
532
|
+
|
|
533
|
+
# Configure
|
|
534
|
+
zn-vault-agent login --url https://vault.example.com \
|
|
535
|
+
--tenant my-tenant --api-key znv_abc123...
|
|
536
|
+
|
|
537
|
+
# Enable and start
|
|
538
|
+
sudo systemctl enable --now zn-vault-agent
|
|
539
|
+
|
|
540
|
+
# View logs
|
|
541
|
+
journalctl -u zn-vault-agent -f
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
### File Locations
|
|
545
|
+
|
|
546
|
+
| Path | Description |
|
|
547
|
+
|------|-------------|
|
|
548
|
+
| `/usr/local/bin/zn-vault-agent` | Agent binary |
|
|
549
|
+
| `/etc/zn-vault-agent/config.json` | Main configuration |
|
|
550
|
+
| `/etc/zn-vault-agent/secrets.env` | Sensitive credentials |
|
|
551
|
+
| `/var/lib/zn-vault-agent/` | State directory |
|
|
552
|
+
| `/var/log/zn-vault-agent/` | Log files |
|
|
553
|
+
|
|
554
|
+
## Troubleshooting
|
|
555
|
+
|
|
556
|
+
### Agent won't start
|
|
557
|
+
|
|
558
|
+
```bash
|
|
559
|
+
# Check configuration
|
|
560
|
+
zn-vault-agent start --validate
|
|
561
|
+
|
|
562
|
+
# Check logs
|
|
563
|
+
journalctl -u zn-vault-agent -n 50
|
|
564
|
+
|
|
565
|
+
# Test vault connectivity
|
|
566
|
+
curl -k https://your-vault/v1/health
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
### Certificates not syncing
|
|
570
|
+
|
|
571
|
+
```bash
|
|
572
|
+
# Check sync status
|
|
573
|
+
znvault agent status
|
|
574
|
+
|
|
575
|
+
# Force manual sync
|
|
576
|
+
znvault agent sync --force
|
|
577
|
+
|
|
578
|
+
# Check health endpoint
|
|
579
|
+
curl http://localhost:9100/health
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
### WebSocket disconnects
|
|
583
|
+
|
|
584
|
+
- Check network connectivity to vault
|
|
585
|
+
- Verify API key is valid
|
|
586
|
+
- Check vault server logs for auth errors
|
|
587
|
+
- Agent will auto-reconnect with exponential backoff
|
|
588
|
+
|
|
589
|
+
### Permission denied
|
|
590
|
+
|
|
591
|
+
```bash
|
|
592
|
+
# Check file ownership
|
|
593
|
+
ls -la /etc/ssl/znvault/
|
|
594
|
+
|
|
595
|
+
# Ensure agent can write
|
|
596
|
+
sudo chown zn-vault-agent:zn-vault-agent /etc/ssl/znvault/
|
|
597
|
+
|
|
598
|
+
# Check reload command permissions
|
|
599
|
+
# Agent runs as zn-vault-agent user, may need sudo rules
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
## Auto-Update
|
|
603
|
+
|
|
604
|
+
The agent automatically updates itself via npm. Updates are checked every 5 minutes by default.
|
|
605
|
+
|
|
606
|
+
### How It Works
|
|
607
|
+
|
|
608
|
+
1. Agent periodically checks `npm view @zincapp/zn-vault-agent version`
|
|
609
|
+
2. If a newer version is available, it runs `npm install -g @zincapp/zn-vault-agent`
|
|
610
|
+
3. Agent sends SIGTERM to itself, systemd restarts with new version
|
|
611
|
+
4. Lock file prevents multiple agents from updating simultaneously
|
|
612
|
+
|
|
613
|
+
### Configuration
|
|
614
|
+
|
|
615
|
+
Auto-update is **enabled by default**. Configure via environment variables:
|
|
616
|
+
|
|
617
|
+
```bash
|
|
618
|
+
# In /etc/zn-vault-agent/agent.env:
|
|
619
|
+
AUTO_UPDATE=true # Enable/disable (default: true)
|
|
620
|
+
AUTO_UPDATE_INTERVAL=300 # Check interval in seconds (default: 300)
|
|
621
|
+
AUTO_UPDATE_CHANNEL=latest # Channel: latest, beta, next (default: latest)
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
Or disable via CLI flag:
|
|
625
|
+
|
|
626
|
+
```bash
|
|
627
|
+
zn-vault-agent start --no-auto-update
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
### Manual Updates
|
|
631
|
+
|
|
632
|
+
```bash
|
|
633
|
+
# Check for updates
|
|
634
|
+
npm outdated -g @zincapp/zn-vault-agent
|
|
635
|
+
|
|
636
|
+
# Update manually
|
|
637
|
+
npm update -g @zincapp/zn-vault-agent
|
|
638
|
+
|
|
639
|
+
# Install specific version
|
|
640
|
+
npm install -g @zincapp/zn-vault-agent@1.3.0
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
### Update Channels (npm dist-tags)
|
|
644
|
+
|
|
645
|
+
| Channel | Command | Description |
|
|
646
|
+
|---------|---------|-------------|
|
|
647
|
+
| `latest` | `npm install -g @zincapp/zn-vault-agent@latest` | Production releases |
|
|
648
|
+
| `beta` | `npm install -g @zincapp/zn-vault-agent@beta` | Pre-release testing |
|
|
649
|
+
| `next` | `npm install -g @zincapp/zn-vault-agent@next` | Development builds |
|
|
650
|
+
|
|
651
|
+
## Security Considerations
|
|
652
|
+
|
|
653
|
+
### Authentication
|
|
654
|
+
1. **Use API keys**: Always use API keys with limited scope in production
|
|
655
|
+
2. **Scope permissions**: Only grant `certificate:read:metadata` and `certificate:read:value`
|
|
656
|
+
3. **IP allowlisting**: Restrict API key usage to specific server IPs
|
|
657
|
+
4. **Rotate annually**: Set expiration to 365 days and rotate before expiry
|
|
658
|
+
|
|
659
|
+
### Credentials Storage
|
|
660
|
+
5. **Use secrets.env**: Store `ZNVAULT_API_KEY` in `/etc/zn-vault-agent/secrets.env`
|
|
661
|
+
6. **File permissions**: `secrets.env` should be `0600` owned by `zn-vault-agent`
|
|
662
|
+
7. **Never commit**: Keep credentials out of version control
|
|
663
|
+
|
|
664
|
+
### Runtime Security
|
|
665
|
+
8. **Reload commands**: Run with minimal privileges (use `sudo` rules if needed)
|
|
666
|
+
9. **TLS verification**: Never use `insecure: true` in production
|
|
667
|
+
10. **Network isolation**: Agent only needs outbound HTTPS to vault
|
|
668
|
+
|
|
669
|
+
### Example secrets.env
|
|
670
|
+
|
|
671
|
+
```bash
|
|
672
|
+
# /etc/zn-vault-agent/secrets.env
|
|
673
|
+
# Permissions: 0600, Owner: zn-vault-agent:zn-vault-agent
|
|
674
|
+
ZNVAULT_API_KEY=znv_abc123...
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
## Documentation
|
|
678
|
+
|
|
679
|
+
For comprehensive documentation including:
|
|
680
|
+
- WebSocket protocol details
|
|
681
|
+
- High availability (HA) setup
|
|
682
|
+
- Cross-node event distribution
|
|
683
|
+
- Advanced troubleshooting
|
|
684
|
+
|
|
685
|
+
See the [Agent Guide](docs/GUIDE.md).
|
|
686
|
+
|
|
687
|
+
## Development
|
|
688
|
+
|
|
689
|
+
```bash
|
|
690
|
+
npm install
|
|
691
|
+
npm run dev # Development with hot reload
|
|
692
|
+
npm run build # Build
|
|
693
|
+
npm run typecheck # Type check
|
|
694
|
+
npm run lint # Lint
|
|
695
|
+
npm test # Test
|
|
696
|
+
npm run test:coverage
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
## License
|
|
700
|
+
|
|
701
|
+
MIT
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/var/log/zn-vault-agent/*.log {
|
|
2
|
+
daily
|
|
3
|
+
rotate 14
|
|
4
|
+
compress
|
|
5
|
+
delaycompress
|
|
6
|
+
missingok
|
|
7
|
+
notifempty
|
|
8
|
+
create 0640 zn-vault-agent zn-vault-agent
|
|
9
|
+
sharedscripts
|
|
10
|
+
postrotate
|
|
11
|
+
# Signal the agent to reopen log files
|
|
12
|
+
systemctl kill -s USR1 zn-vault-agent.service 2>/dev/null || true
|
|
13
|
+
endscript
|
|
14
|
+
}
|