|
| 1 | +import { fromEnv } from "@aws-sdk/credential-provider-env"; |
| 2 | +import { fromContainerMetadata, fromInstanceMetadata } from "@aws-sdk/credential-provider-imds"; |
1 | 3 | import { fromTokenFile } from "@aws-sdk/credential-provider-web-identity";
|
2 | 4 | import { ENV_CONFIG_PATH, ENV_CREDENTIALS_PATH } from "@aws-sdk/shared-ini-file-loader";
|
3 | 5 | import { Credentials } from "@aws-sdk/types";
|
@@ -54,6 +56,10 @@ import { homedir } from "os";
|
54 | 56 |
|
55 | 57 | jest.mock("@aws-sdk/credential-provider-web-identity");
|
56 | 58 |
|
| 59 | +jest.mock("@aws-sdk/credential-provider-imds"); |
| 60 | + |
| 61 | +jest.mock("@aws-sdk/credential-provider-env"); |
| 62 | + |
57 | 63 | const DEFAULT_CREDS = {
|
58 | 64 | accessKeyId: "AKIAIOSFODNN7EXAMPLE",
|
59 | 65 | secretAccessKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
|
@@ -752,6 +758,131 @@ source_profile = default`.trim()
|
752 | 758 | tryNextLink: false,
|
753 | 759 | });
|
754 | 760 | });
|
| 761 | + |
| 762 | + describe("assume role with source credential providers", () => { |
| 763 | + const setUpTest = (credentialSource: string) => { |
| 764 | + const roleArn = `arn:aws:iam::123456789:role/${credentialSource}`; |
| 765 | + const roleSessionName = `${credentialSource}SessionName`; |
| 766 | + const mfaSerial = `mfaSerial${credentialSource}`; |
| 767 | + const mfaCode = Date.now().toString(10); |
| 768 | + __addMatcher( |
| 769 | + join(homedir(), ".aws", "credentials"), |
| 770 | + ` |
| 771 | +[default] |
| 772 | +role_arn = ${roleArn} |
| 773 | +role_session_name = ${roleSessionName} |
| 774 | +mfa_serial = ${mfaSerial} |
| 775 | +credential_source = ${credentialSource} |
| 776 | + `.trim() |
| 777 | + ); |
| 778 | + return { |
| 779 | + roleArn, |
| 780 | + roleSessionName, |
| 781 | + mfaSerial, |
| 782 | + mfaCode, |
| 783 | + }; |
| 784 | + }; |
| 785 | + |
| 786 | + it("should assume role from source credentials from EC2 instance provider", async () => { |
| 787 | + (fromInstanceMetadata as jest.Mock).mockReturnValueOnce(() => Promise.resolve(FOO_CREDS)); |
| 788 | + const { roleArn, roleSessionName, mfaCode, mfaSerial } = setUpTest("Ec2InstanceMetadata"); |
| 789 | + const provider = fromIni({ |
| 790 | + mfaCodeProvider(mfa) { |
| 791 | + expect(mfa).toBe(mfaSerial); |
| 792 | + return Promise.resolve(mfaCode); |
| 793 | + }, |
| 794 | + roleAssumer(sourceCreds: Credentials, params: AssumeRoleParams): Promise<Credentials> { |
| 795 | + expect(fromInstanceMetadata as jest.Mock).toBeCalledTimes(1); |
| 796 | + expect(params.RoleSessionName).toBe(roleSessionName); |
| 797 | + expect(params.RoleArn).toBe(roleArn); |
| 798 | + expect(params.TokenCode).toBe(mfaCode); |
| 799 | + expect(sourceCreds).toEqual(FOO_CREDS); |
| 800 | + return Promise.resolve(FIZZ_CREDS); |
| 801 | + }, |
| 802 | + }); |
| 803 | + expect(await provider()).toEqual(FIZZ_CREDS); |
| 804 | + }); |
| 805 | + |
| 806 | + it("should assume role from source credentials from environmental variable provider", async () => { |
| 807 | + (fromEnv as jest.Mock).mockReturnValueOnce(() => Promise.resolve(FOO_CREDS)); |
| 808 | + const { roleArn, roleSessionName, mfaCode, mfaSerial } = setUpTest("Environment"); |
| 809 | + const provider = fromIni({ |
| 810 | + mfaCodeProvider(mfa) { |
| 811 | + expect(mfa).toBe(mfaSerial); |
| 812 | + return Promise.resolve(mfaCode); |
| 813 | + }, |
| 814 | + roleAssumer(sourceCreds: Credentials, params: AssumeRoleParams): Promise<Credentials> { |
| 815 | + expect(fromEnv as jest.Mock).toBeCalledTimes(1); |
| 816 | + expect(params.RoleSessionName).toBe(roleSessionName); |
| 817 | + expect(params.RoleArn).toBe(roleArn); |
| 818 | + expect(params.TokenCode).toBe(mfaCode); |
| 819 | + expect(sourceCreds).toEqual(FOO_CREDS); |
| 820 | + return Promise.resolve(FIZZ_CREDS); |
| 821 | + }, |
| 822 | + }); |
| 823 | + expect(await provider()).toEqual(FIZZ_CREDS); |
| 824 | + }); |
| 825 | + |
| 826 | + it("should assume role from source credentials from ECS container provider", async () => { |
| 827 | + (fromContainerMetadata as jest.Mock).mockReturnValueOnce(() => Promise.resolve(FOO_CREDS)); |
| 828 | + const { roleArn, roleSessionName, mfaCode, mfaSerial } = setUpTest("EcsContainer"); |
| 829 | + const provider = fromIni({ |
| 830 | + mfaCodeProvider(mfa) { |
| 831 | + expect(mfa).toBe(mfaSerial); |
| 832 | + return Promise.resolve(mfaCode); |
| 833 | + }, |
| 834 | + roleAssumer(sourceCreds: Credentials, params: AssumeRoleParams): Promise<Credentials> { |
| 835 | + expect(fromContainerMetadata as jest.Mock).toBeCalledTimes(1); |
| 836 | + expect(params.RoleSessionName).toBe(roleSessionName); |
| 837 | + expect(params.RoleArn).toBe(roleArn); |
| 838 | + expect(params.TokenCode).toBe(mfaCode); |
| 839 | + expect(sourceCreds).toEqual(FOO_CREDS); |
| 840 | + return Promise.resolve(FIZZ_CREDS); |
| 841 | + }, |
| 842 | + }); |
| 843 | + expect(await provider()).toEqual(FIZZ_CREDS); |
| 844 | + }); |
| 845 | + |
| 846 | + it("should throw if source credentials provider is not supported", () => { |
| 847 | + const someProvider = "SomeProvider"; |
| 848 | + setUpTest(someProvider); |
| 849 | + const provider = fromIni({ |
| 850 | + roleAssumer(): Promise<Credentials> { |
| 851 | + return Promise.resolve(FIZZ_CREDS); |
| 852 | + }, |
| 853 | + }); |
| 854 | + return expect(async () => await provider()).rejects.toMatchObject({ |
| 855 | + message: |
| 856 | + `Unsupported credential source in profile default. Got ${someProvider}, expected EcsContainer or ` + |
| 857 | + `Ec2InstanceMetadata or Environment.`, |
| 858 | + }); |
| 859 | + }); |
| 860 | + |
| 861 | + it("should throw if both source profile and credential source is specified", async () => { |
| 862 | + __addMatcher( |
| 863 | + join(homedir(), ".aws", "credentials"), |
| 864 | + ` |
| 865 | +[profile A] |
| 866 | +aws_access_key_id = abc123 |
| 867 | +aws_secret_access_key = def456 |
| 868 | +[default] |
| 869 | +role_arn = arn:aws:iam::123456789:role/Role |
| 870 | +credential_source = Ec2InstanceMetadata |
| 871 | +source_profile = A |
| 872 | + `.trim() |
| 873 | + ); |
| 874 | + try { |
| 875 | + await fromIni({ |
| 876 | + roleAssumer(): Promise<Credentials> { |
| 877 | + return Promise.resolve(FIZZ_CREDS); |
| 878 | + }, |
| 879 | + })(); |
| 880 | + fail("Expected error to be thrown"); |
| 881 | + } catch (e) { |
| 882 | + expect(e).toBeDefined(); |
| 883 | + } |
| 884 | + }); |
| 885 | + }); |
755 | 886 | });
|
756 | 887 |
|
757 | 888 | describe("assume role with web identity", () => {
|
|
0 commit comments