lambda@edge를 활용한 이미지 워터마킹

Austin
직방 기술 블로그
8 min readJul 10, 2023

--

안녕하세요. 호갱노노 BE 팀의 오스틴입니다.

이번 포스팅에서는 AWS lambda@edge를 활용하여 이미지에 워터마킹 하는방법에 대해서 이야기해보겠습니다.

이미지 워터마킹을 다루기에 앞서 일반적으로 서비스에서는 이미지를 어떤식으로 저장하고 사용하는지를 먼저 다루어 보겠습니다.

이미지 다루기

우리가 접하는 많은 서비스에서 이미지는 모두 온라인상 어딘가에 저장되어 있고, 클라이언트가 요청할 때마다 이미지를 전송합니다.

아주 단순한 시스템에서는 서버내 폴더 어딘가에 저장해 놓았다가 내려주기도 하고, Web Server 와 WAS 가 분리된 구조에서는 정적인 파일(html, js, image)들을 Web Server 에 저장하는 방식으로 서버의 부하를 분산시키고 캐시를 사용하기도 합니다.

AWS 를 사용하는 경우에는 S3 를 image 서버처럼 활용하기도 합니다. 이와 같은 경우에는 image 를 서버로 업로드하는게 아니라, presigned URL 을 활용하여 클라이언트에서 S3로 직접 이미지를 upload 하는 방법을 주로 사용합니다. 다음 그림은 presigned URL 을 생성하는 람다를 활용한 s3 upload 방법입니다.

그림1. 람다를 활용한 presigned URL 취득 및 UPLOAD

CloudFront 와 Lambda@Edge

저희 호갱노노에서는 AWS 를 기본 서버 환경으로 사용하고있고 S3 에 이미지를 저장하고 있습니다.

그리고, 저장된 이미지는 AWS CloudFront 를 통해 사용자에게 전달됩니다. 다음은 CloudFront (이후 CF) 에 대한 AWS 의 설명입니다.

Amazon CloudFront는 .html, .css, .js 및 이미지 파일과 같은 정적 및 동적 웹 콘텐츠를 사용자에게 더 빨리 배포하도록 지원하는 웹 서비스입니다.

그럼 이제 S3 에 있는 이미지를 워터마킹해서 내려주는 방법을 알아보겠습니다.

저희는 CloudFront 를 통해 내려주는 이미지에 워터마킹을 표시하기 위해서 lambda@edge 를 사용하였습니다.

다음은 lambda@edge 에 대한 AWS 에 설명입니다.

Lambda@Edge를 사용하면 Node.js 및 Python Lambda 함수를 실행하여 CloudFront가 제공하는 콘텐츠를 사용자 지정하여 AWS 위치의 함수를 최종 사용자와 더 가깝게 실행할 수 있습니다. 이 함수는 서버 프로비저닝 또는 관리 없이 CloudFront 이벤트에 응답하여 실행됩니다. Lambda 함수를 사용하여 CloudFront 요청 및 응답을 다음과 같이 변경할 수 있습니다.

그러니까 CF 에 들어오는 요청 전후로 람다함수(에지함수)를 이용하여 req/res 를 변경할 수 있습니다. 그리고, 워터마킹은 바로 이 람다함수를 작성하여 실행합니다.

그림2. CF 처리 FLOW

워터 마킹을 위한 Lambda@Edge 설정

  • lambda 페이지로 이동 후 Region을 Virginia로 바꿉니다. 그리고 Create function을 클릭합니다. (lambda edge는 Virginia에서만 사용 가능)
  • 필요한 내용을 채우고 Create Function 을 클릭합니다. 내용은 이름만 적어도 됩니다. (기존에 사용하던 role을 그대로 사용하고 싶다면 Execution role에서 Use an existing role을 선택합니다.)
  • Configuration > Permissions에서 해당 Role을 클릭합니다.
  • 아래 화면에서 Policy 왼쪽 +를 누르면 json이 나오고 Edit을 눌러 아래와 같이 적어줍니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "{resource arn을 적어주세요}"
},
{
"Effect": "Allow",
"Action": [
"iam:CreateServiceLinkedRole",
"lambda:GetFunction",
"lambda:EnableReplication*",
"cloudfront:UpdateDistribution",
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogStreams"
],
"Resource": "*"
}
]
}
  • Trust relationships 탭으로 이동해서 아래와 같이 수정합니다.
    Service 목록에 “edgelambda.amazonaws.com”이 꼭 있어야 합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com",
"edgelambda.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
  • 코드를 작성합니다.코드가 너무 크다면 업로드 할 수 있습니다.

예제 함수들response 생성 및 업데이트 을 확인할 수 있습니다.

다음은 실제 코드중 워터마킹하는 부분만 발췌하였습니다.

/**
* watermark 생성 로직
**/
let resizedWaterMarkImage = sharp('watermark.png').rotate();
const width = imageMetaData.width;
const heigth = imageMetaData.height;

// ....
// 원본이미지에 맞게 워터마크의 크기를 조절한 후,
// ....
resizedWaterMarkImage = await resizedWaterMarkImage.resize(waterWidth, waterHeight, { fit: 'inside' }).toBuffer();
await zigbangImage.composite([{ input: resizedWaterMarkImage, gravity: 'center' }]);
  • 그리고, 테스트를 해봅니다. (이벤트 함수 예제)
    Test할 때 생기는 log는 확인이 가능합니다. CloudWatch Log group에 없다면 생성하면 됩니다.
  • 새 버전을 publish 합니다.
  • publish 한 람다의 ARN을 복사 후 CF 에 붙입니다.
    behavior 까지 새롭게 만드려면 Create behavior 를 하고 그게 아니라면 해당 Behavior를 수정합니다.
  • 적용시 캐시 때문에 시간이 다소 소요될 수 있습니다. 그럼, 다음과 같이 호갱노노 이미지가 워터마크로 이미지에 표시됩니다.

결과물

이상으로 S3 에 저장된 이미지를 CloudFront 의 lambda@edge 를 통해서 워터마킹 하는 방법에 대해서 알아봤습니다.

확실히 AWS 를 활용하면 많은 노력 없이도 쉽고 편리하게 서버에서 이미지를 다룰 수 있다는 점이 참 매력적인거 같습니다.

감사합니다.

--

--