<p>I am not able to use the Python Firebase Admin SDK in a docker container, specifically on Google Kubernetes Engine (GKE). The same container has no problems on Cloud Run. I believe the problem is permissions, but I've gotten pretty stuck. Any help would be appreciated!</p>
<p>Here is the outline of the flask app. All three routes work on Cloud Run, the first two work on GKE and the third fails.</p>
<pre><code># realtime database address 
dbAddress = 'https://[projectID].firebaseio.com/'

# initialize the firebase SDK
credentials = None # the service account should provide the credentials
firebase_admin.initialize_app(credentials,{'databaseURL': dbAddress})

@app.route('/')
def hello_world(): # works on cloud run and GKE
    print('Hello, World print statement!')
    return 'Hello, World!'

@app.route('/simplepost', methods = ['POST'])
def simple_post():# works on cloud run and GKE
    content = request.get_json()
    return {'results': content}, 201

@app.route('/firepost', methods = ['POST'])
def fire_post(): # works on cloud run. FAILS ON GKE!
    jobRef = db.reference('jobs/').push()
    return {'results': jobRef.path}, 201

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))
</code></pre>
<p>Repo with container (requires your own firebase project):
<a href="https://github.com/crispyDyne/GKE-py-fire" rel="nofollow noreferrer">https://github.com/crispyDyne/GKE-py-fire</a></p>
<p>Error from GKE console:</p>
<pre><code>Traceback (most recent call last):
  File &quot;/usr/local/lib/python3.8/site-packages/firebase_admin/db.py&quot;, line 943, in request
    return super(_Client, self).request(method, url, **kwargs)
  File &quot;/usr/local/lib/python3.8/site-packages/firebase_admin/_http_client.py&quot;, line 117, in request
    resp.raise_for_status()
  File &quot;/usr/local/lib/python3.8/site-packages/requests/models.py&quot;, line 941, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: https://[projectName].firebaseio.com/jobs.json
</code></pre>
<p>I've tried to solve permission issue through &quot;Workload Identity&quot;, with no luck.</p>
<p>When I create my GKE cluster, I set a service account for the node pool that has the &quot;owner&quot; role (should be overkill). Under cluster security, I select the &quot;Enable Workload Identity&quot; checkbox.</p>
<p>I then configure the Kubernetes service account using the instructions below:
<a href="https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#gcloud_1" rel="nofollow noreferrer">https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#gcloud_1</a></p>
<p>I deploy the workload from my container registry, and expose it using an external load balancer (port:80, target port: 8080). The first two routes work fine, but they third fails. All three work fine when deployed on Cloud Run.</p>
<p>Hopefully I'm doing something dumb that is an easy fix! Cheers!</p>

<p>After lots of struggles I think I figured it out. Here are three ways create a cluster, deploy a container, and end up with the correct Application Default Credentials in the pod.</p>
<hr />
<p><strong>1. Workload Identity</strong> (basically this <a href="https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity" rel="noreferrer">Workload Identity article</a>, with some deployment details added)</p>
<p>This method is preferred because it allows each pod deployment in a cluster to be granted only the permissions it needs.</p>
<p>The googleServiceAccount used needs to have the appropriate roles assigned (see below).</p>
<p>Create cluster (note: no scopes or service account defined)</p>
<pre><code>gcloud beta container clusters create {cluster-name} \
  --release-channel regular \
  --identity-namespace {projectID}.svc.id.goog

</code></pre>
<p>Then create the k8sServiceAccount, assign roles, and annotate.</p>
<pre><code>gcloud container clusters get-credentials {cluster-name}

kubectl create serviceaccount --namespace default {k8sServiceAccount}

gcloud iam service-accounts add-iam-policy-binding \
  --member serviceAccount:{projectID}.svc.id.goog[default/{k8sServiceAccount}] \
  --role roles/iam.workloadIdentityUser \
  {googleServiceAccount}

kubectl annotate serviceaccount \
  --namespace default \
  {k8sServiceAccount} \
  iam.gke.io/gcp-service-account=$3
</code></pre>
<p>Then I create my deployment, and <strong>set the k8sServiceAccount</strong>.
(Setting the service account was the part that I was missing)</p>
<pre><code>kubectl create deployment {deployment-name} --image={containerImageURL}
kubectl set serviceaccount deployment {deployment-name} {k8sServiceAccount}
</code></pre>
<p>Then expose with a target of 8080</p>
<pre><code>kubectl expose deployment {deployment-name}  --name={service-name} --type=LoadBalancer --port 80 --target-port 8080
</code></pre>
<hr />
<p><strong>2. Cluster Service Account</strong></p>
<p>This method is not preferred, because all VMs and pods in the cluster will have permissions based on the defined service account.</p>
<p>Create cluster with assigned service account</p>
<pre><code>gcloud beta container clusters create [cluster-name] \
 --release-channel regular \
 --service-account {googleServiceAccount}
</code></pre>
<p>The googleServiceAccount used needs to have the appropriate roles assigned (see below).</p>
<p>Then deploy and expose as above, but without setting the k8sServiceAccount</p>
<hr />
<p><strong>3. Scopes</strong></p>
<p>This method is not preferred, because all VMs and pods in the cluster will have permisions based on the scopes defined.</p>
<p>Create cluster with assigned scopes (firestore only requires &quot;cloud-platform&quot;, realtime database also requires &quot;userinfo.email&quot;)</p>
<pre><code>gcloud beta container clusters create $2 \
  --release-channel regular \
  --scopes https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/userinfo.email

</code></pre>
<p>Then deploy and expose as above, but without setting the k8sServiceAccount</p>
<hr />
<p>The first two methods require a Google Service Account with the appropriate roles assigned. Here are the roles I assigned to get a few Firebase products working:</p>
<ul>
<li>FireStore: Cloud Datastore User (Datastore)</li>
<li>Realtime Database: Firebase Realtime Database Admin (Firebase Products)</li>
<li>Storage: Storage Object Admin (Cloud Storage)</li>
</ul>
