Table of Contents

Class WebIdentityCredentialsProvider

Namespace
DynaSharp.Credentials
Assembly
DynaSharp.dll

Supplies temporary credentials of an IAM role for the holder of a web identity token: IAM roles for service accounts (IRSA) on Amazon EKS, and any other OpenID Connect issuer that the account trusts, such as GitHub Actions. It trades the token for credentials with the AssumeRoleWithWebIdentity call of AWS STS, and refreshes them before they expire.

public sealed class WebIdentityCredentialsProvider : IRefreshableCredentialsProvider, ICredentialsProvider
Inheritance
WebIdentityCredentialsProvider
Implements
Inherited Members

Remarks

Without arguments the provider applies when AWS_WEB_IDENTITY_TOKEN_FILE is set and not empty; otherwise GetCredentialsAsync(CancellationToken) throws a CredentialsUnavailableException that says so (the default chain then moves on). AWS_ROLE_ARN must then be set as well: a token file without a role is broken and throws, which also stops the default chain. AWS_ROLE_SESSION_NAME is optional, must be 2 to 64 letters, digits or characters of _+=,.@-, and defaults to dynasharp- and the Unix time in seconds. The variables are read at every fetch. Passing the settings to a constructor replaces them all. A profile with the keys web_identity_token_file, role_arn and role_session_name gets this provider from ProfileCredentialsProvider, with the settings of the profile and the region of its client.

A fetch is a POST of a form to https://sts.{region}.amazonaws.com/, or amazonaws.com.cn for a region whose name starts with cn-. It is not signed: the token is the proof. It asks for no duration, so the session lasts the default hour, which the maximum of the role can never reject. The region is that of the client when a DynamoDbClient made the provider, and otherwise the one passed to the constructor, or else AWS_REGION, AWS_DEFAULT_REGION or the region of the profile, and a fetch without any of these fails. As in botocore, AWS_STS_REGIONAL_ENDPOINTS=legacy selects the global endpoint https://sts.amazonaws.com/ for the regions that used it before regional endpoints existed; other regions, such as those that must be enabled and those of China, keep their regional endpoint.

As in botocore, AWS_ENDPOINT_URL_STS and then AWS_ENDPOINT_URL go ahead of all of that: with either one set the fetch needs no region and AWS_STS_REGIONAL_ENDPOINTS counts for nothing. An empty variable counts as unset, and a value takes what the endpoint of a client takes, an absolute http or https URL without user info, path, query or fragment; any other throws, and names the variable. So a process that points AWS_ENDPOINT_URL at an emulator for DynamoDB sends the token there too, and over http the token travels in the clear; for a host other than a loopback address the provider logs a warning once. All of these variables are read from the environment at every fetch, also when the token file, the role and the region were passed to the constructor. Only an endpoint passed to WebIdentityCredentialsProvider(string, string, Uri, string?) goes ahead of them: as for the token file and the role, an explicit setting replaces the environment, so that provider reads no variable at all and needs no region. The profile settings sts_regional_endpoints and endpoint_url, the services sections of the shared config file and AWS_IGNORE_CONFIGURED_ENDPOINT_URLS are not read.

The token is read from the file for every request, because the kubelet replaces the file before the token expires; leading and trailing whitespace is removed. A file that is missing, empty or unreadable throws. If STS answers ExpiredTokenException, the file is read again and the request is sent once more at once, because the replacement may have arrived since. Each request has 5 seconds. A timeout, a connection error, HTTP 429 and 5xx, the codes IDPCommunicationError and Throttling, and a successful response that is not XML are retried up to 3 attempts in total, one second apart, which keeps a failing fetch within the default AttemptTimeout of a client. Any other answer is permanent and throws a CredentialsUnavailableException that names the code: InvalidIdentityToken, IDPRejectedClaim, AccessDenied and whatever else STS may say. Once the provider applies, the default chain never goes on to another source, so a pod never signs with the instance role of its node.

The requests use the default proxy of the process (HTTPS_PROXY, NO_PROXY), since STS is often reached through an egress proxy, unlike the link-local endpoints of ContainerCredentialsProvider. An endpoint on a loopback address goes past the proxy, because a proxy cannot reach a port of this machine, and HTTP_PROXY would be asked all the same. They go over https unless the endpoint says otherwise, and follow no redirects, so the token reaches no other host. Cookies are not used.

They do not go through HttpHandler, which carries the requests to DynamoDB and no others. A client with a stub handler in a process with AWS_WEB_IDENTITY_TOKEN_FILE set still calls the real STS with that token: a test sets Credentials, or reaches StubSts of DynaSharp.Testing, a server on a port of this machine, by passing its endpoint to the constructor or by pointing AWS_ENDPOINT_URL_STS at it.

