Skip to content

keyFilename makes 12-factor app style deployment difficult #136

Description

@hulbert

I'm trying to use cloud storage which the documentation says I should initialize as such:

var gcloud = require('gcloud'),
    bucket = new gcloud.storage.Bucket({
        bucketName: YOUR_BUCKET_NAME,
        keyFilename: '/path/to/the/key.json'
    });

I dug into the code and this keyFilename option seems to be the only way to specify this required info, and it expects a filepath string. This makes storing the key's JSON as an environmental variable pretty complicated since I'd have to write the env value to a file, then pass the path to gcloud.

This seems to be a similar issue someone faced with Google APIs, a key file, and Heroku: http://ar.zu.my/how-to-store-private-key-files-in-heroku/

As he outlines, it seems there are four options, none super simple:

  1. Include the private key in my git repository.
  2. Store it in S3, and pull it when needed.
  3. Use custom build-pack which will include the key.
  4. Store it as config vars.

Even just having the option to pass this information in as a Javascript object (which makes sense for a node library) would be nice.

Activity

  1. rakyll commented on Aug 26, 2014

    @rakyll
    Contributor

    We should never assume that key file will be read from disk. We should require it to be passed as a plain object. Any other opinions?

  2. added this to the milestone on Aug 26, 2014
  3. silvolu commented on Aug 26, 2014

    @silvolu
    Contributor

    I would add a key option to pass the object, but keep the keyFilename is as well.
    Some people like the 'download the key and pass the path to the constructor'™ approach, mostly in the getting started experience context.

  4. rakyll commented on Aug 26, 2014

    @rakyll
    Contributor

    SGTM as we discussed offline.

  5. ryanseys commented on Aug 26, 2014

    @ryanseys
    Contributor

    Yes, both options is best. keyFilename: 'path/goes/here.json' should more or less just be an alias for key: require('path/goes/here.json') where key accepts a plain JavaScript object.

  6. rakyll commented on Aug 26, 2014

    @rakyll
    Contributor

    keyFilename should work the way it works (without require), otherwise it becomes impossible to specify relative paths to keyFilename. See 7641028.

  7. ryanseys commented on Aug 26, 2014

    @ryanseys
    Contributor

    Interesting... I've never had issues with relative paths + require but I've never pushed it to its limits either. 😄

    fs.readFile is definitely better anyway because it's async and won't automagically cache. 👍

  8. hulbert commented on Aug 26, 2014

    @hulbert
    Author

    Just an end-user perspective/question, is the entire JSON really needed or is it just using the private_key value? If you were to add a key option I would potentially be confused if this is to the whole object or just the value specified for the key private_key in the downloaded JSON file.

    This confusion might be worsened in my example of using environmental variables as I would likely break the JSON file into four ENV variables like so:

    declared environmental vars:

    GOOGLE_CLOUD_private_key_id=value
    GOOGLE_CLOUD_private_key=value
    GOOGLE_CLOUD_client_email=value
    GOOGLE_CLOUD_client_id=value
    GOOGLE_CLOUD_type=value
    

    Initializing gcloud-node:

    var gcloud = require('gcloud'),
        bucket = new gcloud.storage.Bucket({
            bucketName: YOUR_BUCKET_NAME,
            key: {
                "private_key_id": process.env.GOOGLE_CLOUD_private_key_id,
                "private_key": process.env.GOOGLE_CLOUD_private_key,
                "client_email": process.env.GOOGLE_CLOUD_client_email,
                "client_id": process.env.GOOGLE_CLOUD_client_id,
                "type": process.env.GOOGLE_CLOUD_type
            }
        });
  9. rakyll commented on Aug 26, 2014

    @rakyll
    Contributor

    We can rename the key to credentials which is basically what Connection object is doing at the moment. It's reading the file from keyFilename, parse and set it to Connection.prototype.credentials.

    Btw, you only need to provide private_key and client_email.

    var gcloud = require('gcloud'),
        bucket = new gcloud.storage.Bucket({
            bucketName: YOUR_BUCKET_NAME,
            credentials: {
                "private_key": process.env.GOOGLE_CLOUD_private_key,
                "client_email": process.env.GOOGLE_CLOUD_client_email,
            }
        });
  10. hulbert commented on Aug 27, 2014

    @hulbert
    Author

    @rakyll 👍 your example would address my original issue

  11. added 3 commits that reference this issue on Aug 27, 2014
    a553164
    4f1313c
    de4136b
  12. 70 remaining items

  13. added a commit that references this issue on Feb 4, 2026
  14. added a commit that references this issue on Feb 25, 2026
  15. added a commit that references this issue on Feb 26, 2026
  16. added a commit that references this issue on Mar 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

🚨This issue needs some love.triage meI really want to be triaged.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions