Google Cloud Function : support for Google Cloud KMS
T

4

6

I am using a Google Cloud Function (GCF) with a Pubsub trigger which sends a HTTP request to a third party API.

The GCF receives notifications from a Pubsub topic used by a service which should not be aware of the third party API.

The third party API requires an authentication using Basic HTTP Authentication.

In order to not to have to hardcode the password in my source code I am using Google KMS to generate a new encrypted key each time I deploy my function. I am using Google Cloud KMS to decrypt the secret each time the function is instantiated.

For decrypting using KMS I have to provide a private key for a service account to the NodeJS Google API.

My main problem today is that I have to push my private key to the GCloud Bucket if I want my GCF to work properly.

Is it possible by using either the Runtime Configurator or the Deployment Manager to configure secrets for a Google Cloud Function?

Thanks you.

Tica answered 12/6, 2017 at 18:21 Comment(1)
I tried to solve the same problem. I used KMS to encrypt secrets within the deployable package, then I tried to decrypt the secrets at runtime, but then realised that you need to explicitly authenticate from the cloud function - which, as far as I can tell, means that you need to have at least some form of unencrypted secrets in the deployable package.Lorylose
E
4

As of December 2019, the preferred way to store and manage secrets on Google Cloud is Secret Manager:

$ echo -n "user:pass" | gcloud beta secrets create "my-basic-auth" \
  --data-file=- \
  --replication-policy "automatic"

You can also create and manage secrets from API:

// Import the library
const {SecretManagerServiceClient} = require('@google-cloud/secret-manager');

// Create the client
const client = new SecretManagerServiceClient();

// Create the secret
const [secret] = await client.createSecret({
  parent: "projects/<YOUR-PROJECT-ID>",
  secretId:"my-basic-auth",
  secret: {
    replication: {
      automatic: {},
    },
  },
});

// Add the version with your data
const [version] = await client.addSecretVersion({
  parent: secret.name,
  payload: {
    data: Buffer.from("user:pass", "utf8"),
  },
});

Then, in your Cloud Function:

const [version] = await client.accessSecretVersion({
  name:"projects/<YOUR-PROJECT-ID>/secrets/<MY-SECRET>/versions/1",
});

const auth = version.payload.data.toString('utf-8');

// auth is user:pass

The service account with which you deploy your Cloud Function will need roles/secretmanager.secretAccessor permissions.

Exuberance answered 22/12, 2019 at 17:7 Comment(1)
I ended up doing something equivalent when I raised the question. I created a wrapper for interacting with the GCP KMS.Tica
A
4

The other solution to this which came out only in the last few months, is to use Google Cloud Runtime Configuration with Firebase for Functions: https://firebase.google.com/docs/functions/config-env

Firebase for Functions seems to provide access to several features that are not yet available via other means.

Runtime Configurator does not charge for use, but enforces the following API limits and quotas:

  • 1200 Queries Per Minute (QPM) for delete, create, and update requests
  • 600 QPM for watch requests.
  • 6000 QPM for get and list requests.
  • 4MB of data per user, which consists of all data written to the Runtime Configurator service and accompanying metadata.

https://cloud.google.com/deployment-manager/pricing-and-quotas#runtime_configurator


As an aside, I find this conflict in the Firebase for Functions comical:

The Firebase SDK for Cloud Functions offers built-in environment configuration to make it easy to store and retrieve this type of data for your project without having to redeploy your functions.

Then a moment later:

After running functions:config:set, you must redeploy functions to make the new configuration available.


The KMS solution is a viable alternative, however it seems costly for functions. KMS is billed at $0.06 per month per active key, as well as $0.03 per 10,000 operations.

This would then change the cost of your Cloud Function from $0.40 per million invocations, to $3.40 per million invocations. That is quite the jump.

Aureaaureate answered 17/7, 2017 at 4:44 Comment(1)
There is an official library now for pulling configs from the runtime API. npmjs.com/package/@google-cloud/rcloadenvKynan
E
4

As of December 2019, the preferred way to store and manage secrets on Google Cloud is Secret Manager:

$ echo -n "user:pass" | gcloud beta secrets create "my-basic-auth" \
  --data-file=- \
  --replication-policy "automatic"

You can also create and manage secrets from API:

// Import the library
const {SecretManagerServiceClient} = require('@google-cloud/secret-manager');

// Create the client
const client = new SecretManagerServiceClient();

// Create the secret
const [secret] = await client.createSecret({
  parent: "projects/<YOUR-PROJECT-ID>",
  secretId:"my-basic-auth",
  secret: {
    replication: {
      automatic: {},
    },
  },
});

// Add the version with your data
const [version] = await client.addSecretVersion({
  parent: secret.name,
  payload: {
    data: Buffer.from("user:pass", "utf8"),
  },
});

Then, in your Cloud Function:

const [version] = await client.accessSecretVersion({
  name:"projects/<YOUR-PROJECT-ID>/secrets/<MY-SECRET>/versions/1",
});

const auth = version.payload.data.toString('utf-8');

// auth is user:pass

The service account with which you deploy your Cloud Function will need roles/secretmanager.secretAccessor permissions.

Exuberance answered 22/12, 2019 at 17:7 Comment(1)
I ended up doing something equivalent when I raised the question. I created a wrapper for interacting with the GCP KMS.Tica
E
2

Is it possible by using either the Runtime Configurator or the Deployment Manager to configure secrets for a Google Cloud Function?

There is no built-in service that will let you configure secrets to be directly accessed by Google Cloud Functions at this time, so the method you are currently using is the proper way to handle secrets on Cloud functions for the time being. This could change as the product is still in beta.

If you want you can make a feature request to the Cloud Function team by using the appropriate issue tracker.

Exchange answered 14/6, 2017 at 13:30 Comment(0)
S
0

There's also a Google Cloud Key Management Service: Node.js Client.

cd functions
npm install @google-cloud/kms

For example:

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

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

// Build the location name
const locationName = client.locationPath(functions.config().firebase.projectId, functions.config().firebase.locationId);

async function listKeyRings() {
  const [keyRings] = await client.listKeyRings({
    parent: locationName,
  });
  for (const keyRing of keyRings) {
    console.log(keyRing.name);
  }
  return keyRings;
}

return listKeyRings();
Sudden answered 11/2, 2021 at 3:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.