- Newest
- Most votes
- Most comments
The temporary credentials issued by STS are only a cryptographically signed set of tokens, with no mechanism to revoke them explicitly. The indirect but explicit mechanism available would be to modify the access policy of the IAM role to apply an explicit Deny to actions taken with the credentials. The credentials would still be technically valid (for example, sts:GetCallerIdentity
would still accept them and return the identity of the caller), but the permissions policy would block all actions requiring authorisation from being taken with them.
Policy changes propagate very rapidly, even if not quite instantaneously. However, applying those kinds of explicit denies through policy changes wouldn't scale beyond the modest policy size limitations, and removing the denies after the credentials have expired would probably be tedious at best.
Lots of specifics on using policies this way are documented here: https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_disable-perms.html
If you're using the temporary credentials specifically to allow users access to S3, would it be an option to use presigned URLs in S3 (https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html) or CloudFront (https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-urls.html)? The signed URLs can be made specific to a single object URL, and their validity times can be adjusted appropriately for each situation.
Or alternatively, could you make the validity time of the temporary credentials from STS short enough that they wouldn't meaningfully need to be revoked when the user logs off?
Yes, underneath, the Cognito API GetCredentialsForIdentity
(https://docs.aws.amazon.com/cognitoidentity/latest/APIReference/API_GetCredentialsForIdentity.html) gets called and temporary credentials from STS of the form shown in the documentation link are returned. What you do with them after placing them in the credentials
variable, such as storing them in a cookie, you'd have to check from your code.
The Deny
policy statement is of the correct form, although I doubt it'll work for your use case, since it will invalidate all tokens issued before the specified time for all users using the role. I think you posted your reply at 20:00 UTC and the timestamp compared in the policy is 16:40 UTC. Did you test it for a session from several hours before posting the reply?
On a general note, unless this is an internal service for trusted users, it sounds quite complex to allow end users to access all those services directly. Of course, you could use policy statements to control what they can do in DynamoDB, for example, but that's limited to what can be expressed in the policy language. Simple rate-limiting wouldn't even be possible, so anyone logging on could cause arbitrarily high costs for you simply by calling the services with their temporary credentials. Is accessing the services directly from client-side code an intentional choice? I would think many of these access control issues would be simpler if your clients accessed your custom APIs via API Gateway, and you would handle authentication, authorisation, and request validation there. API Gateway also supports WAFv2 and being placed behind a CloudFront distribution for rate-limiting, geo-restrictions, and other general protections.
Thank you Leo,
But I need the IAM STS temporary credentials, not only to access S3 but also DynamoDB, Lambda, and other AWS services, and the roles are apply to different kinds of user groups in Cognito UserPool.
My problem is easy:
When a user Sign-in (using an HTML static page), it obtains from Cognito User Pool: idToken, accessToken and refreshToken, then I pass the idToken to the function fromCognitoIdentityPool and obtain the IAM temporary access token:
import { fromCognitoIdentityPool } from "@aws-sdk/credential-providers"; let credentials = fromCognitoIdentityPool({ clientConfig: { region: 'us-east-1' }, identityPoolId: 'us-east-1:blablabla', logins: { 'cognito-idp.us-east-1.amazonaws.com/us-east-1_{UserPoolId}': idToken, } });
I suppose (not sure), that when this is done, the IAM temporary credential (token) is sent and stored in the cache browser. So, when a new user Sign-In that has NO permission to access a resource, the browser sends the cache credential and it is accepted without looking the permissions for that user (new Sign-in, different idToken).
In this case, the solution is out of the AWS scope, I need to detect a new user Sign-in and Clear the Browser Cache. But, I do not know how :(
Anyway, there is something that catches my attention. If I add a policy: AWSRevokeOlderSessions to the role, the credential still working.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": [
"*"
],
"Resource": [
"*"
],
"Condition": {
"DateLessThan": {
"aws:TokenIssueTime": "2024-07-13T16:40:16.546Z"
}
}
}
]
}
Best Regards, marcelo
Thank you Leo, thank you for your time
Some comments before closing the case.
"The Deny policy statement is of the correct form, although I doubt it'll work for your use case, since it will invalidate all tokens issued before the specified time for all users using the role. I think you posted your reply at 20:00 UTC and the timestamp compared in the policy is 16:40 UTC. Did you test it for a session from several hours before posting the reply?"
Yes, you are right, the revoke all sessions works:
Role: X only one policy: AmazonS3FullAccess
Role X Maximum session duration: 1 hour
Login Laura (in group with Role X) at: 17:34 UTC
GetBucketObject() at: 17:35 UTC
Response httpStatusCode: 200 OK
Add Policy to Role X: AWSRevokeOlderSessions at: *17:45 UTC
"Condition": { "DateLessThan": { "aws:TokenIssueTime": "2024-07-14T17:45:55.373Z" } }
GetBucketObject() at: 17:50 UTC
NotAuthorizedException: Invalid login token. Token expired: 1720979028 >= 1720979023
Good, because I revoke all sessions for this role.
Login Laura (again) at: 18:00 UTC
GetBucketObject() at: 18:05 UTC
Response httpStatusCode: 200 OK
GetBucketObject() at: 19:10 UTC
NotAuthorizedException: Invalid login token. Token expired: 1720983964 >= 1720980597
Good, because the role has a 1-hour session duration.
Anyway, the temporary credential is still active (I guess it has a default of12 hours).
"On a general note, unless this is an internal service for trusted users, it sounds quite complex to allow end users to access all those services directly."
Yes, of course, it is only for testing purposes.
"so anyone logging on could cause arbitrarily high costs for you simply by calling the services with their temporary credentials. Is accessing the services directly from client-side code an intentional choice?"
Intentional choice, just for testing on client side, then it must migrate to the server side.
"if your clients accessed your custom APIs via API Gateway, and you would handle authentication, authorisation, and request validation there."
Mmmmm, can be, but if the authentication and authorization is done trough the API Gateway that calls a Lambda function, the execution of Lambda has a cost also.
Best regards, marcelo
Relevant content
- AWS OFFICIALUpdated 2 years ago
- AWS OFFICIALUpdated 2 years ago