我有一些代码可以从Google Cloud Storage上传和下载文件。下面是一个简短的示例:
import (
"context"
"io"
"cloud.google.com/go/storage"
)
func upload(bucket, keyName, path string, reader io.Reader) error {
ctx := context.Background()
client, err := storage.NewClient(ctx)
if err != nil {
return err
}
defer client.Close()
obj := client.Bucket(bucket).Object(path)
writer := obj.NewWriter(ctx)
defer writer.Close()
writer.KMSKeyName = keyName
if _, err = io.Copy(writer, reader); err != nil {
return err
}
if err = writer.Close(); err != nil {
return err
}
return nil
}
棘手的部分是,我正在使用Google KMS管理用于加密文件的密钥(Google的“客户管理的加密密钥”方案)。我的理解是这种加密发生在Google的一端。
我发现使用Go CDK的唯一解决方案是使用Google KMS加密文件,然后上传加密的Blob。无法像以前使用Go CDK一样指定加密密钥吗?
谢谢
答案 0 :(得分:3)
如果需要在Go CDK中使用提供程序特定的设置,则可以使用各种As
functions来获取基础提供程序API的句柄。在这种情况下,您可能想使用blob.WriterOptions.BeforeWrite
选项。这样做的好处是,如果您决定稍后切换存储桶提供程序(例如用于单元测试),则BeforeWrite
将不操作。
import (
"context"
"io"
"cloud.google.com/go/storage"
"gocloud.dev/blob"
_ "gocloud.dev/blob/gcsblob" // link in "gs://" URLs
)
func upload(ctx context.Context, bucket, keyName, path string, reader io.Reader) error {
bucket, err := blob.OpenBucket(ctx, "gs://" + bucket)
if err != nil {
return err
}
defer bucket.Close()
writeCtx, cancelWrite := context.WithCancel(ctx)
defer cancelWrite()
writer, err := bucket.NewWriter(writeCtx, path, &blob.WriterOptions{
// Use BeforeWrite to set provider-specific properties.
BeforeWrite: func(asFunc func(interface{}) bool) error {
var gcsWriter *storage.Writer
// asFunc returns true if the writer can be converted to the type
// pointed to.
if asFunc(&gcsWriter) {
gcsWriter.KMSKeyName = keyName
}
return nil
},
})
if err != nil {
return err
}
if _, err := io.Copy(writer, reader); err != nil {
cancelWrite() // Abort the write to the bucket.
writer.Close()
return err
}
if err := writer.Close(); err != nil {
return err
}
return nil
}
(虽然与您的问题没有直接关系,但我添加了代码来中止写入错误,以避免将部分对象上传到您的存储提供商。我们正在添加文档,以演示如何使用Go CDK API执行常见任务以后,请参见#1576。)
答案 1 :(得分:1)
您发布的代码是正确的。具体来说,此行指示API使用提供的Cloud KMS密钥对数据进行加密:
writer.KMSKeyName = keyName
可能会妨碍您的事情:
确保您的Cloud KMS密钥和Cloud Storage存储桶位于同一区域。例如,如果您的存储桶位于“美国”,则您的KMS密钥也必须位于“美国”。
确保已授予您的Cloud Storage服务帐户访问权限以使用KMS密钥。您可以find the email of your Cloud Storage service account,然后授予它访问权限以使用您的KMS密钥:
$ gcloud kms keys add-iam-policy-binding my-key \
--project my-project \
--keyring my-keyring \
--location us \
--member serviceAccount:service-1234567890@gs-project-accounts.iam.gserviceaccount.com \
--role roles/cloudkms.cryptoKeyEncrypterDecrypter
确保您正在捕获上游upload
返回的错误。所有这些失败模式都会导致错误,所以我想知道这是否丢失了。
有效的证明:
// Completely unmodified version of your `upload` function
func main() {
bucket := "<hidden>"
kmsKey := "projects/<hidden>/locations/us/keyRings/kr/cryptoKeys/k"
if err := upload(bucket, kmsKey, "foo", strings.NewReader("hello world")); err != nil {
log.Fatal(err)
}
}
执行后,这将在由CMEK支持的GCS中正确创建一个对象。