Search

AWS Lambda + RDS Proxy(rds cluster) + Secrets Manager를 이용한 방법

카테고리
Dev-Ops
태그
AWS
게시일
2024/06/04
수정일
2024/10/09 06:40
시리즈
AWS-Study
1 more property

TL; DR;

RDS Proxy는 데이터베이스 max connections 이슈를 해결하는 좋은 수단임
Lambda에서 사용하려면 VPC 내에 있어야 하며, 이를 위해 layers, IAM role 설정을 잘 해주어야 함
만약 Secrets Manager를 사용하고자 하면, RDS Proxy를 사용하기 위해 Lambda가 VPC 내에 있기 때문에 vpc endpoint와 extension을 추가해주어야 함

1. Intro

메시지 발송 기능을 Infra 레벨에서 컨트롤하는 방법을 연구하면서, 메시지 발송 작업을 마치고 Lambda에서 RDS에 접근하여 특정 필드(status)를 업데이트해주어야 하는 기능이 필요했습니다. 이 과정에서 RDS Proxy의 필요성과 Lambda 에서 RDS Proxy를 사용하기 위한 방법과 유의사항에 대해 작성해보고자 합니다.
간략한 메시지 스케줄링 인프라 구조는 아래와 같습니다. EventBridge Scheduler를 통해 에약된 메시지가 Lambda function을 통해 실행되고, 실행이 끝나면 destination으로 연결된 Field Updater Lambda function이 구동되는 구조입니다.
python boto3를 활용하여 eventbridge scheduler에 스케줄을 등록하는 방법에 대한 리서치는 아래의 링크에서 확인이 가능합니다.

2. RDS Proxy?

먼저 RDS Proxy에 대해 알아보기 위해서는 데이터베이스 서버에 접속할 수 있는 Session에 대해 간단히 알아보면 좋을 것 같습니다.

Database Session

데이터베이스도 서버의 역할을 하고 있기 때문에 session이라는 개념이 존재합니다. 세션은 사용자와 연결된 상태를 증명하는 중요한 수단입니다. 데이터베이스 서버에서 기본적으로 세션 하나당 서버의 자원이 할당되고, 통신이 가능하게끔 유지해주게 되는데, 이 자원 역시 한정돼 있습니다. 때문에 MySQL과 더불어 데이터베이스 서버에서 연결을 유지할 수 있는 최대 세션 수는 한정돼 있습니다.
예제로, MySQL 에서는 max_connections 수로 확인이 가능합니다. 기본적으로 MySQL의 최대 세션 수는 151개로 설정돼 있으며, 해당 커넥션 수는 수정이 가능합니다.
mysql> show variables like 'max_connections'; +-----------------+-------+ | Variable_name | Value | +-----------------+-------+ | max_connections | 151 | +-----------------+-------+ 1 row in set (0.00 sec)
Bash
복사

Too many connections error

만약 이러한 세션이 과하게 할당되어 정상적으로 종료되지 않는다면, 혹은 비동기 작업 Task가 너무 많아 한 번에 많은 양의 접속이 발생하게 된다면 Too many connections error가 발생할 수 있습니다. 이를 방지하기 위해서는 Session을 가지고 있는 객체를 통해 연결을 해제하지 않고 지속해서 통신하거나, 접속할 수 있는 max_connections의 value를 수정하는 방법이 있습니다.
하지만 이런 방법을 사용하는 것 역시 다음과 같은 제약 사항이 있습니다.
session을 유지해주는 객체가 필요하며, 이를 백엔드 서버에 구현하거나 별도의 서비스에서 제공돼야 함
max_connections 값을 올려주더라도, 세션 수가 증가하게 되면 근본적으로 해결할 수 없음
이러한 이슈를 해결하기 위해서는 max_connections를 계산하여 적절한 value 값으로 설정하고, Backend 서버에서 ORM 등으로 이를 관리해주는 것이 좋을 것입니다. 하지만 만약 Lambda와 같이 일시적으로 연결 후 세션을 종료하는 비동기 작업이 많다면, 이를 관리하는 것이 여간 어려운 게 아닐 것입니다. 이러한 이슈를 대응하기 위해 RDS Proxy와 같은 서비스를 적용하면 RDS의 too many connections error 가 발생하지 않고, 앞단에서 제어가 가능하게 됩니다.

