Daniel O.
Daniel O.

Reputation: 813

What is the pythonic way to deal with API keys when distributing a package?

I have created a Python module which I would like to distribute via PyPI. It relies on a third party API which in turn requires a free API key.

Yesterday I asked this question on how to reference a YAML file (which would contain the API keys) using the true path of the module. However that got me thinking of other ways;

  1. Ask the users to save the API key as an environment variable and have the script check for the existence of said variable
  2. Ask the user to pass in the API key as an **kwargs argument when creating a new instance of the object e.g.

    thing = CreateThing(user_key = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', api_key = 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')

I would like to see what the community thinks on this topic.

Upvotes: 3

Views: 3454

Answers (2)

smarie
smarie

Reputation: 5216

From this answer: it is recommended to use the OS keyring. In my lib odsclient I ended up implementing a series of alternatives, from the most secure (keyring) to the less ones (OS environment variable, git-ignored text file, arg-passed apikey possibly obfusctated with getpass()).

You might wish to have a look for inspiration, see this part of the doc in particular.

Upvotes: 1

Exadra37
Exadra37

Reputation: 13104

I have created a Python module which I would like to distribute via PyPI. It relies on a third party API which in turn requires a free API key.

Even being a free api-key you should never have it in your code, even less have your code distributed to the public with it.

My advice is to never have any secrets on your code, not even default secrets as many developers like to put in their calls to get values from environment variables, configuration files, databases or whatsoever they retrieve them from.

When dealing with secrets you must always raise an exception when you fail to obtain one... Once more don't use default values from your code, not even with the excuse that they will be used only during development and/or testing.

I recommend you to read this article I wrote about leaking secrets in your code to understand the consequences of doing so, like this one:

Hackers can, for example, use exposed cloud credentials to spin up servers for bitcoin mining, for launching DDOS attacks, etc and you will be the one paying the bill in the end as in the famous "My $2375 Amazon EC2 Mistake"...

While the article is in the context of leaking secrets in the code a mobile app, must of the article applies to any type of code we write and commit into repositories.

About your proposed solution

  1. Ask the users to save the API key as an environment variable and have the script check for the existence of said variable
  2. Ask the user to pass in the API key as an **kwargs argument when creating a new instance of the object e.g.

    thing = CreateThing(user_key = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', api_key = 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb')

The number 1 is a good one and you sould use here the dot env file approach, maybe using a package like this one. But remember to raise an exception if the values does not exist, please never use defaults from your code.

Regarding solution 2 it is more explicit for the developer using your library, but you should recommend also them the .env file and help them understand how to properly manage them. For example secrets used on .env files should be retrieved from a vault software.

A SECURITY CALL OF ATTENTION

Dot env files cannot be committed into the source code at any time and when committing the .env.example, into your git repo, it must not contain any default values.

Oh you may think if I commit it accidentally to Github I will just clean my commits, rewrite the history and do a force push. Well think twice and see why that will not solve the problem you have created:

Well I have bad news for you... it seems that some services cache all github commits, thus hackers can check these services or employ the same techniques to immediately scan any commit sent to github in a matter of seconds.

Source: the blog post I linked above.

And remember what I have quoted earlier "My $2375 Amazon EC2 Mistake, that was due to leaked credentials in an accidental Github commit.

Upvotes: 2

Related Questions