@vizamodo/aws-sts-core 0.1.45 → 0.1.49
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/dist/sts/issue.d.ts +0 -3
- package/dist/sts/issue.js +60 -76
- package/package.json +1 -1
package/dist/sts/issue.d.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import type { AwsCredentialResult } from "../types";
|
|
2
2
|
/**
|
|
3
3
|
* Issue short-lived AWS credentials via Roles Anywhere.
|
|
4
|
-
* Preserve:
|
|
5
|
-
* - TTL per profile
|
|
6
|
-
* - isolate-level signing material cache
|
|
7
4
|
*/
|
|
8
5
|
export declare function issueAwsCredentials(input: {
|
|
9
6
|
roleArn: string;
|
package/dist/sts/issue.js
CHANGED
|
@@ -23,7 +23,7 @@ async function getSigningMaterial(input) {
|
|
|
23
23
|
function resolveSessionTtlByProfile(profile) {
|
|
24
24
|
switch (profile) {
|
|
25
25
|
case "HubConsoleReadOnly":
|
|
26
|
-
return 1 * 60 * 60; //
|
|
26
|
+
return 1 * 60 * 60; // 1h
|
|
27
27
|
case "HubBillingReadonly":
|
|
28
28
|
case "HubBillingAdmin":
|
|
29
29
|
return 2 * 60 * 60; // 2h
|
|
@@ -36,14 +36,10 @@ function resolveSessionTtlByProfile(profile) {
|
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
38
38
|
* Issue short-lived AWS credentials via Roles Anywhere.
|
|
39
|
-
* Preserve:
|
|
40
|
-
* - TTL per profile
|
|
41
|
-
* - isolate-level signing material cache
|
|
42
39
|
*/
|
|
43
40
|
export async function issueAwsCredentials(input) {
|
|
44
41
|
const { roleArn, profileArn, trustAnchorArn, region, certBase64, privateKeyPkcs8Base64, profile, } = input;
|
|
45
42
|
// 1. Kiểm tra đầu vào & Fix TTL an toàn
|
|
46
|
-
// AWS mặc định chỉ cho phép 3600s, hãy fix cứng 1h để loại trừ lỗi IAM
|
|
47
43
|
const sessionTtl = Math.min(resolveSessionTtlByProfile(profile), 3600);
|
|
48
44
|
const { signingKey } = await getSigningMaterial({ certBase64, privateKeyPkcs8Base64 });
|
|
49
45
|
// 2. Setup constants
|
|
@@ -53,33 +49,61 @@ export async function issueAwsCredentials(input) {
|
|
|
53
49
|
const amzDate = now.toISOString().replace(/\.\d{3}Z$/, "Z").replace(/[:-]/g, "");
|
|
54
50
|
const dateStamp = amzDate.slice(0, 8);
|
|
55
51
|
const service = "rolesanywhere";
|
|
56
|
-
// 3. Chuẩn bị Body & Cert
|
|
52
|
+
// 3. Chuẩn bị Body & Cert
|
|
57
53
|
const body = JSON.stringify({ trustAnchorArn, profileArn, roleArn, durationSeconds: sessionTtl });
|
|
58
54
|
const payloadHash = await sha256Hex(body);
|
|
59
|
-
//
|
|
60
|
-
const normalizedCert = certBase64
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
55
|
+
// --- REFACTOR: Làm sạch chứng chỉ chặt chẽ ---
|
|
56
|
+
const normalizedCert = certBase64
|
|
57
|
+
.replace(/-----BEGIN CERTIFICATE-----/g, "")
|
|
58
|
+
.replace(/-----END CERTIFICATE-----/g, "")
|
|
59
|
+
.replace(/\s+/g, "");
|
|
60
|
+
// --- REFACTOR: Parser ASN.1 an toàn để lấy Serial Number (DECIMAL) ---
|
|
61
|
+
// --- MINIMAL DER WALK: extract serial number ---
|
|
62
|
+
let certSerialDec;
|
|
63
|
+
try {
|
|
64
|
+
const der = new Uint8Array(base64ToArrayBuffer(normalizedCert));
|
|
65
|
+
let offset = 0;
|
|
66
|
+
// helper: read DER length (short + long form)
|
|
67
|
+
function readLen() {
|
|
68
|
+
const b = der[offset++];
|
|
69
|
+
if ((b & 0x80) === 0)
|
|
70
|
+
return b;
|
|
71
|
+
const n = b & 0x7f;
|
|
72
|
+
let len = 0;
|
|
73
|
+
for (let i = 0; i < n; i++) {
|
|
74
|
+
len = (len << 8) | der[offset++];
|
|
75
|
+
}
|
|
76
|
+
return len;
|
|
77
|
+
}
|
|
78
|
+
// Certificate SEQUENCE
|
|
79
|
+
if (der[offset++] !== 0x30)
|
|
80
|
+
throw new Error("bad cert");
|
|
81
|
+
readLen();
|
|
82
|
+
// TBSCertificate SEQUENCE
|
|
83
|
+
if (der[offset++] !== 0x30)
|
|
84
|
+
throw new Error("bad tbs");
|
|
85
|
+
readLen();
|
|
86
|
+
// Optional version [0] EXPLICIT (0xa0)
|
|
87
|
+
if (der[offset] === 0xa0) {
|
|
88
|
+
offset++; // tag
|
|
89
|
+
const vLen = readLen(); // length
|
|
90
|
+
offset += vLen; // skip full version block
|
|
91
|
+
}
|
|
92
|
+
// SerialNumber INTEGER
|
|
93
|
+
if (der[offset++] !== 0x02)
|
|
94
|
+
throw new Error("bad serial tag");
|
|
95
|
+
const serialLen = readLen();
|
|
96
|
+
const serial = der.slice(offset, offset + serialLen);
|
|
97
|
+
certSerialDec = BigInt("0x" +
|
|
98
|
+
Array.from(serial)
|
|
99
|
+
.map(b => b.toString(16).padStart(2, "0"))
|
|
100
|
+
.join("")).toString();
|
|
101
|
+
}
|
|
102
|
+
catch (e) {
|
|
103
|
+
console.error("[issueAwsCredentials] Failed to parse cert serial", e);
|
|
75
104
|
throw new InternalError("invalid_cert_der");
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const certSerialHex = Array.from(serialBytes)
|
|
79
|
-
.map((b) => b.toString(16).padStart(2, "0"))
|
|
80
|
-
.join("")
|
|
81
|
-
.toUpperCase();
|
|
82
|
-
// 4. Tính toán Signature (CẦN Host trong Canonical Request)
|
|
105
|
+
}
|
|
106
|
+
// 4. Tính toán Signature
|
|
83
107
|
const baseHeaders = {
|
|
84
108
|
"content-type": "application/json",
|
|
85
109
|
"host": host,
|
|
@@ -103,14 +127,14 @@ export async function issueAwsCredentials(input) {
|
|
|
103
127
|
canonicalRequestHash: await sha256Hex(canonicalRequest),
|
|
104
128
|
});
|
|
105
129
|
const signatureHex = await signStringToSign(stringToSign, signingKey);
|
|
106
|
-
// 5. Build
|
|
130
|
+
// 5. Build Authorization Header với số Serial (DECIMAL)
|
|
107
131
|
const finalHeaders = new Headers({
|
|
108
132
|
"Content-Type": "application/json",
|
|
109
133
|
"X-Amz-Date": amzDate,
|
|
110
134
|
"X-Amz-X509": normalizedCert,
|
|
111
|
-
"Authorization": `AWS4-X509-ECDSA-SHA256 Credential=${
|
|
135
|
+
"Authorization": `AWS4-X509-ECDSA-SHA256 Credential=${certSerialDec}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signatureHex}`
|
|
112
136
|
});
|
|
113
|
-
// 6. Execution
|
|
137
|
+
// 6. Execution
|
|
114
138
|
try {
|
|
115
139
|
const res = await fetch(`https://${host}${path}`, {
|
|
116
140
|
method: "POST",
|
|
@@ -119,51 +143,11 @@ export async function issueAwsCredentials(input) {
|
|
|
119
143
|
});
|
|
120
144
|
if (!res.ok) {
|
|
121
145
|
const errorBody = await res.text();
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
`curl -X POST "https://${host}${path}" \\`,
|
|
125
|
-
` -H "Content-Type: application/json" \\`,
|
|
126
|
-
` -H "X-Amz-Date: ${amzDate}" \\`,
|
|
127
|
-
` -H "X-Amz-X509: ${normalizedCert}" \\`,
|
|
128
|
-
` -H "Authorization: AWS4-X509-ECDSA-SHA256 Credential=${certSerialHex}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signatureHex}" \\`,
|
|
129
|
-
` -d '${body}'`
|
|
130
|
-
].join("\n");
|
|
131
|
-
console.error("[aws-rejected][LOCAL-CURL-COMMAND]", localCurlCommand);
|
|
132
|
-
console.error("[aws-rejected][RAW-SIGNING-MATERIAL]", {
|
|
133
|
-
certBase64,
|
|
134
|
-
privateKeyPkcs8Base64
|
|
135
|
-
});
|
|
136
|
-
console.error("[aws-rejected][FULL-REQUEST-DUMP]", {
|
|
146
|
+
// Debug logs
|
|
147
|
+
console.error("[aws-rejected] Request details", {
|
|
137
148
|
status: res.status,
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
// ---- Input parameters ----
|
|
141
|
-
roleArn,
|
|
142
|
-
profileArn,
|
|
143
|
-
trustAnchorArn,
|
|
144
|
-
region,
|
|
145
|
-
profile,
|
|
146
|
-
// ---- Derived signing values ----
|
|
147
|
-
host,
|
|
148
|
-
path,
|
|
149
|
-
amzDate,
|
|
150
|
-
dateStamp,
|
|
151
|
-
credentialScope,
|
|
152
|
-
signedHeaders,
|
|
153
|
-
signatureHex,
|
|
154
|
-
// ---- Body & payload ----
|
|
155
|
-
requestBody: body,
|
|
156
|
-
payloadHash,
|
|
157
|
-
// ---- Canonical ----
|
|
158
|
-
canonicalRequest,
|
|
159
|
-
stringToSign,
|
|
160
|
-
// ---- Headers actually sent ----
|
|
161
|
-
sentHeaders: {
|
|
162
|
-
"Content-Type": "application/json",
|
|
163
|
-
"X-Amz-Date": amzDate,
|
|
164
|
-
"X-Amz-X509": normalizedCert,
|
|
165
|
-
"Authorization": `AWS4-X509-ECDSA-SHA256 Credential=${certSerialHex}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signatureHex}`
|
|
166
|
-
}
|
|
149
|
+
response: errorBody,
|
|
150
|
+
serial: certSerialDec
|
|
167
151
|
});
|
|
168
152
|
throw new InternalError("aws_rejected");
|
|
169
153
|
}
|