@datacules/agent-identity-store-spiffe 0.11.0 → 0.11.1
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 +109 -0
- package/dist/cjs/SpiffeCredentialStore.js +177 -0
- package/dist/cjs/SpiffeCredentialStore.js.map +1 -0
- package/dist/cjs/index.js +6 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/esm/SpiffeCredentialStore.js +140 -0
- package/dist/esm/SpiffeCredentialStore.js.map +1 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/types/SpiffeCredentialStore.d.ts +72 -0
- package/dist/types/SpiffeCredentialStore.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +19 -6
package/LICENSE
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
Datacules Agent Identity License — Version 1.0
|
|
2
|
+
Copyright (c) 2026 Datacules LLC. All rights reserved.
|
|
3
|
+
|
|
4
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
PREAMBLE
|
|
6
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
7
|
+
|
|
8
|
+
This software — Agent Identity & Auth Patterns — is developed and owned by
|
|
9
|
+
Datacules LLC. It is made available to the public as open-source software
|
|
10
|
+
under the permissive terms below.
|
|
11
|
+
|
|
12
|
+
Datacules LLC retains ownership and authorship of this software while
|
|
13
|
+
granting broad, royalty-free rights for anyone to use, copy, modify, and
|
|
14
|
+
distribute it — in commercial or non-commercial contexts — without requiring
|
|
15
|
+
that derivative works also become open source.
|
|
16
|
+
|
|
17
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
TERMS AND CONDITIONS
|
|
19
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
1. PERMISSION TO USE
|
|
22
|
+
|
|
23
|
+
Permission is hereby granted, free of charge, to any person or
|
|
24
|
+
organization obtaining a copy of this software and associated
|
|
25
|
+
documentation files (the "Software"), to use, copy, modify, merge,
|
|
26
|
+
publish, distribute, sublicense, and/or sell copies of the Software,
|
|
27
|
+
and to permit persons to whom the Software is furnished to do so,
|
|
28
|
+
subject to the conditions below.
|
|
29
|
+
|
|
30
|
+
2. ATTRIBUTION
|
|
31
|
+
|
|
32
|
+
a. Redistributions of source code must retain this copyright notice,
|
|
33
|
+
this list of conditions, and the disclaimer below.
|
|
34
|
+
|
|
35
|
+
b. Redistributions in binary form or as a product must reproduce this
|
|
36
|
+
copyright notice, this list of conditions, and the disclaimer in the
|
|
37
|
+
documentation and/or other materials provided with the distribution.
|
|
38
|
+
|
|
39
|
+
c. Neither the name "Datacules LLC" nor the names of its contributors
|
|
40
|
+
may be used to endorse or promote products derived from this Software
|
|
41
|
+
without prior written permission from Datacules LLC.
|
|
42
|
+
|
|
43
|
+
3. COMMERCIAL USE
|
|
44
|
+
|
|
45
|
+
Use of this Software in commercial products, SaaS platforms, internal
|
|
46
|
+
enterprise tools, or any revenue-generating context is explicitly
|
|
47
|
+
permitted without royalty, fee, or additional licensing agreement,
|
|
48
|
+
provided that the conditions in Section 2 (Attribution) are met.
|
|
49
|
+
|
|
50
|
+
4. NO COPYLEFT / NO VIRAL REQUIREMENT
|
|
51
|
+
|
|
52
|
+
This license does NOT require that derivative works, modifications,
|
|
53
|
+
or software that uses or embeds this Software be made open source.
|
|
54
|
+
You may incorporate this Software into proprietary or closed-source
|
|
55
|
+
products under your own license terms.
|
|
56
|
+
|
|
57
|
+
5. MODIFICATIONS
|
|
58
|
+
|
|
59
|
+
Modified versions of the Software may be distributed under the same
|
|
60
|
+
terms as this license or under any other permissive open-source
|
|
61
|
+
license (e.g. MIT, Apache 2.0, BSD), provided that:
|
|
62
|
+
|
|
63
|
+
a. The original copyright notice of Datacules LLC is preserved.
|
|
64
|
+
b. Modifications are clearly documented and distinguished from the
|
|
65
|
+
original work.
|
|
66
|
+
|
|
67
|
+
6. COMPATIBILITY
|
|
68
|
+
|
|
69
|
+
This license is compatible with other permissive open-source licenses
|
|
70
|
+
such as MIT, BSD 2-Clause, BSD 3-Clause, and Apache License 2.0. It
|
|
71
|
+
is also GPL-compatible — this Software may coexist with GPL-licensed
|
|
72
|
+
code, though this Software itself is not distributed under the GPL.
|
|
73
|
+
|
|
74
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
75
|
+
DISCLAIMER
|
|
76
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
77
|
+
|
|
78
|
+
THIS SOFTWARE IS PROVIDED BY DATACULES LLC AND CONTRIBUTORS "AS IS" AND
|
|
79
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
80
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
|
|
81
|
+
AND NON-INFRINGEMENT ARE DISCLAIMED.
|
|
82
|
+
|
|
83
|
+
IN NO EVENT SHALL DATACULES LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
84
|
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
85
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
86
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
87
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
88
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
89
|
+
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
90
|
+
|
|
91
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
92
|
+
SUMMARY (non-binding)
|
|
93
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
✔ Use freely — commercial, proprietary, or open-source projects
|
|
96
|
+
✔ Modify and distribute with or without changes
|
|
97
|
+
✔ Sell products built on this Software
|
|
98
|
+
✔ No royalties or fees
|
|
99
|
+
✔ No requirement to open-source your own code
|
|
100
|
+
✔ Attribution to Datacules LLC required in source and binary distributions
|
|
101
|
+
✗ Do not use "Datacules LLC" to endorse derived products without permission
|
|
102
|
+
|
|
103
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
104
|
+
CONTACT
|
|
105
|
+
─────────────────────────────────────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
Datacules LLC
|
|
108
|
+
For licensing enquiries: legal@datacules.com
|
|
109
|
+
Product: https://github.com/hvrcharon1/agent-identity
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @datacules/agent-identity-store-spiffe
|
|
4
|
+
*
|
|
5
|
+
* SPIFFE/SPIRE workload identity credential store.
|
|
6
|
+
*
|
|
7
|
+
* Instead of static credentials stored in a vault, this store uses the
|
|
8
|
+
* SPIFFE Workload API to fetch short-lived X.509 SVIDs (SPIFFE Verifiable
|
|
9
|
+
* Identity Documents) on demand. Each SVID is valid for a configurable TTL
|
|
10
|
+
* (default: 1 hour) and is automatically rotated by the SPIRE agent.
|
|
11
|
+
*
|
|
12
|
+
* How it works:
|
|
13
|
+
* 1. On resolve(), the store looks up a Credential by ref.
|
|
14
|
+
* 2. If the credential is of kind 'spiffe', it calls the Workload API
|
|
15
|
+
* to fetch the current X.509 SVID bundle for the workload's SPIFFE ID.
|
|
16
|
+
* 3. The SVID's leaf certificate + private key are returned as the
|
|
17
|
+
* credential ref — downstream services verify the chain against the
|
|
18
|
+
* trust bundle, not against a static API key.
|
|
19
|
+
* 4. The store caches unexpired SVIDs in memory to avoid Workload API
|
|
20
|
+
* round-trips on every resolve() call.
|
|
21
|
+
*
|
|
22
|
+
* Zero static secrets at rest — a full store compromise yields only
|
|
23
|
+
* workload metadata, not any usable credential material.
|
|
24
|
+
*
|
|
25
|
+
* Compatible with: SPIRE server, SPIRE agent, any SPIFFE-compliant runtime.
|
|
26
|
+
* Workload API socket: unix:///tmp/spire-agent/public/api.sock (default)
|
|
27
|
+
* or SPIFFE_ENDPOINT_SOCKET env var.
|
|
28
|
+
*/
|
|
29
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
30
|
+
if (k2 === undefined) k2 = k;
|
|
31
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
32
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
33
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
34
|
+
}
|
|
35
|
+
Object.defineProperty(o, k2, desc);
|
|
36
|
+
}) : (function(o, m, k, k2) {
|
|
37
|
+
if (k2 === undefined) k2 = k;
|
|
38
|
+
o[k2] = m[k];
|
|
39
|
+
}));
|
|
40
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
41
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
42
|
+
}) : function(o, v) {
|
|
43
|
+
o["default"] = v;
|
|
44
|
+
});
|
|
45
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
46
|
+
var ownKeys = function(o) {
|
|
47
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
48
|
+
var ar = [];
|
|
49
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
50
|
+
return ar;
|
|
51
|
+
};
|
|
52
|
+
return ownKeys(o);
|
|
53
|
+
};
|
|
54
|
+
return function (mod) {
|
|
55
|
+
if (mod && mod.__esModule) return mod;
|
|
56
|
+
var result = {};
|
|
57
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
58
|
+
__setModuleDefault(result, mod);
|
|
59
|
+
return result;
|
|
60
|
+
};
|
|
61
|
+
})();
|
|
62
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
63
|
+
exports.SpiffeCredentialStore = void 0;
|
|
64
|
+
// ─── SpiffeCredentialStore ────────────────────────────────────────────────────
|
|
65
|
+
class SpiffeCredentialStore {
|
|
66
|
+
constructor(options) {
|
|
67
|
+
this.svidCache = new Map();
|
|
68
|
+
this.client = null;
|
|
69
|
+
// Migration reservation map: ref → { migrationId, expiresAt }
|
|
70
|
+
this.reservations = new Map();
|
|
71
|
+
this.options = {
|
|
72
|
+
endpointSocket: options.endpointSocket ??
|
|
73
|
+
(typeof process !== 'undefined'
|
|
74
|
+
? process.env['SPIFFE_ENDPOINT_SOCKET'] ?? 'unix:///tmp/spire-agent/public/api.sock'
|
|
75
|
+
: 'unix:///tmp/spire-agent/public/api.sock'),
|
|
76
|
+
cacheTtlSeconds: options.cacheTtlSeconds ?? 3300,
|
|
77
|
+
trustDomain: options.trustDomain ?? 'example.org',
|
|
78
|
+
credentials: options.credentials,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
// ── CredentialStore interface ──────────────────────────────────────────────
|
|
82
|
+
async findByRef(ref) {
|
|
83
|
+
const meta = this.options.credentials.find((c) => c.ref === ref && c.status === 'active');
|
|
84
|
+
if (!meta)
|
|
85
|
+
return null;
|
|
86
|
+
// Fetch the SVID for this ref (cache hit if not expired)
|
|
87
|
+
const svid = await this.getSvid(ref);
|
|
88
|
+
if (!svid)
|
|
89
|
+
return null;
|
|
90
|
+
// Return the credential with the SVID PEM as the live ref value.
|
|
91
|
+
// Callers use the ref to authenticate — here it contains the PEM cert chain.
|
|
92
|
+
return {
|
|
93
|
+
...meta,
|
|
94
|
+
ref: svid.ref,
|
|
95
|
+
expiresAt: svid.expiresAt.toISOString(),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
async listActive() {
|
|
99
|
+
return this.options.credentials.filter((c) => c.status === 'active');
|
|
100
|
+
}
|
|
101
|
+
async listByKind(kind) {
|
|
102
|
+
return this.options.credentials.filter((c) => c.kind === kind && c.status === 'active');
|
|
103
|
+
}
|
|
104
|
+
async reserve(ref, migrationId, ttlSeconds) {
|
|
105
|
+
const existing = this.reservations.get(ref);
|
|
106
|
+
const now = Date.now();
|
|
107
|
+
if (existing && existing.expiresAt > now && existing.migrationId !== migrationId) {
|
|
108
|
+
return false; // held by another migration
|
|
109
|
+
}
|
|
110
|
+
this.reservations.set(ref, { migrationId, expiresAt: now + ttlSeconds * 1000 });
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
async release(ref, migrationId) {
|
|
114
|
+
const existing = this.reservations.get(ref);
|
|
115
|
+
if (existing?.migrationId === migrationId) {
|
|
116
|
+
this.reservations.delete(ref);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// ── Workload API interaction ───────────────────────────────────────────────
|
|
120
|
+
async getSvid(ref) {
|
|
121
|
+
const cached = this.svidCache.get(ref);
|
|
122
|
+
if (cached && cached.expiresAt > new Date())
|
|
123
|
+
return cached;
|
|
124
|
+
try {
|
|
125
|
+
const client = await this.getClient();
|
|
126
|
+
const response = await client.fetchX509Svids();
|
|
127
|
+
// Match SVID by hint (ref) or by spiffeId path segment
|
|
128
|
+
const matched = response.svids.find((s) => s.hint === ref ||
|
|
129
|
+
s.spiffeId.toString().endsWith(`/${ref}`) ||
|
|
130
|
+
s.spiffeId.toString() === `spiffe://${this.options.trustDomain}/${ref}`);
|
|
131
|
+
if (!matched)
|
|
132
|
+
return null;
|
|
133
|
+
const entry = {
|
|
134
|
+
ref: matched.x509Svid.toString(), // PEM cert chain
|
|
135
|
+
expiresAt: new Date(Date.now() + this.options.cacheTtlSeconds * 1000),
|
|
136
|
+
spiffeId: matched.spiffeId.toString(),
|
|
137
|
+
};
|
|
138
|
+
this.svidCache.set(ref, entry);
|
|
139
|
+
return entry;
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
// Workload API unavailable — fail open with null so the router
|
|
143
|
+
// returns 'no credential matched' rather than crashing
|
|
144
|
+
console.error('[SpiffeCredentialStore] Workload API error:', err);
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async getClient() {
|
|
149
|
+
if (this.client)
|
|
150
|
+
return this.client;
|
|
151
|
+
// Lazy-load the optional peer dep
|
|
152
|
+
try {
|
|
153
|
+
const mod = await Promise.resolve(`${'@spiffe/spiffe-workload-api'}`).then(s => __importStar(require(s)));
|
|
154
|
+
const WorkloadApiClientClass = mod
|
|
155
|
+
.WorkloadApiClient;
|
|
156
|
+
if (!WorkloadApiClientClass)
|
|
157
|
+
throw new Error('WorkloadApiClient not found in module');
|
|
158
|
+
this.client = new WorkloadApiClientClass(this.options.endpointSocket);
|
|
159
|
+
return this.client;
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
throw new Error('[SpiffeCredentialStore] @spiffe/spiffe-workload-api is required but not installed. ' +
|
|
163
|
+
'Run: npm install @spiffe/spiffe-workload-api');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/** Flush the SVID cache — useful in tests or after a known rotation event. */
|
|
167
|
+
flushCache() {
|
|
168
|
+
this.svidCache.clear();
|
|
169
|
+
}
|
|
170
|
+
/** Close the Workload API connection. */
|
|
171
|
+
close() {
|
|
172
|
+
this.client?.close();
|
|
173
|
+
this.client = null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
exports.SpiffeCredentialStore = SpiffeCredentialStore;
|
|
177
|
+
//# sourceMappingURL=SpiffeCredentialStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpiffeCredentialStore.js","sourceRoot":"","sources":["../../src/SpiffeCredentialStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SpiffeCredentialStore = void 0;
|
|
4
|
+
var SpiffeCredentialStore_1 = require("./SpiffeCredentialStore");
|
|
5
|
+
Object.defineProperty(exports, "SpiffeCredentialStore", { enumerable: true, get: function () { return SpiffeCredentialStore_1.SpiffeCredentialStore; } });
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,iEAAgE;AAAvD,8HAAA,qBAAqB,OAAA"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @datacules/agent-identity-store-spiffe
|
|
3
|
+
*
|
|
4
|
+
* SPIFFE/SPIRE workload identity credential store.
|
|
5
|
+
*
|
|
6
|
+
* Instead of static credentials stored in a vault, this store uses the
|
|
7
|
+
* SPIFFE Workload API to fetch short-lived X.509 SVIDs (SPIFFE Verifiable
|
|
8
|
+
* Identity Documents) on demand. Each SVID is valid for a configurable TTL
|
|
9
|
+
* (default: 1 hour) and is automatically rotated by the SPIRE agent.
|
|
10
|
+
*
|
|
11
|
+
* How it works:
|
|
12
|
+
* 1. On resolve(), the store looks up a Credential by ref.
|
|
13
|
+
* 2. If the credential is of kind 'spiffe', it calls the Workload API
|
|
14
|
+
* to fetch the current X.509 SVID bundle for the workload's SPIFFE ID.
|
|
15
|
+
* 3. The SVID's leaf certificate + private key are returned as the
|
|
16
|
+
* credential ref — downstream services verify the chain against the
|
|
17
|
+
* trust bundle, not against a static API key.
|
|
18
|
+
* 4. The store caches unexpired SVIDs in memory to avoid Workload API
|
|
19
|
+
* round-trips on every resolve() call.
|
|
20
|
+
*
|
|
21
|
+
* Zero static secrets at rest — a full store compromise yields only
|
|
22
|
+
* workload metadata, not any usable credential material.
|
|
23
|
+
*
|
|
24
|
+
* Compatible with: SPIRE server, SPIRE agent, any SPIFFE-compliant runtime.
|
|
25
|
+
* Workload API socket: unix:///tmp/spire-agent/public/api.sock (default)
|
|
26
|
+
* or SPIFFE_ENDPOINT_SOCKET env var.
|
|
27
|
+
*/
|
|
28
|
+
// ─── SpiffeCredentialStore ────────────────────────────────────────────────────
|
|
29
|
+
export class SpiffeCredentialStore {
|
|
30
|
+
constructor(options) {
|
|
31
|
+
this.svidCache = new Map();
|
|
32
|
+
this.client = null;
|
|
33
|
+
// Migration reservation map: ref → { migrationId, expiresAt }
|
|
34
|
+
this.reservations = new Map();
|
|
35
|
+
this.options = {
|
|
36
|
+
endpointSocket: options.endpointSocket ??
|
|
37
|
+
(typeof process !== 'undefined'
|
|
38
|
+
? process.env['SPIFFE_ENDPOINT_SOCKET'] ?? 'unix:///tmp/spire-agent/public/api.sock'
|
|
39
|
+
: 'unix:///tmp/spire-agent/public/api.sock'),
|
|
40
|
+
cacheTtlSeconds: options.cacheTtlSeconds ?? 3300,
|
|
41
|
+
trustDomain: options.trustDomain ?? 'example.org',
|
|
42
|
+
credentials: options.credentials,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// ── CredentialStore interface ──────────────────────────────────────────────
|
|
46
|
+
async findByRef(ref) {
|
|
47
|
+
const meta = this.options.credentials.find((c) => c.ref === ref && c.status === 'active');
|
|
48
|
+
if (!meta)
|
|
49
|
+
return null;
|
|
50
|
+
// Fetch the SVID for this ref (cache hit if not expired)
|
|
51
|
+
const svid = await this.getSvid(ref);
|
|
52
|
+
if (!svid)
|
|
53
|
+
return null;
|
|
54
|
+
// Return the credential with the SVID PEM as the live ref value.
|
|
55
|
+
// Callers use the ref to authenticate — here it contains the PEM cert chain.
|
|
56
|
+
return {
|
|
57
|
+
...meta,
|
|
58
|
+
ref: svid.ref,
|
|
59
|
+
expiresAt: svid.expiresAt.toISOString(),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
async listActive() {
|
|
63
|
+
return this.options.credentials.filter((c) => c.status === 'active');
|
|
64
|
+
}
|
|
65
|
+
async listByKind(kind) {
|
|
66
|
+
return this.options.credentials.filter((c) => c.kind === kind && c.status === 'active');
|
|
67
|
+
}
|
|
68
|
+
async reserve(ref, migrationId, ttlSeconds) {
|
|
69
|
+
const existing = this.reservations.get(ref);
|
|
70
|
+
const now = Date.now();
|
|
71
|
+
if (existing && existing.expiresAt > now && existing.migrationId !== migrationId) {
|
|
72
|
+
return false; // held by another migration
|
|
73
|
+
}
|
|
74
|
+
this.reservations.set(ref, { migrationId, expiresAt: now + ttlSeconds * 1000 });
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
async release(ref, migrationId) {
|
|
78
|
+
const existing = this.reservations.get(ref);
|
|
79
|
+
if (existing?.migrationId === migrationId) {
|
|
80
|
+
this.reservations.delete(ref);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// ── Workload API interaction ───────────────────────────────────────────────
|
|
84
|
+
async getSvid(ref) {
|
|
85
|
+
const cached = this.svidCache.get(ref);
|
|
86
|
+
if (cached && cached.expiresAt > new Date())
|
|
87
|
+
return cached;
|
|
88
|
+
try {
|
|
89
|
+
const client = await this.getClient();
|
|
90
|
+
const response = await client.fetchX509Svids();
|
|
91
|
+
// Match SVID by hint (ref) or by spiffeId path segment
|
|
92
|
+
const matched = response.svids.find((s) => s.hint === ref ||
|
|
93
|
+
s.spiffeId.toString().endsWith(`/${ref}`) ||
|
|
94
|
+
s.spiffeId.toString() === `spiffe://${this.options.trustDomain}/${ref}`);
|
|
95
|
+
if (!matched)
|
|
96
|
+
return null;
|
|
97
|
+
const entry = {
|
|
98
|
+
ref: matched.x509Svid.toString(), // PEM cert chain
|
|
99
|
+
expiresAt: new Date(Date.now() + this.options.cacheTtlSeconds * 1000),
|
|
100
|
+
spiffeId: matched.spiffeId.toString(),
|
|
101
|
+
};
|
|
102
|
+
this.svidCache.set(ref, entry);
|
|
103
|
+
return entry;
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
// Workload API unavailable — fail open with null so the router
|
|
107
|
+
// returns 'no credential matched' rather than crashing
|
|
108
|
+
console.error('[SpiffeCredentialStore] Workload API error:', err);
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async getClient() {
|
|
113
|
+
if (this.client)
|
|
114
|
+
return this.client;
|
|
115
|
+
// Lazy-load the optional peer dep
|
|
116
|
+
try {
|
|
117
|
+
const mod = await import('@spiffe/spiffe-workload-api');
|
|
118
|
+
const WorkloadApiClientClass = mod
|
|
119
|
+
.WorkloadApiClient;
|
|
120
|
+
if (!WorkloadApiClientClass)
|
|
121
|
+
throw new Error('WorkloadApiClient not found in module');
|
|
122
|
+
this.client = new WorkloadApiClientClass(this.options.endpointSocket);
|
|
123
|
+
return this.client;
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
throw new Error('[SpiffeCredentialStore] @spiffe/spiffe-workload-api is required but not installed. ' +
|
|
127
|
+
'Run: npm install @spiffe/spiffe-workload-api');
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/** Flush the SVID cache — useful in tests or after a known rotation event. */
|
|
131
|
+
flushCache() {
|
|
132
|
+
this.svidCache.clear();
|
|
133
|
+
}
|
|
134
|
+
/** Close the Workload API connection. */
|
|
135
|
+
close() {
|
|
136
|
+
this.client?.close();
|
|
137
|
+
this.client = null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=SpiffeCredentialStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpiffeCredentialStore.js","sourceRoot":"","sources":["../../src/SpiffeCredentialStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @datacules/agent-identity-store-spiffe
|
|
3
|
+
*
|
|
4
|
+
* SPIFFE/SPIRE workload identity credential store.
|
|
5
|
+
*
|
|
6
|
+
* Instead of static credentials stored in a vault, this store uses the
|
|
7
|
+
* SPIFFE Workload API to fetch short-lived X.509 SVIDs (SPIFFE Verifiable
|
|
8
|
+
* Identity Documents) on demand. Each SVID is valid for a configurable TTL
|
|
9
|
+
* (default: 1 hour) and is automatically rotated by the SPIRE agent.
|
|
10
|
+
*
|
|
11
|
+
* How it works:
|
|
12
|
+
* 1. On resolve(), the store looks up a Credential by ref.
|
|
13
|
+
* 2. If the credential is of kind 'spiffe', it calls the Workload API
|
|
14
|
+
* to fetch the current X.509 SVID bundle for the workload's SPIFFE ID.
|
|
15
|
+
* 3. The SVID's leaf certificate + private key are returned as the
|
|
16
|
+
* credential ref — downstream services verify the chain against the
|
|
17
|
+
* trust bundle, not against a static API key.
|
|
18
|
+
* 4. The store caches unexpired SVIDs in memory to avoid Workload API
|
|
19
|
+
* round-trips on every resolve() call.
|
|
20
|
+
*
|
|
21
|
+
* Zero static secrets at rest — a full store compromise yields only
|
|
22
|
+
* workload metadata, not any usable credential material.
|
|
23
|
+
*
|
|
24
|
+
* Compatible with: SPIRE server, SPIRE agent, any SPIFFE-compliant runtime.
|
|
25
|
+
* Workload API socket: unix:///tmp/spire-agent/public/api.sock (default)
|
|
26
|
+
* or SPIFFE_ENDPOINT_SOCKET env var.
|
|
27
|
+
*/
|
|
28
|
+
import type { Credential, CredentialStore } from '@datacules/agent-identity';
|
|
29
|
+
export interface SpiffeCredentialStoreOptions {
|
|
30
|
+
/**
|
|
31
|
+
* SPIFFE Workload API endpoint.
|
|
32
|
+
* Defaults to SPIFFE_ENDPOINT_SOCKET env var or
|
|
33
|
+
* unix:///tmp/spire-agent/public/api.sock
|
|
34
|
+
*/
|
|
35
|
+
endpointSocket?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Cache SVIDs for up to this many seconds before re-fetching.
|
|
38
|
+
* Should be less than the SVID TTL configured in SPIRE.
|
|
39
|
+
* Default: 3300 (55 minutes — 5 minute buffer before 1h SVID expires).
|
|
40
|
+
*/
|
|
41
|
+
cacheTtlSeconds?: number;
|
|
42
|
+
/**
|
|
43
|
+
* Trust domain for SPIFFE IDs (e.g. 'example.org').
|
|
44
|
+
* Used to construct SPIFFE IDs when matching hints.
|
|
45
|
+
*/
|
|
46
|
+
trustDomain?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Static credential metadata (id, name, kind, scope, etc.) indexed by ref.
|
|
49
|
+
* The ref is matched against SVID hints to find the right SVID.
|
|
50
|
+
* Credential values (actual secrets) come from the Workload API, not here.
|
|
51
|
+
*/
|
|
52
|
+
credentials: Credential[];
|
|
53
|
+
}
|
|
54
|
+
export declare class SpiffeCredentialStore implements CredentialStore {
|
|
55
|
+
private readonly options;
|
|
56
|
+
private svidCache;
|
|
57
|
+
private client;
|
|
58
|
+
private reservations;
|
|
59
|
+
constructor(options: SpiffeCredentialStoreOptions);
|
|
60
|
+
findByRef(ref: string): Promise<Credential | null>;
|
|
61
|
+
listActive(): Promise<Credential[]>;
|
|
62
|
+
listByKind(kind: 'fixed' | 'user-delegated'): Promise<Credential[]>;
|
|
63
|
+
reserve(ref: string, migrationId: string, ttlSeconds: number): Promise<boolean>;
|
|
64
|
+
release(ref: string, migrationId: string): Promise<void>;
|
|
65
|
+
private getSvid;
|
|
66
|
+
private getClient;
|
|
67
|
+
/** Flush the SVID cache — useful in tests or after a known rotation event. */
|
|
68
|
+
flushCache(): void;
|
|
69
|
+
/** Close the Workload API connection. */
|
|
70
|
+
close(): void;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=SpiffeCredentialStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpiffeCredentialStore.d.ts","sourceRoot":"","sources":["../../src/SpiffeCredentialStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAsB,MAAM,2BAA2B,CAAC;AAqCjG,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;OAIG;IACH,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAID,qBAAa,qBAAsB,YAAW,eAAe;IAC3D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;IACjE,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,MAAM,CAAkC;IAEhD,OAAO,CAAC,YAAY,CAAiE;gBAEzE,OAAO,EAAE,4BAA4B;IAe3C,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAiBlD,UAAU,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAInC,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,gBAAgB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAMnE,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAU/E,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAShD,OAAO;YAkCP,SAAS;IAoBvB,8EAA8E;IAC9E,UAAU,IAAI,IAAI;IAIlB,yCAAyC;IACzC,KAAK,IAAI,IAAI;CAId"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,YAAY,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datacules/agent-identity-store-spiffe",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "SPIFFE/SPIRE workload identity credential store for @datacules/agent-identity",
|
|
5
5
|
"private": false,
|
|
6
|
+
"author": "Datacules LLC",
|
|
7
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
6
8
|
"type": "module",
|
|
7
9
|
"exports": {
|
|
8
10
|
".": {
|
|
@@ -16,14 +18,15 @@
|
|
|
16
18
|
"types": "./dist/types/index.d.ts",
|
|
17
19
|
"files": [
|
|
18
20
|
"dist",
|
|
19
|
-
"README.md"
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
20
23
|
],
|
|
21
24
|
"scripts": {
|
|
22
25
|
"build": "tsc -p tsconfig.build.json && tsc -p tsconfig.cjs.json",
|
|
23
26
|
"type-check": "tsc --noEmit"
|
|
24
27
|
},
|
|
25
28
|
"peerDependencies": {
|
|
26
|
-
"@datacules/agent-identity": "^0.
|
|
29
|
+
"@datacules/agent-identity": "^0.11.1",
|
|
27
30
|
"@spiffe/spiffe-workload-api": "^1.0.0"
|
|
28
31
|
},
|
|
29
32
|
"peerDependenciesMeta": {
|
|
@@ -35,9 +38,19 @@
|
|
|
35
38
|
"@datacules/agent-identity": "*",
|
|
36
39
|
"typescript": "^5"
|
|
37
40
|
},
|
|
38
|
-
"license": "MIT",
|
|
39
41
|
"repository": {
|
|
40
42
|
"type": "git",
|
|
41
|
-
"url": "https://github.com/hvrcharon1/agent-identity"
|
|
42
|
-
|
|
43
|
+
"url": "https://github.com/hvrcharon1/agent-identity.git",
|
|
44
|
+
"directory": "packages/stores/spiffe"
|
|
45
|
+
},
|
|
46
|
+
"keywords": [
|
|
47
|
+
"agent-identity",
|
|
48
|
+
"spiffe",
|
|
49
|
+
"spire",
|
|
50
|
+
"workload-identity",
|
|
51
|
+
"x509",
|
|
52
|
+
"zero-trust",
|
|
53
|
+
"ai-agents",
|
|
54
|
+
"datacules"
|
|
55
|
+
]
|
|
43
56
|
}
|