Skip to main content

S3 Presigned URL 잘 사용하기

클라우드의 출현과 함께 Amazon AWS S3(Simple Storage Service)는 대부분의 회사에서 개체, 파일 또는 보다 일반적으로 데이터를 지속적이고 쉽게 액세스할 수 있는 방식으로 저장하는 데 널리 사용되었습니다.

AWS S3 버킷은 S3 버킷을 직접 쿼리할 수 있는 모바일 애플리케이션부터 백엔드 뒤에서 프록시가 될 수 있는 웹 애플리케이션, 단기 및 장기 저장을 위해 처리된 문서, 로그 또는 기타 데이터를 저장합니다.

인프라에서 S3를 사용하는 경우 S3 버킷에서 사용자에게 파일을 반환하거나 사용자가 파일을 S3 버킷에 안전하게 업로드해야 하는 상황에 처하게 될 것입니다. 이 통합을 더 쉽고 안전하게 만들기 위해 S3는 미리 서명된 URL을 제공합니다.

S3 버킷에서 일부 파일을 호스팅하고 이를 사용자에게 노출해야 하지만 버킷을 오픈된 상태로 설정하고 싶지 않고 이러한 파일에 대한 액세스를 일부 제어하고 싶다고 가정해보겠습니다. 예를 들어 사용자가 파일에 액세스할 수 있는 시간을 제한합니다.

미리 서명된 URL을 통해서 사용자가 문서를 업로드하거나 원하는 파일을 S3 버킷에 저장하도록 하라 수 있습니다. 이처럼 AWS S3는 서명된 링크를 생성하여 S3 객체를 쉽게 공유할 수 있는 방법을 제공합니다.

기본적으로 모든 객체는 비공개이며 개체 소유자만 이러한 개체에 액세스할 수 있는 권한이 있습니다. 그러나 개체 소유자는 자신의 보안 자격 증명을 사용하여 미리 서명된 URL을 생성하여 개체를 다운로드할 수 있는 시간 제한 권한을 부여함으로써 선택적으로 다른 사람과 개체를 공유할 수 있습니다.

https://yourbucket.s3.eu-west-1.amazonaws.com/pdf/yourfile.pdf ?
X-Amz-Algorithm = AWS4-HMAC-SHA256 &
X-Amz-Credential = some-aws-credential-to-identify-the-signer &
X-Amz-Date = timestamp-of-generation &
X-Amz-Expires = validity-from-generation-timestamp &
X-Amz-Signature = 4709da5a980e6abc4ab7284c1b6aa9e624f388e08f6a7609e28e5041a43e5dad &
X-Amz-SignedHeaders = host

이러한 매개 변수의 대부분은 AWS SDK 기능을 사용하여 구성 또는 생성됩니다. 기억해야 할 중요한 점은 S3가 선택적 SignedHeaders 매개변수를 계산에 포함하고 서명이 유효한지, 링크가 아직 만료되지 않았는지 확인하는 것을 포함하여 지정된 자격 증명에 대해 동일한 서명을 계산하려고 시도한다는 것입니다.

기억해야 할 또 다른 주용한 점은 개체에 대해 미리 서명된 URL을 생성할 때 SDK에 유효한 자격증명을 제공하여 유효한 서명을 생성해야 한다는 것입니다. 이는 미리 서명된 URL이 생성에 사용한 자격 증명을 대신하여 리소스에 액세스하여 인증절차를 거칩니다.

이상적인 설정은 일반적으로 특정 리소스에 대해 미리 서명된 URL을 생성하고 이를 클라이언트로 반환하기 위해 전용(및 제한된) 자격 증명이 있는 전용 백엔드 서비스를 보유하는 것입니다.

1. 미리 서명된 URL을 재사용할 수 있습니다.

이러한 URL은 일회성 URL이 아니며 미리 서명된 URL을 일시적으로 제한할 수 있는 유일한 것은 X-AMZ-Expires 매개변수입니다. 미리 서명된 URL이 생성되면 만료되기 전에 무제한으로 유효합니다. 즉, 하루 동안 버킷의 객체에 대한 읽기 액세스 권한을 부여하면 링크가 있는 모든 사용자가 하루 종일 해당 객체에 여러 번 액세스할 수 있습니다. 즉, 미리 서명된 URL을 통해 버킷에 1일 동안 쓰기 액세스 권한을 부여하면 URL이 있는 사람은 누구나 원하는 시간에 원하는 파일을 업로드할 수 있습니다.

2. 누구나 유효한 미리 서명된 URL을 사용할 수 있습니다.

