Skip to content
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

Authorize using Firebase CLI credentials #2214

Merged
merged 18 commits into from
Jul 7, 2020
Merged

Conversation

samtstern
Copy link
Contributor

@samtstern samtstern commented May 6, 2020

Description

Fixes #1940

TODO:

  • Add pre-execution warnings about accessing prod
  • Add a description of how auth works in the README

This change will allow the Firebase emulators to pass the credentials from firebase login as Cloud application default credentials.

Currently the emulators rely on picking up gcloud auth application-default login credentials on the machine which is at best annoying and at worst means that the emulators are authorized as the wrong user.

Here's the new behavior matrix:

# Firebase Login Application Default GAC Env Result
1 Emulator has no auth at all
2 CLI passes GAC env to emulator with user credential
3 ADC may be discovered and used
4 Emulator will use explicit GAC credential
5 CLI passes GAC env, ADC is ignored
6 CLI does not pass cred, Emulator will use explicit GAC credential
7 Emulator will use explicit GAC credential, ADC is ignored
8 Emulator will use explicit GAC credential, all others

Note: we can/should change the behavior of Scenario 3 when this bug is fixed:
firebase/firebase-js-sdk#3144

Scenarios Tested

Functions used for all tests:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

async function tryRtdbWrite() {
  const db = admin.database();
  try {
    await db.ref().child('test').set({
      date: new Date().toISOString()
    });
    return true;
  } catch (e) {
    console.warn(e);
    return false;
  }
}

exports.helloWorld = functions.https.onRequest(async (request, response) => {
  response.json({
    creds: process.env.GOOGLE_APPLICATION_CREDENTIALS || null,
    canWriteToDatabase: await tryRtdbWrite()
  });
});

Scenario 1

See logs
$ http http://localhost:5001/fir-dumpster/us-central1/helloWorld

http: error: Request timed out (30s).

Emulator logs

