본문 바로가기

일상

AWS SES 535 Authentication Credentials Invalid 로 메일 발송이 막힐 때 (IAM 액세스 키와 SMTP 자격증명 차이)

반응형

키를 분명히 새로 받았는데 인증만 계속 실패할 때, 어디를 봐야 하는지 알아보는 글입니다.


메일 발송 계정 정보를 갱신하고 나서 발송이 전부 막혔습니다. 로그에는 535 하나만 반복해서 찍혔습니다.

정확히는 javax.mail.AuthenticationFailedException: 535 Authentication Credentials Invalid 였습니다.

키는 방금 발급받은 것이고 오타도 없었습니다. 그런데도 서버는 계속 자격증명이 틀렸다고 답했습니다.

원인은 단순했는데, 콘솔에서 받은 값을 그대로 쓰면 안 되는 자리가 하나 있었습니다.


- 535자격증명이 틀렸다는 뜻이지 권한이나 네트워크 문제가 아니다

- SMTP 비밀번호는 IAM 시크릿 키가 아니다. 별도 변환이 필요하다

- 사용자명은 AKIA...로 시작해서 IAM 키와 똑같이 생겼다

- 변환 결과는 리전마다 다르다

- 갱신할 때 비밀번호만 갈아끼우면 또 막힌다


1. 증상은 한 줄뿐입니다

발송을 시도하면 인증 단계에서 바로 끊깁니다. 스택을 아무리 봐도 더 나올 게 없습니다.

535 Authentication Credentials Invalid 는 SMTP 표준에서 인증 실패를 뜻합니다. 서버까지는 잘 갔고, 연결도 됐고, TLS도 붙었는데 아이디와 비밀번호만 거절당한 상태입니다.

그래서 방화벽이나 포트를 뒤지는 건 대부분 헛수고입니다. 거기까지 갔으니 응답을 받은 것이니까요.



2. 원인은 비밀번호 자리에 있습니다

콘솔에서 액세스 키를 만들면 두 값이 나옵니다. 액세스 키 ID시크릿 액세스 키입니다.

여기서 착각이 생깁니다. 사용자명 자리에 액세스 키 ID를 넣는 건 맞는데, 비밀번호 자리에 시크릿 키를 그대로 넣으면 안 됩니다.

SMTP 비밀번호는 시크릿 키를 정해진 방식으로 변환한 별도의 문자열입니다. 원본을 넣으면 형식은 그럴듯한데 서버는 모르는 값이라 거절합니다.


- 사용자명 = 액세스 키 ID (AKIA로 시작, 그대로 사용)

- 비밀번호 = 시크릿 키를 변환한 값 (원본 아님)


사용자명이 그대로 들어가니까 절반은 맞습니다. 그래서 더 헷갈립니다. 키를 잘못 받았나 싶어 다시 발급받아도 같은 자리에서 막힙니다.


3. 변환은 직접 할 수 있습니다

가장 편한 방법은 콘솔에서 SMTP 전용 자격증명 생성 메뉴를 쓰는 것입니다. 그러면 변환이 끝난 비밀번호를 바로 내려줍니다.

이미 시크릿 키만 가지고 있다면 직접 만들어도 됩니다. 서명 키를 단계별로 파생시킨 뒤 버전 바이트를 붙여 인코딩하는 방식입니다.



여기서 리전이 인자로 들어가는 게 핵심입니다. 같은 시크릿 키라도 리전이 다르면 결과 문자열이 달라집니다.


4. 리전이 어긋나면 똑같이 535입니다

접속하는 주소와 자격증명을 만든 리전은 같아야 합니다.

서울 리전 주소로 접속하면서 버지니아 리전 기준으로 만든 비밀번호를 쓰면, 값 자체는 정상인데 서버가 못 알아봅니다. 증상은 똑같이 535라서 구분이 안 됩니다.


- 접속 주소의 리전과 자격증명 리전을 눈으로 맞춰 볼 것

