From 5f358a53a92fa0dcd83a7dc38feeeb399a3bb18b Mon Sep 17 00:00:00 2001 From: Jerjou Cheng Date: Fri, 27 Jan 2017 17:46:06 -0800 Subject: [PATCH] KMS samples. --- kms/README.md | 25 + kms/pom.xml | 79 +++ kms/src/main/java/com/example/CryptFile.java | 119 +++++ .../java/com/example/CryptFileCommands.java | 91 ++++ kms/src/main/java/com/example/Quickstart.java | 85 ++++ .../java/com/example/SnippetCommands.java | 191 +++++++ kms/src/main/java/com/example/Snippets.java | 467 ++++++++++++++++++ 7 files changed, 1057 insertions(+) create mode 100644 kms/README.md create mode 100644 kms/pom.xml create mode 100644 kms/src/main/java/com/example/CryptFile.java create mode 100644 kms/src/main/java/com/example/CryptFileCommands.java create mode 100644 kms/src/main/java/com/example/Quickstart.java create mode 100644 kms/src/main/java/com/example/SnippetCommands.java create mode 100644 kms/src/main/java/com/example/Snippets.java diff --git a/kms/README.md b/kms/README.md new file mode 100644 index 00000000000..1dc34684e28 --- /dev/null +++ b/kms/README.md @@ -0,0 +1,25 @@ +# Cloud Key Management Service + +Google [Cloud Key Management Service](https://cloud.google.com/kms/) is a +cloud-hosted key management service that lets you manage encryption for your +cloud services the same way you do on-premise. You can generate, use, rotate and +destroy AES256 encryption keys. These sample Java applications demonstrate +how to access the KMS API using the Google Java API Client Libraries. + +## Quickstart + +Install [Maven](http://maven.apache.org/). + +Build your project with: + + mvn clean compile assembly:single + +You can run the quickstart with: + + java -cp target/kms-samples-1.0.0-jar-with-dependencies.jar \ + com.example.Quickstart [your-project-id] + +and can see the available snippet commands with: + + java -cp target/kms-samples-1.0.0-jar-with-dependencies.jar \ + com.example.Snippets diff --git a/kms/pom.xml b/kms/pom.xml new file mode 100644 index 00000000000..059eb14d0a8 --- /dev/null +++ b/kms/pom.xml @@ -0,0 +1,79 @@ + + 4.0.0 + com.google.cloud.kms.samples + kms-samples + jar + + + doc-samples + com.google.cloud + 1.0.0 + .. + + + + + com.google.apis + google-api-services-cloudkms + v1beta1-rev51-1.18.0-rc + + + com.google.api-client + google-api-client + 1.22.0 + + + com.google.http-client + google-http-client-jackson2 + 1.22.0 + + + args4j + args4j + 2.33 + + + + + junit + junit + 4.12 + test + + + com.google.truth + truth + 0.31 + test + + + + + UTF-8 + + + + src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + 5 + 5 + + + + maven-assembly-plugin + + + jar-with-dependencies + + + + + + + diff --git a/kms/src/main/java/com/example/CryptFile.java b/kms/src/main/java/com/example/CryptFile.java new file mode 100644 index 00000000000..08c2d0914af --- /dev/null +++ b/kms/src/main/java/com/example/CryptFile.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * 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.example; + +import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.JsonFactory; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.services.cloudkms.v1beta1.CloudKMS; +import com.google.api.services.cloudkms.v1beta1.CloudKMSScopes; +import com.google.api.services.cloudkms.v1beta1.model.DecryptRequest; +import com.google.api.services.cloudkms.v1beta1.model.DecryptResponse; +import com.google.api.services.cloudkms.v1beta1.model.EncryptRequest; +import com.google.api.services.cloudkms.v1beta1.model.EncryptResponse; + +import org.kohsuke.args4j.CmdLineException; +import org.kohsuke.args4j.CmdLineParser; + +import java.io.IOException; + +public class CryptFile { + + /** + * Creates an authorized CloudKMS client service using Application Default Credentials. + * + * @return an authorized CloudKMS client + * @throws IOException if there's an error getting the default credentials. + */ + public static CloudKMS createAuthorizedClient() throws IOException { + // Create the credential + HttpTransport transport = new NetHttpTransport(); + JsonFactory jsonFactory = new JacksonFactory(); + // Authorize the client using Application Default Credentials + // @see https://g.co/dv/identity/protocols/application-default-credentials + GoogleCredential credential = GoogleCredential.getApplicationDefault(transport, jsonFactory); + + // Depending on the environment that provides the default credentials (e.g. Compute Engine, App + // Engine), the credentials may require us to specify the scopes we need explicitly. + // Check for this case, and inject the scope if required. + if (credential.createScopedRequired()) { + credential = credential.createScoped(CloudKMSScopes.all()); + } + + return new CloudKMS.Builder(transport, jsonFactory, credential) + .setApplicationName("CloudKMS CryptFile") + .build(); + } + + /** + * Encrypts the given bytes, using the specified crypto key. + */ + public static byte[] encrypt(String projectId, String ringId, String keyId, byte[] plaintext) + throws IOException { + String location = "global"; + // The resource name of the cryptoKey + String cryptoKeyName = String.format( + "projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", + projectId, location, ringId, keyId); + // Create the Cloud KMS client. + CloudKMS kms = createAuthorizedClient(); + + EncryptRequest request = new EncryptRequest().encodePlaintext(plaintext); + EncryptResponse response = kms.projects().locations().keyRings().cryptoKeys() + .encrypt(cryptoKeyName, request) + .execute(); + + return response.decodeCiphertext(); + } + + /** + * Decrypts the given encrypted bytes, using the specified crypto key. + */ + public static byte[] decrypt(String projectId, String ringId, String keyId, byte[] encrypted) + throws IOException { + String location = "global"; + // Create the Cloud KMS client. + CloudKMS kms = createAuthorizedClient(); + + // The resource name of the cryptoKey + String cryptoKeyName = String.format( + "projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", + projectId, location, ringId, keyId); + + DecryptRequest request = new DecryptRequest().encodeCiphertext(encrypted); + DecryptResponse response = kms.projects().locations().keyRings().cryptoKeys() + .decrypt(cryptoKeyName, request) + .execute(); + + return response.decodePlaintext(); + } + + public static void main(String[] args) throws IOException { + CryptFileCommands commands = new CryptFileCommands(); + CmdLineParser parser = new CmdLineParser(commands); + + try { + parser.parseArgument(args); + } catch (CmdLineException e) { + System.out.println(e); + System.out.println(); + e.getParser().printUsage(System.out); + System.exit(1); + } + commands.command.run(); + } +} diff --git a/kms/src/main/java/com/example/CryptFileCommands.java b/kms/src/main/java/com/example/CryptFileCommands.java new file mode 100644 index 00000000000..db3cfad674e --- /dev/null +++ b/kms/src/main/java/com/example/CryptFileCommands.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * 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.example; + +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; +import org.kohsuke.args4j.spi.SubCommand; +import org.kohsuke.args4j.spi.SubCommandHandler; +import org.kohsuke.args4j.spi.SubCommands; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; + +/** + * Defines the different sub-commands and their parameters, for command-line invocation. + */ +class CryptFileCommands { + /** + * An interface for a command-line sub-command. + */ + interface Command { + public void run() throws IOException; + } + + // Most of the commands take some subset of the same arguments, so specify groups of arguments + // as classes for greater code reuse. + static class Args { + @Option(name = "--project-id", aliases = "-p", required = true, usage = "Your GCP project ID") + String projectId; + @Argument(metaVar = "ringId", required = true, index = 0, usage = "The ring id") + String ringId; + @Argument(metaVar = "keyId", required = true, index = 1, usage = "The key id") + String keyId; + @Argument(metaVar = "inFile", required = true, index = 1, usage = "The source file") + String inFile; + @Argument(metaVar = "outFile", required = true, index = 1, usage = "The destination file") + String outFile; + } + + public static class EncryptCommand extends Args implements Command { + public void run() throws IOException { + byte[] encrypted = CryptFile.encrypt( + projectId, ringId, keyId, + Files.readAllBytes(Paths.get(inFile))); + + FileOutputStream stream = new FileOutputStream(outFile); + try { + stream.write(encrypted); + } finally { + stream.close(); + } + } + } + + public static class DecryptCommand extends Args implements Command { + public void run() throws IOException { + byte[] decrypted = CryptFile.decrypt( + projectId, ringId, keyId, + Files.readAllBytes(Paths.get(inFile))); + + FileOutputStream stream = new FileOutputStream(outFile); + try { + stream.write(decrypted); + } finally { + stream.close(); + } + } + } + + @Argument(metaVar = "command", required = true, handler = SubCommandHandler.class, + usage = "The subcommand to run") + @SubCommands({ + @SubCommand(name = "encrypt", impl = EncryptCommand.class), + @SubCommand(name = "decrypt", impl = DecryptCommand.class) + }) + Command command; +} diff --git a/kms/src/main/java/com/example/Quickstart.java b/kms/src/main/java/com/example/Quickstart.java new file mode 100644 index 00000000000..69abd5b0597 --- /dev/null +++ b/kms/src/main/java/com/example/Quickstart.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * 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.example; + +import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.JsonFactory; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.services.cloudkms.v1beta1.CloudKMS; +import com.google.api.services.cloudkms.v1beta1.CloudKMSScopes; +import com.google.api.services.cloudkms.v1beta1.model.KeyRing; +import com.google.api.services.cloudkms.v1beta1.model.ListKeyRingsResponse; + +import java.io.IOException; + +// [START kms_quickstart] +public class Quickstart { + /** + * Creates an authorized CloudKMS client service using Application Default Credentials. + * + * @return an authorized CloudKMS client + * @throws IOException if there's an error getting the default credentials. + */ + public static CloudKMS createAuthorizedClient() throws IOException { + // Create the credential + HttpTransport transport = new NetHttpTransport(); + JsonFactory jsonFactory = new JacksonFactory(); + // Authorize the client using Application Default Credentials + // @see https://g.co/dv/identity/protocols/application-default-credentials + GoogleCredential credential = GoogleCredential.getApplicationDefault(transport, jsonFactory); + + // Depending on the environment that provides the default credentials (e.g. Compute Engine, App + // Engine), the credentials may require us to specify the scopes we need explicitly. + // Check for this case, and inject the scope if required. + if (credential.createScopedRequired()) { + credential = credential.createScoped(CloudKMSScopes.all()); + } + + return new CloudKMS.Builder(transport, jsonFactory, credential) + .setApplicationName("CloudKMS quickstart") + .build(); + } + + public static void main(String... args) throws IOException { + if (args.length != 1) { + System.err.println("Usage: Quickstart "); + System.exit(1); + } + + // Your Google Cloud Platform project ID + String projectId = args[0]; + + // Lists keys in the "global" location. + String location = "global"; + // The resource name of the location associated with the KeyRings + String parent = String.format("projects/%s/locations/%s", projectId, location); + // Instantiate the client + CloudKMS kms = createAuthorizedClient(); + // list all key rings for your project + ListKeyRingsResponse response = kms.projects().locations().keyRings().list(parent).execute(); + // Print the key rings + System.out.println("Key Rings: "); + if (null != response.getKeyRings()) { + for (KeyRing keyRing : response.getKeyRings()) { + System.out.println(keyRing.getName()); + } + } else { + System.out.println("No keyrings defined."); + } + } +} +// [END kms_quickstart] diff --git a/kms/src/main/java/com/example/SnippetCommands.java b/kms/src/main/java/com/example/SnippetCommands.java new file mode 100644 index 00000000000..e872b79b8e6 --- /dev/null +++ b/kms/src/main/java/com/example/SnippetCommands.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * 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.example; + +import org.kohsuke.args4j.Argument; +import org.kohsuke.args4j.Option; +import org.kohsuke.args4j.spi.SubCommand; +import org.kohsuke.args4j.spi.SubCommandHandler; +import org.kohsuke.args4j.spi.SubCommands; + +import java.io.IOException; + +/** + * Defines the different sub-commands and their parameters, for command-line invocation. + */ +class SnippetCommands { + /** + * An interface for a command-line sub-command. + */ + interface Command { + public void run() throws IOException; + } + + // Most of the commands take some subset of the same arguments, so specify groups of arguments + // as classes for greater code reuse. + static class ProjectIdArgs { + @Option(name = "--project-id", aliases = "-p", required = true, usage = "Your GCP project ID") + String projectId; + } + + static class KeyRingArgs extends ProjectIdArgs { + @Argument(metaVar = "ringId", required = true, index = 0, usage = "The ring id") + String ringId; + } + + static class KeyArgs extends KeyRingArgs { + @Argument(metaVar = "keyId", required = true, index = 1, usage = "The key id") + String keyId; + } + + static class KeyVersionArgs extends KeyArgs { + @Argument(metaVar = "version", required = true, index = 2, usage = "The key version") + String version; + } + + + public static class CreateKeyRingCommand extends KeyRingArgs implements Command { + public void run() throws IOException { + Snippets.createKeyRing(projectId, ringId); + } + } + + public static class CreateCryptoKeyCommand extends KeyArgs implements Command { + public void run() throws IOException { + Snippets.createCryptoKey(projectId, ringId, keyId); + } + } + + public static class ListCryptoKeysCommand extends KeyRingArgs implements Command { + public void run() throws IOException { + Snippets.listCryptoKeys(projectId, ringId); + } + } + + public static class ListCryptoKeyVersionsCommand extends KeyArgs implements Command { + public void run() throws IOException { + Snippets.listCryptoKeyVersions(projectId, ringId, keyId); + } + } + + public static class DisableCryptoKeyVersionCommand extends KeyVersionArgs implements Command { + public void run() throws IOException { + Snippets.disableCryptoKeyVersion(projectId, ringId, keyId, version); + } + } + + public static class DestroyCryptoKeyVersionCommand extends KeyVersionArgs implements Command { + public void run() throws IOException { + Snippets.destroyCryptoKeyVersion(projectId, ringId, keyId, version); + } + } + + public static class GetKeyRingPolicyCommand extends KeyRingArgs implements Command { + public void run() throws IOException { + Snippets.getKeyRingPolicy(projectId, ringId); + } + } + + public static class GetCryptoKeyPolicyCommand extends KeyArgs implements Command { + public void run() throws IOException { + Snippets.getCryptoKeyPolicy(projectId, ringId, keyId); + } + } + + public static class AddMemberToKeyRingPolicyCommand extends KeyRingArgs implements Command { + @Argument(metaVar = "member", required = true, index = 1, + usage = "The member to add.\n" + + "See https://g.co/cloud/kms/docs/reference/rest/v1beta1/Policy#binding " + + "for valid values.") + String member; + @Argument(metaVar = "role", required = true, index = 2, + usage = "The role for the member.\n" + + "See https://g.co/cloud/iam/docs/understanding-roles for valid values.") + String role; + + public void run() throws IOException { + Snippets.addMemberToKeyRingPolicy(projectId, ringId, member, role); + } + } + + public static class AddMemberToCryptoKeyPolicyCommand extends KeyArgs implements Command { + @Argument(metaVar = "member", required = true, index = 2, + usage = "The member to add.\n" + + "See https://g.co/cloud/kms/docs/reference/rest/v1beta1/Policy#binding " + + "for valid values.") + String member; + @Argument(metaVar = "role", required = true, index = 3, + usage = "The role for the member.\n" + + "See https://g.co/cloud/iam/docs/understanding-roles for valid values.") + String role; + + public void run() throws IOException { + Snippets.addMemberToCryptoKeyPolicy(projectId, ringId, keyId, member, role); + } + } + + public static class RemoveMemberFromKeyRingPolicyCommand extends KeyRingArgs implements Command { + @Argument(metaVar = "member", required = true, index = 1, + usage = "The member to add.\n" + + "See https://g.co/cloud/kms/docs/reference/rest/v1beta1/Policy#binding " + + "for valid values.") + String member; + @Argument(metaVar = "role", required = true, index = 2, + usage = "The role for the member.\n" + + "See https://g.co/cloud/iam/docs/understanding-roles for valid values.") + String role; + + public void run() throws IOException { + Snippets.removeMemberFromKeyRingPolicy(projectId, ringId, member, role); + } + } + + public static class RemoveMemberFromCryptoKeyPolicyCommand extends KeyArgs implements Command { + @Argument(metaVar = "member", required = true, index = 2, + usage = "The member to add.\n" + + "See https://g.co/cloud/kms/docs/reference/rest/v1beta1/Policy#binding " + + "for valid values.") + String member; + @Argument(metaVar = "role", required = true, index = 3, + usage = "The role for the member.\n" + + "See https://g.co/cloud/iam/docs/understanding-roles for valid values.") + String role; + + public void run() throws IOException { + Snippets.removeMemberFromCryptoKeyPolicy(projectId, ringId, keyId, member, role); + } + } + + @Argument(metaVar = "command", required = true, handler = SubCommandHandler.class, + usage = "The subcommand to run") + @SubCommands({ + @SubCommand(name = "createKeyRing", impl = CreateKeyRingCommand.class), + @SubCommand(name = "createCryptoKey", impl = CreateCryptoKeyCommand.class), + @SubCommand(name = "listCryptoKeys", impl = ListCryptoKeysCommand.class), + @SubCommand(name = "listCryptoKeyVersions", impl = ListCryptoKeyVersionsCommand.class), + @SubCommand(name = "disableCryptoKeyVersion", impl = DisableCryptoKeyVersionCommand.class), + @SubCommand(name = "destroyCryptoKeyVersion", impl = DestroyCryptoKeyVersionCommand.class), + @SubCommand(name = "getKeyRingPolicy", impl = GetKeyRingPolicyCommand.class), + @SubCommand(name = "getCryptoKeyPolicy", impl = GetCryptoKeyPolicyCommand.class), + @SubCommand(name = "addMemberToKeyRingPolicy", impl = AddMemberToKeyRingPolicyCommand.class), + @SubCommand(name = "addMemberToCryptoKeyPolicy", + impl = AddMemberToCryptoKeyPolicyCommand.class), + @SubCommand(name = "removeMemberFromKeyRingPolicy", + impl = RemoveMemberFromKeyRingPolicyCommand.class), + @SubCommand(name = "removeMemberFromCryptoKeyPolicy", + impl = RemoveMemberFromCryptoKeyPolicyCommand.class) + }) + Command command; +} diff --git a/kms/src/main/java/com/example/Snippets.java b/kms/src/main/java/com/example/Snippets.java new file mode 100644 index 00000000000..2b6f486ec73 --- /dev/null +++ b/kms/src/main/java/com/example/Snippets.java @@ -0,0 +1,467 @@ +/* + * Copyright (c) 2017 Google Inc. + * + * 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.example; + +import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; +import com.google.api.client.http.HttpTransport; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.JsonFactory; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.api.services.cloudkms.v1beta1.CloudKMS; +import com.google.api.services.cloudkms.v1beta1.CloudKMSScopes; +import com.google.api.services.cloudkms.v1beta1.model.Binding; +import com.google.api.services.cloudkms.v1beta1.model.CryptoKey; +import com.google.api.services.cloudkms.v1beta1.model.CryptoKeyVersion; +import com.google.api.services.cloudkms.v1beta1.model.DestroyCryptoKeyVersionRequest; +import com.google.api.services.cloudkms.v1beta1.model.KeyRing; +import com.google.api.services.cloudkms.v1beta1.model.ListCryptoKeyVersionsResponse; +import com.google.api.services.cloudkms.v1beta1.model.ListCryptoKeysResponse; +import com.google.api.services.cloudkms.v1beta1.model.Policy; +import com.google.api.services.cloudkms.v1beta1.model.SetIamPolicyRequest; + +import org.kohsuke.args4j.CmdLineException; +import org.kohsuke.args4j.CmdLineParser; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +public class Snippets { + + /** + * Creates an authorized CloudKMS client service using Application Default Credentials. + * + * @return an authorized CloudKMS client + * @throws IOException if there's an error getting the default credentials. + */ + public static CloudKMS createAuthorizedClient() throws IOException { + // Create the credential + HttpTransport transport = new NetHttpTransport(); + JsonFactory jsonFactory = new JacksonFactory(); + // Authorize the client using Application Default Credentials + // @see https://g.co/dv/identity/protocols/application-default-credentials + GoogleCredential credential = GoogleCredential.getApplicationDefault(transport, jsonFactory); + + // Depending on the environment that provides the default credentials (e.g. Compute Engine, App + // Engine), the credentials may require us to specify the scopes we need explicitly. + // Check for this case, and inject the scope if required. + if (credential.createScopedRequired()) { + credential = credential.createScoped(CloudKMSScopes.all()); + } + + return new CloudKMS.Builder(transport, jsonFactory, credential) + .setApplicationName("CloudKMS snippets") + .build(); + } + + /** + * Creates a new key ring with the given id. + */ + public static KeyRing createKeyRing(String projectId, String ringId) throws IOException { + String location = "global"; + // Create the Cloud KMS client. + CloudKMS kms = createAuthorizedClient(); + + // The resource name of the location associated with the KeyRing. + String parent = String.format("projects/%s/locations/%s", projectId, location); + // Create the KeyRing for your project. + KeyRing keyring = kms.projects().locations().keyRings() + .create(parent, new KeyRing()) + .setKeyRingId(ringId) + .execute(); + + System.out.println(keyring); + return keyring; + } + + /** + * Creates a new crypto key with the given id. + */ + public static CryptoKey createCryptoKey(String projectId, String ringId, String keyId) + throws IOException { + String location = "global"; + // Create the Cloud KMS client. + CloudKMS kms = createAuthorizedClient(); + + // The resource name of the location associated with the KeyRing. + String parent = String.format( + "projects/%s/locations/%s/keyRings/%s", projectId, location, ringId); + + // This will allow the API access to the key for encryption and decryption. + String purpose = "ENCRYPT_DECRYPT"; + CryptoKey cryptoKey = new CryptoKey(); + cryptoKey.setPurpose(purpose); + + // Create the CryptoKey for your project. + CryptoKey createdKey = kms.projects().locations().keyRings().cryptoKeys() + .create(parent, cryptoKey) + .setCryptoKeyId(keyId) + .execute(); + + System.out.println(createdKey); + return createdKey; + } + + /** + * Disables the given version of the crypto key. + */ + public static CryptoKeyVersion disableCryptoKeyVersion( + String projectId, String ringId, String keyId, String version) + throws IOException { + String location = "global"; + // Create the Cloud KMS client. + CloudKMS kms = createAuthorizedClient(); + + // The resource name of the cryptoKey version + String cryptoKeyVersion = String.format( + "projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s", + projectId, location, ringId, keyId, version); + + CryptoKeyVersion newVersionState = new CryptoKeyVersion() + .setState("DISABLED"); + + CryptoKeyVersion response = kms.projects().locations().keyRings().cryptoKeys() + .cryptoKeyVersions() + .patch(cryptoKeyVersion, newVersionState) + .setUpdateMask("state") + .execute(); + + System.out.println(response); + return response; + } + + /** + * Marks the given version of a crypto key to be destroyed at a scheduled future point. + */ + public static CryptoKeyVersion destroyCryptoKeyVersion( + String projectId, String ringId, String keyId, String version) + throws IOException { + String location = "global"; + // Create the Cloud KMS client. + CloudKMS kms = createAuthorizedClient(); + + // The resource name of the cryptoKey version + String cryptoKeyVersion = String.format( + "projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s/cryptoKeyVersions/%s", + projectId, location, ringId, keyId, version); + + DestroyCryptoKeyVersionRequest destroyRequest = new DestroyCryptoKeyVersionRequest(); + + CryptoKeyVersion destroyed = kms.projects().locations().keyRings().cryptoKeys() + .cryptoKeyVersions() + .destroy(cryptoKeyVersion, destroyRequest) + .execute(); + + System.out.println(destroyed); + return destroyed; + } + + /** + * Retrieves the IAM policy for the given crypto key. + */ + public static Policy getCryptoKeyPolicy(String projectId, String ringId, String keyId) + throws IOException { + String location = "global"; + // Create the Cloud KMS client. + CloudKMS kms = createAuthorizedClient(); + + // The resource name of the cryptoKey + String cryptoKey = String.format( + "projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", + projectId, location, ringId, keyId); + + // Get the current IAM policy and add the new account to it. + Policy iamPolicy = kms.projects().locations().keyRings().cryptoKeys() + .getIamPolicy(cryptoKey) + .execute(); + + System.out.println(iamPolicy.getBindings()); + return iamPolicy; + } + + /** + * Retrieves the IAM policy for the given crypto key. + */ + public static Policy getKeyRingPolicy(String projectId, String ringId) throws IOException { + String location = "global"; + // Create the Cloud KMS client. + CloudKMS kms = createAuthorizedClient(); + + // The resource name of the keyring + String keyring = String.format( + "projects/%s/locations/%s/keyRings/%s", + projectId, location, ringId); + + // Get the current IAM policy and add the new account to it. + Policy iamPolicy = kms.projects().locations().keyRings() + .getIamPolicy(keyring) + .execute(); + + System.out.println(iamPolicy.getBindings()); + return iamPolicy; + } + + /** + * Adds the given member to the given key, with the given role. + * + * @param ringId The id of the keyring. + * @param keyId The id of the crypto key. + * @param member The member to add. Must be in the proper format, eg: + * + * allUsers + * user:$userEmail + * serviceAccount:$serviceAccountEmail + * + * See https://g.co/cloud/kms/docs/reference/rest/v1beta1/Policy#binding + * for more details. + * + * @param role Must be in one of the following formats: + * roles/[role] + * organizations/[organizationId]/roles/[role] + * projects/[projectId]/roles/[role] + * + * See https://g.co/cloud/iam/docs/understanding-roles + * for available values for [role]. + */ + public static Policy addMemberToCryptoKeyPolicy( + String projectId, String ringId, String keyId, String member, String role) + throws IOException { + String location = "global"; + // Create the Cloud KMS client. + CloudKMS kms = createAuthorizedClient(); + + // The resource name of the cryptoKey version + String cryptoKey = String.format( + "projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", + projectId, location, ringId, keyId); + + // Get the current IAM policy + Policy iamPolicy = getCryptoKeyPolicy(projectId, ringId, keyId); + + // Add the new account to it. + Binding newBinding = new Binding() + .setRole(role) + .setMembers(Collections.singletonList(member)); + List bindings = iamPolicy.getBindings(); + if (null == bindings) { + bindings = Collections.singletonList(newBinding); + } else { + bindings.add(newBinding); + } + iamPolicy.setBindings(bindings); + + // Set the new IAM Policy. + Policy newIamPolicy = kms.projects().locations().keyRings().cryptoKeys() + .setIamPolicy(cryptoKey, new SetIamPolicyRequest().setPolicy(iamPolicy)) + .execute(); + + System.out.println(newIamPolicy); + return newIamPolicy; + } + + /** + * Adds the given member to the given keyring, with the given role. + * + * @param ringId The id of the keyring. + * @param member The member to add. Must be in the proper format, eg: + * + * allUsers + * user:$userEmail + * serviceAccount:$serviceAccountEmail + * + * See https://g.co/cloud/kms/docs/reference/rest/v1beta1/Policy#binding + * for more details. + * + * @param role Must be in one of the following formats: + * roles/[role] + * organizations/[organizationId]/roles/[role] + * projects/[projectId]/roles/[role] + * + * See https://g.co/cloud/iam/docs/understanding-roles + * for available values for [role]. + */ + public static Policy addMemberToKeyRingPolicy( + String projectId, String ringId, String member, String role) + throws IOException { + String location = "global"; + // Create the Cloud KMS client. + CloudKMS kms = createAuthorizedClient(); + + // The resource name of the keyring version + String keyring = String.format( + "projects/%s/locations/%s/keyRings/%s", + projectId, location, ringId); + + // Get the current IAM policy + Policy iamPolicy = getKeyRingPolicy(projectId, ringId); + + // Add the new account to it. + Binding newBinding = new Binding() + .setRole(role) + .setMembers(Collections.singletonList(member)); + List bindings = iamPolicy.getBindings(); + if (null == bindings) { + bindings = Collections.singletonList(newBinding); + } else { + bindings.add(newBinding); + } + iamPolicy.setBindings(bindings); + + // Set the new IAM Policy. + Policy newIamPolicy = kms.projects().locations().keyRings() + .setIamPolicy(keyring, new SetIamPolicyRequest().setPolicy(iamPolicy)) + .execute(); + + System.out.println(newIamPolicy); + return newIamPolicy; + } + + /** + * Removes the given member from the given policy. + */ + public static Policy removeMemberFromCryptoKeyPolicy( + String projectId, String ringId, String keyId, String member, String role) + throws IOException { + String location = "global"; + // Create the Cloud KMS client. + CloudKMS kms = createAuthorizedClient(); + + // The resource name of the cryptoKey + String cryptoKey = String.format( + "projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", + projectId, location, ringId, keyId); + + // Get the current IAM policy and add the new account to it. + Policy iamPolicy = getCryptoKeyPolicy(projectId, ringId, keyId); + + List bindings = iamPolicy.getBindings(); + // Filter out the given member + for (Binding b : bindings) { + if (role.equals(b.getRole()) && b.getMembers().contains(member)) { + b.getMembers().remove(member); + break; + } + } + + // Set the new IAM Policy. + Policy newIamPolicy = kms.projects().locations().keyRings().cryptoKeys() + .setIamPolicy(cryptoKey, new SetIamPolicyRequest().setPolicy(iamPolicy)) + .execute(); + + System.out.println(newIamPolicy); + return newIamPolicy; + } + + /** + * Removes the given member from the given policy. + */ + public static Policy removeMemberFromKeyRingPolicy( + String projectId, String ringId, String member, String role) + throws IOException { + String location = "global"; + // Create the Cloud KMS client. + CloudKMS kms = createAuthorizedClient(); + + // The resource name of the cryptoKey + String cryptoKey = String.format( + "projects/%s/locations/%s/keyRings/%s", + projectId, location, ringId); + + // Get the current IAM policy and add the new account to it. + Policy iamPolicy = getKeyRingPolicy(projectId, ringId); + + List bindings = iamPolicy.getBindings(); + // Filter out the given member + for (Binding b : bindings) { + if (role.equals(b.getRole()) && b.getMembers().contains(member)) { + b.getMembers().remove(member); + break; + } + } + + // Set the new IAM Policy. + Policy newIamPolicy = kms.projects().locations().keyRings().cryptoKeys() + .setIamPolicy(cryptoKey, new SetIamPolicyRequest().setPolicy(iamPolicy)) + .execute(); + + System.out.println(newIamPolicy); + return newIamPolicy; + } + + /** + * Prints all the keys in the given key ring. + */ + public static void listCryptoKeys(String projectId, String ringId) throws IOException { + String location = "global"; + // Create the Cloud KMS client. + CloudKMS kms = createAuthorizedClient(); + + // The resource name of the cryptoKey + String keyRingPath = String.format( + "projects/%s/locations/%s/keyRings/%s", + projectId, location, ringId); + + ListCryptoKeysResponse cryptoKeys = kms.projects().locations().keyRings() + .cryptoKeys() + .list(keyRingPath) + .execute(); + + for (CryptoKey key : cryptoKeys.getCryptoKeys()) { + System.out.println(key); + } + } + + /** + * Prints all the versions for the given crypto key. + */ + public static void listCryptoKeyVersions( + String projectId, String ringId, String keyId) throws IOException { + String location = "global"; + // Create the Cloud KMS client. + CloudKMS kms = createAuthorizedClient(); + + // The resource name of the cryptoKey + String cryptoKeys = String.format( + "projects/%s/locations/%s/keyRings/%s/cryptoKeys/%s", + projectId, location, ringId, keyId); + + DestroyCryptoKeyVersionRequest destroyRequest = new DestroyCryptoKeyVersionRequest(); + + ListCryptoKeyVersionsResponse versions = kms.projects().locations().keyRings().cryptoKeys() + .cryptoKeyVersions() + .list(cryptoKeys) + .execute(); + + for (CryptoKeyVersion version : versions.getCryptoKeyVersions()) { + System.out.println(version); + } + } + + + public static void main(String[] args) throws IOException, CmdLineException { + SnippetCommands commands = new SnippetCommands(); + CmdLineParser parser = new CmdLineParser(commands); + + try { + parser.parseArgument(args); + } catch (CmdLineException e) { + System.out.println(e); + System.out.println(); + e.getParser().printUsage(System.err); + System.exit(1); + } + commands.command.run(); + } +}