Hi,
I'm a beginner of Cloud Run and k8s.
Now I'm developing with Node.js to use Cloud Run and trying to use SecretManager to save secrets.
But, it's never successful because the request to Metadata Service on minikube pods failed.
I think my code is not wrong because the code is able to get the secret from SecretManager when the script is executed on my shell.
I think the problem is with the request to the Metadata Service in the pod, since the request outside the pod is successful.
Does anyone know how to solve this problem?
Error:
Error: Could not refresh access token: request to http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token?scopes=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform failed, reason: socket hang up
at Gaxios._request (/Users/takamizawa/dev/functions/node_modules/gaxios/build/src/gaxios.js:148:19)
at process.processTicksAndRejections (/Users/takamizawa/dev/functions/lib/internal/process/task_queues.js:95:5)
at async metadataAccessor (/Users/takamizawa/dev/functions/node_modules/gcp-metadata/build/src/index.js:94:21)
at async Compute.refreshTokenNoCache (/Users/takamizawa/dev/functions/node_modules/google-auth-library/build/src/auth/computeclient.js:57:20)
at async Compute.getRequestMetadataAsync (/Users/takamizawa/dev/functions/node_modules/google-auth-library/build/src/auth/oauth2client.js:298:17)
at async Compute.getRequestHeaders (/workspace/node_modules/google-auth-library/build/src/auth/oauth2client.js:261:26) {config: {…}, response: undefined, error: FetchError, code: 'ECONNRESET', note: 'Exception occurred in retry method that was not classified as transient', …}
Environment:
Cloud Code for VS Code on Mac, Ventura(13.6)
launch.json
{
"configurations": [
{
"name": "Cloud Run: Run/Debug Locally",
"type": "cloudcode.cloudrun",
"request": "launch",
"build": {
"buildpacks": {
"path": "PATH_TO/package.json",
"builder": "gcr.io/buildpacks/builder:latest"
}
},
"image": "functions",
"service": {
"name": "functions",
"containerPort": 8080,
"resources": {
"limits": {
"memory": "512Mi"
}
}
},
"target": {
"minikube": {}
},
"watch": true
}
]
}
package.json
{
"name": "My Cloud Run",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node index.js"
},
"engines": {
"node": ">=16.0.0"
},
"author": "",
"license": "ISC",
"dependencies": {
"@google-cloud/secret-manager": "^5.0.1",
"express": "^4.18.2"
}
}
index.js
const express = require('express');
const bodyParser = require('body-parser');
const crypto = require('crypto');
const {SecretManagerServiceClient} = require('@google-cloud/secret-manager');
const app = express();
app.use(bodyParser.raw({type: 'application/json'}));
app.post('/', async (req, res) => {
console.log('Request received');
try {
const HMAC = req.headers['x-hmac'];
const isValid = await verifyWebhook(HMAC, req.body);
if (!isValid) {
res.status(401).send('Unauthorized');
return;
}
const body = JSON.parse(req.body);
// some process will be implemented.
res.send();
} catch (err) {
console.error(err);
res.status(500).send('Internal Server Error');
}
});
const verifyWebhook = async (HMAC, body) => {
const secret = await getSecret();
const hash = crypto.createHmac('sha256', secret).update(body).digest('base64');
return HMAC === hash;
}
const getSecret = async () => {
const client = new SecretManagerServiceClient({fallback: true});
const name = process.env.SECRET_NAME;
const [secret] = await client.accessSecretVersion({
name: name,
},
{
timeout: 200000
});
return secret.payload.data.toString();
}
const port = parseInt(process.env.PORT) || 8080;
app.listen(port, () => {
console.log(`Listening on port ${port}`);
});
module.exports = app;