The same AwsCredentials instance is returned until it is refreshed. Refreshing starts 15 minutes before the expiration. In that advisory period the fetch runs in the background and every caller keeps the current credentials, so a slow source delays no request; if the fetch fails a warning is logged and it is tried again after 30 seconds. From 10 minutes before the expiration every caller waits for the fetch, and a failure is thrown. If DynamoDB rejects the credentials as expired before that, a client drops them with TryInvalidate(AwsCredentials) and the next call fetches. Concurrent callers share one fetch, which a caller's cancellation does not cancel. The provider is thread-safe.

The token is a bearer credential. It appears in no message, log or trace. The Message of an error of STS is left out of the exception for that reason: it is free text that may quote the request. Look it up by the code, or in CloudTrail.

Constructors

WebIdentityCredentialsProvider()

Initializes a new instance of the WebIdentityCredentialsProvider class that reads its settings from the environment of the current process, reads the token from disk and uses the system clock.

public WebIdentityCredentialsProvider()

WebIdentityCredentialsProvider(string, string, AwsRegion, string?)

Initializes a new instance of the WebIdentityCredentialsProvider class with explicit settings. The variables AWS_WEB_IDENTITY_TOKEN_FILE, AWS_ROLE_ARN and AWS_ROLE_SESSION_NAME are ignored.

public WebIdentityCredentialsProvider(string tokenFile, string roleArn, AwsRegion region, string? roleSessionName = null)

Parameters

tokenFile string

The path of the file that holds the token. It is read at every fetch.

roleArn string

The ARN of the role to assume, for example arn:aws:iam::123456789012:role/orders.

region AwsRegion

The region of the STS endpoint.

roleSessionName string

The name of the session, which shows in CloudTrail: 2 to 64 letters, digits or characters of _+=,.@-. null means dynasharp- and the Unix time in seconds at each fetch.

Exceptions

ArgumentNullException

region is null.

ArgumentException

tokenFile or roleArn is null or empty, or roleSessionName breaks the rule above.

WebIdentityCredentialsProvider(string, string, Uri, string?)

Initializes a new instance of the WebIdentityCredentialsProvider class with explicit settings and an endpoint of its own. It reads no variable of the environment: the endpoint goes ahead of AWS_ENDPOINT_URL_STS, AWS_ENDPOINT_URL, the region and AWS_STS_REGIONAL_ENDPOINTS, which is what the constructor with a region does not do.

public WebIdentityCredentialsProvider(string tokenFile, string roleArn, Uri stsEndpoint, string? roleSessionName = null)

Parameters

tokenFile string

The path of the file that holds the token. It is read at every fetch.

roleArn string

The ARN of the role to assume, for example arn:aws:iam::123456789012:role/orders.

stsEndpoint Uri

The endpoint of STS, for example a VPC endpoint or StubSts.Endpoint of DynaSharp.Testing: an absolute http or https URL without user info, path, query or fragment. Over http the token travels in the clear.

roleSessionName string

The name of the session, which shows in CloudTrail: 2 to 64 letters, digits or characters of _+=,.@-. null means dynasharp- and the Unix time in seconds at each fetch.

Exceptions

ArgumentNullException

stsEndpoint is null.

ArgumentException

tokenFile or roleArn is null or empty, or stsEndpoint or roleSessionName breaks the rule above.

Methods

GetCredentialsAsync(CancellationToken)

Gets the credentials, fetching or refreshing them when needed.

public ValueTask<AwsCredentials> GetCredentialsAsync(CancellationToken cancellationToken)

Parameters

cancellationToken CancellationToken

Stops this call from waiting. The fetch itself, which other callers may share, is not cancelled.

Returns

ValueTask<AwsCredentials>

The same AwsCredentials instance until it is refreshed.

Exceptions

CredentialsUnavailableException

The provider was created without settings and AWS_WEB_IDENTITY_TOKEN_FILE is not set; a setting is missing or invalid; the token file cannot be read; or STS does not return valid credentials. During the mandatory refresh period, the failure of a refresh is thrown as well.

OperationCanceledException

cancellationToken was cancelled.

TryInvalidate(AwsCredentials)

Drops credentials that DynamoDB rejected as expired, so that the next GetCredentialsAsync(CancellationToken) fetches new ones. A client does this by itself.

public bool TryInvalidate(AwsCredentials rejected)

Parameters

rejected AwsCredentials

The instance that was rejected. Any other than the current one has been replaced already, and is ignored.

Returns

bool

Always true: this source can be asked again.

Exceptions

ArgumentNullException

rejected is null.