IT,프로그래밍/AWS

[Lambda + AWS SDK S3] 람다로 S3 접근가능 url 가져오는법

AWS S3는 기본적으로 퍼블릭 권한이 차단되어있다

 

즉, 개발하고 있는 서비스에서 S3에 저장되어있는 리소스를 일반 유저들에게 제공을 해야 하는 상황에서

단순하게 S3의 있는 파일의 링크를 주려고 해봤자 AccessDenied 가 나올뿐이다.

 

이럴때 사용하기 위해서 있는것이 Pre-signed url이다.

 

S3에서는 미리 인증이 되어있는 url을 제공해 줄 수 있는데 방문자등에게 S3에 있는 리소스를 제공할때는 이와 같은 방법을 사용하면 된다.

AWS-SDK S3 getSignedUrl documentation link

https://docs.aws.amazon.com/ko_kr/AWSJavaScriptSDK/latest/AWS/S3.html#getSignedUrl-property

 

documentation을 참고해보면

getObject로는 open/download 가능한 링크를 받아올수 있고

putObject로는 upload 가능한 링크를 받아올수 있다.

나의 경우 람다함수를 이용해서 S3에 저장되어있는 파일의 pre signed url 을 가져올꺼다.

 

{"arrFileKey":["2707a720-118f-497c-890c-4be9c474ed24","405f3a29-7a16-4728-8ab4-d751f8055c88"]}

 

json 이 stringify가 되어있는 배열을 받으면

arrSignedUrl  :  {
  '2707a720-118f-497c-890c-4be9c474ed24': 'https:// ... link ... 2ers=host',
  '405f3a29-7a16-4728-8ab4-d751f8055c88': 'https://... link ... ders=host'
}

위와 같은 형태로 return 을 해주도록 개발을 할것이다.

const AWS = require("aws-sdk");
AWS.config.update({ region: "ap-northeast-2" });
const s3 = new AWS.S3();

const STORAGE_BUCKET_NAME = `버킷이름`; //저장될 버킷

exports.handler = async (event) => {
  try {
    const arrFileKey = event.arrFileKey;
    let arrSignedUrl = {};
    for await (const fileKeyVal of arrFileKey) {
      const params = { Bucket: STORAGE_BUCKET_NAME, Key: fileKeyVal };
      const signedUrl = await s3.getSignedUrlPromise("getObject", params)
      arrSignedUrl[fileKeyVal] = signedUrl;
    }
  } catch (error) {
    console.error(error);
  }
};

여기 아주 심플한 람다가 개발되었다.

const AWS = require("aws-sdk");
AWS.config.update({ region: "ap-northeast-2" });
const s3 = new AWS.S3();

람다의 경우 aws-sdk는 기본으로 탑재되어 있어서 node_module이나 layer로 모듈을 추가 안해줘도 바로 사용이 가능하다.

region을 config에 추가해주고 S3를 이제 사용해보자.

for await (const fileKeyVal of arrFileKey) {
      const params = { Bucket: STORAGE_BUCKET_NAME, Key: fileKeyVal };
      const signedUrl = await s3.getSignedUrlPromise("getObject", params)
      arrSignedUrl[fileKeyVal] = signedUrl;
}

람다 함수는 async로 되어 있기에 흐름제어를 위하여 for await 문을 사용하였다.

또한 s3에서 getSignedUrl을 동기적으로 가져오기위해 Promise를 사용하여 await를 사용해 주었다.

자, 성공적으로 signedurl이 출력되었다! 이제 사용해보자!

.

.

.

응? 왜 안뜨지? 싶겠지만 자세히 보면 AccessDenied 에러가 발생하였다.

 

https://advancedweb.hu/how-s3-signed-urls-work/

 

https://docs.aws.amazon.com/ko_kr/AmazonS3/latest/dev/PresignedUrlUploadObject.html

즉, 람다함수에 S3 access 권한이 없기에 만들어 놓은 signed url이 의미가 없어진것이다.

 

자, 그러면 권한을 추가해주자

 

권한은 미리 IAM에서 역할중에 AmazonS3FullAccess정책을 추가하여 만들어두자.

이글에서는 IAM 역할을 만드는 방법은 다루지 않도록 하겠다.

 

람다에서 보면 구성과 권한, 모니터링이 보이는데 우리가 필요한것은 권한 부분이다.

 

실행역할에서 편집을 누르면 역할을 추가할수있다.

 

필자의 경우 LambdaS3Access라는 이름으로 역할을 미리 만들어 두었기에 사용하였다.

다시 람다를 실행해서 새로운 url을 받은다음에 주소창에 써보자,

 

성공적으로 다운로드 되었다!