이것을 명확히 하기 위해 미리 서명된 URL을 생성하면 누구나 사용할 수 있으며, 이 링크를 생성하는 사용자는 이를 사용하여 다른 사용자를 피싱하고 임의의 파일을 업로드하도록 할 수 있습니다. 서비스에서 파일을 업로드하기 위해 10분 동안 유효한 미리 서명된 URL을 생성하는 경우 다른 방식으로 요청을 확인하지 않는 한 해당 URL은 누구나 사용할 수 있습니다. 솔루션은 허용된 클라이언트만 요청을 수행할 수 있는 방식으로 미리 서명된 URL을 구축하되 추가로 서명된 헤더를 추가하여 취약점을 완화할 수 있습니다.

3. 미리 서명된 URL은 인증을 제공하지 않습니다.

서비스가 미리 서명된 URL을 사용자에게 반환하면 사용자는 이를 사용하여 S3 버킷에서 객체를 직접 읽고 S3 버킷으로 업로드합니다. 이는 서비스가 업로드되기 전에 해당 파일을 직접 처리하지 않음을 의미합니다. 이것은 또한 S3 버킷 앞에 인증 프록시가 없는 한 인증 계층이 일반적으로 배치되지 않음을 의미합니다. 즉, 미리 서명된 URL은 버킷의 특정 객체에 액세스할 수 있는 권한만 제공하며 인증은 미리 서명된 링크를 생성하는 IAM 역할에 암시적으로 연결됩니다.

파일 업로드의 경우 업로드할 개체의 파일 이름으로 UUID를 생성하고 이 UUID를 사용자 식별자와 함께 데이터베이스에 저장하는 것입니다. 또는 사용자 식별자를 파일 이름의 임의 UUID에 직접 추가할 수도 있습니다.

4. 미리 서명된 URL을 생성하는 서비스에 버킷에 대한 전체 액세스 권한을 부여하지 마세요.

백엔드 서비스의 작업이 파일을 버킷에 업로드만 하는 것이라면 버킷의 모든 객체를 읽거나 삭제할 수 있는 IAM 역할을 구성할 필요가 없을 것입니다. 따라서 최소 권한의 원칙을 고수하고 IAM 역할을 구성할 때 필요한 권한만 부여하세요.

필요한 권한보다 더 많은 작업을 수행할 수 있도록 백엔드 서비스가 처리 자격 증명을 갖는 것은 인프라 보안과 사용자에게 큰 위협이 되므로 필요 이상의 권한을 부여하지 마세요.

또한 자격 증명이나 키를 하드코딩해서도 안 됩니다. 시크릿을 안전하게 저장하고 필요할 때 검색할 수 있는 몇 가지 대안이 있으며 AWS 자체에는 AWS Secrets Manager라는 특정 서비스를 사용하여 위 문제를 해결할 수 있습니다.

5. 노출된 S3 버킷의 서버 액세스 로깅 활성화

미리 서명된 URL을 사용하지 않는 경우에도 적용되는 일반적인 권장 사항이며 모든 S3 버킷에 대해 권장됩니다. 서버 액세스 로깅은 버킷에 대한 요청을 레코드로 제공합니다. 서버 액세스 로그는 많은 애플리케이션 및 보안 및 액세스 감사에 유용합니다.

기본적으로 Amazon S3는 서버 액세스 로그를 수집하지 않습니다.

6. 서명된 헤더를 사용하여 파일의 해시를 추가하고 제어되지 않은 파일 업로드를 방지할 수 있습니다.

이전에 말했듯이 미리 서명된 URL이 생성되면 누가 파일을 업로드할 수 있는지 제어할 수 없지만 파일의 md5 해시를 확인하는 미리 서명된 URL을 생성하여 이를 완화할 수 있습니다. X-Amz-SignedHeaders를 사용합니다.

미리 서명된 URL을 생성하는 동안 Content-MD5 헤더를 지정하면 이 헤더에 지정된 값과 파일을 업로드하는 동안 사용자가 받은 값과 동일한 경우에만 서비스에서 미리 서명된 URL이 유효하도록 강제할 수 있습니다. 이렇게 하면 일반 파일이 아닌 특정 파일에 대해 미리 서명된 URL을 생성할 수 있습니다.

그렇다면 S3 Presigned URL은 어떻게 생성할까 ?

presigned url을 사용하는 방법에는 SDK를 사용하거나 S3 작업 콘솔에서 생성하거나 또는 CLI를 사용하여 생성하는 방법등이 있는데 가장 간단한 방법으로 CLI를 사용하여 생성해 보도록 하겠습니다.

caution

AWS CLI을 사용하면 미리 서명된 URL의 최대 만료 시간은 생성 시점으로부터 7일입니다.

aws s3 ls
...
2022-07-22 12:09:23 cloud-trail-log-ap-northeast-2
2023-01-14 11:07:57 ghdwlsgur.github.io
2023-01-08 11:09:30 ghdwlsgur.github.io.log-bucket

aws s3 presign s3://[DOC-EXAMPLE-BUCKET]/test.txt

# 일주일 동안 유효한 키를 생성
aws s3 presign s3://ghdwlsgur.github.io/test.txt \
--expires-in 604800