I tend to overlook this frequently, so as a note to self, it’s possible to store arbitrary passwords or secrets in the macOS keychain, so as to use them from, say, Shell scripts.
From the command line I add an item named myk01
which will contain generic password with
$ security add-generic-password -a jpm -s myk01 -j 'this is for the program xyz' -w
password data for new item:
retype password for new item:
The secret is in the keychain, as this command tells me:
$ security find-generic-password -a jpm -s myk01
keychain: "/Users/jpm/Library/Keychains/login.keychain-db"
version: 512
class: "genp"
attributes:
0x00000007 <blob>="myk01"
0x00000008 <blob>=<NULL>
"acct"<blob>="jpm"
"cdat"<timedate>=0x32303231303431383039313632375A00 "20210418091627Z\000"
"crtr"<uint32>=<NULL>
"cusi"<sint32>=<NULL>
"desc"<blob>=<NULL>
"gena"<blob>=<NULL>
"icmt"<blob>="this is for the program xyz"
"invi"<sint32>=<NULL>
"mdat"<timedate>=0x32303231303431383039313632375A00 "20210418091627Z\000"
"nega"<sint32>=<NULL>
"prot"<blob>=<NULL>
"scrp"<sint32>=<NULL>
"svce"<blob>="myk01"
"type"<uint32>=<NULL>
And I can obtain just the password by adding a -w
to the command:
$ security find-generic-password -a jpm -s myk01 -w
sekr1t
And that latter format is what I will use to obtain a password for this particular command:
#!/bin/sh
export PASS=$(security find-generic-password -a $(whoami) -s myk01 -w)
/usr/local/bin/program-which-uses-that-variable-for-authentication
Useful on occasion.
Golang
I want to access such a generic password from a Go program, which I do with go-keychain. I test with a “personalized” example from the README:
package main
import (
"fmt"
"github.com/keybase/go-keychain"
"log"
)
func main() {
q := keychain.NewItem()
q.SetSecClass(keychain.SecClassGenericPassword)
q.SetMatchLimit(keychain.MatchLimitOne)
q.SetReturnData(true)
q.SetAccount("jpm")
q.SetService("myk01")
fmt.Println(q)
res, err := keychain.QueryItem(q)
if err != nil {
log.Fatal(err)
} else if len(res) != 1 {
fmt.Println("Not found")
} else {
password := string(res[0].Data)
fmt.Printf("Password is: %T: %v\n", password, password)
}
}
{map[acct:jpm class:140735646167104 m_Limit:140735646169888 r_Data:true svce:myk01]}
Password is: string: sekr1t