Repository: googleapis/java-storage
Pull request #1823 (2022-12-21 04:11:52)

test: introduce KmsFixture
Add new `KmsFixture` class to encapsulate and pull the lifecycle of the Kms `KeyRing` and `Keys` up into the Registry.

Remove all KMS/IAM related setup from ITKmsTest in favor of the new Fixture.

Drop use of grpc stubs directly in favor of the GAPIC client for KMS.

Cleanup of TODO from https://github.com/googleapis/java-storage/pull/1785

generated-files-bot[bot]: <!-- probot comment [12634855]-->
*Warning*: This pull request is touching the following templated files:

* renovate.json

Patch:
diff --git a/google-cloud-storage/pom.xml b/google-cloud-storage/pom.xml
index 386a348e..21e88426 100644
--- a/google-cloud-storage/pom.xml
+++ b/google-cloud-storage/pom.xml
@@ -17,7 +17,6 @@
   <properties>
     <site.installationModule>google-cloud-storage</site.installationModule>
     <pubsub-proto.version>1.104.2</pubsub-proto.version>
-    <kms.version>0.101.0</kms.version>
     <junit-platform.version>5.9.1</junit-platform.version>
   </properties>
   <dependencies>
@@ -143,10 +142,6 @@
       <artifactId>grpc-netty-shaded</artifactId>
       <scope>runtime</scope>
     </dependency>
-    <dependency>
-      <groupId>io.grpc</groupId>
-      <artifactId>grpc-auth</artifactId>
-    </dependency>
     <dependency>
       <groupId>io.grpc</groupId>
       <artifactId>grpc-stub</artifactId>
@@ -170,21 +165,17 @@
       <artifactId>grpc-xds</artifactId>
       <scope>runtime</scope>
     </dependency>
-    <dependency>
-      <groupId>com.google.api.grpc</groupId>
-      <artifactId>grpc-google-cloud-kms-v1</artifactId>
-      <version>${kms.version}</version>
-      <scope>test</scope>
-    </dependency>
     <dependency>
       <groupId>com.google.api.grpc</groupId>
       <artifactId>proto-google-cloud-kms-v1</artifactId>
