Попытка преобразовать некоторый код в Go CDK при использовании KMS - PullRequest
4 голосов
/ 23 марта 2019

У меня есть код для загрузки и скачивания файлов из 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, а затем загрузить зашифрованный большой двоичный объект.Нет ли способа задать ключ шифрования так же, как я делал это раньше с Go CDK?

Спасибо

Ответы [ 2 ]

4 голосов
/ 26 марта 2019

Если вам нужно использовать специфичные для провайдера настройки в Go CDK, вы можете использовать различные As функции , чтобы получить дескрипторы к базовому 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
}

(Хотя это не имеет прямого отношения к вашему вопросу,Я добавил код, чтобы прервать запись при ошибке, чтобы избежать частичной загрузки объектов вашему провайдеру хранения. Мы добавляем документы, которые покажут, как в будущем выполнять общие задачи с API Go CDK, см. # 1576 .)

2 голосов
/ 25 марта 2019

Код, который вы разместили, верен.В частности, эта строка инструктирует API для шифрования данных с использованием предоставленного ключа KMS Cloud:

writer.KMSKeyName = keyName

Несколько вещей, которые могут мешать:

  • Makeубедитесь, что ваш ключ Cloud KMS и корзина Cloud Storage находятся в одном регионе.Например, если у вас есть область памяти в «США», ваш ключ KMS также должен быть в «США».

  • Убедитесь, что вы предоставили учетной записи службы облачного хранилища доступ киспользуйте ключ KMS.Вы можете найти адрес электронной почты своей учетной записи службы облачного хранилища и затем предоставить ему доступ к использованию вашего ключа 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)
    }
}

При выполнении,это правильно создает объект в GCS при поддержке CMEK.

proof working

...