3. Lambda + RDS Proxy

먼저 Lambda를 통해 RDS Proxy에 접근하는 방법에 대해 설명하고, RDS Proxy를 이용하여 RDS와 통신하게 만들어보겠습니다.

Lambda

먼저 Lambda function은 python 3.11로 생성하였으며, 아래는 Lambda PoC 코드입니다. PoC 코드가 길어서, 펼쳐보기로 넣어두었습니다. 각 코드 예제는 Secret Manager에 접근하는 방법이 약간의 차이가 있습니다.

Lambda PoC code 펼쳐보기(1)

Lambda PoC code 펼쳐보기(2)

PoC에서는 Secret Manager에서 비밀정보를 가져와 RDS Proxy에 접속하여 SQL을 날리는 형태로 구현되어있습니다.
위의 PoC 코드 내에 선언된 클래스인 LambdaSecretRepository 혹은 SecretRepository를 통해 RDS의 secret 값을 가져옴
boto3 를 활용하지 않은 이유는 vpc endpoint를 이용하여 접근해야 하기 때문
Lambda 내에서만 활용할 수 있는 코드로 작성함
가져온 secret 값을 이용하여 RDSRepository를 선언하고, connection을 맺도록 함
connection 이후 cursor를 가져와 쿼리를 실행
결과 값을 반환받은 result를 출력
Lambda 에서는 기본적으로 VPC 외부에 있기 때문에 RDS Proxy를 사용하려면, VPC를 연결해주어야 합니다. 이 과정에서 VPC 외부에 있는 Secret Manager에 요청이 가지 않을 수 있는 이슈가 있어, VPC 설정과 더불어 SecurityGroup 설정을 잘 해주어야 합니다.

VPC endpoint

Lambda에서 VPC 외부에 있는 Secret Manager로 접근하기 위해 vpc endpoint를 생성해줍니다.
생성할 endpoint와 VPC를 연결해주고, subnet을 연결해줍니다.
다음으로 endpoint에 접근할 수 있는 security group을 연결해주어야 합니다. 저는 lambda-rds-1 이라는 이름으로 지어주었고, in/out 은 0.0.0.0/0 으로 모두 오픈해보았습니다.
Lambda의 설정은 위의 PoC 코드 이외에도 VPC 설정과 Layer 설정을 필수로 해주어야 합니다. 또한 IAM Role에 필요한 권한도 추가해주어야 합니다.

IAM Role

먼저 Lambda에 설정된 Permissions를 확인해보면 어떤 role을 사용하고 있는지 확인할 수 있습니다. 해당 Role에 다음과 같이 AWSLambdaVPCAccessExecutionRole 을 추가해줍니다.
또한 AWSLambdaVPCAccessExecutionRole과 별개로 Secret 값을 가져오기 위해 secretsmanager:GetSecretValue, kms:Decrypt 두 가지 권한을 추가해주어야 합니다. 해당 권한은 VPC endpoint를 통해 secret manager에 접근하였을 때 secret 값을 읽기 위해 필요한 정보입니다.
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "secretsmanager:GetSecretValue", "kms:Decrypt" ], "Resource": "*" } ] }
JSON
복사

VPC & Security Group

Lambda에서 Configuration으로 들어가 VPC를 설정해줍니다.
그리고 Security Group을 설정해주어야 하는데, 해당 설정은 Inbound / Outbound 모두 0.0.0.0/0 으로 열어주시면 됩니다. (특별하게 인바운드를 관리해주어야 한다면 해당 설정은 좋지 않겠지만, 현재는 실습을 위해 열어도두록 하겠습니다.)
위와 같이 Inbound, Outbound를 열어주는 이유는 boto3를 사용하기 위함이며, inbound가 열려있지 않게 되면, 코드가 동작하지 않는 이슈가 있습니다. 이 이슈에 대해서는 추후 좀 더 자세히 연구해서 포스팅해볼 계획입니다.

