AWS S3 에 presigned url 로 파일 업로드할때 실패 해결
프로젝트에서 AWS S3 에 파일을 업로드를 하는데, 서버에서 파일을 직접 올리는 경우가 아니라 클라에서 파일을 올려야 하는 경우가 있다. 보통 인증키를 노출하지 않기 위해서 인데, 이럴때 서버에서 업로드 하려고 하는 파일에 대해서 접근 유효 시간이나 전송 메소드(PUT/POST), 해쉬값 같은거를 포함해서 미리 사인(presign)을 받은 url 을 얻을 수 있다. (AWS API 요청에 서명) 그럼 이 presigned url 을 유효 시간내에 아무나 올릴 수 있게 되고 클라에서 이 url 을 가지고 파일을 업로드 한다.
클라에서 파일을 업로드하는 시나리오는 이렇게 진행하면 되는데, 다음과 같은 url 에서 https 가 시작할때 실패하는 경우가 있다. 강제로 http 로 바꿔서 진행하면 문제없이 파일이 업로드 된다.
https://ABC.co.kr.s3.ap-northeast-2.amazonaws.com/temp/17613021643ccbd61b-272f-408e-a103-7439b1a55ecb.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20181026T031926Z&X-Amz-SignedHeaders=host&X-Amz-Expires=299&X-Amz-Credential=AKIAJ4WSTLHLPJBYOPEQ%2F20181026%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=a0ea001db03018bccfda4cf06e5a12ff443345b678655f533908a9a0ba80feb9
처음에는 이 url 을 받아서 웹 브라우저에서 접속해보면 "SignatureDoesNotMatch" 라는 메시지가 나와서 한참 구글링을 해보았는데, 나와있는 해결책으로는 도저히 적용이 안되었다.
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>
The request signature we calculated does not match the signature you provided. Check your key and signing method.
</Message>
<AWSAccessKeyId>AKIAJ5I6VLCKOZBJICGA</AWSAccessKeyId>
<StringToSign>
AWS4-HMAC-SHA256 20181025T072952Z 20181025/ap-northeast-2/s3/aws4_request 8b6076bcbe9aef4c41c45bcf4e95c5910c7c8e3deb82adb884f26f2282c65001
</StringToSign>
<SignatureProvided>
39f7eab219134e0f2fbae95dce110fdeedda2d529a1841431c4941f3911f5b08
</SignatureProvided>
<StringToSignBytes>
41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 0a 32 30 31 38 31 30 32 35 54 30 37 32 39 35 32 5a 0a 32 30 31 38 31 30 32 35 2f 61 70 2d 6e 6f 72 74 68 65 61 73 74 2d 32 2f 73 33 2f 61 77 73 34 5f 72 65 71 75 65 73 74 0a 38 62 36 30 37 36 62 63 62 65 39 61 65 66 34 63 34 31 63 34 35 62 63 66 34 65 39 35 63 35 39 31 30 63 37 63 38 65 33 64 65 62 38 32 61 64 62 38 38 34 66 32 36 66 32 32 38 32 63 36 35 30 30 31
</StringToSignBytes>
<CanonicalRequest>
GET /temp/17613021642ae358df-7ef0-4178-bb19-4f9485f4188f.png X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAJ5I6VLCKOZBJICGA%2F20181025%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Date=20181025T072952Z&X-Amz-Expires=299&X-Amz-SignedHeaders=host host:ABC.co.kr.s3.ap-northeast-2.amazonaws.com host UNSIGNED-PAYLOAD
</CanonicalRequest>
<CanonicalRequestBytes>
47 45 54 0a 2f 74 65 6d 70 2f 31 37 36 31 33 30 32 31 36 34 32 61 65 33 35 38 64 66 2d 37 65 66 30 2d 34 31 37 38 2d 62 62 31 39 2d 34 66 39 34 38 35 66 34 31 38 38 66 2e 70 6e 67 0a 58 2d 41 6d 7a 2d 41 6c 67 6f 72 69 74 68 6d 3d 41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 26 58 2d 41 6d 7a 2d 43 72 65 64 65 6e 74 69 61 6c 3d 41 4b 49 41 4a 35 49 36 56 4c 43 4b 4f 5a 42 4a 49 43 47 41 25 32 46 32 30 31 38 31 30 32 35 25 32 46 61 70 2d 6e 6f 72 74 68 65 61 73 74 2d 32 25 32 46 73 33 25 32 46 61 77 73 34 5f 72 65 71 75 65 73 74 26 58 2d 41 6d 7a 2d 44 61 74 65 3d 32 30 31 38 31 30 32 35 54 30 37 32 39 35 32 5a 26 58 2d 41 6d 7a 2d 45 78 70 69 72 65 73 3d 32 39 39 26 58 2d 41 6d 7a 2d 53 69 67 6e 65 64 48 65 d 32 2e 61 6d 61 7a 6f 6e 61 77 73 2e 63 6f 6d 0a 0a 68 6f 73 74 0a 55 4e 53 49 47 4e 45 44 2d 50 41 59 4c 4f 41 44
<RequestId>D5F87C2A75B8F0C6</RequestId>
<HostId>
eN+JbS3c3+pi4JtfYXsjq/pD0YZKTRU/Of5tRFUcMEOgYpVC1kjA5rw5L+07QZcBJUO/6uc/5Wg=
</HostId>61 64 65 72 73 3d 68 6f 73 74 0a 68 6f 73 74 3a 64 65 76 2d 69 6d 61 67 65 2e 72 65 64 73 74 61 72 67 61 6d 65 73 2e 63 6f 2e 6b 72 2e 73 33 2e 61 70 2d 6e 6f 72 74 68 65 61 73 74 2
</Error>
S3 를 잘 모르는 상태에서 시작해서인지 "S3 https" 로 검색했을때 cloudfront 와 S3 연동하는 블로그 들이 나와서 cloudfront 를 반드시 사용해야하는건가 착각하게 만들지만, S3 자체적으로 https 를 지원하고 있다. 혹시나해서 s3 에서 html 샘플을 올려서 정적 웹 호스팅이 잘되는지 확인해봤는데, https 로도 웹페이지가 잘 나오고 있었다. (참고로 cloudfront 와 S3 연동은 자체 도메인 주소를 가지고 있고 S3 를 호스팅 서버로 할때 이용하자.)
어떤 해결방안은 IAM 의 시크릿키값에 특수문자(/) 가 많이 포함되어 있는 경우 오류가 날 수 있다고 해서 액서스 키를 여러개 생성해보았지만 그건 아닌거 같다. 할때마다 '/' 는 항상 포함되는거보면 그건 아닌거 같다.
다른 방법을 찾다가 하루를 보냈는데, 잘 동작하고 있는 서비스에 S3 버킷이름이 도메인 형태(A.B.COM) 이 아닌것을 보고 버킷 이름을 "test-image" 로 변경해서 적용을 해보았는데, 업로드에 성공했다.
아마 추측하기로는 ABC.co.kr.s3.ap-northeast-2.amazonaws.com 도메인 주소를 클라의 http 메소드 처리하는 (Unity 용)라이브러리가 (이름이 긴 도메인 주소를) 파싱하다가 오류가 난게 아닌가 추측해본다.
그리고 "SignatureDoesNotMatch" 에 대한 문제는 해결이 안되었다. 버컷이름을 바꾸고나서 생성된 url 을 브라우저에서 확인해보면 동일한 오류 메시지가 나오는데, 정확한 이유는 찾기가 어렵다. AWS 는 먼가 할때마다 고생이 많다.
참조한 사이트
https://aws.amazon.com/ko/blogs/korea/aws-api-call-2-s3-pre-signed-url/
https://docs.aws.amazon.com/ko_kr/general/latest/gr/signature-v4-troubleshooting.html
https://lynlab.co.kr/blog/52/