Note: This site is currently "Under construction". I'm migrating to a new version of my site building software. Lots of things are in a state of disrepair as a result (for example, footnote links aren't working). It's all part of the process of building in public. Most things should still be readable though.

Storing Script Passwords In Macs Keychain

TODO: I'm doing things a little diferently now. This note is to remind me to link that.

_Forward_

- I built my own functions to use Mac's Keychain Access for password storage, but you should probably checkout keyring to do the same thing and more.



I've been using GPG to encrypt my various credentials so I don't accidentally flash them while streaming or taking zoom calls. The process also ensures I never store passwords directly inside a script. A sin that's all to easy to commit.

I drop passwords into individual plain-text files and encrypt them with:

Code

gpg --armor --encrypt --yes -r self@localhost.localdomain PASSWORD_FILE

When I need one, I use this Python function to grab it:

Code

import subprocess

def get_credentials(file_path):    
    return subprocess.check_output([
        '/usr/local/bin/gpg', '--decrypt', 
        '-q', file_path
    ]).decode('utf-8').split("\n")[0]

credential = get_credentials('PASSWORD_FILE.asc')

A bit tedious, but it works great.

#### # set_security_credential.py

Code

#!/usr/bin/env python3

import subprocess
import getpass

def set_security_credential(*, credential_for, credential_value):
    subprocess.run([
        'security', 'add-generic-password', '-U',
        '-a', getpass.getuser(), '-s',
        credential_for, '-w', credential_value
    ])

set_security_credential(
    credential_for = 'alans-example-api',
    credential_value = 'lorem ipsum 9000'
)

#### # get_security_credentail.py

Code

#!/usr/bin/env python3

import getpass
import subprocess

def get_security_credential(*, credential_for):
    return subprocess.run([
        'security', 'find-generic-password',
        '-w', '-a', getpass.getuser(),
        '-s', credential_for
    ], stdout=subprocess.PIPE).stdout.decode('utf-8')

password_value = get_security_credential(
    credential_for = 'alans-example-api'
)

print(password_value)

Because the values are both set and retrieved by the `security` cli tool under your user ID, they don't require an additional password to retrieve them. And, since it's always the `security` app working under the covers, the functions work across different scripts.

My next step will be to drop these into pages on a localhost website. That'll let me add and update credentials from my own little UI. I'll still keep everything in my password manager, but this is how I'll get to them with scripts.

I really like this approach. No more having to mess with credentials to obfuscate them. Just let the system's built tool take care of it.


_Afterword_

- It's important to point out that neither the GPG method nor the `security` cli method provide extra security since they aren't setup to require their own passwords. The only thing they provide is a straightforward way to keep passwords out of scripts and a way obfuscate/hide them so you don't accidentally expose them. - I did this in Python. The same approach can be used by any language/tool that can execute the `security` process and gather its output. - The Keychain Access app is Mac specific. Windows provides Credential locker](https://docs.microsoft.com/en-us/windows/uwp/security/credential-locker) which should be able to do the same thing. Doing that exploration is left as an exercise for the reader (Probably see [keyring.