Layers

VPC 환경에서 boto3를 활용하여 AWS Secret Manager를 활용하기 위해서는 AWS-Parameters-and-Secrets-Lambda-Extension를 추가해주어야 합니다. 또한 PoC 코드 실행을 위해 pymysql도 추가해주어야 하는데 해당 arn 값은 다음과 같습니다.
PyMySQL :
Specify an ARN
arn:aws:lambda:ap-northeast-2:770693421928:layer:Klayers-p311-pymysql:2
Requests
Specify an ARN
arn:aws:lambda:ap-northeast-2:770693421928:layer:Klayers-p311-requests:8
SecretManager :
AWS layers
아래의 사진 참조

RDS Proxy

먼저 RDS Proxy를 설정하는 부분을 먼저 다뤄보고 다음으로 Lambda의 추가 설정을 다뤄보도록 하겠습니다.

Create secrets

RDS Proxy에서 사용할 Secret 정보는 secret manager에서 관리하는 것이 좋습니다. Lambda 내에 static 한 접근정보를 두게 되면, Lambda 코드가 노출된 대상 모두에게 DB 정보가 노출되기 때문에 보안상 좋지 않습니다. 따라서 아래와 같이 secret을 생성하여 관리 및 사용해주도록 합니다.
아래와 같이 DB instance 접속 정보에 대한 ID/PW 를 입력하고, 연결할 database instance를 연결 후 생성해주도록 합니다. 저는 RDS 를 선택해주고, example/development/mysql 로 secret_name을 설정해주었습니다.

Create rds proxy

먼저 RDS Proxy를 생성하기 위해 RDS 서비스로 들어가 Proxies를 선택 후 Create proxy를 클릭해줍니다.
만약 연결 후 close가 원활하지 않을 수 있으니, Idle client connection timeout을 1분으로 해주어도 좋습니다.
아래와 같이 원하는 rds database instance 를 선택하고 connection pool을 선택합니다. RDS Proxy에서 컨트롤 할 수 있는 최대 연결 수는 5000개이지만, 만약 부하테스트의 목적이라면 이를 줄여서 설정하면 됩니다. 저는 10% (500)개로 줄여서 설정해보았습니다.
RDS Database instance는 Serverless V2도 가능하지만, V1은 불가능합니다.
이후 RDS Proxy에서 사용할 IAM Role과 Secret 값을 생성해주어야 합니다. 기존의 role이나 secret을 사용해도 되지만, 해당 포스트에서는 새로 생성해주도록 하겠습니다.
Create IAM Role은 자동으로 role을 생성해주지만 secret 값은 직접 생성해주어야 합니다. secret 값은 위에서 생성해두었던 example 값을 사용하도록 했습니다. 그리고 접근 가능한 Subnet들을 선택해주고 생성을 마무리해줍니다.
저는 public, private subnet이 있어서, 해당 네트워크를 모두 선택해주었습니다.
subnet을 설정해주었으면, RDS Proxy에서 사용할 Security Group도 설정해주어야 합니다. 제 경우에는 별도로 생성해주어 다음과 같이 바라보게 하였습니다.
lambda-sgrds-proxy-sgrds-sg

Update proxy IAM Role

IAM Role이 자동으로 생성되었지만, 여기서 Secret Manager를 사용하도록 우리가 설정해주었기 때문에, RDS Proxy 역시 Secret Manager에 접근할 수 있어야 합니다. 따라서 아래와 같은 설정을 추가해주어야 합니다.

Tests

Body는 {} 값으로 비워두고 호출해도 되도록 PoC를 작성했기 때문에, 테스트에는 별도의 설정이 필요없습니다. 아무런 Test로 설정하여 구동하게 되면 아래와 같이 이슈 없이 실행되는 부분을 확인할 수 있었습니다.

5. References

RDS Proxy for aurora

AWS-Secrets-Lambda-Extension

VPC endpoint