Rotate an encryption key

Rotate an encryption key.

Explore further

For detailed documentation that includes this code sample, see the following:

Code sample

C++

For more information, see the Cloud Storage C++ API reference documentation.

To authenticate to Cloud Storage, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.

namespace gcs = ::google::cloud::storage;
using ::google::cloud::StatusOr;
[](gcs::Client client, std::string const& bucket_name,
   std::string const& object_name, std::string const& old_key_base64,
   std::string const& new_key_base64) {
  StatusOr<gcs::ObjectMetadata> object_metadata =
      client.RewriteObjectBlocking(
          bucket_name, object_name, bucket_name, object_name,
          gcs::SourceEncryptionKey::FromBase64Key(old_key_base64),
          gcs::EncryptionKey::FromBase64Key(new_key_base64));
  if (!object_metadata) throw std::move(object_metadata).status();

  std::cout << "Rotated key on object " << object_metadata->name()
            << " in bucket " << object_metadata->bucket()
            << "\nFull Metadata: " << *object_metadata << "\n";
}

C#

For more information, see the Cloud Storage C# API reference documentation.

To authenticate to Cloud Storage, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.


using Google.Cloud.Storage.V1;
using System;
using System.IO;

public class ObjectRotateEncryptionKeySample
{
    public void ObjectRotateEncryptionKey(
        string bucketName = "your-unique-bucket-name",
        string objectName = "your-object-name",
        string currrentEncryptionKey = "TIbv/fjexq+VmtXzAlc63J4z5kFmWJ6NdAPQulQBT7g=",
        string newEncryptionKey = "ARbt/judaq+VmtXzAsc83J4z5kFmWJ6NdAPQuleuB7g=")
    {
        var storage = StorageClient.Create();

        using var outputStream = new MemoryStream();
        storage.DownloadObject(bucketName, objectName, outputStream, new DownloadObjectOptions()
        {
            EncryptionKey = EncryptionKey.Create(Convert.FromBase64String(currrentEncryptionKey))
        });

        outputStream.Position = 0;

        storage.UploadObject(bucketName, objectName, null, outputStream, new UploadObjectOptions()
        {
            EncryptionKey = EncryptionKey.Create(Convert.FromBase64String(newEncryptionKey))
        });

        Console.WriteLine($"Rotated encryption key for object  {objectName} in bucket {bucketName}");
    }
}

Go

For more information, see the Cloud Storage Go API reference documentation.

To authenticate to Cloud Storage, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.

import (
	"context"
	"fmt"
	"io"
	"time"

	"cloud.google.com/go/storage"
)

// rotateEncryptionKey encrypts an object with the newKey.
func rotateEncryptionKey(w io.Writer, bucket, object string, key, newKey []byte) error {
	// bucket := "bucket-name"
	// object := "object-name"
	// key := []byte("encryption-key")
	// newKey := []byte("new-encryption-key")
	ctx := context.Background()
	client, err := storage.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("storage.NewClient: %w", err)
	}
	defer client.Close()

	ctx, cancel := context.WithTimeout(ctx, time.Second*10)
	defer cancel()

	o := client.Bucket(bucket).Object(object)

	// Optional: set a generation-match precondition to avoid potential race
	// conditions and data corruptions. The request to copy is aborted if the
	// object's generation number does not match your precondition.
	attrs, err := o.Attrs(ctx)
	if err != nil {
		return fmt.Errorf("object.Attrs: %w", err)
	}
	o = o.If(storage.Conditions{GenerationMatch: attrs.Generation})

	// You can't change an object's encryption key directly, you must rewrite the
	// object using the new key.
	_, err = o.Key(newKey).CopierFrom(o.Key(key)).Run(ctx)
	if err != nil {
		return fmt.Errorf("Key(%q).CopierFrom(%q).Run: %w", newKey, key, err)
	}
	fmt.Fprintf(w, "Key rotation complete for blob %v.\n", object)
	return nil
}

Java

For more information, see the Cloud Storage Java API reference documentation.

To authenticate to Cloud Storage, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.

import com.google.cloud.storage.Blob;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;

