이번 주에는 마이 페이지에서 사용자의 프로필 사진을 업데이트하는 기능을 개발하게 되었습니다. 이미지를 저장하기 위해 여러 방법을 고려했는데, 그중 로컬 서버 대신 안정적이고 확장성이 높은 클라우드 스토리지인 AWS S3를 선택하게 되었습니다. AWS S3를 사용하는 방법에 대한 글은 많이 찾아볼 수 있지만, 이번 글에서는 S3를 사용하면서 마주쳤던 문제들과 그 해결 과정에 대해 회고해보려 합니다.
S3 접근 권한 설정
S3 버킷에 파일을 업로드하려면 먼저 해당 버킷에 접근할 수 있는 권한이 필요합니다. 이때 엑세스 키와 시크릿 키라는 두 개의 키가 사용됩니다. 키는 AWS에서 직접 발급할 수 있지만, 보안상 매우 중요한 문제입니다. 만약 키가 외부로 노출된다면, 누군가가 이를 악용해 우리가 모르는 사이 비트코인 채굴 등의 작업을 수행하거나, 막대한 서버 비용을 초래할 수 있습니다.
따라서 절대로 AWS Root 계정으로 발급된 키를 사용해서는 안 됩니다. 대신, S3에만 접근할 수 있는 최소한의 권한을 가진 사용자를 별도로 만들어 그 키를 사용하는 것이 안전합니다. 이를 위해 AWS의 Identity and Access Management(IAM)에서 사용자 그룹을 생성하고, 해당 그룹에 AmazonS3FullAccess 권한을 할당합니다. 이후, 그 그룹에 속한 사용자에게만 엑세스 키를 발급하면, S3 버킷에 대한 안전한 접근이 가능합니다.
IAM에서 권한을 부여하고 키를 발급하는 과정은 다음과 같습니다:
- AWS 관리 콘솔에서 IAM 대시보드로 이동합니다.
- 사용자 그룹을 생성하고, AmazonS3FullAccess 권한을 해당 그룹에 할당합니다.
- 해당 그룹에서 사용자를 생성하고, 그 사용자에게 엑세스 키를 발급합니다.
이제, 이 엑세스 키와 시크릿 키를 사용하여 S3에 접근할 수 있게 됩니다.
GitHub에서의 보안 관리
S3 접근 키를 발급받았다면, 이를 서버에서 안전하게 사용할 방법을 고민해야 합니다. 특히 GitHub에 소스 코드를 올릴 때는 더욱 주의가 필요합니다. 퍼블릭 레포지토리에 키가 노출되면 외부에서 악용될 가능성이 높습니다. 이를 방지하기 위해 GitHub의 Secrets 기능을 활용해 환경 변수를 설정할 수 있습니다. 이렇게 하면 키가 소스 코드에 포함되지 않고도 안전하게 사용할 수 있습니다.
로컬 환경에서는 application.yml 파일을 사용해 키를 관리하는 것이 일반적입니다. 그러나 application.yml 파일이 git ignore에 등록되지 않으면, 실수로 이 파일이 퍼블릭 레포지토리에 노출될 수 있습니다. 이를 방지하기 위해, application-local.yml, application-dev.yml, application-prod.yml처럼 환경별로 파일을 분리하고, application-prod.yml만 실제 서버에 배포하도록 설정하는 것이 좋습니다. 이 방법은 Spring Boot를 사용하는 개발자들에게 특히 유용합니다.
S3 파일 업로드 기능 구현
이제 S3 버킷에 접근하기 위한 설정을 마쳤으니, 본격적으로 파일을 업로드하는 기능을 구현해보겠습니다. 우선, 필요한 의존성을 추가해야 합니다.
Gradle 의존성 추가
S3 파일 업로드를 위해 AWS SDK를 의존성에 추가해야 합니다. Kotlin과 Spring Boot 환경에서 다음과 같이 의존성을 추가할 수 있습니다.
implementation("org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE")
application.yml 설정
application.yml 파일에 S3와 관련된 설정 정보를 입력합니다. 여기에서 stack.auto를 false로 설정하여 Spring Boot가 AWS 인프라를 자동으로 구성하지 않도록 해야 합니다. 또한, region.static 값을 ap-northeast-2로 설정하여 S3 버킷의 리전을 서울로 지정합니다.
cloud:
aws:
s3:
bucket: 본인의 버킷 명
stack.auto: false
region.static: ap-northeast-2
credentials:
accessKey: 본인의 엑세스 키
secretKey: 본인의 시크릿 키
S3Config 설정 클래스
S3에 접근하기 위한 클라이언트를 설정하는 S3Config 클래스를 작성합니다. 이 클래스는 S3 클라이언트를 Spring 애플리케이션에서 빈으로 등록하여 다른 곳에서 재사용할 수 있게 해줍니다.
@Configuration
class S3Config(
@Value("\${cloud.aws.credentials.access-key}") private val accessKey: String,
@Value("\${cloud.aws.credentials.secret-key}") private val secretKey: String,
@Value("\${cloud.aws.region.static}") private val region: String
) {
@Bean
fun amazonS3Client(): AmazonS3Client {
val awsCredentials = BasicAWSCredentials(accessKey, secretKey)
return AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(AWSStaticCredentialsProvider(awsCredentials))
.build() as AmazonS3Client
}
}
파일 업로드 서비스
S3 버킷에 파일을 업로드하기 위한 서비스 클래스를 작성합니다. 이 클래스에서는 파일을 업로드하고, 업로드된 파일의 URL을 반환하는 기능을 구현합니다.
@Service
class S3ImageUploadService(
private val amazonS3Client: AmazonS3
) {
@Value("\${cloud.aws.s3.bucket}")
private lateinit var bucket: String
@Throws(IOException::class)
fun uploadFile(file: MultipartFile): String {
val fileName = generateFileName(file.originalFilename!!)
val metadata = ObjectMetadata()
metadata.contentLength = file.size
amazonS3Client.putObject(bucket, fileName, file.inputStream, metadata)
return amazonS3Client.getUrl(bucket, fileName).toString() // 업로드된 파일의 URL 반환
}
private fun generateFileName(originalFilename: String): String {
val fileExtension = originalFilename.substringAfterLast(".")
return "${UUID.randomUUID()}.$fileExtension"
}
}
마무리
이 글을 통해 AWS S3를 사용하여 이미지를 업로드하는 방법과, 그 과정에서 발생할 수 있는 보안 문제에 대해 다루었습니다. 특히 IAM 권한 관리와 GitHub 보안 설정에 대한 부분은 꼭 주의해야 할 사항입니다. 이를 통해 AWS S3를 효율적이고 안전하게 사용할 수 있기를 바랍니다.
'스프링' 카테고리의 다른 글
@Entity (0) | 2022.02.01 |
---|---|
spring boot 에서 google login을 사용해보았다. (0) | 2021.12.18 |
Spring 웹 계층 (0) | 2021.12.14 |
스프링 서버 단에서 데이터 처리하는 방식 (0) | 2021.11.27 |
Auditing @CreatedDate @LastModifiedDate (0) | 2021.11.27 |