Cloud build: No permission for signining blobs even though I granted them - firebase

I'm trying to build a Java application in cloud build and deploy it to Cloud Run.
I have granted rights to cloud build service account to write blobs
Morover, I have changed default service account for Cloud Run instance, with rights to write blobs.
I'm letting instance figure out service account by doing: FirebaseApp.initializeApp();
When I run my tests, I get:
Caused by: java.io.IOException: Error code 403 trying to sign provided bytes: The caller does not have permission
at com.second.hand.security.jwt.TokenProviderTest.testReturnFalseWhenJWTisMalformed(TokenProviderTest.java:75)
If I print GoogleCredentials.getApplicationDefault(), in Cloud build logs I get ComputeEngineCredentials{..., although I changed Service Account to a different one.
In my local environment, it prints applicationDefaultServiceAccountCredentials{... as expected, since I set GOOGLE_APPLICATION_CREDENTIALS environmental variable
What am I doing wrong? I'm out of ideas

Related

G-cloud sdk --> problems about firebase projects and permissions

I'm developing a backend microservice app with node.js along with #google-cloud/firestore and i'm trying to access my firebase project locally with gcloud-sdk. I've run gcloud init so i can log in and chose the project i need to connect to in order to access the db.
The problem is that, i keep getting 7 PERMISSION_DENIED: Missing or insufficient permissions when i try to make any type of interaction with the db even though i already have all permissions in the project. At the beginning i thought that maybe i was having that problem because i was using a different account that did not have permissions to access these projects, but that didn't make sense because i do not see that account in my list of accounts in the sdk
But, when i gave permissions to the other account that i thought maybe logged in in my sdk, i could access the db, so it was weird, it is like it's stuck with the other account that maybe i added when i first install the sdk.
So, i've tried everything to correct this, i've deleted all accounts from my gcloud sdk, i've deleted the list of configurations, i've uninstalled (twice) the sdk and installed it again (since people that i work with told me that they did this and worked for them, since they had same issue), i've run g cloud init to log in again and all that stuff, and still, when i try to connect to my firebase db, it still says that i still do not have permissions, it's like the account that i'm logging in is not the one that is being saved/used to access my project.
What can i do to make this work ?
EDIT #1 -> How i'm connecting to firebase and sdk commands to connect to the project
Connecting to my project on firestore
import 'reflect-metadata';
import { Firestore } from '#google-cloud/firestore';
import { GCP_PROJECT } from '#util';
export const firestore = new Firestore({ projectId: GCP_PROJECT });
Commands to connect to my project by sdk
-> gcloud init
Welcome! This command will take you through the configuration of gcloud.
Settings from your current configuration [coordinadora-work] are:
core:
account: diego.cifuentes#coordinadora.com
disable_usage_reporting: 'True'
project: cm-reparto-dev
Pick configuration to use:
[1] Re-initialize this configuration [coordinadora-work] with new settings
[2] Create a new configuration
Please enter your numeric choice: 1
Your current configuration has been set to: [coordinadora-work]
You can skip diagnostics next time by using the following flag:
gcloud init --skip-diagnostics
Network diagnostic detects and fixes local network connection issues.
Checking network connection...done.
Reachability Check passed.
Network diagnostic passed (1/1 checks passed).
Choose the account you would like to use to perform operations for this configuration:
[1] diego.cifuentes#coordinadora.com
[2] Log in with a new account
-> Please enter your numeric choice: 1
You are logged in as: [...my account that is having problems...].
Pick cloud project to use:
...
-> Please enter numeric choice or text value (must exactly match list item): 21
Your current project has been set to: [...project that i'm having problems with...].
-> Do you want to configure a default Compute Region and Zone? (Y/n)? n
Your Google Cloud SDK is configured and ready to use!
The Google Cloud Client libraries use the Application Default Credentials, not the current credentials setup using gcloud auth login.
To setup your Application Default Credentials for local development, simple execute gcloud auth application-default login. This will open a browser window and allow you to select the account to use as default credentials.
Another method is setting the environment variable GOOGLE_APPLICATION_CREDENTIALS to point to a service account key file.
Read more here : https://cloud.google.com/docs/authentication/application-default-credentials
When running in GCP, your credentials will get picked up from the environment, i.e. the service account your Cloud Function is running with.
https://cloud.google.com/docs/authentication/client-libraries

How can I authorize Cloud Build to deploy to Firebase Hosting in a different project?

I have GCP project A and Firebase project B (in a separate GCP project). I'm trying to use Cloud Build in A to build a web app and deploy it to Firebase Hosting in B.
In B's IAM page, I have granted A's <id>#cloudbuild.gserviceaccount.com service account the API Keys Admin, Firebase Admin, and Service Account User roles as described in e.g. this question.
The final step in the Cloud Build config used by A is the following:
- id: firebase_deploy
name: gcr.io/$PROJECT_ID/firebase
entrypoint: sh
args:
- '-c'
- |
firebase use $_FIREBASE_PROJECT_ID
firebase target:apply hosting prod $_FIREBASE_HOSTING_TARGET
firebase deploy --project=$_FIREBASE_PROJECT_ID --only=hosting,firestore:rules
I set the _FIREBASE_PROJECT_ID substitution variable to B and the _FIREBASE_HOSTING_TARGET variable to a Hosting alias that I use for the site.
When I trigger a build, it fails with the following error:
...
Step #3 - "firebase_deploy": Error: Invalid project selection, please verify project B exists and you have access.
Step #3 - "firebase_deploy":
Step #3 - "firebase_deploy": Error: Must have an active project to set deploy targets. Try firebase use --add
Step #3 - "firebase_deploy":
Step #3 - "firebase_deploy": Error: Failed to get Firebase project B. Please make sure the project exists and your account has permission to access it.
Finished Step #3 - "firebase_deploy"
I suspect that the problem may be that I'm not running the Firebase CLI's extra login step first. To do that, it seems that I would need to run firebase login:ci locally to generate a token and then pass it via the FIREBASE_TOKEN environment variable as described in the docs, but the permissions associated with the token appear to be much broader than needed:
The build process should only have access to Firebase project B, rather than "all my Firebase data and settings" and "my Google Cloud data".
Is there any way to avoid needing to run firebase login here? It seems like the service account should already have sufficient access to deploy to Firebase Hosting.
If I need to run firebase login, is there any way to create a token with a limited scope (assuming that my understanding of the default scope is correct)?
(I've also given B's service account the Cloud Functions Developer role in A and am able to successfully run gcloud --project=$_FIREBASE_PROJECT_ID functions deploy ... in a different build config. I'm also using a Cloud Build config similar to the one described above to deploy to Firebase Hosting in the same GCP project, so I suspect that firebase login isn't necessary in all cases.)
I found an approach that lets project A's Cloud Build service account deploy to B without needing excessive permissions.
First, I created a service account named deploy under B and granted it the Firebase Hosting Admin, Firebase Rules Admin, and Cloud Datastore Index Admin roles. (I'm not sure whether the Datastore role is needed, but the console showed it as being used recently so I left it.)
Next, I generated a JSON key for the new service account, pasted it (including newlines and double-quotes) as a substitution variable named _DEPLOY_CREDENTIALS, and updated the build step to copy it to the environment:
- id: firebase_deploy
name: gcr.io/$PROJECT_ID/firebase
entrypoint: bash
args: ['-e', '--', 'build/deploy_hosting.sh']
env:
- DEPLOY_CREDENTIALS=$_DEPLOY_CREDENTIALS
- FIREBASE_PROJECT_ID=$_FIREBASE_PROJECT_ID
- FIREBASE_HOSTING_TARGET=$_FIREBASE_HOSTING_TARGET
In deploy_hosting.sh, I write the credentials to a temporary file and then pass them to the firebase command via the GOOGLE_APPLICATION_CREDENTIALS environment variable:
#!/bin/bash
set -e
CREDS=$(mktemp -t creds.json.XXXXXXXXXX)
printenv DEPLOY_CREDENTIALS >"$CREDS"
export GOOGLE_APPLICATION_CREDENTIALS=$CREDS
firebase --debug use "$FIREBASE_PROJECT_ID"
firebase target:apply hosting prod "$FIREBASE_HOSTING_TARGET"
firebase deploy --project="$FIREBASE_PROJECT_ID" --only=hosting,firestore:rules
I created a separate shell script for the step since I ran into problems with quotes being stripped from the credentials when writing them directly from the build step. It would likely be possible to store the credentials in Secret Manager instead, but that felt like overkill for my use case.
I'm still curious about whether there's a way to let A's service account deploy to B without using a service account in B while running the firebase executable.

GCP Permissions Error Only After Deploying Cloud Function (Works Locally)

I am writing files to someone else GCP storage bucket, for which they have made a service account for me, and I'm using the service account key (a .json file) as credentials in my code.
I made a Firebase Cloud Function to run my code, so and when I test it locally everything works as expected. It works when I run the cloud emulator as well.
However, when I deploy the function and try to execute it, I get an error like this in the logs:
ApiError: my-project#appspot.gserviceaccount.com does not have storage.objects.create access to the Google Cloud Storage object
Why might I have permissions locally, but not in the cloud? I thought the service account key should be all I need for credentials here.
As mentioned in the error message the service account
'my-project#appspot.gserviceaccount.com' doesn't have permission to
create bucket or add objects in Google Cloud Storage.
As you are writing into someone else's project, please ask the
project owner to verify if the service account
'my-project#appspot.gserviceaccount.com' have the necessary
permission to write to the Google Cloud Storage bucket. To find an
appropriate role for the service account to be able to access Google Cloud Storage I would recommend you to go
through this link.

Call Google Cloud API from local Firebase Emulator

I've got a function which uses #google-cloud/language.
The function works when deployed live but when running in the local function emulator it complains
I've done firebase login with my Google account but get the following when running the function:
Error: 7 PERMISSION_DENIED: Cloud Natural Language API has not been used in project XXXXX before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/language.googleapis.com/overview?project=XXXXX then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
XXXXX is a project Id I don't recognise - where has this come from and how can I check if I'm mistaken?
The account I'm authed with firebase locally is already in the Owner role for the project, so either the project ID is wrong, or I need to grant permissions to the user?
What do I need to do?
The solution is to set the environment variable GOOGLE_APPLICATION_CREDENTIALS for authentication:
https://cloud.google.com/docs/authentication/getting-started#windows
And restart all the things due to my ENV variable not being updated.

How to avoid "401 Unauthorized" when invoking Firebase callable HTTP Function under GCP organization?

I have a Firebase project under a GCP organization. I have NodeJS 10 callable functions which work fine with Firebase local emulator and in in GCP functions test page, but when attempting to call them in production using httpsCallable in a webapp, I get 401 Unauthorized - Your client does not have permission to the requested URL
There is practically nothing my test function - it just returns a hardcoded string. There is nothing in the logs after the call attempts.
The function call attempt is done after passing Firebase authentication in the webapp, and in development I see that the user is indeed passed to the context parameter.
I use Firebase Tools 8.0.2 to deploy.
In GCP console function details I see "Ingress settings - Allow all traffic", and as I wrote above, it runs successfully from the test tab there.
I tried to make the function public but I can't set permissions in the console or gcloud. When I try to run the following command with gcloud:
gcloud functions add-iam-policy-binding my-function-name \
--member="allUsers" \
--role="roles/cloudfunctions.invoker"
I get:
ERROR: (gcloud.functions.add-iam-policy-binding) ResponseError: status=[403], code=[Forbidden], message=[Permission 'cloudfunctions.functions.setIamPolicy' denied on resource 'projects/my-project-name/locations/us-central1/functions/my-function-name' (or resource may not exist).]
even though my account has the following roles: Project Owner, Cloud Functions Admin, Security Admin, IAP Policy Admin, Organization Administrator
Any guidance will be appreciated.
Per John's instructions, it turned out gcloud was set to an incorrect active account, so I set it to the correct account that had the required permissions using gcloud config set account my-email#my-domain.com and then I was able to make the function publicly invokable using
gcloud functions add-iam-policy-binding my-function-name \
--member="allUsers" \
--role="roles/cloudfunctions.invoker"

Resources