Search code examples
node.jsamazon-web-servicesamazon-s3aws-lambdaaws-sts

How can I create a pre-signed url to download a file from an AWS-s3 Bucket for 36 hours in NodeJS?


My aws-lambda code right now is:


    'use strict';
    
    const AWS = require('aws-sdk');
    
    class AwsS3Repository {
      constructor() {
        this.s3 = new AWS.S3();
      }
    
      async getSignedUrl ({ bucketName, Key, Expires }) {
        const params = { 
          Bucket: "bucket_name", 
          Key: "key_name",
          Expires: 60 * 60 * 36,
        }
    
        return this.s3.getSignedUrl('getObject', params);
      }
    } 
    
    module.exports = AwsS3Repository;

While it's working, the expiration time is ignoring the parameter "expires" and instead is expiring in what seems to be less than one hour.

I've read in the AWS docs that you need to use STS to create links that will be valid to 36 hours, so I've created an STS with trusted policy to my lambda function in AWS, so I'm able to use STS.assume as you can see in this example:


    const AWS = require('aws-sdk');
    // Set the region 
    AWS.config.update({region: 'REGION'});
    
    var roleToAssume = {RoleArn: 'my_role',
                        RoleSessionName: 'session1',
                        DurationSeconds: 900,};
    var roleCreds;
    
    // Create the STS service object    
    var sts = new AWS.STS({apiVersion: '2011-06-15'});
    
    //Assume Role
    sts.assumeRole(roleToAssume, function(err, data) {
        if (err) console.log(err, err.stack);
        else{
            roleCreds = {accessKeyId: data.Credentials.AccessKeyId,
                         secretAccessKey: data.Credentials.SecretAccessKey,
                         sessionToken: data.Credentials.SessionToken};
            stsGetCallerIdentity(roleCreds);
        }
    });
    
    //Get Arn of current identity
    function stsGetCallerIdentity(creds) {
        var stsParams = {credentials: creds };
        // Create STS service object
        var sts = new AWS.STS(stsParams);
            
        sts.getCallerIdentity({}, function(err, data) {
            if (err) {
                console.log(err, err.stack);
            }
            else {
                console.log(data.Arn);
            }
        });    
    }

 

However, I still don't understand how I will use STS to create the pre-signed url.


Solution

  • I fixed the problem by creating an IAM role that has permission to create signed url in my S3 bucket and setting it to trust my lambda through the trust policy option in AWS, then updating the AWS-SDK config to use the IAM credentials returned by the sts.assumeRole method.

    
        async assumeRole() {
        const roleToAssume = {
          RoleArn: 'my-sts-role-in-aws',
          RoleSessionName: 'session1',
          DurationSeconds: 900,
        };
    
        const sts = new AWS.STS({ apiVersion: '2011-06-15' });
    
        const roleCreds = await sts.assumeRole(roleToAssume).promise()
    
        AWS.config.update({ 
          accessKeyId: roleCreds.accessKeyId,
          secretAccessKey: roleCreds.secretAccessKey,
          sessionToken: roleCreds.sessionToken,
          region: 'us-east-1',
          signatureVersion: 'v4'
        });
      }