AWS SES - 535 Authentication Credentials Invalid

Bobby·2023년 8월 23일
0

오답노트

목록 보기
6/6

✉️ 문제 발생

  • aws 계정을 다른 계정으로 이전 하게 되면서 기존에 사용하던 서비스들 새로운 계정으로 옮기는 작업을 진행 중이었다.
  • 그 중 이메일 전송에 java mail api + AWS SES를 사용하고 있었다.
  • 새로 IAM 계정을 만들고, 무려 AmazonSESFullAccess 권한을 주었다..
  • 메일 전송 테스트를 하던 중 인증에러가 발생했다.
  • AmazonSESFullAccess 가지고 있는 계정이 대체 왜와이??

✉️ 이메일 전송 예제

  • jakarta mail api 사용
	implementation 'com.sun.mail:jakarta.mail:2.0.1'
    implementation 'com.sun.activation:jakarta.activation:2.0.1'
public class EmailSender {

    private final String host = "email-smtp.ap-northeast-2.amazonaws.com";
    private final String user = "{acceess-key}";
    private final String password = "{secret-key}";

    public void send() {

        Session session = createProps();
        String text = "Hello world!";
        String subject = "Hello world!";

        try {
            MimeMessage msg = new MimeMessage(session);
            msg.setFrom(new InternetAddress("haerong22@gmail.com"));
            msg.setRecipient(Message.RecipientType.TO, new InternetAddress("haerong22@gmail.com"));
            msg.setSubject(subject, "utf-8");
            msg.setContent(text, "text/html; charset=utf-8");

            Transport transport = session.getTransport();
            transport.connect(host, user, password);
            transport.sendMessage(msg, msg.getAllRecipients());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Session createProps() {
        Properties props = System.getProperties();
        props.put("mail.transport.protocol", "smtp");
        props.put("mail.smtp.port", 587);
        props.put("mail.smtp.starttls.enable", "true");
        props.put("mail.smtp.auth", "true");
        return Session.getDefaultInstance(props);
    }
}

문제 해결

  • aws ses 사용할 때 다음 버튼을 눌러서 IAM계정을 생성해서 사용하면 문제가 없다.
  • AWS SDK를 사용하지 않고 자바 api를 사용하여 SMTP서버로 전송 할 때는 SendRawEmail 권한이 필요한데 해당 권한은 AmazonSESFullAccess가 가지고 있다.
  • 이번에 문제가 발생한 이유는 AmazonSESFullAccess를 추가 한 IAM계정을 만들고 생성한 access key를 사용했기 때문이다.
  • 여기 설명을 보면 IAM계정 엑세스 키랑 SMTP 계정 인증은 다르다고 한다.
  • 따라서 기존 계정에 SMTP보안 인증을 하려면 SMTP 접근용 보안키를 생성해야 한다.
    자세한 설명은 https://docs.aws.amazon.com/ko_kr/ses/latest/dg/smtp-credentials.html

SMTP 보안키 생성

smtp_credentials_generate.py

#!/usr/bin/env python3

import hmac
import hashlib
import base64
import argparse

SMTP_REGIONS = [
    'us-east-2',       # US East (Ohio)
    'us-east-1',       # US East (N. Virginia)
    'us-west-2',       # US West (Oregon)
    'ap-south-1',      # Asia Pacific (Mumbai)
    'ap-northeast-2',  # Asia Pacific (Seoul)
    'ap-southeast-1',  # Asia Pacific (Singapore)
    'ap-southeast-2',  # Asia Pacific (Sydney)
    'ap-northeast-1',  # Asia Pacific (Tokyo)
    'ca-central-1',    # Canada (Central)
    'eu-central-1',    # Europe (Frankfurt)
    'eu-west-1',       # Europe (Ireland)
    'eu-west-2',       # Europe (London)
    'sa-east-1',       # South America (Sao Paulo)
    'us-gov-west-1',   # AWS GovCloud (US)
]

# These values are required to calculate the signature. Do not change them.
DATE = "11111111"
SERVICE = "ses"
MESSAGE = "SendRawEmail"
TERMINAL = "aws4_request"
VERSION = 0x04


def sign(key, msg):
    return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()


def calculate_key(secret_access_key, region):
    if region not in SMTP_REGIONS:
        raise ValueError(f"The {region} Region doesn't have an SMTP endpoint.")

    signature = sign(("AWS4" + secret_access_key).encode('utf-8'), DATE)
    signature = sign(signature, region)
    signature = sign(signature, SERVICE)
    signature = sign(signature, TERMINAL)
    signature = sign(signature, MESSAGE)
    signature_and_version = bytes([VERSION]) + signature
    smtp_password = base64.b64encode(signature_and_version)
    return smtp_password.decode('utf-8')


def main():
    parser = argparse.ArgumentParser(
        description='Convert a Secret Access Key to an SMTP password.')
    parser.add_argument(
        'secret', help='The Secret Access Key to convert.')
    parser.add_argument(
        'region',
        help='The AWS Region where the SMTP password will be used.',
        choices=SMTP_REGIONS)
    args = parser.parse_args()
    print(calculate_key(args.secret, args.region))


if __name__ == '__main__':
    main()

실행

  • 기존 IAM 계정의 보안키를 이용해 STMP 보안키를 생성한다.
python path/to/smtp_credentials_generate.py {IAM계정 secret key} {region}

  • 생성한 보안키를 이용해 전송하면 이메일이 잘 전송된다.
profile
물흐르듯 개발하다 대박나기

0개의 댓글