반응형
안녕하세요.
오늘은 AWS의 메일 기능인 SES을 IAM Programmatic Key(이하, IAM Key)을 발급하지 않고 사용하는 방법에 대해서 알아보도록 하겠습니다.
AWS SES을 사용하는 가장 쉬운 방법은 AWS SES 권한이 포함된 IAM Key을 발급받아 서버에 등록하고 사용하면 됩니다. 다만, 정보보안의 관점에서 IAM Key을 서버에 평문으로 저장되기 때문에 기업에서는 Key을 사용하는 것을 지양하고 있습니다.
그러한 이유로 IAM Key을 사용하지 않고 AWS SES을 사용하는 방법에 대해서 기술하고자 합니다.
!! 이 부분은 단순하게 AWS SES을 사용하는 것에 국한되지 않고 다양하게 활용이 가능합니다.
사전에 AWS SES 사용에 대한 준비를 모두 마친 것을 전제로 내용을 기입했습니다.
EC2 Instance 에 Assume role 롤 정책 등록
EC2에 AWS SES의 권한을 사용할 수 있는 IAM Role을 적용합니다.
- 다른 Account에 존재하는 AWS SES을 사용하는 경우에는 Assume role을 활용합니다.
- 저는 Assume role 사용을 기준으로 내용 기입
(이 부분에 대해서는 google 검색을 통해 자세한 내용 확인이 가능합니다.)
- 저는 Assume role 사용을 기준으로 내용 기입
- 터미널로 서버에 접속해 aws cli 명령어로 iam role 등록 상태를 확인합니다.
- aws configure list
Application 구현
gradle 디펜던시 등록
// Amazon Simple Email Service와 통신하는 데 사용되는 클라이언트 클래스를 보유
implementation 'com.amazonaws:aws-java-sdk-ses:1.12.31'
// AWS Security Token Service와 통신하는 데 사용되는 클라이언트 클래스를 보유
implementation 'com.amazonaws:aws-java-sdk-sts:1.12.31'
application.yml 에 Assume role 정보 기입
aws:
mail:
aws-region: <region name>
aws-role-arn: arn:aws:iam::<Account ID>:role/<role name>
AWSCredentials
role 과 리전 정보로 AssumeRoleResult 의 크리덴셜 정보 가져온다.
package com.subscription.batch.aws;
import com.amazonaws.AmazonClientException;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicSessionCredentials;
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.securitytoken.AWSSecurityTokenService;
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder;
import com.amazonaws.services.securitytoken.model.AssumeRoleRequest;
import com.amazonaws.services.securitytoken.model.AssumeRoleResult;
import com.amazonaws.services.securitytoken.model.Credentials;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@NoArgsConstructor
public class AWSCredentials {
public AWSStaticCredentialsProvider credentials(String roleArn, Regions regions) throws IllegalArgumentException, AmazonClientException {
log.info("AWS Credentials : Role_ARN : {} regions : {} profile : {}", roleArn, regions);
return this.setCredentials(roleArn, regions);
}
protected AWSStaticCredentialsProvider setCredentials(String roleArn, Regions regions) throws IllegalArgumentException, AmazonClientException {
AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder.standard()
.withCredentials(DefaultAWSCredentialsProviderChain.getInstance())
.withRegion(regions)
.build();
AssumeRoleRequest roleRequest = new AssumeRoleRequest()
.withRoleArn(roleArn)
.withRoleSessionName("<role name>")
.withDurationSeconds(900);
AssumeRoleResult assumeRoleResult = stsClient.assumeRole(roleRequest);
Credentials sessionCreds = assumeRoleResult.getCredentials();
BasicSessionCredentials credentials = new BasicSessionCredentials(
sessionCreds.getAccessKeyId(),
sessionCreds.getSecretAccessKey(),
sessionCreds.getSessionToken());
return new AWSStaticCredentialsProvider(credentials);
}
}
EmailSender
package com.subscription.batch.model.email;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.simpleemail.AmazonSimpleEmailService;
import com.amazonaws.services.simpleemail.AmazonSimpleEmailServiceClientBuilder;
import com.amazonaws.services.simpleemail.model.*;
import com.subscription.batch.aws.AWSCredentials;
import lombok.extern.slf4j.Slf4j;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
@Slf4j
public class EmailSender extends AWSCredentials {
private EmailProperties properties;
public EmailSender(EmailProperties properties) {
this.properties = properties;
}
public boolean sender(EmailData email) {
return awsSender(email);
}
public boolean awsSender(EmailData email) {
String awsRegion = this.properties.getAwsRegion();
AWSStaticCredentialsProvider awsStaticCredentialsProvider = this.credentials(
this.properties.getAwsRoleArn(),
Regions.fromName(awsRegion)
);
// 목적지 설정
Destination destination = new Destination();
Optional.ofNullable(email.getTo()).filter(to -> !to.isEmpty()).ifPresent(destination::setToAddresses);
Optional.ofNullable(email.getCc()).filter(cc -> !cc.isEmpty()).ifPresent(destination::setCcAddresses);
// 제목
String charset = StandardCharsets.UTF_8.name();
Content subject = new Content(email.getSubject()).withCharset(charset);
// 내용
Body body = new Body();
Optional.ofNullable(email.getBodyHtml()).ifPresent(html -> body.setHtml(new Content(html).withCharset(charset)));
Optional.ofNullable(email.getBodyText()).ifPresent(text -> body.setText(new Content(text).withCharset(charset)));
// 보낼 메세지. 위에서 만든 제목과 내용으로 만든다.
Message message = new Message(subject, body);
SendEmailRequest request = new SendEmailRequest().withSource(email.getFrom()).withDestination(destination).withMessage(message);
AmazonSimpleEmailService client;
if (awsStaticCredentialsProvider != null) {
client = AmazonSimpleEmailServiceClientBuilder.standard().withCredentials(awsStaticCredentialsProvider).withRegion(Regions.fromName(awsRegion)).build();
} else {
client = AmazonSimpleEmailServiceClientBuilder.standard().withRegion(Regions.fromName(awsRegion)).build();
}
boolean isSend = false;
try {
SendEmailResult emailResult = client.sendEmail(request);
isSend = emailResult.getMessageId().length() > 0;
log.debug("AWS API SES Send : {}", emailResult.getMessageId());
return isSend;
} catch (AmazonServiceException e) {
log.error(String.format("Send Mail[%s] Error = %s", destination.getToAddresses(), e.getMessage()), e);
return isSend;
}
}
}
반응형
'IT기술 > AWS' 카테고리의 다른 글
[AWS][CodeDeploy] CodeDeploy 배포시 파일 중복으로 인한 실패 해결 방법 (0) | 2022.05.31 |
---|---|
[AWS][CloudWatch][Log] CloudWatch log Agent로 log 모니터링 (0) | 2022.05.24 |
[AWS][CloudWatch][Log] CloudWatch Agent로 log 모니터링 (0) | 2022.05.24 |
[AWS][IaC][Cloudformation] 01. 중앙 집중식 로깅 인프라 구현하기_Templete 수정_기존 VPC 사용 (0) | 2022.05.23 |
[AWS] S3 마운트를 위한 goofys 설치 (0) | 2022.05.16 |