使用加密密钥

概览

默认情况下,Cloud Storage 使用 GMEK(Google 管理的加密密钥)和 AES256 加密算法对所有对象数据进行加密。不过,您也可以使用以下两种加密密钥类型之一:您提供的加密密钥,称为 CSEK(客户提供的加密密钥);或您通过 Google Cloud KMS 管理的加密密钥,称为 CMEK(客户管理的加密密钥)。Cloud Storage 不会将 CSEK 永久存储在 Google 服务器上或以其他方式管理 CSEK。如需详细了解这些加密选项,请参阅 CMEKCSEK

gsutil 接受 CSEK 使用 JSON API 与 Cloud Storage 对象进行交互。这些密钥会通过如下所示的 .boto 配置文件提供:

[GSUtil]
encryption_key = ...
decryption_key1 = ...
decryption_key2 = ...

每个密钥都是包含 256 位数据的 RFC 4648 Base64 编码字符串,以便与 AES256 加密算法结合使用。

gsutil 还接受 CMEK 使用 JSON API 来加密对象。请注意,如果您的目标是使用 CMEK 加密某个存储分区中所有新写入的对象,则应设置该存储分区的默认 KMS 密钥(请参阅 gsutil help kms)。或者,您可以在 .boto 配置文件中指定所需的 CMEK,但只需指定 encryption_key 特性:

[GSUtil]
encryption_key = projects/PROJECT_ID/locations/LOCATION/keyRings/KEYRING/cryptoKeys/KEYNAME

虽然解密经过 CSEK 加密的对象要求在某个 decryption_key 特性中提供 CSEK,但由于用于加密对象的 CMEK 的名称存储在对象的元数据中,因此这对于解密经过 CMEK 加密的对象不是必需的。

请注意,如果您要按命令指定 CMEK 而无需修改 boto 文件,则可以将密钥名称指定为顶级 boto 选项:

gsutil -o 'GSUtil:encryption_key=projects/PROJECT_ID/locations/LOCATION/keyRings/KEYRING/cryptoKeys/KEYNAME' \
       cp /some/local/file gs://my-bucket/

加密行为

您可以在 .boto 配置文件中指定一个 encryption_key,并且可以指定多个 decryption_key。

如果 .boto 配置文件中存在 encryption_key,则 gsutil 会确保其在 Cloud Storage 中写入或复制的数据使用该密钥进行加密。如果未提供 encryption_key,则 gsutil 会确保其写入或复制的所有数据都改用目标存储分区的默认加密类型。如果该存储分区设置了默认 KMS 密钥,则使用 CMEK 进行加密;如果未设置默认 KMS 密钥,则使用 Google 管理的加密。

通过 CSEK 加密的对象在任何时间进行下载或复制时(通过 gsutil cat、cp、mv 或 rsync 命令)都要求匹配的解密密钥。查看此类对象的 CRC32C 或 MD5 哈希值(通过 ls -L 或 stat 命令)也要求匹配的解密密钥。

如果 .boto 配置中存在匹配的密钥,则 gsutil 会根据需要在向 Cloud Storage 发出的请求中提供该密钥,并对解密结果执行操作。gsutil 绝不会将加密数据存储在您的本地磁盘上。

通过将密钥的 SHA256 哈希值与 CSEK 的哈希值进行比较,gsutil 可自动检测要用于云对象的正确 CSEK。在搜索匹配项时,gsutil 会考虑配置的加密密钥和最多 100 个解密密钥。解密密钥必须从 1 开始按递增数字顺序在 boto 配置文件中列出。例如,在以下配置中:

decryption_key1 = ...
decryption_key9 = ...
decryption_key10 = ...
decryption_key11 = ...

由于未提供 decryption_key 2 到 8 的值,因此 decryption_key 9、10 和 11 会被忽略。

可恢复操作和加密密钥

如果 boto 配置文件中的 encryption_key 在部分完成的写入或复制操作期间(例如,如果您在命中 ^C 或遇到网络超时后重新运行 gsutil cp 对象上传)发生更改,gsutil 会重启部分完成的操作,以确保目标对象是使用新密钥写入的。

生成 CSEK

使用 Python 您可以轻松生成 256 位 RFC 4648 Base64 编码字符串,以用作加密密钥:

python -c 'import base64; import os;\
           print(base64.encodestring(os.urandom(32)))'

管理 CSEK

由于 Google 不会存储 CSEK,因此如果您丢失了 CSEK,您将永久无法访问使用该密钥加密的所有数据。因此,建议您将每个加密密钥备份到安全位置。.boto 配置文件绝不应是存储密钥的唯一位置。

此外,创建 CSEK 后,任何拥有该密钥和对象访问权限的人员都可以读取这些对象的数据。请采取一些预防措施,以确保加密密钥不会与不受信任方共享。

轮替密钥

如需轮替 CSEK,您可以将 encryption_key 配置值更改为 decryption_key 配置值,然后对 encryption_key 使用新值。然后,您可以使用重写命令在云端轮替密钥,而无需下载和重新上传数据。例如,如果您的初始配置是:

# Old encryption key
encryption_key = keyA...

您可以将该配置更改为:

# New encryption key
encryption_key = keyB...
# Encryption key prior to rotation
decryption_key1 = keyA...

并通过运行以下命令针对对象轮替加密密钥:

gsutil rewrite -k gs://bucket/object temp-file

您还可以通过执行此操作来应用不同的 CMEK,但您无需将 CMEK 添加到 decryption_key 配置值。同样,您可以根据 encryption_key 配置值中指定的密钥类型在 CSEK 和 CMEK 加密之间切换。

加密密钥的性能影响

执行对象列出操作时,使用 CSEK 或 CMEK 加密的对象的元数据将不包含该对象的 CR32C 或 MD5 哈希值。对于需要这些字段的 gsutil 命令(例如 gsutil ls -L),gsutil 会为使用 CSEK 或 CMEK 加密的每个对象执行额外的元数据 GET 请求。因此,使用 -L 标志列出此类对象需要对每个对象执行一项额外的操作,这比列出使用 Google 自有密钥加密的对象慢得多。

CSEK 的安全隐患

gsutil 始终通过 HTTPS 发送加密密钥,因此您的 CSEK 绝不会在网络上显示。但是,这些密钥存在于 .boto 配置文件以及执行 gsutil 的机器内存中。因此,如果此文件或机器遭到破解,您的加密密钥也应视作被破解,您应立即对使用被破解的密钥加密的所有对象执行密钥轮替。

Xml Api 不受支持

gsutil 不支持使用 XML API 与加密对象进行交互,并且如果配置中指定了任何 encryption_key 或 decrypt_key,则 gsutil 将使用 JSON API。