nkhil
nkhil

Reputation: 1610

How do I store a private key using Google Cloud's Cloud KMS?

I've been trying to read documentation, and watching a few of their videos but I'm not entirely clear on how I store a private key using GCP's Cloud KMS.

Is the idea for me to store the private key in storage, then use Cloud KMS to encrypt it? How can I make this key available as a secret to my application?

I know this is a very basic question, but I couldn't find an easy breakdown on how to do this - I'm looking for a simple explanation about the concept. Thanks!

Upvotes: 0

Views: 4390

Answers (2)

Martin Zeitler
Martin Zeitler

Reputation: 76569

Please read for yourself: https://cloud.google.com/kms/docs ...maybe you'll come up with a more focused question. And I think that there's a slight misunderstanding - you'd only be able to retrieve these on the server-side, but not client-side (else the client would need to have the RSA private key of the service account, which has access to Cloud KMS, which is a security breach by itself). So this is generally only useful for a) server-side applications and b) eg. Google Cloud Build.

Generally one has to:

  1. create the keyring with gcloud kms keyrings create

  2. create the key with gcloud kms keys create

  3. then use gcloud kms encrypt and gcloud kms decrypt

I can also provide a usage example (it assumes a key-ring with a key). Just to show, that one doesn't necessarily have to setup secrets. gcloud kms can well provide build secrets - assuming that one can use a service-account with role roles/cloudkms.cryptoKeyEncrypterDecrypter. The given example decrypts all kinds of build secrets - without having to deal with any base64 encoded binary files in meta-data (which is rather a workaround than an actual solution).

Upvotes: 2

nkhil
nkhil

Reputation: 1610

This is a high level description of storing a private key on Google Cloud Platform (GCP):

I ended up using Google KMS, specifically asymmetric encryption feature.

The general steps to create an asymmetric key are:

  • Create a keyring within your project
  • Create a key with ENCRYPT_DECRYPT purpose (if like me, you're trying to do this using Terraform, there's some documentation here

Once we've created the key, we can now encrypt some data we want to secure using the public key from the asymmetric key we created in the previous step.

It is important to note that with an asymmetric key, there is a public-private key pair, and we never handle the private key (i.e. only GCP knows the private key).

Here's how you'd encrypt some data from your local computer:

echo -n my-secret-password | gcloud kms encrypt \
> --project my-project \
> --location us-central1 \
> --keyring my-key-ring \
> --key my-crypto-key \
> --plaintext-file - \
> --ciphertext-file - \
> | base64

This will output some cyphertext with base64 encoding, for eg:

CiQAqD+xX4SXOSziF4a8JYvq4spfAuWhhYSNul33H85HnVtNQW4SOgDu2UZ46dQCRFl5MF6ekabviN8xq+F+2035ZJ85B+xTYXqNf4mZs0RJitnWWuXlYQh6axnnJYu3kDU=

This cyphertext then needs to be stored as a secret. Once stored as a secret, we need to do the following in our application code in order to decrypt the cyphertext into a usable format.

Here is an example of decrypting the cyphertext using the @google-cloud/kms module: https://cloud.google.com/kms/docs/hsm#kms-decrypt-symmetric-nodejs

This is what it looks like in Nodejs:

//
// TODO(developer): Uncomment these variables before running the sample.
//
// const projectId = 'my-project';
// const locationId = 'us-east1';
// const keyRingId = 'my-key-ring';
// const keyId = 'my-key';
// Ciphertext must be either a Buffer object or a base-64 encoded string
// const ciphertext = Buffer.from('...');

// Imports the Cloud KMS library
const {KeyManagementServiceClient} = require('@google-cloud/kms');

// Instantiates a client
const client = new KeyManagementServiceClient();

// Build the key name
const keyName = client.cryptoKeyPath(projectId, locationId, keyRingId, keyId);

// Optional, but recommended: compute ciphertext's CRC32C.
const crc32c = require('fast-crc32c');
const ciphertextCrc32c = crc32c.calculate(ciphertext);

async function decryptSymmetric() {
  const [decryptResponse] = await client.decrypt({
    name: keyName,
    ciphertext: ciphertext,
    ciphertextCrc32c: {
      value: ciphertextCrc32c,
    },
  });

  // Optional, but recommended: perform integrity verification on decryptResponse.
  // For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit:
  // https://cloud.google.com/kms/docs/data-integrity-guidelines
  if (
    crc32c.calculate(decryptResponse.plaintext) !==
    Number(decryptResponse.plaintextCrc32c.value)
  ) {
    throw new Error('Decrypt: response corrupted in-transit');
  }

  const plaintext = decryptResponse.plaintext.toString();

  console.log(`Plaintext: ${plaintext}`);
  return plaintext;
}

return decryptSymmetric();

Upvotes: 2

Related Questions