본문 바로가기
👨‍💻 프로그래밍/⚙️ DevOps

AWS S3, 안전하게 사용하기

by 개발자 진개미 2023. 6. 11.
반응형


S3란?

S3는 AWS에서 제공하는 파일을 업로드하고 접근할 수 있는 서비스입니다.

용도에 따라 Bucket이라는 단위로 구분할 수 있고, 각 Bucket에 업로드한 파일은 Object가 되고, 고유의 Key가 생기게 됩니다.


전체적인 그림

모든 보안이 그렇지만, S3를 안전하게 사용하는 방법도 큰 그림에서 보면 비슷합니다.

 

🐜 필요한 권한만 최소한으로

우선 필요한 권한만 최소한으로 줘야 합니다. Bucket을 용도에 따라 분리하고 그 용도에 맞는 사용자만 접근할 수 있도록 하는 게 좋습니다. 예를 들어 어떤 서비스의 프로필 사진을 저장해야 하는 용도의 Bucket은 불특정 다수가 접근해야 하기 때문에 Public으로 열어 놓아야 하지만 유저 개인의 파일을 보관하는 서비스는 그러면 안 됩니다. 

 

🐜 이해하기 쉽게

보안은 결국 사람이 관리해야 합니다. 최대한 자동화해서 수기 작업을 줄일 수는 있지만 완전히 없앨 수는 없습니다. 근데 Bucket 이름이나 각종 정책의 이름을 알기 힘들게 하면 어떨까요? 관리하기도 어렵고 실수할 여지도 늘어납니다. 이름을 알기 쉽게하고 정책을 간단하게 잡는게 생각보다 엄청 중요합니다.


가능하면 S3를 직접 열지 말고 CloudFront로 간접적으로

내가 어떤 서비스를 쓰고 있는지 공유하는 건 최대한 피하는 게 좋습니다. 허커들이 내가 S3를 쓰고 있는 걸 안다면 S3에 취약점이 발견됐을 때 이용하거나, 내가 이상하게 S3를 쓰고 있다면 그걸 이용할 수도 있습니다.

게다가 S3를 직접 공개한다면 https가 아닌 http를 써야 하고, 이상한 S3의 주소를 그대로 사용해야 합니다.


임의의 TTL이 있는 URL을 생성해서 Object 단위로 공유: Presigned-URL

만약 CloudFront를 열고 여러 설정을 하기 번거로워서 S3를 직접 제공하고 싶다면 Bucket 전체를 열지 않고 필요한 Object 들에 대해 TTL이 있는 URL을 임시로 생성해서 제공할 수 있습니다. 이런 기능을 S3에서는 Presigned-URL이라고 합니다. 

보통 이런 경우 서버에서 S3로 요청을 해서 Presigned-URL을 받아오고, 이걸 Client로 보내는 방식입니다.

AWS SDK를 쓰면 아래와 같이 요청할 수 있습니다.

private val presigner: S3Presigner = S3Presigner.builder()
    .region(Region.AP_NORTHEAST_2)
    .credentialsProvider(DefaultCredentialsProvider.create())
    .build()

fun generatePresignedUrl(bucket: String, key: String, durationMinutes: Long = 5): URL {
    val getObjectRequest = GetObjectRequest.builder()
        .bucket(bucket)
        .key(key)
        .build()

    val presignRequest = GetObjectPresignRequest.builder()
        .signatureDuration(Duration.ofMinutes(durationMinutes))
        .getObjectRequest(getObjectRequest)
        .build()

    return presigner.presignGetObject(presignRequest).url()
}

참고


반응형