Skip to content

Can not request firebase function by using Cloud Task #157

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
RTae opened this issue Nov 2, 2023 · 25 comments · Fixed by #171
Closed

Can not request firebase function by using Cloud Task #157

RTae opened this issue Nov 2, 2023 · 25 comments · Fixed by #171
Assignees
Labels
bug Something isn't working cloud-tasks

Comments

@RTae
Copy link

RTae commented Nov 2, 2023

Hi, I have problem requesting a firebase function by using cloud task

this is my code

tasks_client = tasks_v2.CloudTasksClient()

task_queue = tasks_client.queue_path(
                params.PROJECT_ID.value, 
                SupportedRegion.US_CENTRAL1.value,
                DATA_TASK_NAME
            )
    
task = tasks_v2.Task(
            http_request= {
                "http_method": tasks_v2.HttpMethod.POST,
                "url": "https://cloudrune-service-generate-by-cloud-function.a.run.app",
                "headers":{"Content-type": "application/json"},
                "oidc_token": tasks_v2.OidcToken(
                    service_account_email=f"service_account@{settings.PROJECT_NAME}.iam.gserviceaccount.com",
                ),
                "body": json.dumps({"data":{"update_date": data['update_date']}}).encode()
            }
        )

It will raise an error about authentication.

ERROR:root:Error validating token: The Firebase ID token has an incorrect "aud" (audience) claim. Expected "PROJECT_ID" but got "https://cloudrune-service-generate-by-cloud-function.a.run.app". Make sure the ID token comes from the same Firebase project as the service account used to authenticate this SDK. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.

WARNING: Root:Callable request verification failed: $[('Auth token was rejected.', {'app': 'MISSING', 'auth': 'INVALID', 'logging.googleapis.com/labels': {'firebase-log-type': 'callable-request-verification'}})]

if I add audience in oidc_token with project ID, it will raise another error

The request was not authorized to invoke this service. Read more at https://cloud.google.com/run/docs/securing/authenticating Additional troubleshooting documentation can be found at: https://cloud.google.com/run/docs/troubleshooting#401

From my understanding, both error are about authentication from firebase and cloud run

@exaby73
Copy link
Contributor

exaby73 commented Nov 7, 2023

Hello @RTae. Could you tell me which libraries you're using?

@exaby73 exaby73 added the waiting for customer response Issue is on hold awaiting more information from OP label Nov 7, 2023
@RTae
Copy link
Author

RTae commented Nov 8, 2023

@exaby73 I'm using firebase function to create a cloud task to request another firebase function. Basically, I followed this example but it not working https://firebase.google.com/docs/functions/task-functions?gen=2nd#python

tasks_v2 : https://pypi.org/project/google-cloud-tasks/

@antont
Copy link

antont commented Nov 8, 2023

I also failed to get the auth token biz working similarily, so ended up removing access control from the task queue, to get forward. Our thing is low security anyway, and if needed, I guess I can add an API key to the workers. Would be nice to have proper auth working though ofc.

@kulaone
Copy link

kulaone commented Nov 28, 2023

I tried to follow this Python example too, with no success.
The task is added to the queue, but when the task invoking the function I get:
"The request was not authenticated. Either allow unauthenticated invocations or set the proper Authorization header. Read more at https://cloud.google.com/run/docs/securing/authenticating Additional troubleshooting documentation can be found at: https://cloud.google.com/run/docs/troubleshooting#unauthorized-client"

@exaby73
Copy link
Contributor

exaby73 commented Dec 4, 2023

Is it possible to give me an example I could test with?

@antont
Copy link

antont commented Dec 5, 2023

Is it possible to give me an example I could test with?

That basically is it, I also tried to follow it and got into the same trouble. https://firebase.google.com/docs/functions/task-functions?gen=2nd#python

@spartonia
Copy link

Any luck here? I also followed the docs but no luck.

@ShadowBearVR
Copy link

I am in the same boat. Anyone find a solution to this?

@pr-Mais
Copy link
Member

pr-Mais commented Jan 15, 2024

Hello all, for those following the sample here there's a small issue, first change location: str = SupportedRegion.US_CENTRAL1 to location: str = SupportedRegion.US_CENTRAL1.value, the location was sent as a literal locations/supportedregion.us_central1 thus we get the error Location SupportedRegion.US_CENTRAL1 is not found or access is unauthorized. (it really doesn't exist).

