Skip to content

Commit 0817b5a

Browse files
committed
Add script to get vault password from gpg-agent
1 parent 8d63bdb commit 0817b5a

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed

vault_from_gpg_agent.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/env python
2+
#
3+
# Store your Ansible vault password in gpg-agent.
4+
#
5+
# Usage:
6+
#
7+
# 1. Make sure you have gpg-agent installed and running.
8+
# https://www.gnupg.org/documentation/manuals/gnupg/Invoking-GPG_002dAGENT.html
9+
# (If you're on a Mac, https://gpgtools.org/ makes this very easy.)
10+
#
11+
# 2. Make sure you have gpg-connect-agent on your path. This comes
12+
# with gpg-agent. To test gpg-agent and gpg-connect-agent, try:
13+
#
14+
# echo NOP | gpg-connect-agent
15+
#
16+
# This should respond with just "OK".
17+
#
18+
# 3. Copy this script somewhere and set vault_password_file to point
19+
# at it, or use the --vault-password-file option on the command
20+
# line.
21+
#
22+
# gpg-agent caches the passphrase for 15 minutes by default. See
23+
# https://www.gnupg.org/documentation/manuals/gnupg/Agent-Options.html
24+
# if you want to change this. Run this script with the --clear option
25+
# to clear your passphrase from gpg-agent.
26+
#
27+
# Note that the path to this script is used as the cache key for this
28+
# password in gpg-agent. For example, if you move this script to a
29+
# new path then you may be re-prompted for your password.
30+
31+
import subprocess
32+
import sys
33+
import urllib
34+
import os.path
35+
import hashlib
36+
import base64
37+
import argparse
38+
39+
40+
def get_passphrase(gpg_agent, my_path, cache_id):
41+
description = urllib.quote(
42+
"Please enter the ansible vault password for %s" % (my_path,))
43+
command = "GET_PASSPHRASE %s X X %s\n" % (cache_id, description)
44+
stdout = gpg_agent.communicate(command)[0]
45+
if gpg_agent.returncode != 0:
46+
raise Exception("gpg-connect-agent exited %r" %
47+
(gpg_agent.returncode,))
48+
elif not stdout.startswith("OK"):
49+
raise Exception("gpg-agent says: %s" % (stdout.rstrip(),))
50+
else:
51+
# You'll get an exception here if we get anything we didn't expect.
52+
passphrase = stdout[3:-1].decode("hex")
53+
print passphrase
54+
55+
56+
def clear_passphrase(gpg_agent, cache_id):
57+
stdout = gpg_agent.communicate("CLEAR_PASSPHRASE %s\n" % (cache_id,))[0]
58+
if gpg_agent.returncode != 0:
59+
raise Exception("gpg-connect-agent exited %r" %
60+
(gpg_agent.returncode,))
61+
elif not stdout.startswith("OK"):
62+
raise Exception("gog-agent says: %s" % (stdout.rstrip(),))
63+
64+
65+
def main():
66+
parser = argparse.ArgumentParser()
67+
parser.add_argument("--clear", default=False, action="store_true",
68+
help="Clear password from GPG agent")
69+
gpg_agent = subprocess.Popen(["gpg-connect-agent"], stdin=subprocess.PIPE,
70+
stdout=subprocess.PIPE)
71+
args = parser.parse_args()
72+
my_path = os.path.realpath(sys.argv[0])
73+
# Per the source, cache-id is limited to 50 bytes, so we hash our
74+
# path and Base64 encode the path.
75+
hashed_path = base64.b64encode(hashlib.sha1(my_path).digest())
76+
cache_id = "ansible-vault:%s" % (hashed_path,)
77+
if args.clear:
78+
clear_passphrase(gpg_agent, cache_id)
79+
else:
80+
get_passphrase(gpg_agent, my_path, cache_id)
81+
82+
83+
if __name__ == "__main__":
84+
main()

0 commit comments

Comments
 (0)