-      <version>${kms.version}</version>
+      <version>0.101.0</version>
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>com.google.api.grpc</groupId>
-      <artifactId>grpc-google-iam-v1</artifactId>
+      <groupId>com.google.cloud</groupId>
+      <artifactId>google-cloud-kms</artifactId>
+      <version>2.10.0</version>
+      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>com.google.api.grpc</groupId>
diff --git a/renovate.json b/renovate.json
index 8201f595..b5e21946 100644
--- a/renovate.json
+++ b/renovate.json
@@ -72,6 +72,7 @@
     {
       "groupName": "cross product test dependencies",
       "packagePatterns": [
+        "^com.google.cloud:google-cloud-kms",
         "^com.google.cloud:google-cloud-pubsub",
         "^com.google.api.grpc:grpc-google-cloud-kms-v1",
         "^com.google.api.grpc:proto-google-cloud-kms-v1",


Test patch:
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITKmsTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITKmsTest.java
index 5af68578..9d335ab7 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITKmsTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITKmsTest.java
@@ -25,18 +25,7 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import com.google.api.gax.paging.Page;
-import com.google.auth.Credentials;
 import com.google.cloud.WriteChannel;
-import com.google.cloud.kms.v1.CreateCryptoKeyRequest;
-import com.google.cloud.kms.v1.CreateKeyRingRequest;
-import com.google.cloud.kms.v1.CryptoKey;
-import com.google.cloud.kms.v1.CryptoKeyName;
-import com.google.cloud.kms.v1.GetCryptoKeyRequest;
-import com.google.cloud.kms.v1.GetKeyRingRequest;
-import com.google.cloud.kms.v1.KeyManagementServiceGrpc;
-import com.google.cloud.kms.v1.KeyManagementServiceGrpc.KeyManagementServiceBlockingStub;
-import com.google.cloud.kms.v1.KeyRingName;
-import com.google.cloud.kms.v1.LocationName;
 import com.google.cloud.storage.Blob;
 import com.google.cloud.storage.BlobId;
 import com.google.cloud.storage.BlobInfo;
@@ -44,44 +33,28 @@ import com.google.cloud.storage.Bucket;
 import com.google.cloud.storage.BucketInfo;
 import com.google.cloud.storage.CopyWriter;
 import com.google.cloud.storage.DataGeneration;
-import com.google.cloud.storage.ServiceAccount;
 import com.google.cloud.storage.Storage;
 import com.google.cloud.storage.Storage.BlobField;
-import com.google.cloud.storage.Storage.BucketField;
 import com.google.cloud.storage.StorageException;
-import com.google.cloud.storage.StorageOptions;
 import com.google.cloud.storage.TransportCompatibility.Transport;
 import com.google.cloud.storage.it.runner.StorageITRunner;
 import com.google.cloud.storage.it.runner.annotations.Backend;
 import com.google.cloud.storage.it.runner.annotations.CrossRun;
 import com.google.cloud.storage.it.runner.annotations.Inject;
+import com.google.cloud.storage.it.runner.annotations.ParallelFriendly;
 import com.google.cloud.storage.it.runner.registry.Generator;
+import com.google.cloud.storage.it.runner.registry.KmsFixture;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterators;
 import com.google.common.io.BaseEncoding;
-import com.google.iam.v1.Binding;
-import com.google.iam.v1.IAMPolicyGrpc;
-import com.google.iam.v1.SetIamPolicyRequest;
-import io.grpc.ClientInterceptor;
-import io.grpc.ManagedChannel;
-import io.grpc.ManagedChannelBuilder;
-import io.grpc.Metadata;
-import io.grpc.Status;
-import io.grpc.StatusRuntimeException;
-import io.grpc.auth.MoreCallCredentials;
-import io.grpc.stub.MetadataUtils;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.security.Key;
 import java.util.Iterator;
 import java.util.Random;
 import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 import javax.crypto.spec.SecretKeySpec;
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -90,24 +63,12 @@ import org.junit.runner.RunWith;
 @CrossRun(
     transports = {Transport.HTTP, Transport.GRPC},
     backends = Backend.PROD)
+@ParallelFriendly
 public class ITKmsTest {
 
   private static final long seed = -7071346537822433445L;
   @Rule public final DataGeneration dataGeneration = new DataGeneration(new Random(seed));
 
-  // TODO: either pull the scope of these resources up higher, or make them per-test distinct
-  //   to insulate them from each other
-  private String kmsKeyOneResourcePath;
-  private String kmsKeyTwoResourcePath;
-  private static final String KMS_KEY_RING_NAME = "gcs_test_kms_key_ring";
-  private static final String KMS_KEY_RING_LOCATION = "us";
-  private static final String KMS_KEY_ONE_NAME = "gcs_kms_key_one";
-  private static final String KMS_KEY_TWO_NAME = "gcs_kms_key_two";
-  private Metadata requestParamsHeader = new Metadata();
-  private static Metadata.Key<String> requestParamsKey =
-      Metadata.Key.of("x-goog-request-params", Metadata.ASCII_STRING_MARSHALLER);
-  private ManagedChannel kmsChannel;
-  private static final Logger log = Logger.getLogger(ITKmsTest.class.getName());
   private static final byte[] BLOB_BYTE_CONTENT = {0xD, 0xE, 0xA, 0xD};
   private static final String BLOB_STRING_CONTENT = "Hello Google Cloud Storage!";
   private static final String BASE64_KEY = "JVzfVl8NLD9FjedFuStegjRfES5ll5zc59CIXw572OA=";
@@ -118,179 +79,19 @@ public class ITKmsTest {
   @Inject public Storage storage;
   @Inject public BucketInfo bucket;
   @Inject public Generator generator;
-
-  @Before
-  public void setup() {
-    // Prepare KMS KeyRing for CMEK tests
-    // https://cloud.google.com/storage/docs/encryption/using-customer-managed-keys
-    // We don't care currently if we are using HTTP or gRPC because
-    // these values should be the same.
-    StorageOptions storageOptions = storage.getOptions();
-    String projectId = storageOptions.getProjectId();
-
-    Credentials credentials = storageOptions.getCredentials();
-    // TODO: can we switch all this manual grpc stuff for
-    //   com.google.cloud.kms.v1.KeyManagementServiceClient?
-    kmsChannel = ManagedChannelBuilder.forTarget("cloudkms.googleapis.com:443").build();
-    KeyManagementServiceBlockingStub kmsStub =
-        KeyManagementServiceGrpc.newBlockingStub(kmsChannel)
-            .withCallCredentials(MoreCallCredentials.from(credentials));
-    IAMPolicyGrpc.IAMPolicyBlockingStub iamStub =
-        IAMPolicyGrpc.newBlockingStub(kmsChannel)
-            .withCallCredentials(MoreCallCredentials.from(credentials));
-    ensureKmsKeyRingExistsForTests(kmsStub, projectId, KMS_KEY_RING_LOCATION, KMS_KEY_RING_NAME);
-    ensureKmsKeyRingIamPermissionsForTests(
-        iamStub, projectId, KMS_KEY_RING_LOCATION, KMS_KEY_RING_NAME);
-    kmsKeyOneResourcePath =
-        ensureKmsKeyExistsForTests(
-            kmsStub, projectId, KMS_KEY_RING_LOCATION, KMS_KEY_RING_NAME, KMS_KEY_ONE_NAME);
-    kmsKeyTwoResourcePath =
-        ensureKmsKeyExistsForTests(
-            kmsStub, projectId, KMS_KEY_RING_LOCATION, KMS_KEY_RING_NAME, KMS_KEY_TWO_NAME);
-  }
-
-  @After
-  public void after() {
-    if (kmsChannel != null) {
-      try {
-        kmsChannel.shutdownNow();
-      } catch (Exception e) {
-        log.log(Level.WARNING, "Error while trying to shutdown kms channel", e);
-      }
-      kmsChannel = null;
-    }
-  }
-
-  private String ensureKmsKeyRingExistsForTests(
-      KeyManagementServiceBlockingStub kmsStub,
-      String projectId,
-      String location,
-      String keyRingName)
-      throws StatusRuntimeException {
-    String kmsKeyRingResourcePath = KeyRingName.of(projectId, location, keyRingName).toString();
-    try {
-      // Attempt to Get KeyRing
-      GetKeyRingRequest getKeyRingRequest =
-          GetKeyRingRequest.newBuilder().setName(kmsKeyRingResourcePath).build();
-      requestParamsHeader.put(requestParamsKey, "name=" + kmsKeyRingResourcePath);
-      ClientInterceptor headersInterceptor =
-          MetadataUtils.newAttachHeadersInterceptor(requestParamsHeader);
-      KeyManagementServiceBlockingStub stubForGetKeyRing =
-          kmsStub.withInterceptors(headersInterceptor);
-      stubForGetKeyRing.getKeyRing(getKeyRingRequest);
-    } catch (StatusRuntimeException ex) {
-      if (ex.getStatus().getCode() == Status.Code.NOT_FOUND) {
-        // Create KmsKeyRing
-        String keyRingParent = LocationName.of(projectId, location).toString();
-        CreateKeyRingRequest createKeyRingRequest =
-            CreateKeyRingRequest.newBuilder()
-                .setParent(keyRingParent)
-                .setKeyRingId(keyRingName)
-                .build();
-        requestParamsHeader.put(requestParamsKey, "parent=" + keyRingParent);
-        ClientInterceptor headersInterceptor =
-            MetadataUtils.newAttachHeadersInterceptor(requestParamsHeader);
-        KeyManagementServiceBlockingStub stubForCreateKeyRing =
-            kmsStub.withInterceptors(headersInterceptor);
-        stubForCreateKeyRing.createKeyRing(createKeyRingRequest);
-      } else {
-        throw ex;
-      }
-    }
-
-    return kmsKeyRingResourcePath;
-  }
-
-  private void ensureKmsKeyRingIamPermissionsForTests(
-      IAMPolicyGrpc.IAMPolicyBlockingStub iamStub,
-      String projectId,
-      String location,
-      String keyRingName)
-      throws StatusRuntimeException {
-    ServiceAccount serviceAccount = storage.getServiceAccount(projectId);
-    String kmsKeyRingResourcePath = KeyRingName.of(projectId, location, keyRingName).toString();
-    Binding binding =
-        Binding.newBuilder()
-            .setRole("roles/cloudkms.cryptoKeyEncrypterDecrypter")
-            .addMembers("serviceAccount:" + serviceAccount.getEmail())
-            .build();
-    com.google.iam.v1.Policy policy =
-        com.google.iam.v1.Policy.newBuilder().addBindings(binding).build();
-    SetIamPolicyRequest setIamPolicyRequest =
-        SetIamPolicyRequest.newBuilder()
-            .setResource(kmsKeyRingResourcePath)
-            .setPolicy(policy)
-            .build();
-    requestParamsHeader.put(requestParamsKey, "parent=" + kmsKeyRingResourcePath);
-    ClientInterceptor headersInterceptor =
-        MetadataUtils.newAttachHeadersInterceptor(requestParamsHeader);
-    iamStub = iamStub.withInterceptors(headersInterceptor);
-    try {
-      iamStub.setIamPolicy(setIamPolicyRequest);
-    } catch (StatusRuntimeException e) {
-      if (log.isLoggable(Level.WARNING)) {
-        log.log(Level.WARNING, "Unable to set IAM policy: {0}", e.getMessage());
-      }
-    }
-  }
-
-  private String ensureKmsKeyExistsForTests(
-      KeyManagementServiceBlockingStub kmsStub,
-      String projectId,
-      String location,
-      String keyRingName,
-      String keyName)
-      throws StatusRuntimeException {
-    String kmsKeyResourcePath =
-        CryptoKeyName.of(projectId, location, keyRingName, keyName).toString();
-    try {
-      // Attempt to Get CryptoKey
-      requestParamsHeader.put(requestParamsKey, "name=" + kmsKeyResourcePath);
-      GetCryptoKeyRequest getCryptoKeyRequest =
-          GetCryptoKeyRequest.newBuilder().setName(kmsKeyResourcePath).build();
-      ClientInterceptor headersInterceptor =
-          MetadataUtils.newAttachHeadersInterceptor(requestParamsHeader);
-      KeyManagementServiceGrpc.KeyManagementServiceBlockingStub stubForGetCryptoKey =
-          kmsStub.withInterceptors(headersInterceptor);
-      stubForGetCryptoKey.getCryptoKey(getCryptoKeyRequest);
-    } catch (StatusRuntimeException ex) {
-      if (ex.getStatus().getCode() == Status.Code.NOT_FOUND) {
-        String kmsKeyRingResourcePath = KeyRingName.of(projectId, location, keyRingName).toString();
-        CryptoKey cryptoKey =
-            CryptoKey.newBuilder().setPurpose(CryptoKey.CryptoKeyPurpose.ENCRYPT_DECRYPT).build();
-        CreateCryptoKeyRequest createCryptoKeyRequest =
-            CreateCryptoKeyRequest.newBuilder()
-                .setCryptoKeyId(keyName)
-                .setParent(kmsKeyRingResourcePath)
-                .setCryptoKey(cryptoKey)
-                .build();
-
-        requestParamsHeader.put(requestParamsKey, "parent=" + kmsKeyRingResourcePath);
-        ClientInterceptor headersInterceptor =
-            MetadataUtils.newAttachHeadersInterceptor(requestParamsHeader);
-        KeyManagementServiceGrpc.KeyManagementServiceBlockingStub stubForCreateCryptoKey =
-            kmsStub.withInterceptors(headersInterceptor);
-        stubForCreateCryptoKey.createCryptoKey(createCryptoKeyRequest);
-      } else {
-        throw ex;
-      }
-    }
-    return kmsKeyResourcePath;
-  }
+  @Inject public KmsFixture kms;
 
   @Test
   public void testClearBucketDefaultKmsKeyName() {
     String bucketName = generator.randomBucketName();
-    // TODO: replace with storage
-    // b/246634709
     Bucket remoteBucket =
         storage.create(
             BucketInfo.newBuilder(bucketName)
-                .setDefaultKmsKeyName(kmsKeyOneResourcePath)
-                .setLocation(KMS_KEY_RING_LOCATION)
+                .setDefaultKmsKeyName(kms.getKey1().getName())
+                .setLocation(kms.getKeyRingLocation())
                 .build());
     try {
-      assertEquals(kmsKeyOneResourcePath, remoteBucket.getDefaultKmsKeyName());
+      assertEquals(kms.getKey1().getName(), remoteBucket.getDefaultKmsKeyName());
       Bucket updatedBucket = remoteBucket.toBuilder().setDefaultKmsKeyName(null).build().update();
       assertNull(updatedBucket.getDefaultKmsKeyName());
     } finally {
@@ -300,21 +101,18 @@ public class ITKmsTest {
 
   @Test
   public void testUpdateBucketDefaultKmsKeyName() {
-    // TODO: replace with storage
-    // b/246634709
     String bucketName = generator.randomBucketName();
     Bucket remoteBucket =
         storage.create(
             BucketInfo.newBuilder(bucketName)
-                .setDefaultKmsKeyName(kmsKeyOneResourcePath)
-                .setLocation(KMS_KEY_RING_LOCATION)
+                .setDefaultKmsKeyName(kms.getKey1().getName())
+                .setLocation(kms.getKeyRingLocation())
                 .build());
-
     try {
-      assertEquals(kmsKeyOneResourcePath, remoteBucket.getDefaultKmsKeyName());
+      assertEquals(kms.getKey1().getName(), remoteBucket.getDefaultKmsKeyName());
       Bucket updatedBucket =
-          remoteBucket.toBuilder().setDefaultKmsKeyName(kmsKeyTwoResourcePath).build().update();
-      assertEquals(kmsKeyTwoResourcePath, updatedBucket.getDefaultKmsKeyName());
+          remoteBucket.toBuilder().setDefaultKmsKeyName(kms.getKey2().getName()).build().update();
+      assertEquals(kms.getKey2().getName(), updatedBucket.getDefaultKmsKeyName());
     } finally {
       BucketCleaner.doCleanup(bucketName, storage);
     }
@@ -327,12 +125,12 @@ public class ITKmsTest {
     BlobInfo blob = BlobInfo.newBuilder(bucketName, blobName).build();
     Blob remoteBlob =
         storage.create(
-            blob, BLOB_BYTE_CONTENT, Storage.BlobTargetOption.kmsKeyName(kmsKeyOneResourcePath));
+            blob, BLOB_BYTE_CONTENT, Storage.BlobTargetOption.kmsKeyName(kms.getKey1().getName()));
     assertNotNull(remoteBlob);
     assertEquals(blob.getBucket(), remoteBlob.getBucket());
     assertEquals(blob.getName(), remoteBlob.getName());
     assertNotNull(remoteBlob.getKmsKeyName());
-    assertTrue(remoteBlob.getKmsKeyName().startsWith(kmsKeyOneResourcePath));
+    assertTrue(remoteBlob.getKmsKeyName().startsWith(kms.getKey1().getName()));
     byte[] readBytes = storage.readAllBytes(bucketName, blobName);
     assertArrayEquals(BLOB_BYTE_CONTENT, readBytes);
   }
@@ -345,21 +143,19 @@ public class ITKmsTest {
         blob,
         BLOB_BYTE_CONTENT,
         Storage.BlobTargetOption.encryptionKey(KEY),
-        Storage.BlobTargetOption.kmsKeyName(kmsKeyOneResourcePath));
+        Storage.BlobTargetOption.kmsKeyName(kms.getKey1().getName()));
   }
 
   @Test
   public void testCreateBlobWithDefaultKmsKeyName() {
     String bucketName = generator.randomBucketName();
-    // TODO: replace with storage
-    // b/246634709
     Bucket bucket =
         storage.create(
             BucketInfo.newBuilder(bucketName)
-                .setDefaultKmsKeyName(kmsKeyOneResourcePath)
-                .setLocation(KMS_KEY_RING_LOCATION)
+                .setDefaultKmsKeyName(kms.getKey1().getName())
+                .setLocation(kms.getKeyRingLocation())
                 .build());
-    assertEquals(bucket.getDefaultKmsKeyName(), kmsKeyOneResourcePath);
+    assertEquals(bucket.getDefaultKmsKeyName(), kms.getKey1().getName());
 
     try {
       String blobName = "test-create-with-default-kms-key-name-blob";
@@ -369,7 +165,7 @@ public class ITKmsTest {
       assertEquals(blob.getBucket(), remoteBlob.getBucket());
       assertEquals(blob.getName(), remoteBlob.getName());
       assertNotNull(remoteBlob.getKmsKeyName());
-      assertTrue(remoteBlob.getKmsKeyName().startsWith(kmsKeyOneResourcePath));
+      assertTrue(remoteBlob.getKmsKeyName().startsWith(kms.getKey1().getName()));
       byte[] readBytes = storage.readAllBytes(bucketName, blobName);
       assertArrayEquals(BLOB_BYTE_CONTENT, readBytes);
     } finally {
@@ -381,11 +177,12 @@ public class ITKmsTest {
   public void testGetBlobKmsKeyNameField() {
     String blobName = "test-get-selected-kms-key-name-field-blob";
     BlobInfo blob = BlobInfo.newBuilder(bucket, blobName).setContentType(CONTENT_TYPE).build();
-    assertNotNull(storage.create(blob, Storage.BlobTargetOption.kmsKeyName(kmsKeyOneResourcePath)));
+    assertNotNull(
+        storage.create(blob, Storage.BlobTargetOption.kmsKeyName(kms.getKey1().getName())));
     Blob remoteBlob =
         storage.get(blob.getBlobId(), Storage.BlobGetOption.fields(BlobField.KMS_KEY_NAME));
     assertEquals(blob.getBlobId(), remoteBlob.getBlobId());
-    assertTrue(remoteBlob.getKmsKeyName().startsWith(kmsKeyOneResourcePath));
+    assertTrue(remoteBlob.getKmsKeyName().startsWith(kms.getKey1().getName()));
     assertNull(remoteBlob.getContentType());
   }
 
@@ -398,9 +195,9 @@ public class ITKmsTest {
     BlobInfo blob1 = BlobInfo.newBuilder(bucket, blobNames[0]).setContentType(CONTENT_TYPE).build();
     BlobInfo blob2 = BlobInfo.newBuilder(bucket, blobNames[1]).setContentType(CONTENT_TYPE).build();
     Blob remoteBlob1 =
-        storage.create(blob1, Storage.BlobTargetOption.kmsKeyName(kmsKeyOneResourcePath));
+        storage.create(blob1, Storage.BlobTargetOption.kmsKeyName(kms.getKey1().getName()));
     Blob remoteBlob2 =
-        storage.create(blob2, Storage.BlobTargetOption.kmsKeyName(kmsKeyOneResourcePath));
+        storage.create(blob2, Storage.BlobTargetOption.kmsKeyName(kms.getKey1().getName()));
     assertNotNull(remoteBlob1);
     assertNotNull(remoteBlob2);
     Page<Blob> page =
@@ -424,7 +221,7 @@ public class ITKmsTest {
       Blob remoteBlob = iterator.next();
       assertEquals(bucket.getName(), remoteBlob.getBucket());
       assertTrue(blobSet.contains(remoteBlob.getName()));
-      assertTrue(remoteBlob.getKmsKeyName().startsWith(kmsKeyOneResourcePath));
+      assertTrue(remoteBlob.getKmsKeyName().startsWith(kms.getKey1().getName()));
       assertNull(remoteBlob.getContentType());
     }
   }
@@ -450,14 +247,14 @@ public class ITKmsTest {
         Storage.CopyRequest.newBuilder()
             .setSource(source)
             .setSourceOptions(Storage.BlobSourceOption.decryptionKey(BASE64_KEY))
-            .setTarget(target, Storage.BlobTargetOption.kmsKeyName(kmsKeyOneResourcePath))
+            .setTarget(target, Storage.BlobTargetOption.kmsKeyName(kms.getKey1().getName()))
             .build();
     CopyWriter copyWriter = storage.copy(req);
     assertEquals(bucket.getName(), copyWriter.getResult().getBucket());
     assertEquals(targetBlobName, copyWriter.getResult().getName());
     assertEquals(CONTENT_TYPE, copyWriter.getResult().getContentType());
     assertNotNull(copyWriter.getResult().getKmsKeyName());
-    assertTrue(copyWriter.getResult().getKmsKeyName().startsWith(kmsKeyOneResourcePath));
+    assertTrue(copyWriter.getResult().getKmsKeyName().startsWith(kms.getKey1().getName()));
     assertArrayEquals(BLOB_BYTE_CONTENT, copyWriter.getResult().getContent());
     assertEquals(metadata, copyWriter.getResult().getMetadata());
     assertTrue(copyWriter.isDone());
@@ -488,60 +285,18 @@ public class ITKmsTest {
             .setTarget(
                 target,
                 Storage.BlobTargetOption.encryptionKey(KEY),
-                Storage.BlobTargetOption.kmsKeyName(kmsKeyOneResourcePath))
+                Storage.BlobTargetOption.kmsKeyName(kms.getKey1().getName()))
             .build();
     storage.copy(req);
   }
 
-  @Test
-  public void testListBucketDefaultKmsKeyName() throws InterruptedException {
-    String bucketName = generator.randomBucketName();
-    // TODO: replace with storage
-    // b/246634709
-    Bucket remoteBucket =
-        storage.create(
-            BucketInfo.newBuilder(bucketName)
-                .setDefaultKmsKeyName(kmsKeyOneResourcePath)
-                .setLocation(KMS_KEY_RING_LOCATION)
-                .build());
-    assertNotNull(remoteBucket);
-    assertTrue(remoteBucket.getDefaultKmsKeyName().startsWith(kmsKeyOneResourcePath));
-    try {
-      Iterator<Bucket> bucketIterator =
-          storage
-              .list(
-                  Storage.BucketListOption.prefix(bucketName),
-                  Storage.BucketListOption.fields(BucketField.ENCRYPTION))
-              .iterateAll()
-              .iterator();
-      while (!bucketIterator.hasNext()) {
-        Thread.sleep(500);
-        bucketIterator =
-            storage
-                .list(
-                    Storage.BucketListOption.prefix(bucketName),
-                    Storage.BucketListOption.fields(BucketField.ENCRYPTION))
-                .iterateAll()
-                .iterator();
-      }
-      while (bucketIterator.hasNext()) {
-        Bucket bucket = bucketIterator.next();
-        assertTrue(bucket.getName().startsWith(bucketName));
-        assertNotNull(bucket.getDefaultKmsKeyName());
-        assertTrue(bucket.getDefaultKmsKeyName().startsWith(kmsKeyOneResourcePath));
-      }
-    } finally {
-      BucketCleaner.doCleanup(bucketName, storage);
-    }
-  }
-
   @Test
   public void testWriterWithKmsKeyName() throws IOException {
     // Write an empty object with a kmsKeyName.
     String blobName = "test-empty-blob";
     BlobInfo blobInfo = BlobInfo.newBuilder(bucket, blobName).build();
     Blob blob =
-        storage.create(blobInfo, Storage.BlobTargetOption.kmsKeyName(kmsKeyOneResourcePath));
+        storage.create(blobInfo, Storage.BlobTargetOption.kmsKeyName(kms.getKey1().getName()));
 
     // Create a writer using blob that already has metadata received from Storage API.
     int numberOfBytes;
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/runner/registry/BackendResources.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/runner/registry/BackendResources.java
index 59699b8c..3f37bb3c 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/runner/registry/BackendResources.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/runner/registry/BackendResources.java
@@ -46,7 +46,8 @@ final class BackendResources implements ManagedLifecycle {
       TestRunScopedInstance<StorageInstance> storageGrpc,
       TestRunScopedInstance<BucketInfoShim> bucket,
       TestRunScopedInstance<BucketInfoShim> bucketRequesterPays,
-      TestRunScopedInstance<ObjectsFixture> objectsFixture) {
+      TestRunScopedInstance<ObjectsFixture> objectsFixture,
+      TestRunScopedInstance<KmsFixture> kmsFixture) {
     this.backend = backend;
     this.protectedBucketNames = protectedBucketNames;
     this.registryEntries =
@@ -62,7 +63,8 @@ final class BackendResources implements ManagedLifecycle {
                 backendIs(backend).and(isRequesterPaysBucket())),
             RegistryEntry.of(
                 7, BucketInfo.class, bucket, backendIs(backend).and(isDefaultBucket())),
-            RegistryEntry.of(8, ObjectsFixture.class, objectsFixture, backendIs(backend)));
+            RegistryEntry.of(8, ObjectsFixture.class, objectsFixture, backendIs(backend)),
+            RegistryEntry.of(9, KmsFixture.class, kmsFixture, backendIs(backend)));
   }
 
   public ImmutableList<RegistryEntry<?>> getRegistryEntries() {
@@ -139,8 +141,18 @@ final class BackendResources implements ManagedLifecycle {
         TestRunScopedInstance.of(
             "OBJECTS_FIXTURE_" + backend.name(),
             () -> new ObjectsFixture(storageJson.get().getStorage(), bucket.get().getBucketInfo()));
+    TestRunScopedInstance<KmsFixture> kmsFixture =
+        TestRunScopedInstance.of(
+            "KMS_FIXTURE_" + backend.name(), () -> KmsFixture.of(storageJson.get().getStorage()));
 
     return new BackendResources(
-        backend, protectedBucketNames, storageJson, storageGrpc, bucket, bucketRp, objectsFixture);
+        backend,
+        protectedBucketNames,
+        storageJson,
+        storageGrpc,
+        bucket,
+        bucketRp,
+        objectsFixture,
+        kmsFixture);
   }
 }
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/runner/registry/KmsFixture.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/runner/registry/KmsFixture.java
new file mode 100644
index 00000000..e7099da0
--- /dev/null
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/runner/registry/KmsFixture.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.storage.it.runner.registry;
+
+import com.google.api.gax.rpc.NotFoundException;
+import com.google.cloud.kms.v1.CreateCryptoKeyRequest;
+import com.google.cloud.kms.v1.CreateKeyRingRequest;
+import com.google.cloud.kms.v1.CryptoKey;
+import com.google.cloud.kms.v1.CryptoKey.CryptoKeyPurpose;
+import com.google.cloud.kms.v1.CryptoKeyName;
+import com.google.cloud.kms.v1.CryptoKeyVersion.CryptoKeyVersionAlgorithm;
+import com.google.cloud.kms.v1.CryptoKeyVersionTemplate;
+import com.google.cloud.kms.v1.KeyManagementServiceClient;
+import com.google.cloud.kms.v1.KeyRing;
+import com.google.cloud.kms.v1.KeyRingName;
+import com.google.cloud.kms.v1.LocationName;
+import com.google.cloud.storage.ServiceAccount;
+import com.google.cloud.storage.Storage;
+import com.google.iam.v1.Binding;
+import com.google.iam.v1.Policy;
+import com.google.iam.v1.SetIamPolicyRequest;
+import io.grpc.StatusRuntimeException;
+import java.io.IOException;
+
+public class KmsFixture implements ManagedLifecycle {
+
+  private final Storage storage;
+  private final String keyRingLocation;
+  private final String keyRingName;
+  private final String key1Name;
+  private final String key2Name;
+
+  private KeyRing keyRing;
+  private CryptoKey key1;
+  private CryptoKey key2;
+
+  private KmsFixture(
+      Storage storage,
+      String keyRingLocation,
+      String keyRingName,
+      String key1Name,
+      String key2Name) {
+    this.storage = storage;
+    this.keyRingLocation = keyRingLocation;
+    this.keyRingName = keyRingName;
+    this.key1Name = key1Name;
+    this.key2Name = key2Name;
+  }
+
+  public String getKeyRingLocation() {
+    return keyRingLocation;
+  }
+
+  public KeyRing getKeyRing() {
+    return keyRing;
+  }
+
+  public CryptoKey getKey1() {
+    return key1;
+  }
+
+  public CryptoKey getKey2() {
+    return key2;
+  }
+
+  @Override
+  public Object get() {
+    return this;
+  }
+
+  @Override
+  public void start() {
+    try (KeyManagementServiceClient kms = KeyManagementServiceClient.create()) {
+      keyRing = resolveKeyRing(kms);
+      Policy ignore = grantStorageServiceAccountRolesToKeyRing(kms);
+      key1 = resolveKey(kms, key1Name);
+      key2 = resolveKey(kms, key2Name);
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  @Override
+  public void stop() {
+    // KMS prevents key and ring deletion, https://cloud.google.com/kms/docs/faq#cannot_delete
+  }
+
+  static KmsFixture of(Storage s) {
+    // KMS prevents key and ring deletion, https://cloud.google.com/kms/docs/faq#cannot_delete
+    // therefore we instead prefer stable names to not blow out the number of keys and rings
+    // in a project.
+    return new KmsFixture(s, "us", "gcs_test_kms_key_ring", "gcs_kms_key_one", "gcs_kms_key_two");
+  }
+
+  private KeyRing resolveKeyRing(KeyManagementServiceClient kms) throws StatusRuntimeException {
+    String projectId = storage.getOptions().getProjectId();
+    KeyRingName ringName = KeyRingName.of(projectId, keyRingLocation, keyRingName);
+    try {
+      return kms.getKeyRing(ringName.toString());
+    } catch (NotFoundException ex) {
+      CreateKeyRingRequest req =
+          CreateKeyRingRequest.newBuilder()
+              .setParent(LocationName.of(projectId, keyRingLocation).toString())
+              .setKeyRingId(keyRingName)
+              .setKeyRing(KeyRing.newBuilder().build())
+              .build();
+      System.out.println("req = " + req);
+      return kms.createKeyRing(req);
+    }
+  }
+
+  private Policy grantStorageServiceAccountRolesToKeyRing(KeyManagementServiceClient kms) {
+    String projectId = storage.getOptions().getProjectId();
+    ServiceAccount serviceAccount = storage.getServiceAccount(projectId);
+    Binding binding =
+        Binding.newBuilder()
+            .setRole("roles/cloudkms.cryptoKeyEncrypterDecrypter")
+            .addMembers("serviceAccount:" + serviceAccount.getEmail())
+            .build();
+    SetIamPolicyRequest setIamPolicyRequest =
+        SetIamPolicyRequest.newBuilder()
+            .setResource(keyRing.getName())
+            .setPolicy(Policy.newBuilder().addBindings(binding).build())
+            .build();
+
+    return kms.setIamPolicy(setIamPolicyRequest);
+  }
+
+  private CryptoKey resolveKey(KeyManagementServiceClient kms, String keyName) {
+    CryptoKeyName cryptoKeyName = cryptoKeyNameOnRing(keyRing, keyName);
+    try {
+      return kms.getCryptoKey(cryptoKeyName);
+    } catch (NotFoundException ex) {
+      CreateCryptoKeyRequest req =
+          CreateCryptoKeyRequest.newBuilder()
+              .setParent(keyRing.getName())
+              .setCryptoKeyId(keyName)
+              .setCryptoKey(
+                  CryptoKey.newBuilder()
+                      .setPurpose(CryptoKeyPurpose.ENCRYPT_DECRYPT)
+                      .setVersionTemplate(
+                          CryptoKeyVersionTemplate.newBuilder()
+                              .setAlgorithm(CryptoKeyVersionAlgorithm.GOOGLE_SYMMETRIC_ENCRYPTION)))
+              .build();
+      return kms.createCryptoKey(req);
+    }
+  }
+
+  private static CryptoKeyName cryptoKeyNameOnRing(KeyRing keyRing, String keyName) {
+    KeyRingName krn = KeyRingName.parse(keyRing.getName());
+    return CryptoKeyName.of(krn.getProject(), krn.getLocation(), krn.getKeyRing(), keyName);
+  }
+}