11

I was hoping to trigger a Pub/Sub function (using functions.pubsub / onPublish) whenever a new Pub/Sub message is sent to a topic/subscription in a third-party project i.e. cross projects.

After some research and experimentation I found that TopicBuilder throws an error if the topic name contains a / and it defaults to "projects/" + process.env.GCLOUD_PROJECT + "/topics/" + topic (https://github.com/firebase/firebase-functions/blob/master/src/providers/pubsub.ts).

I also found a post in Stack Overflow that says that "Firebase provides a (relatively thin) wrapper around Google Cloud Functions" (What is the difference between Cloud Function and Firebase Functions?)

This led me to look into Google Cloud Functions. Whilst I was able to create a subscription in a project I own to a topic in a third-party project - after changing permissions in IAM - I could not find a way associate a function with the topic. Nor was I successful in associating a function with a topic and subscription in a third-party project. In the console I only see the topics in my project and I had no success using gcloud.

Has anyone had any success in using a function across projects and, if so, how did you achieve this and is there a documentation URL you could provide? If a function can't be triggered by a message to a topic and subscription in a third-party project can you think of a way that I could ingest third-party Pub/Sub data?

As Pub/Sub fees are billed to the project that contains the subscription I would prefer that the subscription resides in the third-party project with the topic.

Thank you

Community
  • 1
  • 1
R M
  • 113
  • 2
  • 5

3 Answers3

6

Google Cloud Functions currently does not not allow a function to listen to a resource in another project. For Cloud Pub/Sub triggers specifically you could get around this by deploying an HTTP-function and add a Pub/Sub push subscription to the topic that you want to fire that cross-project function.

Thomas Bouldin
  • 3,707
  • 19
  • 21
  • @Thomas_Bouldin wouldn't that require your Firebase CF http listener be a public endpoint w/ no auth? – Joseph Lust Jun 12 '17 at 00:27
  • 1
    This would require you to roll your own auth. A cheap and easy way for you to do this is to add a secret key as a query fragment in the publish URL. Your Cloud Function would reject requests that did not match the secret key. – Thomas Bouldin Jun 20 '17 at 18:02
  • Pub/sub also requires you to do domain ownership validation, which is a big headache, particularly if you're trying to deploy simple cloud functions: https://cloud.google.com/pubsub/docs/push#domain_ownership_validation – jacob Nov 29 '19 at 17:02
1
  • A Google Cloud Function can't be triggered by a subsription to a topic of another project (since you can't subscribe to another project's topic).

  • But a Google Cloud Function can publish to a topic of another project (and then subscribers of this topic will be triggered).

I solved it by establishing a Google Cloud Function in the original project which listens to the original topic and reacts with publishing to a new topic in the other project. Therefore, the service account (...@appspot.gserviceaccount.com) of this function "in the middle" needs to be authorized by the new topic (console.cloud.google.com/cloudpubsub/topic/detail/...?project=...), i.e. add principal with role: "Pub/Sub Publisher"

enter image description here

import base64
import json
import os

from google.cloud import pubsub_v1


#https://cloud.google.com/functions/docs/calling/pubsub?hl=en#publishing_a_message_from_within_a_function


# Instantiates a Pub/Sub client
publisher = pubsub_v1.PublisherClient()

def notify(event, context):
    project_id = os.environ.get('project_id')  
    topic_name = os.environ.get('topic_name')  

    # References an existing topic
    topic_path = publisher.topic_path(project_id, topic_name)  

    message_json = json.dumps({
        'data': {'message': 'here would be the message'},  # or you can pass the message of event/context
    })
    message_bytes = message_json.encode('utf-8')

    # Publishes a message
    try:
        publish_future = publisher.publish(topic_path, data=message_bytes)
        publish_future.result()  # Verify the publish succeeded
        return 'Message published.'
    except Exception as e:
        print(e)
        return (e, 500)
Yves
  • 229
  • 2
  • 6
0

google endpoints can be a easier solution to add auth to the function http.

Fargo-Zhu
  • 25
  • 4