Incerteza
Incerteza

Reputation: 34884

Storing the secrets (passwords) in a separate file

What's the simplest way to store the application secrets (passwords, access tokens) for a Python script? I thought it'd be a *.yml file like in Ruby but surprisingly I found that it wasn't the case. So what is it then? What are the most simplest solutions?

I want to put them in a separate file because that way I'll be able not to push that file to a GitHub repository.

Upvotes: 80

Views: 123432

Answers (5)

RazorSharp5621
RazorSharp5621

Reputation: 9

Please do not rely on git ignore to keep files out of your repo. It is just too easy to make a mistake and all of a sudden, your passwords are in plain text for all the world to see (if it is a public repo). Then, when you realize it, you will delete the file--but may not realize the history still holds it. You may also neglect to change the password so, if someone already got it before you deleted it, you are still vulnerable. At the very least, encrypt them. You still have the problem of where to store the decryption key, but at least there is one more level of protection (security by obscurity).

O.S. environment variables are better in some ways, but aren't very safe either. Sys admins can see them and anyone able to run commands can do "env" command to get them all. Running remote commands is always a high prize for a bad actor for this reason (and others).

If your organization has an enterprise password manager, that is the obvious answer. If not, perhaps create a free AWS account and use their "Secrets Manager" service (or Microsoft or Google--they all have this ability and are considered very secure).

Only a little off topic, don't put secrets on the command line. While the process is running, the "ps" command will show the secret. After the process stops, there is the "history" command.

Upvotes: 0

Tea Tech
Tea Tech

Reputation: 102

Probably a little late to answer over here but still I want to share the way I think is easier to do and doesn't need much coding either.

Use ini files to store your secrets like this:

[section_name]
key1 = value1
key2 = value2

Then use the configparser library to read the ini file and extract different values from it.

Apart from this if you have just few variables to work with then I think that using .env files should also work.

In both of the above methods you will be able to ensure that you secrets are not acidentally uploaded on github by just adding *.ini or *.env in your .gitignore file.

Upvotes: 2

CraZ
CraZ

Reputation: 1824

I was dealing exactly the same question and actually ended up with the same solution as kecer suggested. Since I need to use it in dozens of scripts, I've created own library. Let me share this solution with you.

credlib.py -- universal library to handle credentials

class credential:
    def __init__(self, hostname, username, password):
        self.hostname = hostname
        self.username = username
        self.password = password

mycredentials.py -- my local file to store all credentials

from credlib import credential
sys_prod = credential("srv01", "user", "pass")
sys_stg = credential("srv02", "user", "pass")
sys_db = credential("db01", "userdb", "passdb")

mysystemlib.py -- this is a general library to access my system (both new credential system and legacy is supported)

from credlib import credential

def system_login(*args): # this is new function definition
#def system_login(hostname, username, password): # this was previous function definition

    if len(args) == 1 and isinstance(args[0], credential):
        hostname = args[0].hostname
        username = args[0].username
        password = args[0].password
    elif len(args) == 3:
        hostname = args[0]
        username = args[1]
        password = args[2]
    else:
        raise ValueError('Invalid arguments')

    do_login(hostname, username, password) # this is original system login call

main.py -- main script that combines credentials and system libs

from mycredentials import sys_stg, sys_db
import mysystemlib
...
mysystemlib.system_login(sys_stg)

Please note that the legacy hostname/username/password way still works so it does not affect old scripts:

mysystemlib.system_login("srv02", "user", "pass")

This has a lot benefits:

  • same credential system across all our python scripts
  • files with passwords are separated (files can have more strict permissions)
  • files are not stored in our git repositories (excluded via .gitignore) so that our python scripts/libs can be shared with others without exposing credentials (everyone defines their own credentials in their local files)
  • if a password needs to be changed, we do it at a single place only

Upvotes: 18

Scott Jermaine Guyton
Scott Jermaine Guyton

Reputation: 161

Personally I prefer to use yaml files, with the pyyaml library. Documentation here: https://pyyaml.org/wiki/PyYAMLDocumentation

Creating a .gitignore rule is very quick and painless and there is zero chances of making a mistake. You can added the rule with echo on Linux / UNIX like system with:

echo -e '*.yaml\n*.yml' >> .gitignore

Below is an example of retrieving the settings from a settings .yaml file in the same folder / location of the reader.

Code Snippets:

#!/usr/bin/env python3

import yaml
from pathlib import Path


def get_settings():
    full_file_path = Path(__file__).parent.joinpath('settings.yaml')
    with open(full_file_path) as settings:
        settings_data = yaml.load(settings, Loader=yaml.Loader)
    return settings_data

Upvotes: 13

kecer
kecer

Reputation: 3131

I think storing credentials inside another *py file is your safest bet. Then just import it. Example would look like this

config.py

username = "xy"
password = "abcd"

main.py

import config
login(config.username, config.password)

Upvotes: 116

Related Questions