- 주소를 바꿨으면 비밀번호도 다시 만들어야 한다


5. 갱신할 때 비밀번호만 바꾸면 또 막힙니다

주기적으로 키를 교체하는 곳이라면 이 함정이 한 번은 옵니다.

새 키를 받으면 사용자명도 같이 바뀝니다. 그런데 설정 파일에서 비밀번호 줄만 눈에 띄다 보니, 사용자명은 예전 값 그대로 두고 비밀번호만 갈아끼우는 일이 생깁니다.

그러면 예전 사용자명과 새 비밀번호가 짝이 안 맞아서 또 535입니다.



갱신 후에는 두 값을 나란히 놓고 확인하는 게 확실합니다. 특히 여러 서비스가 같은 설정을 공유하고 있으면 한 곳만 남아 있어도 그쪽에서만 실패합니다.


6. 허용 IP가 걸려 있으면 값이 맞아도 거절됩니다

여기까지 다 맞췄는데도 막힌다면, 자격증명에 접속 IP 조건이 붙어 있는지 봐야 합니다.

콘솔에 허용 IP 목록 같은 화면이 따로 있는 건 아닙니다. 자격증명에 연결된 권한 정책에 조건으로 들어갑니다.



이 목록에 없는 곳에서 접속하면 자격증명이 아무리 정확해도 인증 단계에서 거절됩니다. 그리고 돌아오는 응답은 똑같이 535라서, 값이 틀린 건지 위치가 틀린 건지 구분이 안 됩니다.


- 서버를 옮겼다면 새 서버가 나가는 IP를 목록에 넣어야 한다

- 회선이나 NAT가 바뀌었다면 예전 IP가 그대로 남아 있을 수 있다

- 목록을 고치고 나면 바로 반영되므로 재발급은 필요 없다


그래서 값이 확실한데 계속 막힌다면, 키를 다시 만들기 전에 나가는 IP부터 확인하는 게 빠릅니다.


함정이 하나 더 있습니다. 사설망 안에서 전용 통로를 거쳐 나가는 구성이라면, 출발지 IP라는 정보 자체가 잡히지 않습니다.

그 경우 IP 조건은 아무도 만족시킬 수 없어서 모두가 막힙니다. 이때는 IP 대신 통로 자체를 조건으로 거는 방식으로 바꿔야 합니다.


7. 그래도 안 되면 볼 곳

여기까지 맞췄는데도 막힌다면 남은 후보는 좁습니다.


- 권한 - 발송 권한이 정책에 들어 있는지

- 포트와 암호화 - 587은 STARTTLS, 465는 처음부터 TLS. 섞이면 인증 전에 끊긴다

- 디버그 로그 - 메일 라이브러리의 디버그 옵션을 켜면 어느 단계에서 끊겼는지 한 줄로 나온다


디버그를 켜면 인증 실패인지 연결 실패인지가 바로 갈립니다. 추측하기 전에 켜는 게 빠릅니다.


8. 정리

535를 보면 키를 다시 발급받고 싶어지는데, 대부분은 키가 아니라 넣는 자리의 문제입니다.

정리하면 이렇습니다.


- 535 = 자격증명 불일치. 네트워크나 권한이 아니다

- 비밀번호는 시크릿 키가 아니라 변환한 값

- 사용자명은 액세스 키 ID 그대로

- 변환 결과는 리전에 묶여 있다

- 갱신할 때는 사용자명과 비밀번호를 한 쌍으로 교체

- 허용 IP 조건이 붙어 있으면 값이 맞아도 거절된다


한 번 알고 나면 다시는 안 걸리는데, 모르는 상태에서는 키만 계속 다시 발급받게 되는 함정입니다. 비밀번호 자리를 먼저 의심해 보시면 시간을 많이 아낍니다.

여기까지 AWS SES의 535 인증 실패에 대해서 작성해봤습니다. 여기까지 읽어주셔서 감사합니다!

반응형