env-secrets 0.1.10 → 0.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/.devcontainer/devcontainer.json +33 -0
- package/.dockerignore +9 -0
- package/.eslintignore +4 -2
- package/.github/dependabot.yml +4 -0
- package/.github/workflows/build-main.yml +6 -2
- package/.github/workflows/deploy-docs.yml +50 -0
- package/.github/workflows/e2e-tests.yaml +54 -0
- package/.github/workflows/lint.yaml +6 -2
- package/.github/workflows/release.yml +13 -3
- package/.github/workflows/snyk.yaml +5 -1
- package/.github/workflows/unittests.yaml +18 -6
- package/.lintstagedrc +2 -7
- package/.prettierignore +6 -0
- package/AGENTS.md +149 -0
- package/Dockerfile +14 -0
- package/README.md +507 -36
- package/__e2e__/README.md +160 -0
- package/__e2e__/index.test.ts +339 -0
- package/__e2e__/setup.ts +58 -0
- package/__e2e__/utils/debug-logger.ts +45 -0
- package/__e2e__/utils/test-utils.ts +645 -0
- package/__tests__/index.test.ts +573 -31
- package/__tests__/vaults/secretsmanager.test.ts +460 -0
- package/__tests__/vaults/utils.test.ts +183 -0
- package/__tests__/version.test.ts +8 -0
- package/dist/index.js +36 -10
- package/dist/vaults/secretsmanager.js +44 -43
- package/dist/vaults/utils.js +2 -2
- package/docker-compose.yaml +29 -0
- package/docs/AWS.md +257 -0
- package/jest.config.js +4 -1
- package/jest.e2e.config.js +8 -0
- package/package.json +18 -10
- package/src/index.ts +44 -10
- package/src/vaults/secretsmanager.ts +48 -48
- package/src/vaults/utils.ts +6 -4
- package/website/docs/advanced-usage.mdx +399 -0
- package/website/docs/best-practices.mdx +416 -0
- package/website/docs/cli-reference.mdx +204 -0
- package/website/docs/examples.mdx +960 -0
- package/website/docs/faq.mdx +302 -0
- package/website/docs/index.mdx +56 -0
- package/website/docs/installation.mdx +30 -0
- package/website/docs/overview.mdx +17 -0
- package/website/docs/production-deployment.mdx +622 -0
- package/website/docs/providers/aws-secrets-manager.mdx +28 -0
- package/website/docs/security.mdx +122 -0
- package/website/docs/troubleshooting.mdx +236 -0
- package/website/docs/tutorials/local-dev/devcontainer-localstack.mdx +31 -0
- package/website/docs/tutorials/local-dev/docker-compose.mdx +22 -0
- package/website/docs/tutorials/local-dev/nextjs.mdx +18 -0
- package/website/docs/tutorials/local-dev/node-python-go.mdx +39 -0
- package/website/docs/tutorials/local-dev/quickstart.mdx +23 -0
- package/website/docusaurus.config.ts +89 -0
- package/website/package.json +21 -0
- package/website/sidebars.ts +33 -0
- package/website/src/css/custom.css +1 -0
- package/website/static/img/env-secrets.png +0 -0
- package/website/static/img/favicon.ico +0 -0
- package/website/static/img/logo.svg +4 -0
- package/website/yarn.lock +8764 -0
|
@@ -0,0 +1,622 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Production Deployment
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Production Deployment
|
|
6
|
+
|
|
7
|
+
This guide covers best practices for deploying applications with `env-secrets` in production environments.
|
|
8
|
+
|
|
9
|
+
## Pre-Deployment Checklist
|
|
10
|
+
|
|
11
|
+
Before deploying to production, ensure you have:
|
|
12
|
+
|
|
13
|
+
- [ ] **IAM Roles Configured**: Use IAM roles instead of access keys
|
|
14
|
+
- [ ] **Secrets Created**: All required secrets exist in AWS Secrets Manager
|
|
15
|
+
- [ ] **Permissions Verified**: Applications can access their required secrets
|
|
16
|
+
- [ ] **Monitoring Setup**: CloudTrail and CloudWatch logging enabled
|
|
17
|
+
- [ ] **Backup Strategy**: Secrets are backed up and recoverable
|
|
18
|
+
- [ ] **Rotation Plan**: Secret rotation procedures documented
|
|
19
|
+
|
|
20
|
+
## AWS Infrastructure Setup
|
|
21
|
+
|
|
22
|
+
### IAM Roles and Policies
|
|
23
|
+
|
|
24
|
+
Create dedicated IAM roles for your applications:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"Version": "2012-10-17",
|
|
29
|
+
"Statement": [
|
|
30
|
+
{
|
|
31
|
+
"Effect": "Allow",
|
|
32
|
+
"Action": "secretsmanager:GetSecretValue",
|
|
33
|
+
"Resource": [
|
|
34
|
+
"arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/myapp/*",
|
|
35
|
+
"arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/myapp-api/*"
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### VPC Endpoints (Optional)
|
|
43
|
+
|
|
44
|
+
For enhanced security, use VPC endpoints for AWS Secrets Manager:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Create VPC endpoint
|
|
48
|
+
aws ec2 create-vpc-endpoint \
|
|
49
|
+
--vpc-id vpc-12345678 \
|
|
50
|
+
--service-name com.amazonaws.us-east-1.secretsmanager \
|
|
51
|
+
--subnet-ids subnet-12345678 subnet-87654321 \
|
|
52
|
+
--security-group-ids sg-12345678
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Container Deployment
|
|
56
|
+
|
|
57
|
+
### Docker
|
|
58
|
+
|
|
59
|
+
#### Single Container
|
|
60
|
+
|
|
61
|
+
```dockerfile
|
|
62
|
+
# Dockerfile
|
|
63
|
+
FROM node:18-alpine
|
|
64
|
+
|
|
65
|
+
WORKDIR /app
|
|
66
|
+
COPY package*.json ./
|
|
67
|
+
RUN npm ci --only=production
|
|
68
|
+
|
|
69
|
+
COPY . .
|
|
70
|
+
|
|
71
|
+
# Use env-secrets as entrypoint
|
|
72
|
+
ENTRYPOINT ["env-secrets", "aws", "-s", "prod/myapp", "-r", "us-east-1", "--"]
|
|
73
|
+
CMD ["node", "app.js"]
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
#### Multi-Container with Docker Compose
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
# docker-compose.prod.yml
|
|
80
|
+
version: '3.8'
|
|
81
|
+
services:
|
|
82
|
+
app:
|
|
83
|
+
build: .
|
|
84
|
+
environment:
|
|
85
|
+
- AWS_REGION=us-east-1
|
|
86
|
+
command:
|
|
87
|
+
[
|
|
88
|
+
'env-secrets',
|
|
89
|
+
'aws',
|
|
90
|
+
'-s',
|
|
91
|
+
'prod/myapp',
|
|
92
|
+
'-r',
|
|
93
|
+
'us-east-1',
|
|
94
|
+
'--',
|
|
95
|
+
'node',
|
|
96
|
+
'app.js'
|
|
97
|
+
]
|
|
98
|
+
restart: unless-stopped
|
|
99
|
+
healthcheck:
|
|
100
|
+
test:
|
|
101
|
+
[
|
|
102
|
+
'CMD',
|
|
103
|
+
'env-secrets',
|
|
104
|
+
'aws',
|
|
105
|
+
'-s',
|
|
106
|
+
'health/check',
|
|
107
|
+
'-r',
|
|
108
|
+
'us-east-1',
|
|
109
|
+
'--',
|
|
110
|
+
'echo',
|
|
111
|
+
'healthy'
|
|
112
|
+
]
|
|
113
|
+
interval: 30s
|
|
114
|
+
timeout: 10s
|
|
115
|
+
retries: 3
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Kubernetes
|
|
119
|
+
|
|
120
|
+
#### Deployment with env-secrets
|
|
121
|
+
|
|
122
|
+
```yaml
|
|
123
|
+
# deployment.yaml
|
|
124
|
+
apiVersion: apps/v1
|
|
125
|
+
kind: Deployment
|
|
126
|
+
metadata:
|
|
127
|
+
name: myapp
|
|
128
|
+
labels:
|
|
129
|
+
app: myapp
|
|
130
|
+
spec:
|
|
131
|
+
replicas: 3
|
|
132
|
+
selector:
|
|
133
|
+
matchLabels:
|
|
134
|
+
app: myapp
|
|
135
|
+
template:
|
|
136
|
+
metadata:
|
|
137
|
+
labels:
|
|
138
|
+
app: myapp
|
|
139
|
+
spec:
|
|
140
|
+
serviceAccountName: myapp-sa
|
|
141
|
+
containers:
|
|
142
|
+
- name: app
|
|
143
|
+
image: myapp:latest
|
|
144
|
+
command: ['env-secrets']
|
|
145
|
+
args:
|
|
146
|
+
[
|
|
147
|
+
'aws',
|
|
148
|
+
'-s',
|
|
149
|
+
'prod/myapp',
|
|
150
|
+
'-r',
|
|
151
|
+
'us-east-1',
|
|
152
|
+
'--',
|
|
153
|
+
'node',
|
|
154
|
+
'app.js'
|
|
155
|
+
]
|
|
156
|
+
env:
|
|
157
|
+
- name: AWS_REGION
|
|
158
|
+
value: 'us-east-1'
|
|
159
|
+
ports:
|
|
160
|
+
- containerPort: 3000
|
|
161
|
+
livenessProbe:
|
|
162
|
+
exec:
|
|
163
|
+
command:
|
|
164
|
+
- env-secrets
|
|
165
|
+
- aws
|
|
166
|
+
- -s
|
|
167
|
+
- health/check
|
|
168
|
+
- -r
|
|
169
|
+
- us-east-1
|
|
170
|
+
- --
|
|
171
|
+
- echo
|
|
172
|
+
- 'healthy'
|
|
173
|
+
initialDelaySeconds: 30
|
|
174
|
+
periodSeconds: 10
|
|
175
|
+
readinessProbe:
|
|
176
|
+
httpGet:
|
|
177
|
+
path: /health
|
|
178
|
+
port: 3000
|
|
179
|
+
initialDelaySeconds: 5
|
|
180
|
+
periodSeconds: 5
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### Service Account
|
|
184
|
+
|
|
185
|
+
```yaml
|
|
186
|
+
# service-account.yaml
|
|
187
|
+
apiVersion: v1
|
|
188
|
+
kind: ServiceAccount
|
|
189
|
+
metadata:
|
|
190
|
+
name: myapp-sa
|
|
191
|
+
annotations:
|
|
192
|
+
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/myapp-role
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
#### ConfigMap for Configuration
|
|
196
|
+
|
|
197
|
+
```yaml
|
|
198
|
+
# configmap.yaml
|
|
199
|
+
apiVersion: v1
|
|
200
|
+
kind: ConfigMap
|
|
201
|
+
metadata:
|
|
202
|
+
name: myapp-config
|
|
203
|
+
data:
|
|
204
|
+
AWS_REGION: 'us-east-1'
|
|
205
|
+
SECRET_NAME: 'prod/myapp'
|
|
206
|
+
NODE_ENV: 'production'
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Serverless Deployment
|
|
210
|
+
|
|
211
|
+
### AWS Lambda
|
|
212
|
+
|
|
213
|
+
```yaml
|
|
214
|
+
# serverless.yml
|
|
215
|
+
service: myapp
|
|
216
|
+
|
|
217
|
+
provider:
|
|
218
|
+
name: aws
|
|
219
|
+
runtime: nodejs18.x
|
|
220
|
+
region: us-east-1
|
|
221
|
+
iam:
|
|
222
|
+
role:
|
|
223
|
+
statements:
|
|
224
|
+
- Effect: Allow
|
|
225
|
+
Action:
|
|
226
|
+
- secretsmanager:GetSecretValue
|
|
227
|
+
Resource:
|
|
228
|
+
- arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/myapp/*
|
|
229
|
+
|
|
230
|
+
functions:
|
|
231
|
+
api:
|
|
232
|
+
handler: handler.api
|
|
233
|
+
events:
|
|
234
|
+
- http:
|
|
235
|
+
path: /{proxy+}
|
|
236
|
+
method: ANY
|
|
237
|
+
environment:
|
|
238
|
+
SECRET_NAME: prod/myapp
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
```javascript
|
|
242
|
+
// handler.js
|
|
243
|
+
const { spawn } = require('child_process');
|
|
244
|
+
|
|
245
|
+
exports.api = async (event, context) => {
|
|
246
|
+
return new Promise((resolve, reject) => {
|
|
247
|
+
const child = spawn(
|
|
248
|
+
'env-secrets',
|
|
249
|
+
[
|
|
250
|
+
'aws',
|
|
251
|
+
'-s',
|
|
252
|
+
process.env.SECRET_NAME,
|
|
253
|
+
'-r',
|
|
254
|
+
'us-east-1',
|
|
255
|
+
'--',
|
|
256
|
+
'node',
|
|
257
|
+
'app.js'
|
|
258
|
+
],
|
|
259
|
+
{
|
|
260
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
261
|
+
}
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
// Handle Lambda event
|
|
265
|
+
child.stdin.write(JSON.stringify(event));
|
|
266
|
+
child.stdin.end();
|
|
267
|
+
|
|
268
|
+
let output = '';
|
|
269
|
+
child.stdout.on('data', (data) => {
|
|
270
|
+
output += data.toString();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
child.on('close', (code) => {
|
|
274
|
+
if (code === 0) {
|
|
275
|
+
resolve(JSON.parse(output));
|
|
276
|
+
} else {
|
|
277
|
+
reject(new Error(`Process exited with code ${code}`));
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
};
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### AWS ECS
|
|
285
|
+
|
|
286
|
+
```json
|
|
287
|
+
{
|
|
288
|
+
"family": "myapp",
|
|
289
|
+
"networkMode": "awsvpc",
|
|
290
|
+
"requiresCompatibilities": ["FARGATE"],
|
|
291
|
+
"cpu": "256",
|
|
292
|
+
"memory": "512",
|
|
293
|
+
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
|
|
294
|
+
"taskRoleArn": "arn:aws:iam::123456789012:role/myapp-task-role",
|
|
295
|
+
"containerDefinitions": [
|
|
296
|
+
{
|
|
297
|
+
"name": "app",
|
|
298
|
+
"image": "myapp:latest",
|
|
299
|
+
"command": [
|
|
300
|
+
"env-secrets",
|
|
301
|
+
"aws",
|
|
302
|
+
"-s",
|
|
303
|
+
"prod/myapp",
|
|
304
|
+
"-r",
|
|
305
|
+
"us-east-1",
|
|
306
|
+
"--",
|
|
307
|
+
"node",
|
|
308
|
+
"app.js"
|
|
309
|
+
],
|
|
310
|
+
"environment": [
|
|
311
|
+
{
|
|
312
|
+
"name": "AWS_REGION",
|
|
313
|
+
"value": "us-east-1"
|
|
314
|
+
}
|
|
315
|
+
],
|
|
316
|
+
"portMappings": [
|
|
317
|
+
{
|
|
318
|
+
"containerPort": 3000,
|
|
319
|
+
"protocol": "tcp"
|
|
320
|
+
}
|
|
321
|
+
],
|
|
322
|
+
"healthCheck": {
|
|
323
|
+
"command": [
|
|
324
|
+
"env-secrets",
|
|
325
|
+
"aws",
|
|
326
|
+
"-s",
|
|
327
|
+
"health/check",
|
|
328
|
+
"-r",
|
|
329
|
+
"us-east-1",
|
|
330
|
+
"--",
|
|
331
|
+
"echo",
|
|
332
|
+
"healthy"
|
|
333
|
+
],
|
|
334
|
+
"interval": 30,
|
|
335
|
+
"timeout": 5,
|
|
336
|
+
"retries": 3,
|
|
337
|
+
"startPeriod": 60
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
]
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## CI/CD Integration
|
|
345
|
+
|
|
346
|
+
### GitHub Actions
|
|
347
|
+
|
|
348
|
+
```yaml
|
|
349
|
+
# .github/workflows/deploy.yml
|
|
350
|
+
name: Deploy to Production
|
|
351
|
+
|
|
352
|
+
on:
|
|
353
|
+
push:
|
|
354
|
+
branches: [main]
|
|
355
|
+
|
|
356
|
+
jobs:
|
|
357
|
+
deploy:
|
|
358
|
+
runs-on: ubuntu-latest
|
|
359
|
+
steps:
|
|
360
|
+
- uses: actions/checkout@v3
|
|
361
|
+
|
|
362
|
+
- name: Setup Node.js
|
|
363
|
+
uses: actions/setup-node@v3
|
|
364
|
+
with:
|
|
365
|
+
node-version: '18'
|
|
366
|
+
|
|
367
|
+
- name: Configure AWS credentials
|
|
368
|
+
uses: aws-actions/configure-aws-credentials@v2
|
|
369
|
+
with:
|
|
370
|
+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
371
|
+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
372
|
+
aws-region: us-east-1
|
|
373
|
+
|
|
374
|
+
- name: Install env-secrets
|
|
375
|
+
run: npm install -g env-secrets
|
|
376
|
+
|
|
377
|
+
- name: Build Docker image
|
|
378
|
+
run: docker build -t myapp:${{ github.sha }} .
|
|
379
|
+
|
|
380
|
+
- name: Deploy to ECS
|
|
381
|
+
run: |
|
|
382
|
+
aws ecs update-service \
|
|
383
|
+
--cluster production \
|
|
384
|
+
--service myapp \
|
|
385
|
+
--force-new-deployment
|
|
386
|
+
|
|
387
|
+
- name: Verify deployment
|
|
388
|
+
run: |
|
|
389
|
+
env-secrets aws -s prod/myapp -r us-east-1 -- curl -f http://localhost:3000/health
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### GitLab CI
|
|
393
|
+
|
|
394
|
+
```yaml
|
|
395
|
+
# .gitlab-ci.yml
|
|
396
|
+
stages:
|
|
397
|
+
- test
|
|
398
|
+
- deploy
|
|
399
|
+
|
|
400
|
+
test:
|
|
401
|
+
stage: test
|
|
402
|
+
image: node:18
|
|
403
|
+
script:
|
|
404
|
+
- npm install -g env-secrets
|
|
405
|
+
- env-secrets aws -s test/myapp -r us-east-1 -- npm test
|
|
406
|
+
|
|
407
|
+
deploy:
|
|
408
|
+
stage: deploy
|
|
409
|
+
image: node:18
|
|
410
|
+
before_script:
|
|
411
|
+
- npm install -g env-secrets
|
|
412
|
+
script:
|
|
413
|
+
- env-secrets aws -s prod/myapp -r us-east-1 -- npm run deploy
|
|
414
|
+
environment:
|
|
415
|
+
name: production
|
|
416
|
+
only:
|
|
417
|
+
- main
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
## Monitoring and Alerting
|
|
421
|
+
|
|
422
|
+
### CloudWatch Alarms
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
# Create alarm for secret access failures
|
|
426
|
+
aws cloudwatch put-metric-alarm \
|
|
427
|
+
--alarm-name "SecretAccessFailures" \
|
|
428
|
+
--alarm-description "Alarm when secret access fails" \
|
|
429
|
+
--metric-name "Errors" \
|
|
430
|
+
--namespace "AWS/SecretsManager" \
|
|
431
|
+
--statistic "Sum" \
|
|
432
|
+
--period 300 \
|
|
433
|
+
--threshold 1 \
|
|
434
|
+
--comparison-operator "GreaterThanThreshold" \
|
|
435
|
+
--evaluation-periods 1
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Health Checks
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
#!/bin/bash
|
|
442
|
+
# health-check.sh
|
|
443
|
+
|
|
444
|
+
# Check if secrets are accessible
|
|
445
|
+
if env-secrets aws -s health/check -r us-east-1 -- echo "OK" 2>/dev/null; then
|
|
446
|
+
echo "Secrets accessible"
|
|
447
|
+
exit 0
|
|
448
|
+
else
|
|
449
|
+
echo "Secrets not accessible"
|
|
450
|
+
exit 1
|
|
451
|
+
fi
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### Application Health Endpoint
|
|
455
|
+
|
|
456
|
+
```javascript
|
|
457
|
+
// health.js
|
|
458
|
+
app.get('/health', (req, res) => {
|
|
459
|
+
const requiredVars = ['DATABASE_URL', 'API_KEY'];
|
|
460
|
+
const missing = requiredVars.filter(var => !process.env[var]);
|
|
461
|
+
|
|
462
|
+
if (missing.length > 0) {
|
|
463
|
+
res.status(503).json({
|
|
464
|
+
status: 'unhealthy',
|
|
465
|
+
missing: missing
|
|
466
|
+
});
|
|
467
|
+
} else {
|
|
468
|
+
res.json({
|
|
469
|
+
status: 'healthy',
|
|
470
|
+
timestamp: new Date().toISOString()
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
## Disaster Recovery
|
|
477
|
+
|
|
478
|
+
### Secret Backup Strategy
|
|
479
|
+
|
|
480
|
+
```bash
|
|
481
|
+
#!/bin/bash
|
|
482
|
+
# backup-secrets.sh
|
|
483
|
+
|
|
484
|
+
SECRETS=("prod/myapp" "prod/myapp-api" "prod/myapp-db")
|
|
485
|
+
|
|
486
|
+
for secret in "${SECRETS[@]}"; do
|
|
487
|
+
echo "Backing up $secret..."
|
|
488
|
+
aws secretsmanager get-secret-value \
|
|
489
|
+
--secret-id "$secret" \
|
|
490
|
+
--query SecretString \
|
|
491
|
+
--output text > "backup/$secret.json"
|
|
492
|
+
done
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### Recovery Procedures
|
|
496
|
+
|
|
497
|
+
```bash
|
|
498
|
+
#!/bin/bash
|
|
499
|
+
# restore-secrets.sh
|
|
500
|
+
|
|
501
|
+
SECRET_NAME="prod/myapp"
|
|
502
|
+
BACKUP_FILE="backup/$SECRET_NAME.json"
|
|
503
|
+
|
|
504
|
+
if [ -f "$BACKUP_FILE" ]; then
|
|
505
|
+
echo "Restoring $SECRET_NAME..."
|
|
506
|
+
aws secretsmanager create-secret \
|
|
507
|
+
--name "$SECRET_NAME" \
|
|
508
|
+
--secret-string "$(cat $BACKUP_FILE)"
|
|
509
|
+
else
|
|
510
|
+
echo "Backup file not found: $BACKUP_FILE"
|
|
511
|
+
exit 1
|
|
512
|
+
fi
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
## Security Hardening
|
|
516
|
+
|
|
517
|
+
### Network Security
|
|
518
|
+
|
|
519
|
+
```bash
|
|
520
|
+
# Restrict access to specific IP ranges
|
|
521
|
+
aws secretsmanager update-secret \
|
|
522
|
+
--secret-id prod/myapp \
|
|
523
|
+
--policy '{
|
|
524
|
+
"Version": "2012-10-17",
|
|
525
|
+
"Statement": [
|
|
526
|
+
{
|
|
527
|
+
"Effect": "Deny",
|
|
528
|
+
"Principal": "*",
|
|
529
|
+
"Action": "secretsmanager:*",
|
|
530
|
+
"Resource": "*",
|
|
531
|
+
"Condition": {
|
|
532
|
+
"NotIpAddress": {
|
|
533
|
+
"aws:SourceIp": ["192.168.1.0/24", "10.0.0.0/8"]
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
]
|
|
538
|
+
}'
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
### Encryption
|
|
542
|
+
|
|
543
|
+
```bash
|
|
544
|
+
# Use customer-managed KMS keys
|
|
545
|
+
aws secretsmanager create-secret \
|
|
546
|
+
--name prod/myapp \
|
|
547
|
+
--secret-string '{"DATABASE_URL":"postgres://..."}' \
|
|
548
|
+
--kms-key-id arn:aws:kms:us-east-1:123456789012:key/myapp-key
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
## Performance Optimization
|
|
552
|
+
|
|
553
|
+
### Connection Pooling
|
|
554
|
+
|
|
555
|
+
```javascript
|
|
556
|
+
// Use connection pooling with secrets
|
|
557
|
+
const pool = new Pool({
|
|
558
|
+
connectionString: process.env.DATABASE_URL,
|
|
559
|
+
max: 20,
|
|
560
|
+
idleTimeoutMillis: 30000,
|
|
561
|
+
connectionTimeoutMillis: 2000
|
|
562
|
+
});
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
### Caching Strategy
|
|
566
|
+
|
|
567
|
+
While `env-secrets` doesn't cache secrets, implement application-level caching:
|
|
568
|
+
|
|
569
|
+
```javascript
|
|
570
|
+
// Cache frequently accessed data
|
|
571
|
+
const cache = new Map();
|
|
572
|
+
|
|
573
|
+
function getCachedData(key) {
|
|
574
|
+
if (cache.has(key)) {
|
|
575
|
+
return cache.get(key);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
const data = fetchData(key);
|
|
579
|
+
cache.set(key, data);
|
|
580
|
+
return data;
|
|
581
|
+
}
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
## Rollback Procedures
|
|
585
|
+
|
|
586
|
+
### Application Rollback
|
|
587
|
+
|
|
588
|
+
```bash
|
|
589
|
+
#!/bin/bash
|
|
590
|
+
# rollback.sh
|
|
591
|
+
|
|
592
|
+
VERSION=$1
|
|
593
|
+
|
|
594
|
+
echo "Rolling back to version $VERSION..."
|
|
595
|
+
|
|
596
|
+
# Update deployment to previous version
|
|
597
|
+
kubectl set image deployment/myapp app=myapp:$VERSION
|
|
598
|
+
|
|
599
|
+
# Verify rollback
|
|
600
|
+
kubectl rollout status deployment/myapp
|
|
601
|
+
|
|
602
|
+
echo "Rollback completed"
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
### Secret Rollback
|
|
606
|
+
|
|
607
|
+
```bash
|
|
608
|
+
#!/bin/bash
|
|
609
|
+
# rollback-secret.sh
|
|
610
|
+
|
|
611
|
+
SECRET_NAME="prod/myapp"
|
|
612
|
+
VERSION=$1
|
|
613
|
+
|
|
614
|
+
echo "Rolling back secret $SECRET_NAME to version $VERSION..."
|
|
615
|
+
|
|
616
|
+
# Restore previous secret version
|
|
617
|
+
aws secretsmanager restore-secret \
|
|
618
|
+
--secret-id "$SECRET_NAME" \
|
|
619
|
+
--secret-version-id "$VERSION"
|
|
620
|
+
|
|
621
|
+
echo "Secret rollback completed"
|
|
622
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: AWS Secrets Manager
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
`env-secrets` supports pulling a single JSON secret from AWS Secrets Manager, mapping each top-level key to an environment variable.
|
|
6
|
+
|
|
7
|
+
### Create a secret (JSON)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
aws secretsmanager create-secret --region us-east-1 --name local/sample --secret-string '{"user":"marka","password":"mypassword"}'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Run a command with injected vars
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
env-secrets aws -s local/sample -r us-east-1 -- echo $user/$password
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Parameters
|
|
20
|
+
|
|
21
|
+
- `-s, --secret` — **required** secret name/id
|
|
22
|
+
- `-r, --region` — AWS region (or `AWS_DEFAULT_REGION`)
|
|
23
|
+
- `-p, --profile` — AWS profile to use
|
|
24
|
+
|
|
25
|
+
### Tips
|
|
26
|
+
|
|
27
|
+
- Use `DEBUG=env-secrets,env-secrets:secretsmanager` for verbose logs.
|
|
28
|
+
- Prefer least-privilege IAM (`secretsmanager:GetSecretValue`).
|