Reputation: 367
I am developing a mobile app where authenticated users can trigger a Cloud Function that creates a Cloud Run instance. Each Cloud Run instance should be accessible only by the user who created it. I initially considered using Google IAM for access management, but it seems to be more focused on employee access rather than end-user access.
As an alternative, I thought of creating a Google service account with exclusive access to these Cloud Run instances and regulating access to them via Cloud Functions. In the Cloud Function, I would verify if the user has the right to access the requested instance and then trigger the request using the Google service account.
Here's an example of how I create a Cloud Run instance in a Cloud Function:
export const createCloudRunService = functions
.firestore
.document("services/{serviceUid}")
.onCreate(async (change, context) => {
//... Creating the Cloud Run service
const runClient = new ServicesClient({
credentials: saJson,
});
const request = {
parent,
service,
serviceId,
};
const [operation] = await runClient.createService(request);
const [response] = await operation.promise();
const serviceUrl = response.uri;
//... Updating Firestore document with status and URL
});
And here's an example of how I am currently calling the Cloud Run instance:
export const queryCloudRunService = functions
.firestore
.document("services/{serviceUid}/queries/{queryUid}")
.onCreate(async (change, context) => {
//... Fetching service data and URL from Firestore
const serviceUrl = serviceData.data()!.url;
const serviceEndpointUrl = `${serviceUrl}/endpoint_example`;
//... Calling the service's endpoint_example endpoint
const response = await fetch(serviceEndpointUrl);
});
Is this approach recommended, or are there better ways to manage end-user access to Cloud Run instances using Firebase Authentication and service accounts? How should I modify the code to call the Cloud Run instance using the Google service account? Any guidance or best practices would be appreciated.
Upvotes: 0
Views: 221
Reputation: 2917
You are setting the serviceUrl
correctly with cloud functions and assume that your clou run instance was also created successfully.
You are having issue for best practice for setting the serviceUrl to who has created and also authorizing it after further access to the cloud run for that you can use google-auth-library
to set the accessToken for the same and store it in the same user document as follows :
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import { GoogleAuth } from "google-auth-library";
admin.initializeApp();
export const queryCloudRunService = functions.firestore
.document("services/{serviceUid}/queries/{queryUid}")
.onCreate(async (change, context) => {
const serviceUrl = change.data()!.url;
const serviceEndpointUrl = `${serviceUrl}/endpoint_to_cloud_run_service`;
const auth = new GoogleAuth({
scopes: ["https://www.googleapis.com/auth/cloud-platform"],
projectId: "<project-id>", // project id for the project where you have created the cloud run instace
keyFilename: "./serviceAccountKey.json", // service account json key
});
const accessToken = await auth.getAccessToken();
const response = await fetch(serviceEndpointUrl, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
}); // give access to the valid Authorization token
// TODO: update the user document with the access token so for next time the user can access the cloud run he/she has created. Just for redundancy.
});
Here you will need to give access to only who has a valid access token based on headers we are passing to the cloud run instance.
Reference : google-auth-library-nodejs.
Upvotes: 0