S3에 파일을 올리고 콘솔에서 ‘다운로드’를 눌렀다. 잘 내려온다. 그런데 옆에 적힌 객체 URL을 새 브라우저 창에 붙여 넣으면 AccessDenied가 뜬다. 방금 받은 파일인데, 링크로는 왜 못 받을까? 같은 객체라도 요청하는 사람이 달라졌기 때문이다.
S3 콘솔 다운로드와 객체 URL은 무엇이 다를까?
콘솔에서 다운로드할 때는 로그인한 AWS 사용자·역할의 권한으로 요청한다. 반면 일반 객체 URL을 다른 사람이나 로그인 정보가 없는 브라우저에서 열면, 그 요청에는 콘솔에서 사용한 권한이 따라가지 않는다. URL은 객체의 주소이지, 읽기 허가증이 아니다.
예를 들어 비공개 버킷의 reports/summary.pdf를 생각해 보자. 주소가 정확하더라도 익명 요청에 s3:GetObject 권한이 없다면 S3는 읽기를 거부한다. AWS의 S3 요청 권한 평가 설명도 요청자에게 유효한 권한이 없을 때 403 AccessDenied가 반환된다고 설명한다.
| 같은 객체를 읽는 요청 | 요청에 적용되는 권한 | 가능한 결과 |
|---|---|---|
| 권한 있는 AWS 콘솔의 다운로드 | 로그인한 사용자·역할의 허용 범위 | 다운로드 성공 |
| 일반 객체 URL을 익명 브라우저에서 열기 | 익명 읽기 허용이 없다면 권한 없음 | 403 AccessDenied |
유효한 GET presigned URL 열기 | URL을 서명한 주체의 허용 범위 | 유효 기간 동안 다운로드 가능 |
표는 비공개 객체이고 콘솔 사용자는 읽기 권한이 있다는 조건의 비교다. 실제 403은 공개 차단, 명시적 거부, 다른 정책이나 객체·경로 문제에서도 발생할 수 있으므로 오류 한 줄만 보고 원인을 단정하지는 말자.
비공개 파일을 공유하려면 버킷을 공개해야 할까?
그럴 필요는 없다. 정해진 사람에게 잠시 파일을 전달하려는 목적이라면, 읽을 수 있는 주체가 특정 객체에 대한 GET presigned URL을 만들어 전달할 수 있다. URL을 받은 사람은 별도 AWS 로그인 없이 해당 객체를 요청한다. 버킷 전체의 공개 정책을 바꾸지 않는 방법이다. AWS의 presigned URL 설명에서 생성 주체의 권한과 유효 기간을 확인할 수 있다.
다만 ‘서명된 URL’은 단순한 주소가 아니라 링크를 가진 사람이 만료 전까지 사용할 수 있는 전달용 권한이다. 필요한 객체와 짧은 만료 시간을 정하고, 채팅방·접근 로그·분석 도구에 URL 전체가 남지 않도록 다뤄야 한다. 임시 자격 증명으로 만들었다면 설정한 만료 시각보다 자격 증명이 먼저 끝나 URL도 일찍 무효가 될 수 있다.
공개 웹사이트의 정적 파일처럼 누구나 계속 읽어야 하는 객체라면 이야기가 달라진다. 공개 배포 경로를 별도로 설계해야 한다. 파일 하나가 열리지 않는다는 이유만으로 버킷의 퍼블릭 액세스 차단을 전부 끄고 모든 객체에 GetObject를 허용하는 것은 목적보다 훨씬 넓은 변경이다.
AccessDenied가 뜨면 무엇부터 확인할까?
- 같은 객체인가? 콘솔에서 내려받은 버킷·키와 URL의 대상이 같은지 확인한다. 객체 키에 들어간
/도 이름의 일부다. - 어떤 요청인가? 콘솔처럼 권한 있는 주체의 요청인지, 일반 URL을 연 익명 요청인지 구분한다. 콘솔 성공은 익명 읽기 성공의 증거가 아니다.
- 공유 목적은 무엇인가? 일시적인 비공개 전달이면
GETpresigned URL을 검토한다. 누구나 읽는 공개 자산이라면 별도 공개 배포 설계를 검토한다. - 서명된 URL도 실패하는가? 서명 주체의 객체 읽기 권한, 만료 시각과 원래 자격 증명의 유효성을 확인한다. URL의 서명·토큰 전체는 문의 글이나 로그에 붙이지 않는다.
실제 버킷을 공개하거나 AWS 계정에서 요청을 실행한 결과가 아니라, 요청 주체와 권한 조건을 비교한 예시다. 버킷의 정책·공개 차단·암호화 설정에 따라 추가 확인이 필요할 수 있다.
핵심 요약
S3 콘솔 다운로드가 된다는 사실은 일반 객체 URL도 공개된다는 뜻이 아니다. 콘솔의 권한 있는 요청과 브라우저의 익명 요청을 먼저 구분하자. 비공개 파일을 잠시 공유한다면 버킷 전체를 공개하기보다, 필요한 객체에만 유효한 GET presigned URL을 쓰는 편이 목적에 맞다.

