通过Python脚本设置S3存储桶的Bucket Key

一、背景

在使用AWS Config服务开启内置规则、对本账号进行诊断的时候,可能会发现有一条规则是提示S3存储桶的Bucket Key功能没有打开,这会带来成本影响。这个选项是什么意思呢?本文讲解如何启用这个选项。

S3存储桶的加密方式有SSE-S3、KMS、Dual Layer KMS三种。在这三种加密机制使用场景下,有一个名为Bucket Key的功能,与加密场景密切相关。当不使用Bucket Key时候,每次对S3存储桶的读写调用都需要访问KMS,这样带来KMS的大量请求费用。当开启Bucket Key的功能后,由S3服务管理一个短期有效的密钥并在S3服务层面缓存,日常调用存储桶的读写,将不需要访问KMS,而是使用这个Bucket key。当Bucket Key过期后,自动与KMS服务交互重新生成新的Key。由此,即可节约99%的KMS费用。

在创建S3存储桶时候,页面会询问存储加密类型,以及是否打开Bucket Key。如果本账号已经有大量的存储桶,且分别使用了不同的加密规则,但是一些存储桶创建时候没有打开Bucket Key功能,那么如何快速为所有存储桶打开Bucket Key?在AWS控制台上一个个点击存储桶的过程会非常麻烦没有效率,因此推荐编写Python脚本完成这个配置。

另外在编写脚本的过程中可发现,这几个加密选项在AWS控制台上以及API上看上去的名字是不同的,API层面的标签如下:

  • 控制台网页上的SSE-S3: 在API层面的标签是AES256,也就是默认使用的加密算法
  • 控制台网页上的SSE-KMS:在API层面的标签是aws:kms,表示密钥由KMS管理
  • 控制台网页上的Dual-Layer SSE-KMS:在在API层面的标签是aws:kms:dsse,表示双层KMS级别的加密

这样就可以把本存储桶的加密类型和API调用类型对应起来了。

二、Python脚本

使用Python脚本需要事先安装好Python语言的AWS SDK,即Boto3。命令如下:

pip install boto3

然后编写如下文件:

import boto3

profile_name = 'bjs'

# 定义设置bucket key的函数
def enable_default_encryption_for_buckets(bucket_name,SSEAlgorithm):  
    print("Set bucket key to enabled...")
    # 创建新的加密配置
    new_encryption = {
        'Rules': [
            {
                'ApplyServerSideEncryptionByDefault': {
                    'SSEAlgorithm': SSEAlgorithm  # 输入值 AES256代表SSE-S3 或 aws:kms代表KMS
                },
                'BucketKeyEnabled': True
            }
        ]
    }
    # 设置新的加密配置
    s3_client.put_bucket_encryption(
        Bucket=bucket_name,
        ServerSideEncryptionConfiguration=new_encryption
    )
    return("Bucket key is enabled for bucket: " + bucket_name)

# 主函数
if __name__ == "__main__":
    session = boto3.Session(profile_name=profile_name)
    s3_client = session.client('s3')
    response = s3_client.list_buckets()
    
    # 遍历每个存储桶
    for bucket in response['Buckets']:
        bucket_name = bucket['Name']    
        print(f"Bucket: {bucket_name}")
        
        # 获取当前存储桶的现有加密配置
        encryption_response = s3_client.get_bucket_encryption(Bucket=bucket_name)
        encryption_type = encryption_response["ServerSideEncryptionConfiguration"]["Rules"][0]["ApplyServerSideEncryptionByDefault"]["SSEAlgorithm"]
        bucket_key_enabled = encryption_response["ServerSideEncryptionConfiguration"]["Rules"][0]["BucketKeyEnabled"]
        print("Type:", encryption_type, "| BucketKey:", bucket_key_enabled)
        
        # 跳过已经开启Bucket Key的存储桶,如果没起开启的,则打开
        if bucket_key_enabled == True:
          print("skipping")
        else:
          print("Updating...")
          # 打开存储桶Bucket Key,加密类型保持现有的不变
          enable_default_encryption_for_buckets(bucket_name,encryption_type)
        print("")

注意,以上代码还使用了Profile配置,这是因为在开发者本机上,可能有使用AWSCLI配置多个Profile,分别用不同的AKSK连接不同的Region。参考这篇博客。那么这里可以指定要使用的Profile,确认Profile名字与~/.aws/config文件中的相同,即可使用对应的AKSK调用对应的Region。

执行后返回结果类似如下:

Bucket: appstream-logs-ap-northeast-1-0123456789023-cdjyw6pg
Type: aws:kms | BucketKey: False
Updating...
Set bucket key to enabled...

Bucket: aws-athena-query-results-0123456789023-us-east-1
Type: AES256 | BucketKey: False
Updating...
Set bucket key to enabled...

Bucket: aws-athena-query-results-0123456789023-us-west-2
Type: AES256 | BucketKey: True
skipping

三、参考文档

https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-key.html