>  [2020-07-07T18:30:07.387Z]  @firebase/database: FIREBASE WARNING: {"code":"app/invalid-credential","message":"Credential implementation provided to initializeApp() via the \"credential\" property failed to fetch a valid Google OAuth2 access token with the following error: \"Error fetching access token: Error while making request: getaddrinfo ENOTFOUND metadata.google.int

Scenario 2

See logs
$ http http://localhost:5001/fir-dumpster/us-central1/helloWorld
HTTP/1.1 200 OK
connection: keep-alive
content-length: 127
content-type: application/json; charset=utf-8
date: Tue, 07 Jul 2020 18:32:07 GMT
etag: W/"7f-QwapyiMrFDzSQjxgEK52zAhX9pU"
x-powered-by: Express

{
    "canWriteToDatabase": true,
    "creds": "/Users/samstern/.config/firebase/samstern_google_com_application_default_credentials.json"
}

Scenario 3

See logs
$ http http://localhost:5001/fir-dumpster/us-central1/helloWorld
HTTP/1.1 200 OK
connection: keep-alive
content-length: 40
content-type: application/json; charset=utf-8
date: Tue, 07 Jul 2020 18:40:37 GMT
etag: W/"28-0p3KpSLf1GtAozwuGH12/ekZOZY"
x-powered-by: Express

{
    "canWriteToDatabase": true,
    "creds": null
}

Scenario 4

See logs
$ http http://localhost:5001/fir-dumpster/us-central1/helloWorld
HTTP/1.1 200 OK
connection: keep-alive
content-length: 104
content-type: application/json; charset=utf-8
date: Tue, 07 Jul 2020 18:36:43 GMT
etag: W/"68-YwHpi6KFuPjLagvh8WBTCXYvjUY"
x-powered-by: Express

{
    "canWriteToDatabase": true,
    "creds": "/Users/samstern/service-accounts/fir-dumpster/service-account.json"
}

Scenario 5

See logs
$ http http://localhost:5001/fir-dumpster/us-central1/helloWorld
HTTP/1.1 200 OK
connection: keep-alive
content-length: 127
content-type: application/json; charset=utf-8
date: Tue, 07 Jul 2020 18:38:08 GMT
etag: W/"7f-QwapyiMrFDzSQjxgEK52zAhX9pU"
x-powered-by: Express

{
    "canWriteToDatabase": true,
    "creds": "/Users/samstern/.config/firebase/samstern_google_com_application_default_credentials.json"
}

Scenario 6

See logs
$ http http://localhost:5001/fir-dumpster/us-central1/helloWorld
HTTP/1.1 200 OK
connection: keep-alive
content-length: 104
content-type: application/json; charset=utf-8
date: Tue, 07 Jul 2020 18:34:23 GMT
etag: W/"68-YwHpi6KFuPjLagvh8WBTCXYvjUY"
x-powered-by: Express

{
    "canWriteToDatabase": true,
    "creds": "/Users/samstern/service-accounts/fir-dumpster/service-account.json"
}

Scenario 7

See logs
$ http http://localhost:5001/fir-dumpster/us-central1/helloWorld
HTTP/1.1 200 OK
connection: keep-alive
content-length: 104
content-type: application/json; charset=utf-8
date: Tue, 07 Jul 2020 18:39:34 GMT
etag: W/"68-YwHpi6KFuPjLagvh8WBTCXYvjUY"
x-powered-by: Express

{
    "canWriteToDatabase": true,
    "creds": "/Users/samstern/service-accounts/fir-dumpster/service-account.json"
}

Scenario 8

See logs
$ http http://localhost:5001/fir-dumpster/us-central1/helloWorld
HTTP/1.1 200 OK
connection: keep-alive
content-length: 104
content-type: application/json; charset=utf-8
date: Tue, 07 Jul 2020 18:38:46 GMT
etag: W/"68-YwHpi6KFuPjLagvh8WBTCXYvjUY"
x-powered-by: Express

{
    "canWriteToDatabase": true,
    "creds": "/Users/samstern/service-accounts/fir-dumpster/service-account.json"
}

Sample Commands

N/A

@googlebot googlebot added the cla: yes Manual indication that this has passed CLA. label May 6, 2020
@samtstern samtstern marked this pull request as draft May 6, 2020 17:41
@samtstern samtstern requested a review from yuchenshi May 19, 2020 12:49
@samtstern samtstern marked this pull request as ready for review May 19, 2020 12:51
Copy link
Member

@yuchenshi yuchenshi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval for TypeScript readability. Please add more folks for the context of the change if possible.

src/emulator/controller.ts Outdated Show resolved Hide resolved
src/defaultCredentials.ts Outdated Show resolved Hide resolved
src/defaultCredentials.ts Outdated Show resolved Hide resolved
src/defaultCredentials.ts Outdated Show resolved Hide resolved
Copy link

@hiranya911 hiranya911 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation LGTM, although I'm not familiar with how these different components are wired together in the emulator suite.

@hiranya911 hiranya911 removed their assignment May 21, 2020

// We could use fs.writeFileSync() here but it's important that the caller understands
// that this is a somewhat expensive operation so we make it a Promise.
return new Promise((res, rej) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this overwrite whatever is currently in that path? Is that the behavior we want?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that's the behavior we want. I'm willing to pay this small extra cost to avoid the whole class of bugs that come with potentially out of date credentials.

@samtstern samtstern requested a review from bkendall May 28, 2020 16:08
Copy link
Contributor

@mbleigh mbleigh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple tactical comments, also here's some broad thinking:

This is a broadly useful thing in terms of making it possible for your local environment to be application default credentialed for the things you want to access. It's also a little dangerous in that regard, and I know gcloud is moving away from using user-based credentials for anything. If I have a major reservation about doing it at all, it's that -- the credentials associated with the Firebase CLI are broad.

Separately though, the fact that you can do this at all might unblock firebase shell and could be really useful for developers who want to write firebase-admin scripts. Having a command like firebase account:credentials that populates this file for non-emulator use might be worth considering.

src/defaultCredentials.ts Outdated Show resolved Hide resolved
src/defaultCredentials.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@bkendall bkendall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have my 👍 , pending your TODOs - let me know if you want me to come back and look at this again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes Manual indication that this has passed CLA.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Functions shell/emulator unable to load default credentials
6 participants