question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Allow for IAM credentials with longer duration than 1 hour (re: storage upload)

See original GitHub issue

Is your feature request related to a problem? Please describe. I have large files that need to be uploaded and the Storage functionality is very useful, but always gets back credentials that expire in the default time of 1 hour, and the uploads tend to take longer.

Describe the solution you’d like Because IAM roles allow for longer duration (up to 12 hours), and because the Storage.put operation is not retryable (the underlying .upload multipart function), it does not seem possible to catch expiration, update credentials and try again. It seems that the only solution is to get longer-lasting credentials in the first place. From what I’ve read, it looks like the longer-lasting credentials (a) need to be set up in the IAM role (a quick edit) and (b) require a longer duration parameter (DurationSeconds) when requested. The introduction of a DurationSeconds-like parameter for getting storage upload credential would be quite helpful.

Describe alternatives you’ve considered Initially, I tried to catch the error, update the authentication and retry, but when that didn’t work, I did some further research and came to the conclusions above. I have tried to get my own credentials using code similar to the AWS Amplify code as a start, but for some reason the credentials I get back are always expired, so I’m stuck and can’t move forward with an outside-of-aws-amplify solution:

private _setCredentialsFromSession(session): Promise<ICredentials> {
        logger.debug('set credentials from session');
        const idToken = session.getIdToken().getJwtToken();
        const { region, userPoolId, identityPoolId } = this._config;
        if (!identityPoolId) {
            logger.debug('No Cognito Federated Identity pool provided');
            return Promise.reject('No Cognito Federated Identity pool provided');
        }
        const key = 'cognito-idp.' + region + '.amazonaws.com/' + userPoolId;
        const logins = {};
        logins[key] = idToken;
        const credentials = new AWS.CognitoIdentityCredentials(
            {
            IdentityPoolId: identityPoolId,
            Logins: logins
        },  {
            region
        });

Additional context Thanks for the terrific library and the effort put into it thus far.

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:7
  • Comments:14

github_iconTop GitHub Comments

1reaction
wildcat63commented, Jul 18, 2019

I needed a workaround, so I came up with the following. It’s a bit ugly, I’m sure, but so far it’s worked for me. The idea is to ultimately use a method that gives temporary credentials but allows for “DurationSeconds” to be used. Following the explanation in the CognitoIdentityCredentials API, this approach uses STS’ assumeRoleWithWebIdentity after getting Cognito’s getOpenIdToken.

export const longUpload = async (key, object, config) => {
    // I kept the same inputs as Storage.put so I could choose when to use the long upload fn
    // the user pool web app, identity pool, region, etc. are stored in my .env file
    // they probably can be pulled from existing amplify objects, though
    const userEmailKey = `CognitoIdentityServiceProvider.${
        process.env.REACT_APP_USER_POOL_WEB_APP_ID
    }.LastAuthUser`;
    const userEmail = localStorage.getItem(userEmailKey);
    const idTokenKey = `CognitoIdentityServiceProvider.${
        process.env.REACT_APP_USER_POOL_WEB_APP_ID
    }.${userEmail}.idToken`;
    const token = localStorage.getItem(idTokenKey);
    if (!token) {
        throw new Error("no id token"); // temporary approach to errors throughout
    }

    const identityIdKey = `aws.cognito.identity-id.${
        process.env.REACT_APP_IDENTITY_POOL_ID
    }`;
    const identityId = localStorage.getItem(identityIdKey);
    if (!identityId) {
        throw new Error("no identityId");
    }

    const tokenKey = `cognito-idp.${process.env.REACT_APP_REGION}.amazonaws.com/${process.env.REACT_APP_USER_POOL_ID}`;
    const logins = {};
    logins[tokenKey] = token;

    const openIdParams = {
        IdentityId: identityId,
        Logins: logins,
    };

    try {
        const cognitoidentity = new AWS.CognitoIdentity({region: process.env.REACT_APP_REGION});
        const openIdToken = await cognitoidentity.getOpenIdToken(openIdParams).promise();

        const stsParams = {
            DurationSeconds: 43200,
            // optional / intersection: Policy: "{\"Version\":\" etc.
            RoleArn: "arn:aws:iam::917249922596:role/football-20181219132837-authRole",
            RoleSessionName: userEmail, // probably can be anything that's not too long
            WebIdentityToken: openIdToken.Token,
        };

        try {
            const sts = new AWS.STS();
            // @ts-ignore -- code copied from API; maybe types for this method are wrong
            const credentials = await sts.assumeRoleWithWebIdentity(stsParams).promise();

            const accessparams = {
                accessKeyId: credentials.Credentials.AccessKeyId,
                httpOptions: {timeout: 0}, // had some timeout issues
                maxRetries: 20,  // don't want to lose a 10gb upload partway through
                secretAccessKey: credentials.Credentials.SecretAccessKey,
                sessionToken: credentials.Credentials.SessionToken,
              };
            const s3 = await new AWS.S3(accessparams);

            const storageBucket = process.env.REACT_APP_PROD_STORAGE;

            // most of the following is very similar to what's in the amplify put method
            const finalKey = "protected/" + identityId + "/" + key;
            const s3UploadParams: any = {
                Body: object,
                Bucket: storageBucket,
                ContentType: config.contentType,
                Key: finalKey,
            };

            const upload = s3
            .upload(s3UploadParams)
            .on("httpUploadProgress", (progress) => {
                if (config.progressCallback) {
                    if (typeof config.progressCallback === "function") {
                        config.progressCallback(progress);
                    } else {
                        console.log("progressCallback should be a function, not a " + typeof config.progressCallback);
                    }
                }
            });
            const data = await upload.promise();
            return data;
        } catch (e) {
            console.log(e);
        }

    } catch (e) {
        console.log(e);
        }

};
0reactions
joa44741commented, Nov 11, 2022

any updates? 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

Enable Federated API Access to your AWS Resources for up ...
In this post, I show you how to configure the maximum session duration for an existing IAM role to 4 hours (maximum allowed...
Read more >
Create short-lived credentials for a service account
Short-lived credentials have a limited lifetime, with durations of just a few hours or shorter. Short-lived service account credentials are useful for scenarios ......
Read more >
Presigned URL for Amazon S3 bucket expires before ...
AWS Security Token Service (STS): Valid up to 36 hours when signed by an AWS Identity and Access Management (IAM) user, or valid...
Read more >
How can I use IAM policies to grant user-specific access to ...
Find more details in the AWS Knowledge Center: https://amzn.to/2YS2tjOJansen, an AWS Cloud Support Engineer, shows you how you can use IAM ...
Read more >
Securing Access To AWS With Short-Lived Credentials And MFA
Using IAM Roles is one of the most important security measures you can take when running systems on AWS. They let you use...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found