@lamalibre/create-lamaste 4.0.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/LICENSE.md +118 -0
- package/README.md +114 -0
- package/bin/create-lamaste.js +15 -0
- package/package.json +54 -0
- package/scripts/bundle-vendor.js +110 -0
- package/scripts/lamaste-cert-info +62 -0
- package/scripts/lamaste-certbot +96 -0
- package/scripts/lamaste-priv +693 -0
- package/src/index.js +646 -0
- package/src/lib/accounts.js +86 -0
- package/src/lib/binaries.js +137 -0
- package/src/lib/cert-help-page.js +160 -0
- package/src/lib/env.js +132 -0
- package/src/lib/http-redirect.js +38 -0
- package/src/lib/ownership.js +231 -0
- package/src/lib/relay-services.js +103 -0
- package/src/lib/secrets.js +19 -0
- package/src/lib/service-config.js +311 -0
- package/src/lib/summary.js +131 -0
- package/src/lib/wrappers.js +63 -0
- package/src/tasks/gatekeeper.js +233 -0
- package/src/tasks/harden.js +293 -0
- package/src/tasks/mtls.js +193 -0
- package/src/tasks/nginx.js +265 -0
- package/src/tasks/node.js +110 -0
- package/src/tasks/panel.js +408 -0
- package/src/tasks/redeploy.js +438 -0
- package/vendor/docs/00-introduction/how-it-works.md +447 -0
- package/vendor/docs/00-introduction/quickstart.md +472 -0
- package/vendor/docs/00-introduction/what-is-lamaste.md +112 -0
- package/vendor/docs/01-concepts/authentication.md +464 -0
- package/vendor/docs/01-concepts/authorization.md +242 -0
- package/vendor/docs/01-concepts/certificates.md +452 -0
- package/vendor/docs/01-concepts/dns-and-domains.md +343 -0
- package/vendor/docs/01-concepts/mtls.md +490 -0
- package/vendor/docs/01-concepts/nginx-reverse-proxy.md +540 -0
- package/vendor/docs/01-concepts/security-model.md +600 -0
- package/vendor/docs/01-concepts/tickets.md +414 -0
- package/vendor/docs/01-concepts/tunneling.md +367 -0
- package/vendor/docs/02-guides/agent-setup.md +194 -0
- package/vendor/docs/02-guides/certificate-management.md +341 -0
- package/vendor/docs/02-guides/cloud-provisioning.md +406 -0
- package/vendor/docs/02-guides/desktop-app-setup.md +226 -0
- package/vendor/docs/02-guides/disaster-recovery.md +464 -0
- package/vendor/docs/02-guides/first-tunnel.md +230 -0
- package/vendor/docs/02-guides/installation.md +393 -0
- package/vendor/docs/02-guides/managing-users.md +255 -0
- package/vendor/docs/02-guides/onboarding.md +244 -0
- package/vendor/docs/02-guides/standalone-plugin-with-tickets.md +375 -0
- package/vendor/docs/02-guides/static-sites.md +364 -0
- package/vendor/docs/03-architecture/e2e-three-vm-sequences.md +457 -0
- package/vendor/docs/03-architecture/installer-flow.md +151 -0
- package/vendor/docs/03-architecture/installer.md +445 -0
- package/vendor/docs/03-architecture/management-flow.md +288 -0
- package/vendor/docs/03-architecture/nginx-configuration.md +830 -0
- package/vendor/docs/03-architecture/onboarding-flow.md +164 -0
- package/vendor/docs/03-architecture/overview.md +541 -0
- package/vendor/docs/03-architecture/panel-client.md +416 -0
- package/vendor/docs/03-architecture/panel-server.md +695 -0
- package/vendor/docs/03-architecture/state-management.md +529 -0
- package/vendor/docs/03-architecture/system-overview.md +167 -0
- package/vendor/docs/04-api-reference/certificates.md +1141 -0
- package/vendor/docs/04-api-reference/gatekeeper.md +592 -0
- package/vendor/docs/04-api-reference/onboarding.md +473 -0
- package/vendor/docs/04-api-reference/overview.md +404 -0
- package/vendor/docs/04-api-reference/services.md +267 -0
- package/vendor/docs/04-api-reference/settings.md +343 -0
- package/vendor/docs/04-api-reference/sites.md +716 -0
- package/vendor/docs/04-api-reference/system.md +268 -0
- package/vendor/docs/04-api-reference/tickets.md +618 -0
- package/vendor/docs/04-api-reference/tunnels.md +417 -0
- package/vendor/docs/04-api-reference/users.md +333 -0
- package/vendor/docs/05-operations/backup-and-restore.md +342 -0
- package/vendor/docs/05-operations/monitoring.md +285 -0
- package/vendor/docs/05-operations/uninstalling.md +344 -0
- package/vendor/docs/05-operations/upgrades.md +270 -0
- package/vendor/docs/06-reference/config-files.md +1080 -0
- package/vendor/docs/06-reference/glossary.md +528 -0
- package/vendor/docs/06-reference/installer-flags.md +260 -0
- package/vendor/docs/06-reference/ports-and-services.md +244 -0
- package/vendor/docs/06-reference/troubleshooting.md +665 -0
- package/vendor/docs/_index.json +233 -0
- package/vendor/docs/gatekeeper-design.md +953 -0
- package/vendor/docs/package.json +15 -0
- package/vendor/docs/todo/lib-cli-desktop-refactor.md +641 -0
- package/vendor/gatekeeper/dist/boot.d.ts +1 -0
- package/vendor/gatekeeper/dist/boot.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/boot.js +17 -0
- package/vendor/gatekeeper/dist/boot.js.map +1 -0
- package/vendor/gatekeeper/dist/cli/commands/access.d.ts +2 -0
- package/vendor/gatekeeper/dist/cli/commands/access.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/cli/commands/access.js +33 -0
- package/vendor/gatekeeper/dist/cli/commands/access.js.map +1 -0
- package/vendor/gatekeeper/dist/cli/commands/grants.d.ts +2 -0
- package/vendor/gatekeeper/dist/cli/commands/grants.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/cli/commands/grants.js +110 -0
- package/vendor/gatekeeper/dist/cli/commands/grants.js.map +1 -0
- package/vendor/gatekeeper/dist/cli/commands/groups.d.ts +2 -0
- package/vendor/gatekeeper/dist/cli/commands/groups.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/cli/commands/groups.js +98 -0
- package/vendor/gatekeeper/dist/cli/commands/groups.js.map +1 -0
- package/vendor/gatekeeper/dist/cli/index.d.ts +3 -0
- package/vendor/gatekeeper/dist/cli/index.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/cli/index.js +45 -0
- package/vendor/gatekeeper/dist/cli/index.js.map +1 -0
- package/vendor/gatekeeper/dist/index.d.ts +9 -0
- package/vendor/gatekeeper/dist/index.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/index.js +13 -0
- package/vendor/gatekeeper/dist/index.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/authz.d.ts +16 -0
- package/vendor/gatekeeper/dist/lib/authz.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/authz.js +42 -0
- package/vendor/gatekeeper/dist/lib/authz.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/cache-bust.d.ts +15 -0
- package/vendor/gatekeeper/dist/lib/cache-bust.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/cache-bust.js +19 -0
- package/vendor/gatekeeper/dist/lib/cache-bust.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/constants.d.ts +82 -0
- package/vendor/gatekeeper/dist/lib/constants.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/constants.js +79 -0
- package/vendor/gatekeeper/dist/lib/constants.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/grants.d.ts +32 -0
- package/vendor/gatekeeper/dist/lib/grants.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/grants.js +314 -0
- package/vendor/gatekeeper/dist/lib/grants.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/groups.d.ts +10 -0
- package/vendor/gatekeeper/dist/lib/groups.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/groups.js +247 -0
- package/vendor/gatekeeper/dist/lib/groups.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/migration.d.ts +17 -0
- package/vendor/gatekeeper/dist/lib/migration.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/migration.js +79 -0
- package/vendor/gatekeeper/dist/lib/migration.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0001_groups.sql +7 -0
- package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0002_access_grants.sql +14 -0
- package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0003_access_request_log.sql +9 -0
- package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0001_groups.sql +7 -0
- package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0002_access_grants.sql +14 -0
- package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0003_access_request_log.sql +9 -0
- package/vendor/gatekeeper/dist/lib/state-db.d.ts +16 -0
- package/vendor/gatekeeper/dist/lib/state-db.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/state-db.js +154 -0
- package/vendor/gatekeeper/dist/lib/state-db.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/templates.d.ts +21 -0
- package/vendor/gatekeeper/dist/lib/templates.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/templates.js +151 -0
- package/vendor/gatekeeper/dist/lib/templates.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/types.d.ts +178 -0
- package/vendor/gatekeeper/dist/lib/types.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/types.js +2 -0
- package/vendor/gatekeeper/dist/lib/types.js.map +1 -0
- package/vendor/gatekeeper/dist/server/index.d.ts +15 -0
- package/vendor/gatekeeper/dist/server/index.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/server/index.js +251 -0
- package/vendor/gatekeeper/dist/server/index.js.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/access-request.d.ts +7 -0
- package/vendor/gatekeeper/dist/server/routes/access-request.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/access-request.js +17 -0
- package/vendor/gatekeeper/dist/server/routes/access-request.js.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/authz.d.ts +3 -0
- package/vendor/gatekeeper/dist/server/routes/authz.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/authz.js +279 -0
- package/vendor/gatekeeper/dist/server/routes/authz.js.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/diagnostic.d.ts +13 -0
- package/vendor/gatekeeper/dist/server/routes/diagnostic.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/diagnostic.js +249 -0
- package/vendor/gatekeeper/dist/server/routes/diagnostic.js.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/grants.d.ts +3 -0
- package/vendor/gatekeeper/dist/server/routes/grants.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/grants.js +112 -0
- package/vendor/gatekeeper/dist/server/routes/grants.js.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/groups.d.ts +3 -0
- package/vendor/gatekeeper/dist/server/routes/groups.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/server/routes/groups.js +139 -0
- package/vendor/gatekeeper/dist/server/routes/groups.js.map +1 -0
- package/vendor/gatekeeper/package.json +49 -0
- package/vendor/server/bin/lamaste-server.js +204 -0
- package/vendor/server/package.json +31 -0
- package/vendor/server/src/commands/certs.js +224 -0
- package/vendor/server/src/commands/chisel.js +132 -0
- package/vendor/server/src/commands/logs.js +49 -0
- package/vendor/server/src/commands/plugins.js +321 -0
- package/vendor/server/src/commands/reset-admin.js +478 -0
- package/vendor/server/src/commands/restart.js +94 -0
- package/vendor/server/src/commands/sites.js +257 -0
- package/vendor/server/src/commands/status.js +158 -0
- package/vendor/server/src/commands/tunnels.js +365 -0
- package/vendor/server/src/commands/uninstall.js +326 -0
- package/vendor/server/src/config.js +38 -0
- package/vendor/server/src/exec.js +26 -0
- package/vendor/server/src/logger.js +39 -0
- package/vendor/server/src/ndjson.js +56 -0
- package/vendor/server/src/panel-api.js +85 -0
- package/vendor/server/src/state.js +45 -0
- package/vendor/server-ui/dist/assets/index-B0nWuUyL.js +257 -0
- package/vendor/server-ui/dist/assets/index-BqWWFlTU.css +1 -0
- package/vendor/server-ui/dist/index.html +13 -0
- package/vendor/serverd/package.json +44 -0
- package/vendor/serverd/src/boot.js +13 -0
- package/vendor/serverd/src/index.js +191 -0
- package/vendor/serverd/src/lib/app-error.js +14 -0
- package/vendor/serverd/src/lib/authelia.js +85 -0
- package/vendor/serverd/src/lib/certbot.js +74 -0
- package/vendor/serverd/src/lib/chisel-args.js +6 -0
- package/vendor/serverd/src/lib/chisel-reconcile.js +232 -0
- package/vendor/serverd/src/lib/chisel-runtime.js +46 -0
- package/vendor/serverd/src/lib/chisel-users.js +109 -0
- package/vendor/serverd/src/lib/chisel.js +81 -0
- package/vendor/serverd/src/lib/config.js +190 -0
- package/vendor/serverd/src/lib/constants.js +8 -0
- package/vendor/serverd/src/lib/csr-signing.js +331 -0
- package/vendor/serverd/src/lib/enrollment.js +302 -0
- package/vendor/serverd/src/lib/files.js +19 -0
- package/vendor/serverd/src/lib/gatekeeper-client.js +135 -0
- package/vendor/serverd/src/lib/invite-page.js +281 -0
- package/vendor/serverd/src/lib/ip-utils.js +79 -0
- package/vendor/serverd/src/lib/migrations/state/0001_enrollment_tokens.sql +17 -0
- package/vendor/serverd/src/lib/migrations/state/0002_tickets.sql +70 -0
- package/vendor/serverd/src/lib/migrations/state/0003_plugins.sql +15 -0
- package/vendor/serverd/src/lib/migrations/state/0004_agents.sql +19 -0
- package/vendor/serverd/src/lib/mtls.js +795 -0
- package/vendor/serverd/src/lib/nginx.js +1090 -0
- package/vendor/serverd/src/lib/pki-paths.js +41 -0
- package/vendor/serverd/src/lib/pki-sign.js +103 -0
- package/vendor/serverd/src/lib/plugins.js +538 -0
- package/vendor/serverd/src/lib/push-install.js +390 -0
- package/vendor/serverd/src/lib/revocation.js +112 -0
- package/vendor/serverd/src/lib/services.js +131 -0
- package/vendor/serverd/src/lib/session.js +151 -0
- package/vendor/serverd/src/lib/state-db.js +130 -0
- package/vendor/serverd/src/lib/state.js +140 -0
- package/vendor/serverd/src/lib/storage.js +63 -0
- package/vendor/serverd/src/lib/system-stats.js +58 -0
- package/vendor/serverd/src/lib/tickets.js +1556 -0
- package/vendor/serverd/src/lib/totp.js +76 -0
- package/vendor/serverd/src/lib/tunnel-deps.js +41 -0
- package/vendor/serverd/src/lib/user-access-session.js +142 -0
- package/vendor/serverd/src/lib/user-access.js +52 -0
- package/vendor/serverd/src/middleware/errors.js +63 -0
- package/vendor/serverd/src/middleware/mtls.js +120 -0
- package/vendor/serverd/src/middleware/onboarding-guard.js +30 -0
- package/vendor/serverd/src/middleware/role-guard.js +58 -0
- package/vendor/serverd/src/middleware/twofa-session.js +65 -0
- package/vendor/serverd/src/middleware/user-access-session.js +52 -0
- package/vendor/serverd/src/routes/enrollment.js +120 -0
- package/vendor/serverd/src/routes/health.js +22 -0
- package/vendor/serverd/src/routes/invite.js +163 -0
- package/vendor/serverd/src/routes/management/agents.js +182 -0
- package/vendor/serverd/src/routes/management/certs.js +911 -0
- package/vendor/serverd/src/routes/management/gatekeeper-proxy.js +160 -0
- package/vendor/serverd/src/routes/management/identity.js +107 -0
- package/vendor/serverd/src/routes/management/invitations.js +166 -0
- package/vendor/serverd/src/routes/management/logs.js +218 -0
- package/vendor/serverd/src/routes/management/plugins.js +560 -0
- package/vendor/serverd/src/routes/management/services.js +63 -0
- package/vendor/serverd/src/routes/management/settings.js +325 -0
- package/vendor/serverd/src/routes/management/sites.js +522 -0
- package/vendor/serverd/src/routes/management/storage.js +192 -0
- package/vendor/serverd/src/routes/management/system.js +201 -0
- package/vendor/serverd/src/routes/management/tickets.js +457 -0
- package/vendor/serverd/src/routes/management/tunnels.js +709 -0
- package/vendor/serverd/src/routes/management/users.js +377 -0
- package/vendor/serverd/src/routes/management.js +36 -0
- package/vendor/serverd/src/routes/onboarding/dns.js +101 -0
- package/vendor/serverd/src/routes/onboarding/domain.js +42 -0
- package/vendor/serverd/src/routes/onboarding/index.js +18 -0
- package/vendor/serverd/src/routes/onboarding/provision.js +327 -0
- package/vendor/serverd/src/routes/onboarding/status.js +12 -0
- package/vendor/serverd/src/routes/plugin-router.js +79 -0
- package/vendor/serverd/src/routes/user-access.js +389 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lamaste-server certs — Certificate status and renewal.
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* status Show certificate expiry and renewal status
|
|
6
|
+
* renew Force certificate renewal via certbot
|
|
7
|
+
* agents List agent certificates
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
import { execa } from 'execa';
|
|
12
|
+
import { getMtlsCerts, listAgentCerts } from '@lamalibre/lamaste/server';
|
|
13
|
+
import { PKI_DIR } from '../config.js';
|
|
14
|
+
import { exec } from '../exec.js';
|
|
15
|
+
import { emit, emitStep, emitError, emitComplete } from '../ndjson.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {string[]} args
|
|
19
|
+
* @param {{ json: boolean }} options
|
|
20
|
+
*/
|
|
21
|
+
export async function runCerts(args, { json }) {
|
|
22
|
+
const sub = args[0] || 'status';
|
|
23
|
+
|
|
24
|
+
switch (sub) {
|
|
25
|
+
case 'status':
|
|
26
|
+
return certStatus({ json });
|
|
27
|
+
case 'renew':
|
|
28
|
+
return certRenew({ json });
|
|
29
|
+
case 'agents':
|
|
30
|
+
return agentCerts({ json });
|
|
31
|
+
default:
|
|
32
|
+
printCertUsage();
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function printCertUsage() {
|
|
38
|
+
const b = chalk.bold;
|
|
39
|
+
const c = chalk.cyan;
|
|
40
|
+
console.log(`
|
|
41
|
+
${b('Usage:')} lamaste-server certs <subcommand>
|
|
42
|
+
|
|
43
|
+
${b('Subcommands:')}
|
|
44
|
+
${c('status')} Show mTLS and Let's Encrypt certificate status (default)
|
|
45
|
+
${c('renew')} Force Let's Encrypt certificate renewal
|
|
46
|
+
${c('agents')} List agent certificates with expiry info
|
|
47
|
+
`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @param {{ json: boolean }} options
|
|
52
|
+
*/
|
|
53
|
+
async function certStatus({ json }) {
|
|
54
|
+
// mTLS certs
|
|
55
|
+
const mtlsCerts = await getMtlsCerts(PKI_DIR, exec);
|
|
56
|
+
|
|
57
|
+
// Let's Encrypt certs
|
|
58
|
+
let letsencryptCerts = [];
|
|
59
|
+
try {
|
|
60
|
+
const { stdout } = await execa('sudo', ['certbot', 'certificates', '--non-interactive'], {
|
|
61
|
+
timeout: 30000,
|
|
62
|
+
});
|
|
63
|
+
letsencryptCerts = parseCertbotOutput(stdout);
|
|
64
|
+
} catch {
|
|
65
|
+
// certbot may not be installed or may have no certs
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (json) {
|
|
69
|
+
emit({ mtls: mtlsCerts, letsencrypt: letsencryptCerts });
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const b = chalk.bold;
|
|
74
|
+
const c = chalk.cyan;
|
|
75
|
+
const g = chalk.green;
|
|
76
|
+
const y = chalk.yellow;
|
|
77
|
+
const r = chalk.red;
|
|
78
|
+
const d = chalk.dim;
|
|
79
|
+
|
|
80
|
+
console.log('');
|
|
81
|
+
console.log(b(' mTLS Certificates'));
|
|
82
|
+
console.log(d(' ' + '\u2500'.repeat(40)));
|
|
83
|
+
|
|
84
|
+
if (mtlsCerts.length === 0) {
|
|
85
|
+
console.log(` ${d('No mTLS certificates found.')}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
for (const cert of mtlsCerts) {
|
|
89
|
+
const label = cert.type === 'mtls-ca' ? 'CA' : 'Client';
|
|
90
|
+
const status = cert.expiringSoon ? y('expiring soon') : g('valid');
|
|
91
|
+
console.log(
|
|
92
|
+
` ${b(label + ':')} ${status} ${d(`expires in ${cert.daysUntilExpiry} days`)} ${d(cert.expiresAt)}`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (letsencryptCerts.length > 0) {
|
|
97
|
+
console.log('');
|
|
98
|
+
console.log(b(" Let's Encrypt Certificates"));
|
|
99
|
+
console.log(d(' ' + '\u2500'.repeat(40)));
|
|
100
|
+
|
|
101
|
+
for (const cert of letsencryptCerts) {
|
|
102
|
+
const daysLeft = cert.daysUntilExpiry;
|
|
103
|
+
const status = daysLeft <= 7 ? r('critical') : daysLeft <= 30 ? y('expiring') : g('valid');
|
|
104
|
+
console.log(` ${c(cert.domain)} ${status} ${d(`expires in ${daysLeft} days`)}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
console.log('');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @param {{ json: boolean }} options
|
|
113
|
+
*/
|
|
114
|
+
async function certRenew({ json }) {
|
|
115
|
+
if (json) emitStep('renew', 'running', 'Forcing certificate renewal');
|
|
116
|
+
else process.stderr.write(' Forcing certificate renewal...');
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
await execa(
|
|
120
|
+
'sudo',
|
|
121
|
+
['certbot', 'renew', '--force-renewal', '--no-random-sleep-on-renew', '--non-interactive'],
|
|
122
|
+
{
|
|
123
|
+
timeout: 120000,
|
|
124
|
+
},
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
// Reload nginx to pick up new certs
|
|
128
|
+
await execa('sudo', ['nginx', '-t']);
|
|
129
|
+
await execa('sudo', ['systemctl', 'reload', 'nginx']);
|
|
130
|
+
|
|
131
|
+
if (json) {
|
|
132
|
+
emitStep('renew', 'complete');
|
|
133
|
+
emitComplete({ renewed: true });
|
|
134
|
+
} else {
|
|
135
|
+
console.log(` ${chalk.green('ok')}`);
|
|
136
|
+
console.log(' Certificates renewed and nginx reloaded.\n');
|
|
137
|
+
}
|
|
138
|
+
} catch (err) {
|
|
139
|
+
const msg = err.stderr || err.message;
|
|
140
|
+
if (json) {
|
|
141
|
+
emitStep('renew', 'failed', msg);
|
|
142
|
+
emitError(msg);
|
|
143
|
+
} else {
|
|
144
|
+
console.log(` ${chalk.red('failed')}`);
|
|
145
|
+
console.error(` ${chalk.red(msg)}\n`);
|
|
146
|
+
}
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* @param {{ json: boolean }} options
|
|
153
|
+
*/
|
|
154
|
+
async function agentCerts({ json }) {
|
|
155
|
+
const agents = await listAgentCerts(PKI_DIR);
|
|
156
|
+
|
|
157
|
+
if (json) {
|
|
158
|
+
emit({ agents });
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const b = chalk.bold;
|
|
163
|
+
const c = chalk.cyan;
|
|
164
|
+
const r = chalk.red;
|
|
165
|
+
const y = chalk.yellow;
|
|
166
|
+
const d = chalk.dim;
|
|
167
|
+
|
|
168
|
+
console.log('');
|
|
169
|
+
console.log(b(' Agent Certificates'));
|
|
170
|
+
console.log(d(' ' + '\u2500'.repeat(50)));
|
|
171
|
+
|
|
172
|
+
if (agents.length === 0) {
|
|
173
|
+
console.log(` ${d('No agent certificates.')}`);
|
|
174
|
+
console.log('');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
for (const agent of agents) {
|
|
179
|
+
const revoked = agent.revoked ? r(' [REVOKED]') : '';
|
|
180
|
+
const expiring = agent.expiringSoon ? y(' [EXPIRING]') : '';
|
|
181
|
+
const method = agent.enrollmentMethod === 'hardware-bound' ? d(' (hw-bound)') : '';
|
|
182
|
+
const certType = agent.certType === 'plugin-agent' ? d(' (plugin)') : '';
|
|
183
|
+
console.log(` ${c(agent.label)}${certType}${method} ${d(agent.serial)}${revoked}${expiring}`);
|
|
184
|
+
|
|
185
|
+
if (agent.capabilities.length > 0) {
|
|
186
|
+
console.log(` ${d('capabilities:')} ${agent.capabilities.join(', ')}`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (agent.expiresAt) {
|
|
190
|
+
console.log(` ${d(`expires: ${agent.expiresAt}`)}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
console.log('');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Parse certbot certificates output into structured data.
|
|
198
|
+
* @param {string} output
|
|
199
|
+
* @returns {Array<{ domain: string, daysUntilExpiry: number, expiresAt: string }>}
|
|
200
|
+
*/
|
|
201
|
+
function parseCertbotOutput(output) {
|
|
202
|
+
const certs = [];
|
|
203
|
+
const blocks = output.split('Certificate Name:').slice(1);
|
|
204
|
+
|
|
205
|
+
for (const block of blocks) {
|
|
206
|
+
const domainMatch = block.match(/Domains:\s+(.+)/);
|
|
207
|
+
const expiryMatch = block.match(/Expiry Date:\s+(\S+ \S+ \S+ \S+ \S+)/);
|
|
208
|
+
|
|
209
|
+
if (domainMatch && expiryMatch) {
|
|
210
|
+
const domain = domainMatch[1].trim().split(/\s+/)[0];
|
|
211
|
+
const expiryDate = new Date(expiryMatch[1]);
|
|
212
|
+
const daysUntilExpiry = Math.floor(
|
|
213
|
+
(expiryDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24),
|
|
214
|
+
);
|
|
215
|
+
certs.push({
|
|
216
|
+
domain,
|
|
217
|
+
daysUntilExpiry,
|
|
218
|
+
expiresAt: expiryDate.toISOString(),
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return certs;
|
|
224
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lamaste-server chisel — manage chisel tunnel-server credentials.
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* rotate-credential --label <label> Mint a fresh chisel password for an
|
|
6
|
+
* existing agent and restart the
|
|
7
|
+
* chisel service. The agent must
|
|
8
|
+
* re-fetch via
|
|
9
|
+
* `lamaste-agent chisel refresh-credential`.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import chalk from 'chalk';
|
|
13
|
+
import { panelRequest } from '../panel-api.js';
|
|
14
|
+
import { emit, emitError, emitComplete } from '../ndjson.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {string[]} args
|
|
18
|
+
* @param {{ json: boolean }} options
|
|
19
|
+
*/
|
|
20
|
+
export async function runChisel(args, { json }) {
|
|
21
|
+
const sub = args[0];
|
|
22
|
+
|
|
23
|
+
switch (sub) {
|
|
24
|
+
case 'rotate-credential':
|
|
25
|
+
return rotateCredential(args.slice(1), { json });
|
|
26
|
+
default:
|
|
27
|
+
printChiselUsage();
|
|
28
|
+
process.exit(sub ? 1 : 0);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function printChiselUsage() {
|
|
33
|
+
const b = chalk.bold;
|
|
34
|
+
const c = chalk.cyan;
|
|
35
|
+
console.log(`
|
|
36
|
+
${b('Usage:')} lamaste-server chisel <subcommand>
|
|
37
|
+
|
|
38
|
+
${b('Subcommands:')}
|
|
39
|
+
${c('rotate-credential')} --label <label> Mint a new chisel credential for an agent
|
|
40
|
+
|
|
41
|
+
${b('Notes:')}
|
|
42
|
+
After rotating, the affected agent must run
|
|
43
|
+
${c('lamaste-agent chisel refresh-credential --label <label>')} to pick up
|
|
44
|
+
the new credential. Until then its tunnels will fail to authenticate.
|
|
45
|
+
`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {string[]} args
|
|
50
|
+
* @param {{ json: boolean }} options
|
|
51
|
+
*/
|
|
52
|
+
async function rotateCredential(args, { json }) {
|
|
53
|
+
const label = getArg(args, 'label');
|
|
54
|
+
if (!label) {
|
|
55
|
+
const msg = 'Error: --label is required';
|
|
56
|
+
if (json) emitError(msg);
|
|
57
|
+
else console.error(`\n ${msg}\n`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!json) {
|
|
62
|
+
process.stderr.write(` Rotating chisel credential for ${chalk.cyan(label)}...`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
// The panel API does the heavy lifting: writes the new credential, regenerates
|
|
67
|
+
// the chisel-users authfile, and restarts the chisel service.
|
|
68
|
+
const result = await panelRequest(
|
|
69
|
+
'POST',
|
|
70
|
+
`/api/agents/${encodeURIComponent(label)}/chisel-credential/rotate`,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
if (json) {
|
|
74
|
+
emitComplete({
|
|
75
|
+
label: result.label,
|
|
76
|
+
user: result.user,
|
|
77
|
+
password: result.password,
|
|
78
|
+
restartOk: result.restartOk,
|
|
79
|
+
restartError: result.restartError || null,
|
|
80
|
+
});
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
console.log(` ${chalk.green('ok')}`);
|
|
85
|
+
console.log('');
|
|
86
|
+
console.log(` ${chalk.bold('user:')} ${chalk.cyan(result.user)}`);
|
|
87
|
+
// SECURITY: the rotated chisel password is NEVER written to a log sink
|
|
88
|
+
// (stdout/stderr/console). It is persisted server-side in the chisel
|
|
89
|
+
// credentials store (mode 0600). Scripted consumers must use the
|
|
90
|
+
// non-interactive JSON mode (`--json`), which emits the password in
|
|
91
|
+
// the NDJSON `complete` event for direct programmatic capture.
|
|
92
|
+
console.log(
|
|
93
|
+
` ${chalk.bold('password:')} ${chalk.dim('*** (redacted — use --json to retrieve)')}`,
|
|
94
|
+
);
|
|
95
|
+
if (!result.restartOk) {
|
|
96
|
+
console.log('');
|
|
97
|
+
console.log(
|
|
98
|
+
` ${chalk.yellow('warning:')} chisel service restart failed: ${result.restartError}`,
|
|
99
|
+
);
|
|
100
|
+
console.log(
|
|
101
|
+
` ${chalk.dim('Run `sudo systemctl restart chisel` manually before any tunnels reconnect.')}`,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
console.log('');
|
|
105
|
+
console.log(
|
|
106
|
+
` ${chalk.dim('On the agent host, run:')} ${chalk.cyan(`lamaste-agent chisel refresh-credential --label ${label}`)}`,
|
|
107
|
+
);
|
|
108
|
+
console.log('');
|
|
109
|
+
} catch (err) {
|
|
110
|
+
if (json) {
|
|
111
|
+
emitError(err.message);
|
|
112
|
+
} else {
|
|
113
|
+
console.log(` ${chalk.red('failed')}`);
|
|
114
|
+
console.error(` ${chalk.red(err.message)}\n`);
|
|
115
|
+
}
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Silence linter for unused emit
|
|
120
|
+
void emit;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @param {string[]} args
|
|
125
|
+
* @param {string} name
|
|
126
|
+
* @returns {string | null}
|
|
127
|
+
*/
|
|
128
|
+
function getArg(args, name) {
|
|
129
|
+
const idx = args.indexOf(`--${name}`);
|
|
130
|
+
if (idx === -1 || idx + 1 >= args.length) return null;
|
|
131
|
+
return args[idx + 1];
|
|
132
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lamaste-server logs — View server log output.
|
|
3
|
+
*
|
|
4
|
+
* Wraps journalctl for the panel service. Supports --follow and --lines.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { execa } from 'execa';
|
|
8
|
+
import { PANEL_SERVICE, GATEKEEPER_SERVICE } from '../config.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {string[]} args Remaining CLI arguments after 'logs'
|
|
12
|
+
* @param {{ json: boolean }} options
|
|
13
|
+
*/
|
|
14
|
+
export async function runLogs(args, { json }) {
|
|
15
|
+
const follow = args.includes('--follow') || args.includes('-f');
|
|
16
|
+
const service = args.includes('--gatekeeper') ? GATEKEEPER_SERVICE : PANEL_SERVICE;
|
|
17
|
+
|
|
18
|
+
let lines = '50';
|
|
19
|
+
for (let i = 0; i < args.length; i++) {
|
|
20
|
+
if ((args[i] === '--lines' || args[i] === '-n') && args[i + 1]) {
|
|
21
|
+
lines = args[i + 1];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const journalArgs = ['-u', service, '-n', lines, '--no-pager'];
|
|
26
|
+
|
|
27
|
+
if (follow) {
|
|
28
|
+
journalArgs.push('-f');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (json) {
|
|
32
|
+
journalArgs.push('-o', 'json');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// For --follow we need to stream output to the user's terminal.
|
|
36
|
+
// For non-follow we capture and print.
|
|
37
|
+
if (follow) {
|
|
38
|
+
const proc = execa('journalctl', journalArgs, { stdio: 'inherit' });
|
|
39
|
+
// Let the user Ctrl+C to stop
|
|
40
|
+
await proc.catch((err) => {
|
|
41
|
+
// SIGINT/SIGTERM are expected when tailing
|
|
42
|
+
if (err.signal === 'SIGINT' || err.signal === 'SIGTERM') return;
|
|
43
|
+
throw err;
|
|
44
|
+
});
|
|
45
|
+
} else {
|
|
46
|
+
const { stdout } = await execa('journalctl', journalArgs);
|
|
47
|
+
process.stdout.write(stdout + '\n');
|
|
48
|
+
}
|
|
49
|
+
}
|