public class RotateObjectEncryptionKey {
  public static void rotateObjectEncryptionKey(
      String projectId,
      String bucketName,
      String objectName,
      String oldEncryptionKey,
      String newEncryptionKey) {
    // The ID of your GCP project
    // String projectId = "your-project-id";

    // The ID of your GCS bucket
    // String bucketName = "your-unique-bucket-name";

    // The ID of your GCS object
    // String objectName = "your-object-name";

    // The Base64 encoded AES-256 encryption key originally used to encrypt the object. See the
    // documentation
    // on Customer-Supplied Encryption keys for more info:
    // https://cloud.google.com/storage/docs/encryption/using-customer-supplied-keys
    // String oldEncryptionKey = "TIbv/fjexq+VmtXzAlc63J4z5kFmWJ6NdAPQulQBT7g="

    // The new encryption key to use
    // String newEncryptionKey = "0mMWhFvQOdS4AmxRpo8SJxXn5MjFhbz7DkKBUdUIef8="

    Storage storage = StorageOptions.newBuilder().setProjectId(projectId).build().getService();
    BlobId blobId = BlobId.of(bucketName, objectName);
    Blob blob = storage.get(blobId);
    if (blob == null) {
      System.out.println("The object " + objectName + " wasn't found in " + bucketName);
      return;
    }

    // Optional: set a generation-match precondition to avoid potential race
    // conditions and data corruptions. The request to upload returns a 412 error if
    // the object's generation number does not match your precondition.
    Storage.BlobSourceOption precondition =
        Storage.BlobSourceOption.generationMatch(blob.getGeneration());

    // You can't change an object's encryption key directly, the only way is to overwrite the object
    Storage.CopyRequest request =
        Storage.CopyRequest.newBuilder()
            .setSource(blobId)
            .setSourceOptions(
                Storage.BlobSourceOption.decryptionKey(oldEncryptionKey), precondition)
            .setTarget(blobId, Storage.BlobTargetOption.encryptionKey(newEncryptionKey))
            .build();
    storage.copy(request);

    System.out.println(
        "Rotated encryption key for object " + objectName + "in bucket " + bucketName);
  }
}

Node.js

For more information, see the Cloud Storage Node.js API reference documentation.

To authenticate to Cloud Storage, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// The ID of your GCS bucket
// const bucketName = 'your-unique-bucket-name';

// The ID of your GCS file
// const fileName = 'your-file-name';

// The Base64 encoded AES-256 encryption key originally used to encrypt the
// object. See the documentation on Customer-Supplied Encryption keys for
// more info:
// https://cloud.google.com/storage/docs/encryption/using-customer-supplied-keys
// The Base64 encoded AES-256 encryption key originally used to encrypt the
// const oldKey = 'TIbv/fjexq+VmtXzAlc63J4z5kFmWJ6NdAPQulQBT7g=';

// The new encryption key to use
// const newKey = '0mMWhFvQOdS4AmxRpo8SJxXn5MjFhbz7DkKBUdUIef8=';

// Imports the Google Cloud client library
const {Storage} = require('@google-cloud/storage');

// Creates a client
const storage = new Storage();

async function rotateEncryptionKey() {
  const rotateEncryptionKeyOptions = {
    encryptionKey: Buffer.from(newKey, 'base64'),

    // Optional: set a generation-match precondition to avoid potential race
    // conditions and data corruptions. The request to copy is aborted if the
    // object's generation number does not match your precondition.
    preconditionOpts: {
      ifGenerationMatch: generationMatchPrecondition,
    },
  };
  await storage
    .bucket(bucketName)
    .file(fileName, {
      encryptionKey: Buffer.from(oldKey, 'base64'),
    })
    .rotateEncryptionKey({
      rotateEncryptionKeyOptions,
    });

  console.log('Encryption key rotated successfully');
}

rotateEncryptionKey().catch(console.error);

PHP

For more information, see the Cloud Storage PHP API reference documentation.

To authenticate to Cloud Storage, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.

use Google\Cloud\Storage\StorageClient;

