grep

Engineering

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

직방

2023년 7월 10일

원문에서 보기 ↗

안녕하세요. 호갱노노 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 설정

{
    "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": "*"
        }
    ]
}
{
    "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' }]);

결과물

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

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

감사합니다.