@kulaone @antont @spartonia @ShadowBearVR have you followed the instructions here? the error indicates that the service account used doesn't have the role roles/cloudfunctions.invoker.

@RTae you're trying to use a service account other than the ADC right?

@ShadowBearVR
Copy link

@pr-Mais I can confirm the required permissions (and extra) were added and I still got the same type of errors.

@pr-Mais
Copy link
Member

pr-Mais commented Jan 15, 2024

@ShadowBearVR can you post the exact error message you're getting and if it's the same as the issue author?

@pr-Mais pr-Mais self-assigned this Jan 17, 2024
@sjudd
Copy link

sjudd commented Jan 21, 2024

I'm also unable to get this to work. The example doesn't include an auth header or token:

task_queue = tasks_client.queue_path(project_id, REGION.value, <function_name>)
    target_uri = get_function_url(<function_name>)
   body = {}
    task = tasks_v2.Task(
        http_request={
            "http_method": tasks_v2.HttpMethod.POST,
            "url": target_uri,
            "headers": {
                "Content-type": "application/json",
            },
            "body": json.dumps(body).encode(),
        }
    )
    tasks_client.create_task(parent=task_queue, task=task)

This produces an error indicating that an authorization token is required in the function that consumes the queue:

"The request was not authenticated. Either allow unauthenticated invocations or set the proper Authorization header. Read more at https://cloud.google.com/run/docs/securing/authenticating Additional troubleshooting documentation can be found at: https://cloud.google.com/run/docs/troubleshooting#unauthorized-client"

The roles for my default compute service account include cloud run invoker and cloud function invoker:
image

If you follow https://cloud.google.com/run/docs/authenticating/service-to-service#run-service-to-service-example-python, that suggests that you set the url from your service as the audience and create a bearer token you pass through:

    target_uri = get_function_url(function_name)
    auth_req = google.auth.transport.requests.Request()
    id_token = google.oauth2.id_token.fetch_id_token(auth_req, target_uri)

    task = tasks_v2.Task(
        http_request={
            "http_method": tasks_v2.HttpMethod.POST,
            "url": target_uri,
            "headers": {
                "Content-type": "application/json",
                "Authorization": f"Bearer {id_token}",
            },
            "body": json.dumps(body).encode(),
        }
    )
    tasks_client.create_task(parent=task_queue, task=task)

This produces a different error in the queue consumer:

ERROR:root:Error validating token: Firebase ID token has incorrect "aud" (audience) claim. Expected "<project_id>" but got "https://us-central1-<project_id>cloudfunctions.net/<function_name>". Make sure the ID token comes from the same Firebase project as the service account used to authenticate this SDK. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve ID token."

If you change the audience from the function to the firebase project (<project_id>), you get a different error:

textPayload: "The request was not authorized to invoke this service. Read more at https://cloud.google.com/run/docs/securing/authenticating Additional troubleshooting documentation can be found at: https://cloud.google.com/run/docs/troubleshooting#401"

That certainly looks like the service account doesn't have the required permission, but it does at least have functions invoker and cloud run invoker.

It would be really helpful to have a working example. Based on the very first error, it seems like you must explicitly pass some kind of auth information to tasks_v2.Task, but the example doesn't do so.

Edit: It looks like there are two different auth checks being performed with two different (and maybe incompatible) sets of requirements. The first looks like a standard firebase auth check. The second seems like it's the underlying cloud tasks. The error messages make it look like we're able to satisfy either Firebase or Cloud Tasks checks, but not both.

@sjudd
Copy link

sjudd commented Jan 22, 2024

And just for fun, I tried creating a task queue using typescript and calling it from python. That works perfectly if you follow the guidance in https://cloud.google.com/run/docs/authenticating/service-to-service#run-service-to-service-example-python:

target_uri = get_function_url(function_name)
auth_req = google.auth.transport.requests.Request()
id_token = google.oauth2.id_token.fetch_id_token(auth_req, target_uri)

task = tasks_v2.Task(
    http_request={
        "http_method": tasks_v2.HttpMethod.POST,
        "url": target_uri,
        "headers": {
            "Content-type": "application/json",
            "Authorization": f"Bearer {id_token}",
        },
        "body": json.dumps(body).encode(),
    }
)
tasks_client.create_task(parent=task_queue, task=task)

If I instead define the queue in python and call it with exactly the same code, I get:

ERROR:root:Error validating token: Firebase ID token has incorrect "aud" (audience) claim. Expected "<project_id>" but got "https://<function-name>-NNNN-uc.a.run.app". Make sure the ID token comes from the same Firebase project as the service account used to authenticate this SDK. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve ID token."

This seems problematic? https://github.com/firebase/firebase-functions-python/blob/7f83050dc44f7877a58a590a5aae1006a6f14358/src/firebase_functions/private/util.py#L218C28-L218C43. That's calling a firebase function to validate auth. The only other use of that method I see is for https functions where using Firebase's auth makes more sense because the caller is very likely to be external: https://github.com/search?q=repo%3Afirebase/firebase-functions-python%20_on_call_handler&type=code. It definitely seems like Firebase's auth requirements differ from the Cloud Run Service's auth requirements. Since they both use the same header it's not possible to satisfy both.

A workaround seems to be to enable "Allow unauthenticated invocations" for the service. Firebase might still pass through and validate its own auth token if you do this (I haven't tried to validate that), but you can also pass through a secret or an auth token using the body and manually validate it.

@cons-andreas-kahmann
Copy link

I have the same issue. Following the example "https://firebase.google.com/docs/functions/task-functions?gen=2nd", whatever configuration I use, I always get some kind of authentication / authorization error

@jacobg
Copy link

jacobg commented Jan 25, 2024

I'm having the same issue here. I tried adding an oidc_token to the task http_request. If audience is set to the project, Cloud Run returns 401 with error logged:

The request was not authorized to invoke this service. Read more at https://cloud.google.com/run/docs/securing/authenticating Additional troubleshooting documentation can be found at: https://cloud.google.com/run/docs/troubleshooting#401

If audience is set to the function url, then the function does seem to get invoked but the Firebase task wrapper fails with this error:

ERROR:root:Error validating token: Firebase ID token has incorrect "aud" (audience) claim. Expected "PROJECT-ID" but got "FUNCTION-URL". Make sure the ID token comes from the same Firebase project as the service account used to authenticate this SDK. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve ID token.

As a previous poster notes, it seems there are two layers of authentication that conflict with each other.

Can Firebase team please follow up on this issue? Many people here need help. Thanks!

@jacobg
Copy link

jacobg commented Jan 25, 2024

Since the Cloud Run service is already doing the authentication, it seems we can patch the Firebase SDK inside the function to bypass auth:

import firebase_functions.private.util as firebase_private_util
def _on_call_check_auth_token(*args, **kwargs):
    return None
firebase_private_util._on_call_check_auth_token = _on_call_check_auth_token

Then when enqueing a task, make sure to set the oidc_token in the task's http_request to meet the requirements of Cloud Run:

            "oidc_token": {
                'service_account_email': FUNCTION_IDENTITY,
                'audience': task_http_request_url,
            }

I verified this works.

@pr-Mais
Copy link
Member

pr-Mais commented Jan 29, 2024

Thanks, everyone for providing such detailed comments! we were able to reproduce.

@jacobg This might be the issue, we are working on a fix ASAP.

@jacobg
Copy link

jacobg commented Jan 29, 2024

Thank you @pr-Mais 👍

@exaby73 exaby73 linked a pull request Feb 3, 2024 that will close this issue
@exaby73 exaby73 added bug Something isn't working cloud-tasks and removed waiting for customer response Issue is on hold awaiting more information from OP labels Feb 3, 2024
@exaby73
Copy link
Contributor

exaby73 commented Feb 13, 2024

This issue should be fixed and will go out in the next release

@AdamGreenAwardMatcher
Copy link

Any update for when this will be released?

@GoodluckH
Copy link

GoodluckH commented Mar 24, 2024

^ Same question. Wonder if there're any temporary workarounds for this?

@vitoras
Copy link

vitoras commented Apr 6, 2024

This issue should be fixed and will go out in the next release

Hi @exaby73, any updates on this? When will the next release happen?

^ Same question. Wonder if there're any temporary workarounds for this?

@GoodluckH , the workaround is to define your function as @https_fn.on_request instead of @tasks_fn.on_task_dispatched

@exaby73
Copy link
Contributor

exaby73 commented Apr 7, 2024

We're planning a release soon. Keep a lookout in the next couple of days

@milanmitrovic
Copy link

Any updates? I also have the same issue.

@collbreno
Copy link

I had the same issue here. Updating firebase-functions from 0.2.0 to 0.4.1 fixed it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working cloud-tasks
Projects
None yet
Development

Successfully merging a pull request may close this issue.