Breaking up with our Secure-Drive, Google Cloud KMS to the rescue!

Onur Dincol
codeshakeio
Published in
6 min readMar 22, 2021

Remote working, yay! But what about those sensitive files you share through an encrypted USB stick, which is probably dusting in your long-forgotten empty office.

Maybe this is not the story you experienced, to be honest, keeping the sensitive files in a git repo on the USB stick with a birth-date of the first developer who created it as its password was a crime against the notion of security on our part. So maybe not the story, but the reality you share with us; we do have sensitive files that can’t just be sent through slack or email.

There are probably more than enough services out there you can just use, and most of the time they will be ‘easier’ to setup or use than the one we ended up with. But for the sake of telling the story, I will share what Google Cloud KMS can offer for this particular problem.

First things first, I need to share some things about the Codeshake which will help you to understand the setting we had while coming up with this solution;

  • We are a company made up of developers only. Even the only guy who does not develop actually has a bachelor’s in computer science, so using the terminal to run some script is something all of us are familiar with.
  • We use Google Cloud Platform for our products, from App Engine to Cloud Run, Cloud Functions, Firebase, Dataflow, and many more which I will not include in this potentially never-ending sentence to keep it short. But the message here is, GCP is something we use in on a daily basis.

So we were already using the Google Cloud KMS in our services for various functionalities, mainly to read sensitive information in the runtime; you encrypt your sensitive files with the KMS, put them in somewhere the application can reach, and give the runtime service account of your deployment the right to decrypt and Voila! You have your sensitive information available in the runtime.

Nowadays there are better solutions for configurations like this, namely Cloud Runtime Configuration API and Secret Manager in the GCP, which we currently use. But the experiences with the KMS still lingered in the back of our heads when we realized we didn’t have access to our beloved secure-USB-stick from our homes.

I will not go in-depth with the KMS, but mention certain aspects which played nicely into the problem, or rather the solution, we had. From their website:

“A cloud-hosted key management service that lets you manage symmetric and asymmetric cryptographic keys for your cloud services the same way you do on-premises. You can generate, use, rotate, and destroy AES256, RSA 2048, RSA 3072, RSA 4096, EC P256, and EC P384 cryptographic keys.”

So service in the cloud in which you can generate, use, rotate and destroy some keys, nice. But there is more; the access is governed by the Cloud Identity and Access Management (IAM) within the GCP. Since we also use Google Workspace, our Google accounts can be authorized to use these keys in any granularity we want, again from their website:

“In Cloud KMS, resources are organized into a hierarchy. This hierarchy helps you manage and grant access to resources at various levels of granularity. Keys are contained within key rings, and key rings exist within a project. Projects can be further organized into folders or organizations.”

So what we had at our disposal was a cloud service in which we can provision cryptographic keys, and accounts that can be authorized to use them in the encryption and decryption of a payload.

And as a cherry on top; encryption and decryption operations are possible with the Google Cloud SDK, a tool we know by heart and use daily in our development adventures.

It looked like a perfect fit!

Why a perfect fit? Well a step back from this narrative and clearly defining what we wanted in the first place might be helpful to answer that question.

We wanted to have an encryption/decryption functionality that is shared among the team so we can securely send any file we deemed sensitive via Slack.

The communication medium can be oddly specific for your taste, but defining what you want/need to this degree always helps to eliminate some other alternatives, alternatives that sound good but don’t really match what you wanted in the first place. And you may ask; why Slack? The answer to that question is as simple as it can get; we were already using Slack for “the medium” to talk, and if one of us asks for a file, we wanted to send it as if it was any other file; through slack, with just dragging that file into the conversation window, even that file looks suspiciously sensitive.

This requirement eliminates most of the solutions that we could have used as out-of-the-shelf alternatives. We didn’t want to have a central secure-location to upload files and then send the message through slack; “I have uploaded it to the super-secure-vault, go check it out”, instead of just sending the file. It also eliminates some other alternatives in the GCP, remember me mentioning the Secure Manager as the step forward for our deployments? That also falls into the category of super-secure-vaults.

So Google Cloud KMS, as an encryption/decryption functionality that is shared among the team, met all our needs. And the best part is; we don’t have to trust any other party than the one we already trust; Google.

So how does this work?

Short version; the one who has the file encrypts it with the key in our Vault project, which all other developers have rights to encrypt/decrypt with via the Cloud SDK, then sends it to the requesting party which in turn decrypts it in their local machine using the same key.

Long version; well, to be honest, there is no long version. It is as simple as it sounds. Instead of a long version maybe I should explain how to set it up in a bit more detail.

  • First, you need to have a GCP project; their documentation on how to create one: reference. And don’t forget to enable the billing!
  • After you have your project it's time to have your Cloud SDK ready: reference.

At this point, you could choose to continue via either the Cloud Console or the Cloud SDK. If you go to the Cloud Console and search for the KMS in the header bar you will find a nice UI in which you can create and manage your keys. But to not litter this page with the screenshots with badly drawn red circles to point out the button you need to press, I will continue with the Cloud SDK.

As a start you need to create your key-ring;

gcloud kms keyrings create <your-keyring-name> \
--location global

After that you can create your key:

gcloud kms keys create <your-key-name> \
--keyring <your-keyring-name> \
--location global \
--purpose "encryption"

As the last step, you need to add IAM permissions for other people to let them use this key for encryption and decryption

gcloud kms keys add-iam-policy-binding key \
--keyring <your-keyring-name> \
--location global \
--member user:<email-of-a-user> \
--role roles/cloudkms.cryptoKeyEncrypterDecrypter

There are more options than the defaults I accepted here with the location and the member targeting in the IAM policy, also there are some key security concepts to follow like separation of duties and least privilege. Further reading on this resource can be helpful to answer some questions.

You are pretty much all set; Cloud SDK has the following syntax to encrypt/decrypt any file via the terminal;

gcloud kms encrypt \
--key=<your-key-name> \
--keyring=<your-key-ring> \
--location=global \
--project=<your-project-name> \
--plaintext-file=path/to/input/plaintext \
--ciphertext-file=path/to/output/ciphertext
gcloud kms decrypt \
--key=<your-key-name> \
--keyring=<your-key-ring> \
--location=global \
--project=<your-project-name> \
--plaintext-file=path/to/input/plaintext \
--ciphertext-file=path/to/output/ciphertext

We do have a utility function in our bash profiles to make this as easy as possible:

encrypt() {
gcloud kms encrypt --plaintext-file=$1 --ciphertext-file=$1.enc --location=global --project=<your-project-name> --keyring=<your-keyring-name> --key=<your-key-name>
}
decrypt() {
gcloud kms decrypt --ciphertext-file=$1 --plaintext-file=${1%.enc} --location=global --project=<your-project-name> --keyring=<your-keyring-name> --key=<your-key-name>
}

so we can simply say encrypt /path/to/file or decrypt /path/to/file and the magic will follow. The output of the encrypt call, with our utility function, will be the file-name.enc which you can send to anyone via slack with ease-of-mind, solving the problem we had.

There are more ways to achieve this, more tools that are non-developer friendly but as I said, for us, this was a quick, familiar, and effective solution.

Thank you for reading!

--

--