0

I need to implement pubsub event based cloud function along with secrets. Secret contains database password. I need to use the db credentials in processing the data received in pubsub.

I am trying to access the db password from secret and to be used in hello_pubsub. I am new to secrets topic and here is my code. It's not working.

import base64
import json
import os
import datetime
from google.cloud import secretmanager

client = secretmanager.SecretManagerServiceClient()
secret_name = "my_db_password"
project_id = "project_id"
request = {"name": f"projects/{project_id}/secrets/{secret_name}/versions/latest"}
response = client.access_secret_version(request)
secret_string = response.payload.data.decode("UTF-8")

def secret_hello(request):
    return secret_string
    
def hello_pubsub(event, context):
    """Triggered from a message on a Cloud Pub/Sub topic.
    Args:
         event (dict): Event payload.
         context (google.cloud.functions.Context): Metadata for the event.
    """
    print("""This Function was triggered by messageId {} published at {} to {}
    """.format(
            context.event_id, context.timestamp, context.resource["name"]
        )
    )
    print(event)
    print(context)
:
James Z
  • 12,209
  • 10
  • 24
  • 44
Sekhar
  • 627
  • 4
  • 14
  • 34
  • Are there any errors? Have you tried following this link on [configuring secrets](https://cloud.google.com/functions/docs/configuring/secrets) to be accessible to a function? – Robert G Jun 30 '23 at 17:04
  • The intension is to access the db password in hello_pubsub function. I think my code was wrong somewhere. I have configured the secrets tabs while creating cloud function. I could not access the db password in my cloud function. – Sekhar Jul 02 '23 at 11:58

2 Answers2

2

Here is my working code. I can access my secret value in hello_pubsub function.

from google.cloud import storage
import base64
import json
import os
import datetime
from google.cloud import secretmanager

def hello_pubsub(event, context):
    """Triggered from a message on a Cloud Pub/Sub topic.
    Args:
         event (dict): Event payload.
         context (google.cloud.functions.Context): Metadata for the event.
    """
    client = secretmanager.SecretManagerServiceClient()
    secret_name = "my_secret"
    project_id = "997217777776"
    request = {"name": f"projects/{project_id}/secrets/{secret_name}/versions/latest"}
    response = client.access_secret_version(request)
    secret_string = response.payload.data.decode("UTF-8")
    print(secret_string)
    
    pubsub_message = base64.b64decode(event['data']).decode('utf-8')
    #print(pubsub_message)
:
Sekhar
  • 627
  • 4
  • 14
  • 34
0

Don't access secrets using the Secret Manager library. Access secrets by injecting them as environment variables when your function is deployed and then accessing the named environment variables to retrieve the secret value.

It is a subtle but important difference in how the secrets are accessed. In the scenario you're describing you are giving the code and the service account under which it runs both the permissions and capabilities needed to make API calls to Secret Manager. In the scenario that I am describing, only the specific secrets needed by your application are provided and they are provided at the moment of deployment by the deployer.

This is discussed in the Google Cloud Blog post What's the key to a more secure Cloud Function? It's a secret!:

Suppose the following cloud function invoked via HTTP uses a secret token to invoke an upstream API:

const https = require('https');
const token = process.env.TOKEN;

exports.secretDemo = (req, res) => {
  https.get(`https://upstream-api.example.com?token=${token}`, (innerRes) => {
    innerRes.on('end', () => { res.send('OK') });
  }).on('error', (err) => {
    res.send(`Error: ${err}`);
  });
}

To improve the security of this code, migrate the secret to Secret Manager in the same project:

gcloud secrets create "my_token" \
  --replication-policy "automatic" \
  --data-file - <<< "abcd1234"

Finally, without changing any code in the function re-deploy with slightly different flags:

gcloud beta functions deploy "secretDemo" \
  --runtime "nodejs14" \
  --trigger-http \
  --allow-unauthenticated \
  --set-secrets "TOKEN=my_token:latest"

This is explained in greater detail in the documentation Cloud Functions documentation Configure secrets:

You can use Secret Manager to securely store API keys, passwords, and other sensitive information. This guide shows you how to configure Cloud Functions to access secrets stored in Secret Manager.

This document covers both ways of making a secret available to your function:

  • Mounting the secret as a volume. This makes the secret available to the function as a file. If you reference a secret as a volume, your function accesses the secret value from Secret Manager each time the file is read from disk. This makes mounting as a volume a good strategy if you want to reference the latest version of the secret instead of a pinned version of the secret. This method also works well if you plan to implement secret rotation.

  • Passing the secret as an environment variable. Environment variable values are resolved at instance startup time, so if you use this method, we recommend referencing a pinned version of the secret instead of referencing the latest version of the secret.

anothermh
  • 9,815
  • 3
  • 33
  • 52