使用KMS时尝试将某些代码转换为Go CDK

问题描述 投票:2回答:2

我有一些代码可以从Google云端存储上传和下载文件。以下是一个简短的例子:

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
}

棘手的部分是我使用谷歌KMS来管理我用来加密文件的密钥(谷歌所谓的“客户管理的加密密钥”方案)。我的理解是这种加密发生在谷歌的最后。

我使用Go CDK找到的唯一解决方案是使用Google KMS加密文件,然后上传加密的blob。是否无法以与之前使用Go CDK相同的方式指定加密密钥?

谢谢

go google-cloud-storage google-cloud-kms go-cdk
2个回答
4
投票

如果您需要在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。)


2
投票

您发布的代码是正确的。具体来说,此行指示API使用提供的Cloud KMS密钥加密数据:

writer.KMSKeyName = keyName

可能会遇到的一些问题:

  • 确保您的Cloud KMS密钥和云存储桶位于同一区域。例如,如果您的存储桶位于“US”中,则您的KMS密钥也必须位于“US”中。
  • 确保您已授予Cloud Storage Service帐户访问权限以使用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:[email protected] \ --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中正确创建对象。

proof working

© www.soinside.com 2019 - 2024. All rights reserved.