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.