[AWS] Lambda + EventBridge 를 통한 RDS 데이터베이스를 자동으로 중지 및 실행하기
RDS 인스턴스는 DB 인스턴스 시간, 프로비저닝된 스토리지, 백업 스토리지, I/O 요청, 프로비저닝된 IOPS 및 데이터 전송에 대해 청구됩니다. 사용하지 않는 리소스들을 중지하지 않을 경우 지속적으로 비용이 발생하며 이 문서에서는 Amazon EventBridge와 AWS Lambda의 조합을 사용하여 일정에 따라 모든 지역에 대하여 미사용 RDS 인스턴스를 중지/시작하기 위한 자동화된 솔루션을 구현하는 방법을 살펴보겠습니다.
단계 :
1. 사전 구성
2. IAM 정책 및 역할 생성
3. Lambda 함수 생성
4. EventBridge 규칙 생성
5. 테스트
1. 사전 구성
AWS 서비스에 프로그래밍 방식으로 연결하려면 엔드포인트를 사용해야 합니다.
그러나 일부 리전(opt-in)들은 기본적으로 비활성화 되어 있으며 해당 리전들의 DB 인스턴스 정보를 가져오기 위해선 활성화를 진행해주어야 합니다.
opt-in region
아프리카(케이프타운)
아시아 태평양(홍콩)
유럽(밀라노)
중동(바레인)
아시아 태평양(자카르타)
권한이 있는 계정으로 콘솔에 로그인 후 우측 상단 계정 선택 – 계정 – AWS 리전 비활성화 되어있는 5개의 리전들을 활성화 상태로 변경합니다.
테스트를 진행할 DB 인스턴스를 생성합니다. 총 3개 리전에 대하여 테스트 해보겠습니다.
홍콩 : MariaDB
오사카 : AWS Aurora
서울 : Mysql
2. IAM 정책 및 역할 생성
RDS Stop/Start 역할을 위한 정책을 생성합니다. IAM 콘솔에서 정책 – 정책 생성
RDS Stop/Start 를 위한 역할을 생성합니다. IAM 콘솔에서 역할 – 역할 만들기
AWS Lambda를 신뢰할 수 있는 엔터티로 선택 후 다음을 클릭합니다.
생성한 정책 RDS-Stop-Start-Policy 필터링 후 선택 – 다음을 클릭합니다.
RDS-Stop-Start-Role 이름 입력 후 역할 생성을 클릭합니다.
3. Lambda 함수 생성
AWS Lambda 함수를 생성하여 RDS DB 인스턴스를 Stop 시키도록 하겠습니다.
Region은 어느 지역이던 상관 없으나 여기선 서울 Region에 생성해보겠습니다.
RDS 인스턴스를 Stop할 Lambda 함수를 생성합니다. Lambda 콘솔 함수 – 함수 생성
다음과 같이 입력 후 함수를 생성합니다.
함수 이름 : StopRDS
런타임 : Python 3.9
권한 : 기본 실행 역할 변경 – 기존 역할 사용 – 생성한 역할 RDS-Stop-Start-Role 선택
Boto3, Botocore를 이용하여 Python 코드 작성을 진행합니다.
Boto : AWS에서 Python 프로그래밍 언어의 사용을 개선하도록 설계뙨 소프트웨어 개발 키트(SDK) 이며 가장 최신 버전인 Boto3 까지 나와있습니다.Botocore : AWS 도구에 대해 기본적인 액세스를 제공하며 low-level의 클라이언트 요청을 만들고 API에서 결과를 가져옵니다.
# StopRDS 함수 코드importboto3importbotocore# get all regionsavailable_regions=boto3.Session().get_available_regions('rds')deflambda_handler(event, context):forregioninavailable_regions:rds=boto3.client('rds', region_name=region)# Define instancesinstances=rds.describe_db_instances()stopInstances= []# stop instances.fordbininstances["DBInstances"]:try:stopInstances.append(db["DBInstanceIdentifier"])rds.stop_db_instance(DBInstanceIdentifier=db['DBInstanceIdentifier'])exceptbotocore.exceptions.ClientErroraserr:print(err)# get all aurora db clustersrds_aurora=rds.describe_db_clusters()# stop all aurora clusterforaurora_clusterinrds_aurora['DBClusters']:try:rds.stop_db_cluster(DBClusterIdentifier=aurora_cluster['DBClusterIdentifier'])exceptbotocore.exceptions.ClientErroraserr:print(err)# print all instances that will stop.iflen(stopInstances) >0:print ("stopInstances")else:print ("No rds instances to shutdown.")
stop_db_instance API는 Aurora 클러스터의 일부인 인스턴스를 종료할 수 없기 때문에 별도로 Aurora DB에 대하여 stop_db_cluster API 호출을 해주어야 합니다.
StartRDS 함수 작성을 하고자 할 경우 아래 코드를 입력하여 함수를 생성하면 됩니다.
# StartRDS 함수 코드importboto3importbotocore# get all regionsavailable_regions=boto3.Session().get_available_regions('rds')deflambda_handler(event, context):forregioninavailable_regions:rds=boto3.client('rds', region_name=region)# Define instancesinstances=rds.describe_db_instances()startInstances= []# start instances.fordbininstances["DBInstances"]:try:startInstances.append(db["DBInstanceIdentifier"])rds.start_db_instance(DBInstanceIdentifier=db['DBInstanceIdentifier'])exceptbotocore.exceptions.ClientErroraserr:print(err)# get all aurora db clustersrds_aurora=rds.describe_db_clusters()# stop all aurora clusterforaurora_clusterinrds_aurora['DBClusters']:try:rds.start_db_cluster(DBClusterIdentifier=aurora_cluster['DBClusterIdentifier'])exceptbotocore.exceptions.ClientErroraserr:print(err)# print all instances that will stop.iflen(startInstances) >0:print ("startInstances")else:print ("No rds instances to start.")
4. EventBridge 규칙 생성
Amazon EventBridge 콘솔에서 규칙 – 규칙 생성을 클릭합니다.
규칙 세부 정보에서 RDS_Instances_Stop 규칙 이름으로 입력 및 규칙 유형 일정 선택 후 다음을 클릭합니다.
생성한 Lambda 함수, EventBridge 규칙으로 3개 Region DB 들에 대하여 테스트를 진행해보겠습니다.
Amazon Lambda 콘솔에서 StopRDS 선택 후 테스트를 클릭, StopTest 이름을 작성한 뒤 기본 템플릿 hello-world 로 저장합니다.
저장된 템플릿 에서 테스트를 클릭합니다.
테스트가 정상적으로 성공했다면 다음과 같은 화면을 볼 수 있습니다.
이제 3개 리전에 대한 RDS 데이터베이스를 확인해보겠습니다.
서울 리전 Mysql 인스턴스, opt-in 리전인 홍콩 Mssql 정상적으로 Stop 되고 있으며 오사카 리전 Aurora DB Cluster도 정상적으로 Stop 중인 상태를 확인할 수 있습니다.
감사합니다.
[AWS] Route53 + Workmail + SES 를 통한 메일 서비스 사용
목 차
무료 도메인 구매
route53 호스팅영역 추가
Workmail 생성
Workmail Add Domain
Domain record 추가
Workmail user 생성
Workmail Test
무료 도메인 구매
[링크] https://my.freenom.com/clientarea.php
무료 도메인 사이트로 무난해 보이는 “freenom” 선택
<주의사항>1. 사용 가능한 TLD 가 제한적 => (.tk, .ml, .ga, .gq, .cf)
2. 연장 시기 놓치면 유료화 - 발급밭은 도메인은 최대 1년 단위로 연장해야되며, 연장은 만료일로부터 2주 안에 신청 가능
3. 인기있는 도메인 강제 하이재킹 - 인기가 높아지면 접속량도 증가하며, freenom에서는 트래픽 모니터링을 하여 실제 트래픽이 많아진 도메인은 강제로 유료로 전환
4. 제한적인 DNS 서버 - 국내 DNS 서버의 경우 Freenom 도메인 정보가 공유되지 않아 국내 환경에서는 접속이 어려워지는 현상이 발생하기도 함.
위 주의사항에도 테스트 용도로는 문제 없기에 도메인 구매를 진행함.1. freenom 가입
2. domain 발급
1) [Register a new Domain] 을 선택 후 원하는 도메인 이름 검색
2) 원하는 TLD 오른쪽에 [Get it now!] 클릭하여 Selected 한 후에 Checkout 버튼 클릭
3) [Use DNS] - Use Freenom DNS Service 에서 IP address 작성 ==> Domain과 매칭 될 IP 작성
4) Total Due Today : $0.00USD 비용 확인 -> 약관 동의 -> Complete Order 클릭하여 구매
Route53 호스팅 영역 추가
route 53 – 호스팅 영역 – 호스팅 영역 생성
1. 도메인 이름 : <freenom에서 구입한 주소>2. 유형 - 퍼블릭 호스팅 영역 체크(외부로 메일 사용하기 위함.)
3. 호스팅 영역 생성 클릭
WorkMail 생성
Workmail – Create organization
1. Create organization
2. Email domain : Existing Route 53 domain
- Route 53 hosted zone : <Freenom에서 구입한 주소>3. Alias : alias name 작성
- 별칭은 Workmail 웹 어플리케이션에 엑세스 할 url에 사용됨.(https://<alias>.awsapps.com/mail)
4. Advanced settings
- User directory :
1) Create Amazon Workmail directory - 사용할 디렉토리가 존재하지 않을 경우 Workmail로 사용할 디렉토리 생성
2) Use existing directory - AWS Directory Servise 사용하여 생성 된 Simple AD, 관리형 AD, AD 커넥터를 사용중이며, workmail가 관리대상일 경우 해당 디렉토리 선택
- Encryption :
1) use Amazon WorkMail managed key - AWS 로 관리되는 키를 선택하며, 직접 관리되지 않음
2) Use existing customer managed key(CMK) - AWS KMS 에서 customer managed key(CMK)를 통해 생성한 key 사용
5. Create organization 클릭
Workmail Add Domain
WorkMail-Organizations-<생성한 organization>-Domains
1. Add domain 클릭
2. Domain name - route53에 등록되있는 domain 선택 후 생성
3. 도메인 안에 레코드 값 확인
- Domain ownership : 도메인을 소유하고 있음을 인증하는 TXT 레코드
- WorkMail configuration : Workmail용 MX, CNAME 레코드
- Improved security : 제대로된 도메인 이라는 것을 인증하는 레코드들(DKIM, SPF, DMARC)
- Improved email delivery4. Organization - Domains 에서 [my domain] 체크 후 "Set as default" 클릭하여 default 도메인을 [my domain]으로 변경
Domain record 추가
Route 53 – 호스팅 영역 – <개인 도메인> – 레코드 – 레코드 생성
1. subdomain 작성(main domain 일 경우 작성 X)
2. 레코드 Type 선택하기(TXT, MX, CNAME..)
3. 레코드의 값 작성
** 위 "Workmail Add Domain" 의 3번과 동일한 값을 추가 **
Workmail User 생성
Workmail – organization – Users
User details
1. User name - user name을 이용해서 AWS WorkMail 웹메일에 로그인 가능함.
2. Display name - 시스템 상 표시되는 name
Email setup
1. Email address
-<User name>@<workmail 도메인>2. Password , Repeat password
- Email 접속시 필요한 비밀번호
Workmail Test
<Mail login>
1. WorkMail - Organizations - [my organization] 에서 아래에 url 주소로 접속
- https://xxx.awsapps.com/mail
2. Workmail user 이름(Email address 이름은 x), user 비밀번호 작성하여 로그인
<발신>
<수신>
Amazon Elastic Container Registry Public (ECR Public)
Amazon Elastic Container Registry Public (ECR Public) 사용해보기
Amazon Elastic Container Registry(Amazon ECR)는 안전하고 확장 가능하고 신뢰할 수 있는 AWS 관리형 컨테이너 이미지 레지스트리 서비스 입니다. Amazon ECR은 AWS IAM을 사용하여 리소스 기반 권한이 있는 퍼블릭/프라이빗 이미지 리포지토리를 지원 합니다. 따라서 AWS 제공하는 ECS, EKS등에서 ECR을 쉽게 엑세스 할 수 있습니다.
root@hostway-bmt:~# aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/n3n4q5v6
WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
이미지에 태그를 지정
root@hostway-bmt:~# docker tag grafana:8.0.4 public.ecr.aws/n3n4q5v6/ecr-bmt-hostway:8.0.4
root@hostway-bmt:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
grafana 8.0.4 4a61138b1602 2 weeks ago 206MB
public.ecr.aws/n3n4q5v6/ecr-bmt-hostway 8.0.4 4a61138b1602 2 weeks ago 206MB
Auther from scratch 선택
Lambda Function 이름 : StartEC2Instance / StopEC2Instance
Runtime : Python3.8
Permissions - Use an existing role - 생성해두었던 role 선택
[Lambda Code]
import boto3
region = 'ap-northeast-2'
instances = []
ec2_r = boto3.resource('ec2')
ec2 = boto3.client('ec2', region_name=region)
//
for instance in ec2_r.instances.all():
instances.append(instance.id)
def lambda_handler(event, context):
ec2.start_instances(InstanceIds=instances)
print('started your instances: ' + str(instances))
태그를 설정하여 특정 ec2에만 스크립트 적용될 수 있도록 할수도 있습니다.
import boto3
region = 'ap-northeast-2'
instances = []
ec2_r = boto3.resource('ec2')
ec2 = boto3.client('ec2', region_name=region)
for instance in ec2_r.instances.all():
for tag in instance.tags:
if tag['Key'] == 'auto-schedule':
if tag['Value'] == 'auto':
instances.append(instance.id)
def lambda_handler(event, context):
ec2.start_instances(InstanceIds=instances)
print('start your instances: ' + str(instances))
정상적으로 스크립트가 구동되는지 테스트를 해봅시다.
Lambda - Deploy - Test
구동이 제대로 안된다면,
1) IAM Policy, Lambda code 확인
2) Lambda-General configuration - Timeout 을 3(default) -> 15로 변경.
3) 지정한 region에 있는 ec2의 Instance state가 1EA라도 terminate 되어있는 상태라면 스크립트가 구동되지 않음.
3. CloudWatch 스케줄링 등록
Event - Rules - Go to Amazon EventBridge
step1)
규칙 이름 : StartEC2Instance
Event bus : default
Rule type : Schedule
step2)
GMT 기준 cron 표현식으로 원하는 시간 지정
step3)
target types : AWS service
Select a target : Lambda function
Function : Lambda Function 선택 (StartEC2Instance)
++ 타겟 추가 가능
step4)
태그 설정
(선택) 4. Lmabda code 성공/실패 메일 알람
[SNS]
topic 생성
subscription 생성
Protocol : Email
Endpoint : 수신받을 이메일 지정
[Lambda]
Configuration - Destinations - Add destination
source : Asynchronous invocation
Condition : On Failure / On Success
Destination Type : SNS topic
Destination : 생성한 topic 선택
AWS SSM 을 통한 VPC Private Network 접근
목적
- VPC 내의 Private Network 에 외부 공인 대역에서 Shell 로 접근 ( VPN 역할 )
특징
- SSM 을 통해 AWS 연결을 하는 것으로, IGW 나 EIP 등의 VPC내 별도 제약이 필요없다
- EC2 SSH 접근 용도의 Password 나 Key-Pair 가 필요없다.
- Shell 전환으로 SSH 와 거의 동일하게 사용할 수 있다.
- AWS Client VPN 과 비교 시, 비용적으로 유리하다.
요구사항
- AWS CLi 를 설치 및 AWS 리소스에 접근할 수 있는 공인망 환경 ( VM / CT / Server )
일부 리전의 경우 AWS Console 내에서 Cloudshell 사용 가능
Aamazon 2 리눅스 인스턴스의 경우에는 기본 설정되어 있을 수 있다.
[root@ip-10-10-20-201 ~]# sudo yum install -y https://s3.region.amazonaws.com/amazon-ssm-region/latest/linux_amd64/amazon-ssm-agent.rpm
Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
Cannot open: https://s3.region.amazonaws.com/amazon-ssm-region/latest/linux_amd64/amazon-ssm-agent.rpm. Skipping.
Error: Nothing to do
[root@ip-10-10-20-201 ~]# wget https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
--2022-03-29 02:49:06-- https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_amd64/amazon-ssm-agent.rpm
Resolving s3.amazonaws.com (s3.amazonaws.com)... 52.217.196.240
Connecting to s3.amazonaws.com (s3.amazonaws.com)|52.217.196.240|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 26724168 (25M) [binary/octet-stream]
Saving to: ‘amazon-ssm-agent.rpm’
100%[==================================================================================================>] 26,724,168 12.7MB/s in 2.0s
2022-03-29 02:49:08 (12.7 MB/s) - ‘amazon-ssm-agent.rpm’ saved [26724168/26724168]
설치 후 자동시작 활성화한다.
[root@ip-10-10-20-201 ~]# rpm -Uvh amazon-ssm-agent.rpm
warning: amazon-ssm-agent.rpm: Header V4 RSA/SHA1 Signature, key ID 693eca21: NOKEY
Preparing... ################################# [100%]
Updating / installing...
1:amazon-ssm-agent-3.1.1080.0-1 ################################# [100%]
Created symlink from /etc/systemd/system/multi-user.target.wants/amazon-ssm-agent.service to /etc/systemd/system/amazon-ssm-agent.service.
[root@ip-10-10-20-201 ~]# systemctl enable amazon-ssm-agent
[root@ip-10-10-20-201 ~]# systemctl start amazon-ssm-agent
[root@ip-10-10-20-201 ~]# systemctl status amazon-ssm-agent
-- amazon-ssm-agent.service - amazon-ssm-agent
Loaded: loaded (/etc/systemd/system/amazon-ssm-agent.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2022-03-29 02:53:54 UTC; 21s ago
Main PID: 3355 (amazon-ssm-agen)
CGroup: /system.slice/amazon-ssm-agent.service
├─3355 /usr/bin/amazon-ssm-agent
└─3382 /usr/bin/ssm-agent-worker
Mar 29 02:53:54 ip-10-10-20-201.us-west-2.compute.internal amazon-ssm-agent[3355]: 2022-03-29 02:53:54 INFO Agent will take identity f...EC2
Mar 29 02:53:54 ip-10-10-20-201.us-west-2.compute.internal amazon-ssm-agent[3355]: 2022-03-29 02:53:54 INFO [amazon-ssm-agent] using n...IPC
Mar 29 02:53:55 ip-10-10-20-201.us-west-2.compute.internal amazon-ssm-agent[3355]: 2022-03-29 02:53:54 INFO [amazon-ssm-agent] using n...IPC
Mar 29 02:53:55 ip-10-10-20-201.us-west-2.compute.internal amazon-ssm-agent[3355]: 2022-03-29 02:53:54 INFO [amazon-ssm-agent] using n...IPC
Mar 29 02:53:55 ip-10-10-20-201.us-west-2.compute.internal amazon-ssm-agent[3355]: 2022-03-29 02:53:54 INFO [amazon-ssm-agent] amazon-...0.0
Mar 29 02:53:55 ip-10-10-20-201.us-west-2.compute.internal amazon-ssm-agent[3355]: 2022-03-29 02:53:54 INFO [amazon-ssm-agent] OS: lin...d64
Mar 29 02:53:55 ip-10-10-20-201.us-west-2.compute.internal amazon-ssm-agent[3355]: 2022-03-29 02:53:54 INFO [CredentialRefresher] Iden...her
Mar 29 02:53:55 ip-10-10-20-201.us-west-2.compute.internal amazon-ssm-agent[3355]: 2022-03-29 02:53:55 INFO [amazon-ssm-agent] [LongRu...ess
Mar 29 02:53:55 ip-10-10-20-201.us-west-2.compute.internal amazon-ssm-agent[3355]: 2022-03-29 02:53:55 INFO [amazon-ssm-agent] [LongRu...ted
Mar 29 02:53:55 ip-10-10-20-201.us-west-2.compute.internal amazon-ssm-agent[3355]: 2022-03-29 02:53:55 INFO [amazon-ssm-agent] [LongRu...nds
Hint: Some lines were ellipsized, use -l to show in full.
4. AWS Cli 에서 SSM 을 통한 EC2 접속
외부 CT 에 AWSCli 를 설치 후 IAM API Key 권한을 설정한다.
## 접속할 Client의 IP 확인
$ curl http://icanhazip.com
1.2.3.4
## AWSCli 설치
(중요) SSM의 Session-Plugin 을 사용하기 위해서는 AWSCli 1.16 버전 이상이어야 한다.
$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
## Linux 용 SSM Session-Manager Plugin 설치
$ curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/linux_64bit/session-manager-plugin.rpm" -o "session-manager-plugin.rpm"
$ rpm -Uvh session-manager-plugin.rpm
$ session-manager-plugin
The Session Manager plugin was installed successfully. Use the AWS CLI to start a session.
## 접근 정보 설정
본문 내용의 키는 임의 생성한 내용.
$ aws configure
AWS Access Key ID [None]: AKIAQ25632EPN7T7FFVT
AWS Secret Access Key [None]: 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
Default region name [None]: us-west-2
Default output format [None]: json
CMK 공유 설정 없이, 암호화된 볼륨이 있는 프라이빗 AMI 를 AWS 계정간에 공유하면 새 인스턴스 시작 시에 에러 메세지 없이 생성 후 그냥 인스턴스가 자동 종료(Terminated)되어 버립니다.
키 또한 권한을 공유하여 사용해야 합니다.
# 공유할 이미지를 지정해 주는 부분입니다.
# 원본 AMI 계정에 IAM 관리형 정책을 만들고 IAM 에 할당합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:ModifyImageAttribute"
],
"Resource": [
"arn:aws:ec2:us-west-2::image/<0e9fcdb7ae40e8f4c>"
## 공유할 이미지의 리전 위치와 id ( ami-xxxxxxxxxxxxxxxxxx 에서 xxx부분입니다 )
]
}
]
}
# KMS 서비스에서 Key 를 공유 가능한 어카운트를 설정합니다.
# 원본 AMI 계정의 KMS 서비스에 가서 공유 할 AWS Account 넘버를 공유에 등록해 줍니다.
# 공유 받은 쪽에서 복호화할 CMK 를 요청하는 부분입니다.
# 공유 받은 계정의 IAM 에 관리형 정책을 등록합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"kms:DescribeKey",
"kms:ReEncrypt*",
"kms:CreateGrant",
"kms:Decrypt"
],
"Resource": [
"arn:aws:kms:us-west-2:891977874274:key/bc52517a-676b-4f1a-9d1a-d50241563abc"
## 원본 AMI 의 KMS Key 권한을 요청하는 정책입니다.
]
}
]
}
이제 정상적으로 공유 받은 이미지에서 EC2 가 생성되고 정상 시작되는 것을 확인할 수 있습니다.
참고 AWS Docs : https://aws.amazon.com/ko/blogs/security/how-to-share-encrypted-amis-across-accounts-to-launch-encrypted-ec2-instances/