ShivanKaul
ShivanKaul

Reputation: 757

Reading secret config file on Heroku without using env vars

I'm using the Google Cloud Pub Sub API with NodeJS, as documented here. I'm using Heroku to run my server.

The sample code on the Node JS + Pub Sub page asks me to specify a path to a file:

pubsub = gcloud.pubsub({
    projectId: 'my-project',
    keyFilename: '/path/to/keyfile.json'
});

I typically use Heroku's config vars to store secrets and API keys, but in this case it seems that the GCloud API requires me to specify the path to a file. So, I would need to check in a file into Heroku, but not my GitHub repo.

I have tried the following: Pushing .gitignore files to specific remote and How can I upload my application to github but remove sensitive authorization information? but the trouble is that once I force add (git add -f keyfile.json) the json file and make a commit out of it and make a new branch, I can't push that commit to Heroku because when I do git push heroku master, it says Everything is up to date. In any case, that seems very messy. There has got to be a cleaner way to make Google Cloud work with Heroku.

What should I do?

Upvotes: 6

Views: 3073

Answers (2)

ShivanKaul
ShivanKaul

Reputation: 757

Was answered by the lovely folks over at GoogleCloudPlatform: https://github.com/GoogleCloudPlatform/gcloud-node/issues/761

It's not mentioned in the code sample in the documentation, but you can just add a credentials object and pass that to your config. The credentials object can read env vars.

More information here: https://googlecloudplatform.github.io/gcloud-node/#/authorization.
Updated link: https://googleapis.dev/nodejs/pubsub/latest/global.html#ClientConfig

Upvotes: 3

Serkan
Serkan

Reputation: 160

Not for nodejs but for GO (GOLANG) keep each field value as a separate key in environment variables and then you will need to do something like this, create struct, convert to json (replacing every \\n to \n in the private_key), feed into option.WithCredentialsJSON:

type credentialsData struct {
    Type                    string `json:"type"`
    ProjectId               string `json:"project_id"`
    PrivateKeyId            string `json:"private_key_id"`
    PrivateKey              string `json:"private_key"`
    ClientEmail             string `json:"client_email"`
    ClientId                string `json:"client_id"`
    AuthUri                 string `json:"auth_uri"`
    TokenUri                string `json:"token_uri"`
    AuthProviderX509CertUrl string `json:"auth_provider_x509_cert_url"`
    ClientX509CertUrl       string `json:"client_x509_cert_url"`
}

func firebase_init() *firebase.App {
    backSlashFix := strings.Replace(os.Getenv("FIREBASE_PRIVATE_KEY"), "\\n", "\n", -1)
    json_cred := &credentialsData{
        Type:                    os.Getenv("FIREBASE_ACCOUNT_TYPE"),
        ProjectId:               os.Getenv("FIREBASE_PROJECT_ID"),
        PrivateKeyId:            os.Getenv("FIREBASE_PRIVATE_KEY_ID"),
        PrivateKey:              backSlashFix,
        ClientEmail:             os.Getenv("FIREBASE_CLIENT_EMAIL"),
        ClientId:                os.Getenv("FIREBASE_CLIENT_ID"),
        AuthUri:                 os.Getenv("FIREBASE_AUTH_URI"),
        TokenUri:                os.Getenv("FIREBASE_TOKEN_URI"),
        AuthProviderX509CertUrl: os.Getenv("FIREBASE_AUTH_PROVIDER_X509_CERT_URL"),
        ClientX509CertUrl:       os.Getenv("FIREBASE_CLIENT_X509_CERT_URL"),
    }

    bytes, e := json.Marshal(json_cred)
    if e != nil {
        panic(fmt.Errorf("Could not create json from credentials struct", e))
    }
    opt := option.WithCredentialsJSON([]byte(string(bytes)))
    app, err := firebase.NewApp(context.Background(), &firebase.Config{ProjectID: "<your project id>"}, opt)
    if err != nil {
        panic(fmt.Errorf("error initializing app: %v", err))
    }

    return app
}

Upvotes: 0

Related Questions