Skip to content

Commit 406f850

Browse files
author
Chase Coalwell
authored
add process credentials provider (#219)
1 parent 7427181 commit 406f850

File tree

16 files changed

+1250
-6
lines changed

16 files changed

+1250
-6
lines changed

packages/credential-provider-ini/src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ export function fromIni(init: FromIniInit = {}): CredentialProvider {
123123
);
124124
}
125125

126-
function getMasterProfileName(init: FromIniInit): string {
126+
export function getMasterProfileName(init: FromIniInit): string {
127127
return init.profile || process.env[ENV_PROFILE] || DEFAULT_PROFILE;
128128
}
129129

@@ -207,7 +207,7 @@ async function resolveProfileData(
207207
);
208208
}
209209

210-
function parseKnownFiles(init: FromIniInit): Promise<ParsedIniData> {
210+
export function parseKnownFiles(init: FromIniInit): Promise<ParsedIniData> {
211211
const { loadedConfig = loadSharedConfigFiles(init) } = init;
212212

213213
return loadedConfig.then(parsedFiles => {

packages/credential-provider-node/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ AWS credentials from a Node.JS environment. It will attempt to find credentials
55
from the following sources (listed in order of precedence):
66
_ Environment variables exposed via `process.env`
77
_ Shared credentials and config ini files \* The EC2/ECS Instance Metadata Service
8-
8+
99
The default credential provider will invoke one provider at a time and only
1010
continue to the next if no credentials have been located. For example, if the
1111
process finds values defined via the `AWS_ACCESS_KEY_ID` and

packages/credential-provider-node/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"@aws-sdk/credential-provider-env": "^0.1.0-preview.4",
2626
"@aws-sdk/credential-provider-imds": "^0.1.0-preview.3",
2727
"@aws-sdk/credential-provider-ini": "^0.1.0-preview.3",
28+
"@aws-sdk/credential-provider-process": "^0.1.0-preview.1",
2829
"@aws-sdk/property-provider": "^0.1.0-preview.3",
2930
"@aws-sdk/types": "^0.1.0-preview.3",
3031
"tslib": "^1.8.0"

packages/credential-provider-node/src/index.spec.ts

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,24 @@ import {
2121
fromIni,
2222
FromIniInit
2323
} from "@aws-sdk/credential-provider-ini";
24+
2425
import {
2526
ENV_CONFIG_PATH,
2627
ENV_CREDENTIALS_PATH
2728
} from "@aws-sdk/shared-ini-file-loader";
2829

30+
jest.mock("@aws-sdk/credential-provider-process", () => {
31+
const processProvider = jest.fn();
32+
return {
33+
ENV_PROFILE: "AWS_PROFILE",
34+
fromProcess: jest.fn(() => processProvider)
35+
};
36+
});
37+
import {
38+
fromProcess,
39+
FromProcessInit
40+
} from "@aws-sdk/credential-provider-process";
41+
2942
jest.mock("@aws-sdk/credential-provider-imds", () => {
3043
const containerMdsProvider = jest.fn();
3144
const instanceMdsProvider = jest.fn();
@@ -67,10 +80,12 @@ beforeEach(() => {
6780

6881
(fromEnv() as any).mockClear();
6982
(fromIni() as any).mockClear();
83+
(fromProcess() as any).mockClear();
7084
(fromContainerMetadata() as any).mockClear();
7185
(fromInstanceMetadata() as any).mockClear();
7286
(fromEnv as any).mockClear();
7387
(fromIni as any).mockClear();
88+
(fromProcess as any).mockClear();
7489
(fromContainerMetadata as any).mockClear();
7590
(fromInstanceMetadata as any).mockClear();
7691
});
@@ -97,6 +112,7 @@ describe("defaultProvider", () => {
97112
expect(await defaultProvider()()).toEqual(creds);
98113
expect((fromEnv() as any).mock.calls.length).toBe(1);
99114
expect((fromIni() as any).mock.calls.length).toBe(0);
115+
expect((fromProcess() as any).mock.calls.length).toBe(0);
100116
expect((fromContainerMetadata() as any).mock.calls.length).toBe(0);
101117
expect((fromInstanceMetadata() as any).mock.calls.length).toBe(0);
102118
});
@@ -115,29 +131,55 @@ describe("defaultProvider", () => {
115131
expect(await defaultProvider()()).toEqual(creds);
116132
expect((fromEnv() as any).mock.calls.length).toBe(1);
117133
expect((fromIni() as any).mock.calls.length).toBe(1);
134+
expect((fromProcess() as any).mock.calls.length).toBe(0);
118135
expect((fromContainerMetadata() as any).mock.calls.length).toBe(0);
119136
expect((fromInstanceMetadata() as any).mock.calls.length).toBe(0);
120137
});
121138

122-
it("should continue on to the IMDS provider if no env or ini credentials have been found", async () => {
139+
it("should stop after the process provider if credentials have been found", async () => {
123140
const creds = {
124141
accessKeyId: "foo",
125142
secretAccessKey: "bar"
126143
};
127144

145+
(fromEnv() as any).mockImplementation(() =>
146+
Promise.reject(new ProviderError("Nothing here!"))
147+
);
148+
(fromIni() as any).mockImplementation(() =>
149+
Promise.reject(new ProviderError("Nothing here!"))
150+
);
151+
(fromProcess() as any).mockImplementation(() => Promise.resolve(creds));
152+
153+
expect(await defaultProvider()()).toEqual(creds);
154+
expect((fromEnv() as any).mock.calls.length).toBe(1);
155+
expect((fromIni() as any).mock.calls.length).toBe(1);
156+
expect((fromProcess() as any).mock.calls.length).toBe(1);
157+
expect((fromContainerMetadata() as any).mock.calls.length).toBe(0);
158+
expect((fromInstanceMetadata() as any).mock.calls.length).toBe(0);
159+
});
160+
161+
it("should continue on to the IMDS provider if no env, ini or process credentials have been found", async () => {
162+
const creds = {
163+
accessKeyId: "foo",
164+
secretAccessKey: "bar"
165+
};
128166
(fromEnv() as any).mockImplementation(() =>
129167
Promise.reject(new ProviderError("Keep moving!"))
130168
);
131169
(fromIni() as any).mockImplementation(() =>
132170
Promise.reject(new ProviderError("Nothing here!"))
133171
);
172+
(fromProcess() as any).mockImplementation(() =>
173+
Promise.reject(new ProviderError("Nor here!"))
174+
);
134175
(fromInstanceMetadata() as any).mockImplementation(() =>
135176
Promise.resolve(creds)
136177
);
137178

138179
expect(await defaultProvider()()).toEqual(creds);
139180
expect((fromEnv() as any).mock.calls.length).toBe(1);
140181
expect((fromIni() as any).mock.calls.length).toBe(1);
182+
expect((fromProcess() as any).mock.calls.length).toBe(1);
141183
expect((fromContainerMetadata() as any).mock.calls.length).toBe(0);
142184
expect((fromInstanceMetadata() as any).mock.calls.length).toBe(1);
143185
});
@@ -154,6 +196,9 @@ describe("defaultProvider", () => {
154196
(fromIni() as any).mockImplementation(() =>
155197
Promise.reject(new ProviderError("Nothing here!"))
156198
);
199+
(fromProcess() as any).mockImplementation(() =>
200+
Promise.reject(new ProviderError("Nor here!"))
201+
);
157202
(fromInstanceMetadata() as any).mockImplementation(() =>
158203
Promise.resolve(creds)
159204
);
@@ -177,6 +222,9 @@ describe("defaultProvider", () => {
177222
(fromIni() as any).mockImplementation(() =>
178223
Promise.reject(new ProviderError("Nothing here!"))
179224
);
225+
(fromProcess() as any).mockImplementation(() =>
226+
Promise.reject(new ProviderError("Nor here!"))
227+
);
180228
(fromInstanceMetadata() as any).mockImplementation(() =>
181229
Promise.reject(new Error("PANIC"))
182230
);
@@ -189,6 +237,7 @@ describe("defaultProvider", () => {
189237
expect(await defaultProvider()()).toEqual(creds);
190238
expect((fromEnv() as any).mock.calls.length).toBe(1);
191239
expect((fromIni() as any).mock.calls.length).toBe(1);
240+
expect((fromProcess() as any).mock.calls.length).toBe(1);
192241
expect((fromContainerMetadata() as any).mock.calls.length).toBe(1);
193242
expect((fromInstanceMetadata() as any).mock.calls.length).toBe(0);
194243
});
@@ -224,6 +273,33 @@ describe("defaultProvider", () => {
224273
expect((fromIni as any).mock.calls[0][0]).toBe(iniConfig);
225274
});
226275

276+
it("should pass configuration on to the process provider", async () => {
277+
const processConfig: FromProcessInit = {
278+
filepath: "/home/user/.secrets/credentials.ini",
279+
configFilepath: "/home/user/.secrets/credentials.ini"
280+
};
281+
282+
(fromEnv() as any).mockImplementation(() =>
283+
Promise.reject(new ProviderError("Keep moving!"))
284+
);
285+
(fromIni() as any).mockImplementation(() =>
286+
Promise.reject(new ProviderError("Nothing here!"))
287+
);
288+
(fromProcess() as any).mockImplementation(() =>
289+
Promise.resolve({
290+
accessKeyId: "foo",
291+
secretAccessKey: "bar"
292+
})
293+
);
294+
295+
(fromProcess as any).mockClear();
296+
297+
await expect(defaultProvider(processConfig)()).resolves;
298+
expect((fromProcess as any).mock.calls.length).toBe(1);
299+
expect((fromProcess as any).mock.calls.length).toBe(1);
300+
expect((fromProcess as any).mock.calls[0][0]).toBe(processConfig);
301+
});
302+
227303
it("should pass configuration on to the IMDS provider", async () => {
228304
const imdsConfig: RemoteProviderInit = {
229305
timeout: 2000,
@@ -236,6 +312,9 @@ describe("defaultProvider", () => {
236312
(fromIni() as any).mockImplementation(() =>
237313
Promise.reject(new ProviderError("Nothing here!"))
238314
);
315+
(fromProcess() as any).mockImplementation(() =>
316+
Promise.reject(new ProviderError("Nor here!"))
317+
);
239318
(fromInstanceMetadata() as any).mockImplementation(() =>
240319
Promise.resolve({
241320
accessKeyId: "foo",
@@ -370,6 +449,9 @@ describe("defaultProvider", () => {
370449
Promise.reject(new Error("PANIC"))
371450
);
372451
(fromIni() as any).mockImplementation(() => Promise.resolve(creds));
452+
(fromProcess() as any).mockImplementation(() =>
453+
Promise.reject(new Error("PANIC"))
454+
);
373455
(fromInstanceMetadata() as any).mockImplementation(() =>
374456
Promise.reject(new Error("PANIC"))
375457
);
@@ -381,6 +463,7 @@ describe("defaultProvider", () => {
381463
expect(await defaultProvider()()).toEqual(creds);
382464
expect((fromEnv() as any).mock.calls.length).toBe(0);
383465
expect((fromIni() as any).mock.calls.length).toBe(1);
466+
expect((fromProcess() as any).mock.calls.length).toBe(0);
384467
expect((fromContainerMetadata() as any).mock.calls.length).toBe(0);
385468
expect((fromInstanceMetadata() as any).mock.calls.length).toBe(0);
386469
});

packages/credential-provider-node/src/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ import {
1212
fromIni,
1313
FromIniInit
1414
} from "@aws-sdk/credential-provider-ini";
15+
import {
16+
fromProcess,
17+
FromProcessInit
18+
} from "@aws-sdk/credential-provider-process";
1519
import { CredentialProvider } from "@aws-sdk/types";
1620

1721
export const ENV_IMDS_DISABLED = "AWS_EC2_METADATA_DISABLED";
@@ -37,18 +41,20 @@ export const ENV_IMDS_DISABLED = "AWS_EC2_METADATA_DISABLED";
3741
* environment variables
3842
* @see fromIni The function used to source credentials from INI
3943
* files
44+
* @see fromProcess The functino used to sources credentials from
45+
* credential_process in INI files
4046
* @see fromInstanceMetadata The function used to source credentials from the
4147
* EC2 Instance Metadata Service
4248
* @see fromContainerMetadata The function used to source credentials from the
4349
* ECS Container Metadata Service
4450
*/
4551
export function defaultProvider(
46-
init: FromIniInit & RemoteProviderInit = {}
52+
init: FromIniInit & RemoteProviderInit & FromProcessInit = {}
4753
): CredentialProvider {
4854
const { profile = process.env[ENV_PROFILE] } = init;
4955
const providerChain = profile
5056
? fromIni(init)
51-
: chain(fromEnv(), fromIni(init), remoteProvider(init));
57+
: chain(fromEnv(), fromIni(init), fromProcess(init), remoteProvider(init));
5258

5359
return memoize(
5460
providerChain,
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/node_modules/
2+
/build/
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/src/
2+
/coverage/
3+
tsconfig.test.json
4+
5+
*.spec.js
6+
*.spec.d.ts
7+
*.spec.js.map
8+
9+
*.mock.js
10+
*.mock.d.ts
11+
*.mock.js.map
12+
13+
*.fixture.js
14+
*.fixture.d.ts
15+
*.fixture.js.map
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Change Log
2+
3+
All notable changes to this project will be documented in this file.
4+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

0 commit comments

Comments
 (0)