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
tokenFilestringThe path of the file that holds the token. It is read at every fetch.
roleArnstringThe ARN of the role to assume, for example
arn:aws:iam::123456789012:role/orders.regionAwsRegionThe region of the STS endpoint.
roleSessionNamestringThe name of the session, which shows in CloudTrail: 2 to 64 letters, digits or characters of
_+=,.@-. null meansdynasharp-and the Unix time in seconds at each fetch.
Exceptions
- ArgumentNullException
regionis null.- ArgumentException
tokenFileorroleArnis null or empty, orroleSessionNamebreaks 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
tokenFilestringThe path of the file that holds the token. It is read at every fetch.
roleArnstringThe ARN of the role to assume, for example
arn:aws:iam::123456789012:role/orders.stsEndpointUriThe endpoint of STS, for example a VPC endpoint or
StubSts.EndpointofDynaSharp.Testing: an absolute http or https URL without user info, path, query or fragment. Over http the token travels in the clear.roleSessionNamestringThe name of the session, which shows in CloudTrail: 2 to 64 letters, digits or characters of
_+=,.@-. null meansdynasharp-and the Unix time in seconds at each fetch.
Exceptions
- ArgumentNullException
stsEndpointis null.- ArgumentException
tokenFileorroleArnis null or empty, orstsEndpointorroleSessionNamebreaks the rule above.
Methods
GetCredentialsAsync(CancellationToken)
Gets the credentials, fetching or refreshing them when needed.
public ValueTask<AwsCredentials> GetCredentialsAsync(CancellationToken cancellationToken)
Parameters
cancellationTokenCancellationTokenStops 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_FILEis 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
cancellationTokenwas 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
rejectedAwsCredentialsThe instance that was rejected. Any other than the current one has been replaced already, and is ignored.
Returns
Exceptions
- ArgumentNullException
rejectedis null.