본 포스팅에서는 Lambda로 SFTP 서버에 S3 버킷의 파일을 SFTP 서버로 전송하는 방법을 다룬다.
Lambda는 AWS에서 제공하는 서버리스 서비스로 AWS 리소스와 연계가 용이하다는 장점이 있다. 이 Lambda는 특정 이벤트가 발생하였을 때 동작하며, 이를 트리거라고 한다. AWS에서는 EventBridge (cron을 작성하여 주기적으로 lambda 실행 가능), API GateWay 등 다양한 트리거를 제공하며 본 포스팅에서는 API GateWay로 REST API를 lambda에 보내는 방법을 테스트한다. (매월 28일 데이터 전송과 같이 주기적인 작업이 필요 할 경우 EventBridge를 사용하면 좋다)
본 테스트에는 다음과 같은 사전 준비가 필요하다.
- SFTP 서버
- SFTP 서버에 접근 할 수 있는 private key
전체적인 구조는 다음과 같으며 SFTP - S3 (sftp 용 버킷) 사이에는 별도의 SFTP 서버를 사용해도 된다.
포스팅에서의 작업 순서는
- Private Key 업로드
- Lambda 함수 작성
- 함수 생성
- 권한 수정
- 코드 작성
- Layer 추가
- API GateWay 테스트
순으로 진행한다.
나는 SFTP 서버를 AWS Transfer family 기반 S3 SFTP 서버로 정하여 테스트 하였으며, SFTP 서버 구성과, key 생성 및 등록 방법은 다음 포스팅에 상세히 적혀있다.
2022.02.25 - [AWS/S3] - [AWS/Transfer family, S3] AWS Transfer family와 S3로 SFTP 서버 구성하기
1. Private key 업로드
SFTP에 접근하는 방법은 ID/PW, RSA키 방식이 있으며, 본 포스팅에서는 RSA 키 방식을 사용한다. SFTP 접근을 위해서는 private key를 Lambda 함수가 가지고 있어야 하지만 Lambda는 서버리스이므로 환경 내에 해당 데이터를 영구 저장할 수 없다.
따라서 S3에 private key를 저장하고 S3로부터 Lambda가 private key를 임시로 다운로드 받아오도록 구현한다.
S3에는 다음과 같은 구조에 업로드한다.
- 출발지 S3 버킷/private_key/
2. Lambda 함수 작성
2.1 Lambda 함수 생성
함수 기본 정보 (이름, 런타임 설정)
Python을 사용할 예정이므로 런타임은 Python3.8 선택한다.
- Lambda > 함수 > 함수생성
2.2 Lambda 함수 권한 수정
Lambda 생성시 기본으로 IAM 역할이 함께 생성되며 이 역할에는 Cloudwatch logs 에 Lambda의 print, error log 등을 기록할 수 있는 권한이 주어져있다.
본 포스팅에서는 Lambda 함수가 S3에 액세스하여 데이터를 다운로드 받아와야하므로 다음과 같이 정책을 추가한다.
2.3 Lambda 함수 작성
동작 단계는 총 세 단계이다.
- 트리거에 따른 API 내용 확인
- S3 (출발지 버킷) 에서 파일 다운로드 (SFTP 서버 다운로드
- SFTP 서버로 전송
언어는 Python을 사용하였으며, SFTP 통신을 위한 paramiko 라이브러리를 사용하였다.
이번 테스트에서 lambda_handler에 입력되는 event 값은 API로부터 입력되는 요청으로서, 형식은 다음과같다.
* event 입력 형식 (이 이벤트 형식은 3. API GateWay 테스트에서 사용됨)
{
"operation": "send",
"data": {
"bucket": "출발지 BUCKET",
"sourceDir": "대상파일이 존재하는 경로",
"sourceFile": "파일이름",
"destination": "SFTP에 저장될 경로"
}
}
* Lambda 코드 (작성된 Lambda 코드는 event 입력 형식에 따라 달라질 수 있으며, 본 포스팅에서는 이 event 값을 기준으로 코드 작성을 하였다.)
import json
import boto3
import os
import paramiko
lambda_rsaKey = "/tmp/key/"
lambda_data = "/tmp/s3_data/"
def lambda_handler(event, context):
# event json에서 operation 값 확인
operation = event['operation']
operations = ['send']
if operation in operations:
s3_get_object(event.get('data'))
sftp(event.get('data'))
else:
raise ValueError('Unrecognized operation "{}"'.format(operation))
def s3_get_object(data):
print(os.listdir("/tmp"))
try:
print(os.makedirs(lambda_data))
print(os.makedirs(lambda_rsaKey))
except FileExistsError:
pass
sourceDir = data["sourceDir"]
sourceFile = data["sourceFile"]
s3 = boto3.resource('s3')
# 데이터 다운로드
s3.meta.client.download_file('l23058-sbpark-bucket', sourceDir + sourceFile, lambda_data + sourceFile)
# private_key 다운로드
s3.meta.client.download_file('l23058-sbpark-bucket', 'private_key/user_linux_key', lambda_rsaKey + 'user_linux_key')
def sftp(data):
print(os.listdir("/tmp"))
print(os.listdir(lambda_data))
print(os.listdir(lambda_rsaKey))
sourceFile = data["sourceFile"]
destination = data["destination"]
host = "SFTP IP or ENDPOINT"
port = 22
username = "SFTP_USER_NAME"
sftp_key = lambda_rsaKey + "/user_linux_key"
sftp_key = paramiko.RSAKey.from_private_key_file(sftp_key)
transport = paramiko.Transport((host, port))
transport.start_client(event=None, timeout=15)
transport.get_remote_server_key()
transport.auth_publickey(username, sftp_key, event=None)
sftp = paramiko.SFTPClient.from_transport(transport)
sftp.put(lambda_data + sourceFile, destination + sourceFile)
sftp.close()
transport.close()
2.4 Lambda Layer 추가
위 코드에서 사용된 paramiko 라이브러리는 파이썬에서 기본으로 제공하고있지 않은 외부 라이브러리이다.
AWS에서는 이러한 외부 라이브러리 및 기타 종속성을 Lambda에서 사용할 수 있도록 zip 형태로 패키징하는 Layer 기능을 제공한다.
AWS에서는 각 런타임에 따라 다음과 같은 구조를 권고하니 반드시 지켜서 업로드해야한다.
레이어 생성에 대한 보다 자세한 내용은 이전 포스팅에서 확인 할 수 있다.
2022.03.03 - [AWS] - [AWS/Lambda] Lambda에 외부 라이브러리 import 하기 (Lambda layer)
생성된 레이어를 람다 함수에 등록한다.
3. API GateWay 테스트
마지막으로 API GateWay를 생성하고 Post 방식으로 테스트를 진행해본다.
3.1 API GateWay 생성
API 생성 > REST API 선택 > 새 API > API 이름 입력
3.2 POST 매서드 생성
API가 생성되었으면 POST 메서드를 생성한다.
POST 요청에 대한 설정을 입력한다.
- 이때 작성한 람다 함수 이름을 입력해야 함
3.3 테스트 내용을 작성해서 Lambda 함수 작동 테스트
생성된 POST 메서드에서 테스트 클릭
테스트에 입력 할 내용은 2.3 Lambda 함수 작성 단계에서 잠시 소개한 event 형식에 따른다.
테스트를 클릭 후 대상 SFTP 서버를 확인하면 해당 파일이 추가된 것을 알 수 있다.
본 포스팅의 경우 SFTP 서버를 S3로 사용하였으므로 (테스트 목적으로 Transfer Family를 사용하여 S3 SFTP를 사용하였음) 버킷을 확인한 결과, 1.PNG가 testDir에 추가된 것을 확인할 수 있었다.
[참고]
https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/configuration-layers.html
https://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/how-to-deploy-api.html
https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/services-apigateway-tutorial.html
'AWS' 카테고리의 다른 글
[AWS/CloudFront] CloudFront로 S3 컨텐츠 제공하기 - ② CloudFront 대체 도메인 구성 (1) | 2022.03.24 |
---|---|
[AWS/CloudFront] CloudFront로 S3 컨텐츠 제공하기 - ① CloudFront 구성 및 동작 확인 (0) | 2022.03.23 |
[AWS/ECS] ECS 클러스터 구성 및 컨테이너 서비스하기 (0) | 2022.03.09 |
[CodeBuild] ECR 업로드시 CodeBuild Role 권한 오류 (0) | 2022.02.08 |
[AWS] Route53, ELB로 EC2의 웹 서비스 하기 (0) | 2022.01.19 |
댓글