@vizamodo/aws-sts-core 0.1.43 → 0.1.47
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 +46 -56
- 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,12 +49,46 @@ 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
|
-
|
|
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
|
+
let certSerialDec;
|
|
62
|
+
try {
|
|
63
|
+
const certDer = base64ToArrayBuffer(normalizedCert);
|
|
64
|
+
const derBytes = new Uint8Array(certDer);
|
|
65
|
+
let offset = 0;
|
|
66
|
+
// X509v3 structure check
|
|
67
|
+
if (derBytes[offset++] !== 0x30)
|
|
68
|
+
throw new Error("Not a sequence");
|
|
69
|
+
offset += derBytes[offset] & 0x80 ? (derBytes[offset] & 0x7f) + 1 : 1;
|
|
70
|
+
if (derBytes[offset++] !== 0x30)
|
|
71
|
+
throw new Error("Not a sequence");
|
|
72
|
+
offset += derBytes[offset] & 0x80 ? (derBytes[offset] & 0x7f) + 1 : 1;
|
|
73
|
+
// INTEGER (Serial Number)
|
|
74
|
+
if (derBytes[offset++] !== 0x02)
|
|
75
|
+
throw new Error("Not an integer");
|
|
76
|
+
const serialLength = derBytes[offset++];
|
|
77
|
+
// Bounds check
|
|
78
|
+
if (offset + serialLength > derBytes.length)
|
|
79
|
+
throw new Error("Bounds error");
|
|
80
|
+
const serialBytes = derBytes.slice(offset, offset + serialLength);
|
|
81
|
+
// Convert to Decimal string
|
|
82
|
+
certSerialDec = BigInt("0x" + Array.from(serialBytes)
|
|
83
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
84
|
+
.join(""))
|
|
85
|
+
.toString();
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
console.error("[issueAwsCredentials] Failed to parse cert serial", e);
|
|
89
|
+
throw new InternalError("invalid_cert_der");
|
|
90
|
+
}
|
|
91
|
+
// 4. Tính toán Signature
|
|
62
92
|
const baseHeaders = {
|
|
63
93
|
"content-type": "application/json",
|
|
64
94
|
"host": host,
|
|
@@ -82,14 +112,14 @@ export async function issueAwsCredentials(input) {
|
|
|
82
112
|
canonicalRequestHash: await sha256Hex(canonicalRequest),
|
|
83
113
|
});
|
|
84
114
|
const signatureHex = await signStringToSign(stringToSign, signingKey);
|
|
85
|
-
// 5. Build
|
|
115
|
+
// 5. Build Authorization Header với số Serial (DECIMAL)
|
|
86
116
|
const finalHeaders = new Headers({
|
|
87
117
|
"Content-Type": "application/json",
|
|
88
118
|
"X-Amz-Date": amzDate,
|
|
89
119
|
"X-Amz-X509": normalizedCert,
|
|
90
|
-
"Authorization": `AWS4-X509-ECDSA-SHA256 Credential=${
|
|
120
|
+
"Authorization": `AWS4-X509-ECDSA-SHA256 Credential=${certSerialDec}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signatureHex}`
|
|
91
121
|
});
|
|
92
|
-
// 6. Execution
|
|
122
|
+
// 6. Execution
|
|
93
123
|
try {
|
|
94
124
|
const res = await fetch(`https://${host}${path}`, {
|
|
95
125
|
method: "POST",
|
|
@@ -98,51 +128,11 @@ export async function issueAwsCredentials(input) {
|
|
|
98
128
|
});
|
|
99
129
|
if (!res.ok) {
|
|
100
130
|
const errorBody = await res.text();
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
`curl -X POST "https://${host}${path}" \\`,
|
|
104
|
-
` -H "Content-Type: application/json" \\`,
|
|
105
|
-
` -H "X-Amz-Date: ${amzDate}" \\`,
|
|
106
|
-
` -H "X-Amz-X509: ${normalizedCert}" \\`,
|
|
107
|
-
` -H "Authorization: AWS4-X509-ECDSA-SHA256 Credential=${profileArn}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signatureHex}" \\`,
|
|
108
|
-
` -d '${body}'`
|
|
109
|
-
].join("\n");
|
|
110
|
-
console.error("[aws-rejected][LOCAL-CURL-COMMAND]", localCurlCommand);
|
|
111
|
-
console.error("[aws-rejected][RAW-SIGNING-MATERIAL]", {
|
|
112
|
-
certBase64,
|
|
113
|
-
privateKeyPkcs8Base64
|
|
114
|
-
});
|
|
115
|
-
console.error("[aws-rejected][FULL-REQUEST-DUMP]", {
|
|
131
|
+
// Debug logs
|
|
132
|
+
console.error("[aws-rejected] Request details", {
|
|
116
133
|
status: res.status,
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
// ---- Input parameters ----
|
|
120
|
-
roleArn,
|
|
121
|
-
profileArn,
|
|
122
|
-
trustAnchorArn,
|
|
123
|
-
region,
|
|
124
|
-
profile,
|
|
125
|
-
// ---- Derived signing values ----
|
|
126
|
-
host,
|
|
127
|
-
path,
|
|
128
|
-
amzDate,
|
|
129
|
-
dateStamp,
|
|
130
|
-
credentialScope,
|
|
131
|
-
signedHeaders,
|
|
132
|
-
signatureHex,
|
|
133
|
-
// ---- Body & payload ----
|
|
134
|
-
requestBody: body,
|
|
135
|
-
payloadHash,
|
|
136
|
-
// ---- Canonical ----
|
|
137
|
-
canonicalRequest,
|
|
138
|
-
stringToSign,
|
|
139
|
-
// ---- Headers actually sent ----
|
|
140
|
-
sentHeaders: {
|
|
141
|
-
"Content-Type": "application/json",
|
|
142
|
-
"X-Amz-Date": amzDate,
|
|
143
|
-
"X-Amz-X509": normalizedCert,
|
|
144
|
-
"Authorization": `AWS4-X509-ECDSA-SHA256 Credential=${profileArn}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signatureHex}`
|
|
145
|
-
}
|
|
134
|
+
response: errorBody,
|
|
135
|
+
serial: certSerialDec
|
|
146
136
|
});
|
|
147
137
|
throw new InternalError("aws_rejected");
|
|
148
138
|
}
|