boto3를 사용하여 S3에 저장할 때는 default_acl 설정을 확인해야 한다.
민감 데이터를 S3 버킷에 Boto3를 활용하여 Private 하게 객체를 적재해야 하는 작업으로 기본값으로 S3 버킷을 만들고 객체를 put하였는데 ACL(Access Control List) 관련 에러 메시지와 마주하였다.
botocore.exceptions.ClientError: An error occurred (AccessControlListNotSupported) when calling the PutObject operation: The bucket does not allow ACLs
시도한 해결 방법
어느 지점이 문제가 되는지 파악하기 위해 ACL을 활성화 다시 put 시도하였더니 에러 내용이 다음과 같이 변경되었다.
botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
AWS Access key가 버킷을 생성한 IAM 계정과 달라서 생긴 문제일까하는 의심으로 시작하여 버킷 정책을 수정을 시도하였으나 해결되지 않았다.
{
"Version": "2012-10-17",
"Id": "ExampleBucketPutObjPolicy",
"Statement": [
{
"Sid": "ExampleBucketPut",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::<AWS_ACCOUNT_ID>:user/<MY_USER_NAME>",
"arn:aws:iam::<AWS_ACCOUNT_ID>:user/<CO_WORKER1_USER_NAME>",
"arn:aws:iam::<AWS_ACCOUNT_ID>:user/<CO_WORKER2_USER_NAME>",
"arn:aws:iam::<AWS_ACCOUNT_ID>:user/<CO_WORKER3_USER_NAME>",...
]
},
"Action": "s3:PutObject",
"Resource": [
"arn:aws:s3:::<MY_BUCKET_NAME>",
"arn:aws:s3:::<MY_BUCKET_NAME>/*"
]
}
]
}
객체에 대한 퍼블릭 액세스를 허용하지 않으면서도 Access Denied 오류가 발생하지 않도록 퍼블릭 액세스 구성 변경을 시도해보았는데, 이 역시 해결되지 않았다. 공식문서를 확인해보니 공용 Put Object ACL 호출은 실패할 수 있다고 나와있었다.
S3 public access options
그러나 “모든 퍼블릭 액세스"를 차단하는 것이 아니라는 문제점이 있었다.
S3 bucket permissions
다른 해결 방법을 찾아보았고, 적용하지 않은 옵션을 확인하여 문서를 자세히 읽어보았다. 문서에서는 공용 Put Object ACL 호출에 실패할 수 있다고 나와있었다.
이를 단서로 자세한 내용을 파악하기 위해 Boto SDK를 검토하기 시작했다.
이를 단서로 Boto SDK를 확인하기 시작하여, Boto SDK에서 기본 설정 중 AWS_DEFAULT_ACL을 확인하였다.
def get_default_settings(self):
...(중략)...
return {
"access_key": setting('AWS_S3_ACCESS_KEY_ID', setting('AWS_ACCESS_KEY_ID')),
...(중략)...
"default_acl": setting('AWS_DEFAULT_ACL', None),
}
쉘로 확인해보니 이 설정이 public-read로 되어 있음을 발견했다. 즉, 기본적으로 퍼블릭 리드 권한을 가지고 있었던 것이다.
>>> from django.conf import settings
>>> settings.AWS_DEFAULT_ACL
'public-read'
이 설정은 다른 앱에서도 사용하는 전역 설정 값이기 때문에 수정할 수 없었다. 따라서 문제가 발생하는 모델의 값을 수정하기로 결정했다.
class S3SampleStorage(S3Boto3Storage):
record_prefix = "root_dir/"
def __init__(self, *args, **kwargs):
self.access_key = settings.AWS_ACCESS_KEY
self.secret_key = settings.AWS_SECRET_KEY
self.bucket_name = settings.AWS_SAMPLE_BUCKET_NAME
self.custom_domain = settings.AWS_SAMPLE_CUSTOM_DOMAIN
self.default_acl = "private"
super().__init__(*args, **kwargs)
변경 후에는 정책을 삭제하고 ACL을 비활성화한 후에도 퍼블릭 액세스가 차단되고 데이터가 정상적으로 저장되는 것을 확인했다. 이제 boto3로 S3에 데이터를 저장할 때 default_acl 설정을 확인하여 데이터 보안을 유지할 수 있게 되었다.
결론
boto3를 사용하여 S3에 데이터를 저장할 때는 default_acl 설정을 주의하고, 데이터의 보안을 유지하기 위해 필요한 액세스 권한을 명시적으로 설정해야 한다.