Skip to content

Commit 52de007

Browse files
committed
feat(credential-provider-web-identity): support web federated id
1 parent 325d6b4 commit 52de007

File tree

5 files changed

+259
-62
lines changed

5 files changed

+259
-62
lines changed

packages/credential-provider-web-identity/README.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,92 @@
77

88
This module includes functions which get credentials by calling STS assumeRoleWithWebIdentity API.
99

10+
## fromWebToken
11+
12+
The function `fromWebToken` returns `CredentialProvider` that get credentials calling sts:assumeRoleWithWebIdentity
13+
API via `roleAssumerWithWebIdentity`.
14+
15+
### Supported configuration
16+
17+
This configuration supports all the input parameters from
18+
[sts:AssumeWithWebIdentity](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-sts/modules/assumerolewithwebidentityrequest.html)API. The following options are supported:
19+
20+
- `roleArn` - The Amazon Resource Name (ARN) of the role that the caller is assuming.
21+
- `webIdentityToken` - The OAuth 2.0 access token or OpenID Connect ID token that is provided by the identity provider.
22+
- `roleSessionName` - An identifier for the assumed role session.
23+
- `providerId` - The fully qualified host component of the domain name of the identity provider. Do not specify this
24+
value for OpenID Connect ID tokens.
25+
- `policyArns` - The Amazon Resource Names (ARNs) of the IAM managed policies that you want to use as managed session
26+
policies.
27+
- `policy` - An IAM policy in JSON format that you want to use as an inline session policy.
28+
- `durationSeconds` - The duration, in seconds, of the role session. Default to 3600.
29+
- `roleAssumerWithWebIdentity` - A function that assumes a role with web identity
30+
and returns a promise fulfilled with credentials for the assumed role. You may call
31+
`sts:assumeRoleWithWebIdentity` API within this function.
32+
33+
### Examples
34+
35+
You can directly configure individual identity providers to access AWS resources using web identity federation. AWS
36+
currently supports authenticating users using web identity federation through several identity providers:
37+
38+
- [Login with Amazon](https://login.amazon.com/)
39+
40+
- [Facebook Login](https://developers.facebook.com/docs/facebook-login/web/)
41+
42+
- [Google Sign-in](https://developers.google.com/identity/)
43+
44+
You must first register your application with the providers that your application supports. Next, create an IAM role and
45+
set up permissions for it. The IAM role you create is then used to grant the permissions you configured for it through
46+
the respective identity provider. For example, you can set up a role that allows users who logged in through Facebook
47+
to have read access to a specific Amazon S3 bucket you control.
48+
49+
After you have both an IAM role with configured privileges and an application registered with your chosen identity
50+
providers, you can set up the SDK to get credentials for the IAM role using helper code, as follows:
51+
52+
```javascript
53+
= new AWS.WebIdentityCredentials({
54+
RoleArn: 'arn:aws:iam::<AWS_ACCOUNT_ID>/:role/<WEB_IDENTITY_ROLE_NAME>',
55+
ProviderId: 'graph.facebook.com|www.amazon.com', // this is null for Google
56+
WebIdentityToken: ACCESS_TOKEN
57+
});
58+
59+
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
60+
import { STSClient, AssumeRoleWithWebIdentityCommand } from "@aws-sdk/client-sts";
61+
import { fromWebToken } from "@aws-sdk/credential-provider-web-identity";
62+
63+
const stsClient = new STSClient({});
64+
65+
const roleAssumerWithWebIdentity = async (params) => {
66+
const { Credentials } = await stsClient.send(
67+
new AssumeRoleWithWebIdentityCommand(params)
68+
);
69+
if (!Credentials || !Credentials.AccessKeyId || !Credentials.SecretAccessKey) {
70+
throw new Error(`Invalid response from STS.assumeRole call with role ${params.RoleArn}`);
71+
}
72+
return {
73+
accessKeyId: Credentials.AccessKeyId,
74+
secretAccessKey: Credentials.SecretAccessKey,
75+
sessionToken: Credentials.SessionToken,
76+
expiration: Credentials.Expiration,
77+
};
78+
};
79+
80+
const dynamodb = new DynamoDBClient({
81+
region,
82+
credentials: fromWebToken({
83+
roleArn: 'arn:aws:iam::<AWS_ACCOUNT_ID>/:role/<WEB_IDENTITY_ROLE_NAME>',
84+
providerId: 'graph.facebook.com|www.amazon.com', // this is null for Google
85+
webIdentityToken: ACCESS_TOKEN // from OpenID token identity provider
86+
roleAssumerWithWebIdentity,
87+
})
88+
});
89+
90+
```
91+
92+
The value in the ProviderId parameter depends on the specified identity provider. The value in the WebIdentityToken
93+
parameter is the access token retrieved from a successful login with the identity provider. For more information on how
94+
to configure and retrieve access tokens for each identity provider, see the documentation for the identity provider.
95+
1096
## fromTokenFile
1197

1298
The function `fromTokenFile` returns `CredentialProvider` that reads credentials as follows:

packages/credential-provider-web-identity/src/fromTokenFile.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { ProviderError } from "@aws-sdk/property-provider";
22
import { readFileSync } from "fs";
33

4-
import { AssumeRoleWithWebIdentityParams, fromTokenFile, FromTokenFileInit } from "./fromTokenFile";
4+
import { fromTokenFile, FromTokenFileInit } from "./fromTokenFile";
5+
import { AssumeRoleWithWebIdentityParams } from "./index";
56

67
const ENV_TOKEN_FILE = "AWS_WEB_IDENTITY_TOKEN_FILE";
78
const ENV_ROLE_ARN = "AWS_ROLE_ARN";
Lines changed: 12 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,29 @@
1-
import { ProviderError } from "@aws-sdk/property-provider";
2-
import { CredentialProvider, Credentials } from "@aws-sdk/types";
1+
import { CredentialProvider } from "@aws-sdk/types";
32
import { readFileSync } from "fs";
43

4+
import { fromWebToken, FromWebTokenInit } from "./fromWebToken";
5+
56
const ENV_TOKEN_FILE = "AWS_WEB_IDENTITY_TOKEN_FILE";
67
const ENV_ROLE_ARN = "AWS_ROLE_ARN";
78
const ENV_ROLE_SESSION_NAME = "AWS_ROLE_SESSION_NAME";
89

9-
export interface AssumeRoleWithWebIdentityParams {
10-
/**
11-
* <p>The Amazon Resource Name (ARN) of the role that the caller is assuming.</p>
12-
*/
13-
RoleArn: string;
14-
/**
15-
* <p>An identifier for the assumed role session. Typically, you pass the name or identifier
16-
* that is associated with the user who is using your application. That way, the temporary
17-
* security credentials that your application will use are associated with that user. This
18-
* session name is included as part of the ARN and assumed role ID in the
19-
* <code>AssumedRoleUser</code> response element.</p>
20-
* <p>The regex used to validate this parameter is a string of characters
21-
* consisting of upper- and lower-case alphanumeric characters with no spaces. You can
22-
* also include underscores or any of the following characters: =,.@-</p>
23-
*/
24-
RoleSessionName: string;
25-
/**
26-
* <p>The OAuth 2.0 access token or OpenID Connect ID token that is provided by the identity
27-
* provider. Your application must get this token by authenticating the user who is using your
28-
* application with a web identity provider before the application makes an
29-
* <code>AssumeRoleWithWebIdentity</code> call. </p>
30-
*/
31-
WebIdentityToken: string;
32-
}
33-
export interface FromTokenFileInit {
10+
export interface FromTokenFileInit extends Partial<FromWebTokenInit> {
3411
/**
3512
* File location of where the `OIDC` token is stored.
3613
*/
3714
webIdentityTokenFile?: string;
38-
39-
/**
40-
* The IAM role wanting to be assumed.
41-
*/
42-
roleArn?: string;
43-
44-
/**
45-
* The IAM session name used to distinguish sessions.
46-
*/
47-
roleSessionName?: string;
48-
49-
/**
50-
* A function that assumes a role with web identity and returns a promise fulfilled with
51-
* credentials for the assumed role.
52-
*
53-
* @param sourceCreds The credentials with which to assume a role.
54-
* @param params
55-
*/
56-
roleAssumerWithWebIdentity?: (params: AssumeRoleWithWebIdentityParams) => Promise<Credentials>;
5715
}
5816

5917
/**
6018
* Represents OIDC credentials from a file on disk.
6119
*/
62-
export const fromTokenFile = (init: FromTokenFileInit): CredentialProvider => async () => {
63-
const { webIdentityTokenFile, roleArn, roleSessionName, roleAssumerWithWebIdentity } = init;
64-
65-
if (!roleAssumerWithWebIdentity) {
66-
throw new ProviderError(
67-
`Role Arn '${roleArn ?? process.env[ENV_ROLE_ARN]}' needs to be assumed with web identity,` +
68-
` but no role assumption callback was provided.`,
69-
false
70-
);
71-
}
72-
73-
return roleAssumerWithWebIdentity({
74-
WebIdentityToken: readFileSync(webIdentityTokenFile ?? process.env[ENV_TOKEN_FILE]!, { encoding: "ascii" }),
75-
RoleArn: roleArn ?? process.env[ENV_ROLE_ARN]!,
76-
RoleSessionName: roleSessionName ?? process.env[ENV_ROLE_SESSION_NAME] ?? `aws-sdk-js-session-${Date.now()}`,
20+
export const fromTokenFile = (init: FromTokenFileInit): CredentialProvider => {
21+
const { webIdentityTokenFile, roleArn, roleSessionName } = init;
22+
23+
return fromWebToken({
24+
...init,
25+
webIdentityToken: readFileSync(webIdentityTokenFile ?? process.env[ENV_TOKEN_FILE]!, { encoding: "ascii" }),
26+
roleArn: roleArn ?? process.env[ENV_ROLE_ARN]!,
27+
roleSessionName: roleSessionName ?? process.env[ENV_ROLE_SESSION_NAME] ?? `aws-sdk-js-session-${Date.now()}`,
7728
});
7829
};
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import { ProviderError } from "@aws-sdk/property-provider";
2+
import { CredentialProvider, Credentials } from "@aws-sdk/types";
3+
4+
export interface AssumeRoleWithWebIdentityParams {
5+
/**
6+
* <p>The Amazon Resource Name (ARN) of the role that the caller is assuming.</p>
7+
*/
8+
RoleArn: string;
9+
/**
10+
* <p>An identifier for the assumed role session. Typically, you pass the name or identifier
11+
* that is associated with the user who is using your application. That way, the temporary
12+
* security credentials that your application will use are associated with that user. This
13+
* session name is included as part of the ARN and assumed role ID in the
14+
* <code>AssumedRoleUser</code> response element.</p>
15+
* <p>The regex used to validate this parameter is a string of characters
16+
* consisting of upper- and lower-case alphanumeric characters with no spaces. You can
17+
* also include underscores or any of the following characters: =,.@-</p>
18+
*/
19+
RoleSessionName: string;
20+
/**
21+
* <p>The OAuth 2.0 access token or OpenID Connect ID token that is provided by the identity
22+
* provider. Your application must get this token by authenticating the user who is using your
23+
* application with a web identity provider before the application makes an
24+
* <code>AssumeRoleWithWebIdentity</code> call. </p>
25+
*/
26+
WebIdentityToken: string;
27+
28+
/**
29+
* <p>The fully qualified host component of the domain name of the identity provider.</p>
30+
* <p>Specify this value only for OAuth 2.0 access tokens. Currently
31+
* <code>www.amazon.com</code> and <code>graph.facebook.com</code> are the only supported
32+
* identity providers for OAuth 2.0 access tokens. Do not include URL schemes and port
33+
* numbers.</p>
34+
* <p>Do not specify this value for OpenID Connect ID tokens.</p>
35+
*/
36+
ProviderId?: string;
37+
38+
/**
39+
* <p>The Amazon Resource Names (ARNs) of the IAM managed policies that you want to use as
40+
* managed session policies. The policies must exist in the same account as the role.</p>
41+
* <p>This parameter is optional. You can provide up to 10 managed policy ARNs. However, the
42+
* plain text that you use for both inline and managed session policies can't exceed 2,048
43+
* characters. For more information about ARNs, see <a href="https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html">Amazon Resource Names (ARNs) and AWS
44+
* Service Namespaces</a> in the AWS General Reference.</p>
45+
* <note>
46+
* <p>An AWS conversion compresses the passed session policies and session tags into a
47+
* packed binary format that has a separate limit. Your request can fail for this limit
48+
* even if your plain text meets the other requirements. The <code>PackedPolicySize</code>
49+
* response element indicates by percentage how close the policies and tags for your
50+
* request are to the upper size limit.
51+
* </p>
52+
* </note>
53+
*
54+
* <p>Passing policies to this operation returns new
55+
* temporary credentials. The resulting session's permissions are the intersection of the
56+
* role's identity-based policy and the session policies. You can use the role's temporary
57+
* credentials in subsequent AWS API calls to access resources in the account that owns
58+
* the role. You cannot use session policies to grant more permissions than those allowed
59+
* by the identity-based policy of the role that is being assumed. For more information, see
60+
* <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session">Session
61+
* Policies</a> in the <i>IAM User Guide</i>.</p>
62+
*/
63+
PolicyArns?: { arn?: string }[];
64+
65+
/**
66+
* <p>An IAM policy in JSON format that you want to use as an inline session policy.</p>
67+
* <p>This parameter is optional. Passing policies to this operation returns new
68+
* temporary credentials. The resulting session's permissions are the intersection of the
69+
* role's identity-based policy and the session policies. You can use the role's temporary
70+
* credentials in subsequent AWS API calls to access resources in the account that owns
71+
* the role. You cannot use session policies to grant more permissions than those allowed
72+
* by the identity-based policy of the role that is being assumed. For more information, see
73+
* <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session">Session
74+
* Policies</a> in the <i>IAM User Guide</i>.</p>
75+
* <p>The plain text that you use for both inline and managed session policies can't exceed
76+
* 2,048 characters. The JSON policy characters can be any ASCII character from the space
77+
* character to the end of the valid character list (\u0020 through \u00FF). It can also
78+
* include the tab (\u0009), linefeed (\u000A), and carriage return (\u000D)
79+
* characters.</p>
80+
* <note>
81+
* <p>An AWS conversion compresses the passed session policies and session tags into a
82+
* packed binary format that has a separate limit. Your request can fail for this limit
83+
* even if your plain text meets the other requirements. The <code>PackedPolicySize</code>
84+
* response element indicates by percentage how close the policies and tags for your
85+
* request are to the upper size limit.
86+
* </p>
87+
* </note>
88+
*/
89+
Policy?: string;
90+
91+
/**
92+
* <p>The duration, in seconds, of the role session. The value can range from 900 seconds (15
93+
* minutes) up to the maximum session duration setting for the role. This setting can have a
94+
* value from 1 hour to 12 hours. If you specify a value higher than this setting, the
95+
* operation fails. For example, if you specify a session duration of 12 hours, but your
96+
* administrator set the maximum session duration to 6 hours, your operation fails. To learn
97+
* how to view the maximum value for your role, see <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html#id_roles_use_view-role-max-session">View the
98+
* Maximum Session Duration Setting for a Role</a> in the
99+
* <i>IAM User Guide</i>.</p>
100+
* <p>By default, the value is set to <code>3600</code> seconds. </p>
101+
* <note>
102+
* <p>The <code>DurationSeconds</code> parameter is separate from the duration of a console
103+
* session that you might request using the returned credentials. The request to the
104+
* federation endpoint for a console sign-in token takes a <code>SessionDuration</code>
105+
* parameter that specifies the maximum length of the console session. For more
106+
* information, see <a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_enable-console-custom-url.html">Creating a URL
107+
* that Enables Federated Users to Access the AWS Management Console</a> in the
108+
* <i>IAM User Guide</i>.</p>
109+
* </note>
110+
*/
111+
DurationSeconds?: number;
112+
}
113+
114+
type LowerCaseKey<T> = { [K in keyof T as `${Uncapitalize<string & K>}`]: T[K] };
115+
export interface FromWebTokenInit extends Omit<LowerCaseKey<AssumeRoleWithWebIdentityParams>, "roleSessionName"> {
116+
/**
117+
* The IAM session name used to distinguish sessions.
118+
*/
119+
roleSessionName?: string;
120+
121+
/**
122+
* A function that assumes a role with web identity and returns a promise fulfilled with
123+
* credentials for the assumed role.
124+
*
125+
* @param params input parameter of sts:AssumeRoleWithWebIdentity API.
126+
*/
127+
roleAssumerWithWebIdentity?: (params: AssumeRoleWithWebIdentityParams) => Promise<Credentials>;
128+
}
129+
130+
export const fromWebToken = (init: FromWebTokenInit): CredentialProvider => () => {
131+
const {
132+
roleArn,
133+
roleSessionName,
134+
webIdentityToken,
135+
providerId,
136+
policyArns,
137+
policy,
138+
durationSeconds,
139+
roleAssumerWithWebIdentity,
140+
} = init;
141+
142+
if (!roleAssumerWithWebIdentity) {
143+
throw new ProviderError(
144+
`Role Arn '${roleArn}' needs to be assumed with web identity,` + ` but no role assumption callback was provided.`,
145+
false
146+
);
147+
}
148+
149+
return roleAssumerWithWebIdentity({
150+
RoleArn: roleArn,
151+
RoleSessionName: roleSessionName ?? "web-identity",
152+
WebIdentityToken: webIdentityToken,
153+
ProviderId: providerId,
154+
PolicyArns: policyArns,
155+
Policy: policy,
156+
DurationSeconds: durationSeconds,
157+
});
158+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from "./fromTokenFile";
2+
export * from "./fromWebToken";

0 commit comments

Comments
 (0)