@sebspark/gcp-iam 0.3.1 → 0.4.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/README.md +7 -0
- package/dist/index.d.mts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +27 -19
- package/dist/index.mjs +24 -16
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
1
|
# `@sebspark/gcp-iam`
|
|
2
2
|
|
|
3
3
|
Google IAM utilities. This package is intended to be run in GCP contexts, such as running under a GKE service account using Workload Identity.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# Explanation
|
|
7
|
+
|
|
8
|
+
It generates the JWT that we put into the proxy-authorization header. That JWT is signed by the GCP service account and the aud part of the JWT is set to the URL we are going to call in the API Gateway.
|
|
9
|
+
|
|
10
|
+
Generating and signing the JWT uses a bunch of CPU cycles, so it makes sense to cache them for a short time.
|
package/dist/index.d.mts
CHANGED
|
@@ -8,6 +8,11 @@ import { Logger } from 'winston';
|
|
|
8
8
|
* @param logger An optional logger to use for logging.
|
|
9
9
|
* @returns A JWT.
|
|
10
10
|
*/
|
|
11
|
-
declare const getApiGatewayToken: (apiURL
|
|
11
|
+
declare const getApiGatewayToken: ({ apiURL, key, ttl, logger, }: {
|
|
12
|
+
apiURL: string;
|
|
13
|
+
key?: string;
|
|
14
|
+
ttl?: number;
|
|
15
|
+
logger?: Logger;
|
|
16
|
+
}) => Promise<string>;
|
|
12
17
|
|
|
13
18
|
export { getApiGatewayToken };
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,11 @@ import { Logger } from 'winston';
|
|
|
8
8
|
* @param logger An optional logger to use for logging.
|
|
9
9
|
* @returns A JWT.
|
|
10
10
|
*/
|
|
11
|
-
declare const getApiGatewayToken: (apiURL
|
|
11
|
+
declare const getApiGatewayToken: ({ apiURL, key, ttl, logger, }: {
|
|
12
|
+
apiURL: string;
|
|
13
|
+
key?: string;
|
|
14
|
+
ttl?: number;
|
|
15
|
+
logger?: Logger;
|
|
16
|
+
}) => Promise<string>;
|
|
12
17
|
|
|
13
18
|
export { getApiGatewayToken };
|
package/dist/index.js
CHANGED
|
@@ -18,11 +18,11 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
|
|
20
20
|
// src/index.ts
|
|
21
|
-
var
|
|
22
|
-
__export(
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
23
|
getApiGatewayToken: () => getApiGatewayToken
|
|
24
24
|
});
|
|
25
|
-
module.exports = __toCommonJS(
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
26
|
|
|
27
27
|
// src/apiGatewayToken.ts
|
|
28
28
|
var import_iam_credentials = require("@google-cloud/iam-credentials");
|
|
@@ -32,17 +32,17 @@ var import_google_auth_library = require("google-auth-library");
|
|
|
32
32
|
var LruCache = class {
|
|
33
33
|
values = /* @__PURE__ */ new Map();
|
|
34
34
|
maxEntries = 1e4;
|
|
35
|
-
|
|
36
|
-
//
|
|
35
|
+
defaultTTL = 1e3 * 10;
|
|
36
|
+
// 10 seconds
|
|
37
37
|
constructor(props) {
|
|
38
|
-
this.
|
|
39
|
-
this.maxEntries =
|
|
38
|
+
this.defaultTTL = props?.ttl ?? this.defaultTTL;
|
|
39
|
+
this.maxEntries = props?.maxEntries ?? this.maxEntries;
|
|
40
40
|
}
|
|
41
41
|
get(key) {
|
|
42
42
|
const hasKey = this.values.has(key);
|
|
43
43
|
if (hasKey) {
|
|
44
44
|
const entry = this.values.get(key);
|
|
45
|
-
if (Date.now() - entry.timestamp >
|
|
45
|
+
if (Date.now() - entry.timestamp > entry.ttl) {
|
|
46
46
|
this.values.delete(key);
|
|
47
47
|
return void 0;
|
|
48
48
|
}
|
|
@@ -51,22 +51,29 @@ var LruCache = class {
|
|
|
51
51
|
return entry.data;
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
-
put(key, value) {
|
|
54
|
+
put(key, value, ttl) {
|
|
55
55
|
if (this.values.size >= this.maxEntries) {
|
|
56
56
|
const keyToDelete = this.values.keys().next().value;
|
|
57
57
|
this.values.delete(keyToDelete);
|
|
58
58
|
}
|
|
59
|
-
this.values.set(key, {
|
|
59
|
+
this.values.set(key, {
|
|
60
|
+
data: value,
|
|
61
|
+
timestamp: Date.now(),
|
|
62
|
+
ttl: ttl || this.defaultTTL
|
|
63
|
+
});
|
|
60
64
|
}
|
|
61
65
|
};
|
|
62
66
|
|
|
63
67
|
// src/apiGatewayToken.ts
|
|
64
68
|
var expInSeconds = 60 * 60;
|
|
65
|
-
var apiGatewayJwtCache = new LruCache(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
var apiGatewayJwtCache = new LruCache();
|
|
70
|
+
var getApiGatewayToken = async ({
|
|
71
|
+
apiURL,
|
|
72
|
+
key,
|
|
73
|
+
ttl,
|
|
74
|
+
logger
|
|
75
|
+
}) => {
|
|
76
|
+
const cachedJwt = apiGatewayJwtCache.get(key || apiURL);
|
|
70
77
|
if (cachedJwt) {
|
|
71
78
|
return cachedJwt;
|
|
72
79
|
}
|
|
@@ -78,7 +85,7 @@ var getApiGatewayToken = async (apiURL, logger) => {
|
|
|
78
85
|
if (!serviceAccountEmail) {
|
|
79
86
|
throw new Error("No service account e-mail could be found.");
|
|
80
87
|
}
|
|
81
|
-
logger
|
|
88
|
+
logger?.info(`Serice account e-mail beeing used: ${serviceAccountEmail}`);
|
|
82
89
|
const header = {
|
|
83
90
|
alg: "RS256",
|
|
84
91
|
typ: "JWT"
|
|
@@ -106,16 +113,17 @@ var getApiGatewayToken = async (apiURL, logger) => {
|
|
|
106
113
|
"signBlob(...) returned an empty response. Cannot sign JWT."
|
|
107
114
|
);
|
|
108
115
|
}
|
|
116
|
+
console.log("IAM KeyID", response.keyId);
|
|
109
117
|
const signature = Buffer.from(response.signedBlob).toString("base64");
|
|
110
118
|
const signedJWT = `${unsignedJWT}.${signature}`;
|
|
111
|
-
apiGatewayJwtCache.put(apiURL, signedJWT);
|
|
119
|
+
apiGatewayJwtCache.put(key || apiURL, signedJWT, ttl);
|
|
112
120
|
return signedJWT;
|
|
113
121
|
} catch (error) {
|
|
114
122
|
if (process.env.GCP_IAM_SOFT_FAIL === "true") {
|
|
115
|
-
logger
|
|
123
|
+
logger?.warn("Soft fail enabled, returning empty JWT");
|
|
116
124
|
return "";
|
|
117
125
|
}
|
|
118
|
-
logger
|
|
126
|
+
logger?.error("Error generating system JWT", error);
|
|
119
127
|
throw new Error(`Error generating system JWT: ${JSON.stringify(error)}`);
|
|
120
128
|
}
|
|
121
129
|
};
|
package/dist/index.mjs
CHANGED
|
@@ -6,17 +6,17 @@ import { GoogleAuth } from "google-auth-library";
|
|
|
6
6
|
var LruCache = class {
|
|
7
7
|
values = /* @__PURE__ */ new Map();
|
|
8
8
|
maxEntries = 1e4;
|
|
9
|
-
|
|
10
|
-
//
|
|
9
|
+
defaultTTL = 1e3 * 10;
|
|
10
|
+
// 10 seconds
|
|
11
11
|
constructor(props) {
|
|
12
|
-
this.
|
|
13
|
-
this.maxEntries =
|
|
12
|
+
this.defaultTTL = props?.ttl ?? this.defaultTTL;
|
|
13
|
+
this.maxEntries = props?.maxEntries ?? this.maxEntries;
|
|
14
14
|
}
|
|
15
15
|
get(key) {
|
|
16
16
|
const hasKey = this.values.has(key);
|
|
17
17
|
if (hasKey) {
|
|
18
18
|
const entry = this.values.get(key);
|
|
19
|
-
if (Date.now() - entry.timestamp >
|
|
19
|
+
if (Date.now() - entry.timestamp > entry.ttl) {
|
|
20
20
|
this.values.delete(key);
|
|
21
21
|
return void 0;
|
|
22
22
|
}
|
|
@@ -25,22 +25,29 @@ var LruCache = class {
|
|
|
25
25
|
return entry.data;
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
put(key, value) {
|
|
28
|
+
put(key, value, ttl) {
|
|
29
29
|
if (this.values.size >= this.maxEntries) {
|
|
30
30
|
const keyToDelete = this.values.keys().next().value;
|
|
31
31
|
this.values.delete(keyToDelete);
|
|
32
32
|
}
|
|
33
|
-
this.values.set(key, {
|
|
33
|
+
this.values.set(key, {
|
|
34
|
+
data: value,
|
|
35
|
+
timestamp: Date.now(),
|
|
36
|
+
ttl: ttl || this.defaultTTL
|
|
37
|
+
});
|
|
34
38
|
}
|
|
35
39
|
};
|
|
36
40
|
|
|
37
41
|
// src/apiGatewayToken.ts
|
|
38
42
|
var expInSeconds = 60 * 60;
|
|
39
|
-
var apiGatewayJwtCache = new LruCache(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
var apiGatewayJwtCache = new LruCache();
|
|
44
|
+
var getApiGatewayToken = async ({
|
|
45
|
+
apiURL,
|
|
46
|
+
key,
|
|
47
|
+
ttl,
|
|
48
|
+
logger
|
|
49
|
+
}) => {
|
|
50
|
+
const cachedJwt = apiGatewayJwtCache.get(key || apiURL);
|
|
44
51
|
if (cachedJwt) {
|
|
45
52
|
return cachedJwt;
|
|
46
53
|
}
|
|
@@ -52,7 +59,7 @@ var getApiGatewayToken = async (apiURL, logger) => {
|
|
|
52
59
|
if (!serviceAccountEmail) {
|
|
53
60
|
throw new Error("No service account e-mail could be found.");
|
|
54
61
|
}
|
|
55
|
-
logger
|
|
62
|
+
logger?.info(`Serice account e-mail beeing used: ${serviceAccountEmail}`);
|
|
56
63
|
const header = {
|
|
57
64
|
alg: "RS256",
|
|
58
65
|
typ: "JWT"
|
|
@@ -80,16 +87,17 @@ var getApiGatewayToken = async (apiURL, logger) => {
|
|
|
80
87
|
"signBlob(...) returned an empty response. Cannot sign JWT."
|
|
81
88
|
);
|
|
82
89
|
}
|
|
90
|
+
console.log("IAM KeyID", response.keyId);
|
|
83
91
|
const signature = Buffer.from(response.signedBlob).toString("base64");
|
|
84
92
|
const signedJWT = `${unsignedJWT}.${signature}`;
|
|
85
|
-
apiGatewayJwtCache.put(apiURL, signedJWT);
|
|
93
|
+
apiGatewayJwtCache.put(key || apiURL, signedJWT, ttl);
|
|
86
94
|
return signedJWT;
|
|
87
95
|
} catch (error) {
|
|
88
96
|
if (process.env.GCP_IAM_SOFT_FAIL === "true") {
|
|
89
|
-
logger
|
|
97
|
+
logger?.warn("Soft fail enabled, returning empty JWT");
|
|
90
98
|
return "";
|
|
91
99
|
}
|
|
92
|
-
logger
|
|
100
|
+
logger?.error("Error generating system JWT", error);
|
|
93
101
|
throw new Error(`Error generating system JWT: ${JSON.stringify(error)}`);
|
|
94
102
|
}
|
|
95
103
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sebspark/gcp-iam",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -20,6 +20,6 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@google-cloud/iam-credentials": "3.3.0",
|
|
23
|
-
"google-auth-library": "
|
|
23
|
+
"google-auth-library": "9.15.1"
|
|
24
24
|
}
|
|
25
25
|
}
|