/**
 * Change the encryption key used to store an existing object.
 *
 * @param string $bucketName The name of your Cloud Storage bucket.
 *        (e.g. 'my-bucket')
 * @param string $objectName The name of your Cloud Storage object.
 *        (e.g. 'my-object')
 * @param string $oldBase64EncryptionKey The Base64 encoded AES-256 encryption
 *     key originally used to encrypt the object. See the documentation on
 *     Customer-Supplied Encryption keys for more info:
 *     https://cloud.google.com/storage/docs/encryption/using-customer-supplied-keys
 *        (e.g. 'TIbv/fjexq+VmtXzAlc63J4z5kFmWJ6NdAPQulQBT7g=')
 * @param string $newBase64EncryptionKey The new base64 encoded encryption key.
 *        (e.g. '0mMWhFvQOdS4AmxRpo8SJxXn5MjFhbz7DkKBUdUIef8=')
 */
function rotate_encryption_key(
    string $bucketName,
    string $objectName,
    string $oldBase64EncryptionKey,
    string $newBase64EncryptionKey
): void {
    $storage = new StorageClient();
    $object = $storage->bucket($bucketName)->object($objectName);

    $rewrittenObject = $object->rewrite($bucketName, [
        'encryptionKey' => $oldBase64EncryptionKey,
        'destinationEncryptionKey' => $newBase64EncryptionKey,
    ]);

    printf('Rotated encryption key for object gs://%s/%s' . PHP_EOL,
        $bucketName, $objectName);
}

Python

For more information, see the Cloud Storage Python API reference documentation.

To authenticate to Cloud Storage, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.

import base64

from google.cloud import storage


def rotate_encryption_key(
    bucket_name, blob_name, base64_encryption_key, base64_new_encryption_key
):
    """Performs a key rotation by re-writing an encrypted blob with a new
    encryption key."""
    storage_client = storage.Client()
    bucket = storage_client.bucket(bucket_name)
    current_encryption_key = base64.b64decode(base64_encryption_key)
    new_encryption_key = base64.b64decode(base64_new_encryption_key)

    # Both source_blob and destination_blob refer to the same storage object,
    # but destination_blob has the new encryption key.
    source_blob = bucket.blob(
        blob_name, encryption_key=current_encryption_key
    )
    destination_blob = bucket.blob(
        blob_name, encryption_key=new_encryption_key
    )
    generation_match_precondition = None
    token = None

    # Optional: set a generation-match precondition to avoid potential race conditions
    # and data corruptions. The request to rewrite is aborted if the object's
    # generation number does not match your precondition.
    source_blob.reload()  # Fetch blob metadata to use in generation_match_precondition.
    generation_match_precondition = source_blob.generation

    while True:
        token, bytes_rewritten, total_bytes = destination_blob.rewrite(
            source_blob, token=token, if_generation_match=generation_match_precondition
        )
        if token is None:
            break

    print(f"Key rotation complete for Blob {blob_name}")

Ruby

For more information, see the Cloud Storage Ruby API reference documentation.

To authenticate to Cloud Storage, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.

def rotate_encryption_key bucket_name:, file_name:, current_encryption_key:, new_encryption_key:
  # The ID of your GCS bucket
  # bucket_name = "your-unique-bucket-name"

  # The ID of your GCS object
  # file_name = "your-file-name"

  # The Base64 encoded AES-256 encryption key originally used to encrypt the object.
  # See the documentation on Customer-Supplied Encryption keys for more info:
  # https://cloud.google.com/storage/docs/encryption/using-customer-supplied-keys
  # current_encryption_key = "TIbv/fjexq+VmtXzAlc63J4z5kFmWJ6NdAPQulQBT7g="

  # The new encryption key to use
  # new_encryption_key = "0mMWhFvQOdS4AmxRpo8SJxXn5MjFhbz7DkKBUdUIef8="

  require "google/cloud/storage"

  storage = Google::Cloud::Storage.new
  bucket  = storage.bucket bucket_name, skip_lookup: true
  file    = bucket.file file_name, encryption_key: current_encryption_key

  file.rotate encryption_key:     current_encryption_key,
              new_encryption_key: new_encryption_key

  puts "The encryption key for #{file.name} in #{bucket.name} was rotated."
end

What's next

To search and filter code samples for other Google Cloud products, see the Google Cloud sample browser.