Last active
October 30, 2021 00:27
-
-
Save henrydobson/edaa07827a31d3a653e7dd1b2139fb7e to your computer and use it in GitHub Desktop.
A Puppet Server autosign script, which includes some whitelisted certnames, CSR attribute evaluation and Duo push auth via the auth API. Credit to nmcspadden who's script https://github.com/macadmins/docker-puppetmaster-whdcli/blob/master/check_csr.py helped greatly for the CSR eval portion of this script. Big thanks to futureimperfect for guida…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import os, sys, time, subprocess, logging | |
import urllib, duo_client | |
### Puppet VARS ### | |
################### | |
CERTNAME = sys.argv[1] | |
CSR = sys.stdin.read() | |
### DUO VARS ### | |
################ | |
### Enter your own values ### | |
DUO_API_HOSTNAME = '' | |
DUO_INTEGRATION_KEY = '' | |
DUO_SECRET_KEY = '' | |
DUO_USERNAME = '' | |
### Setup logging ### | |
##################### | |
LOG_FILENAME = '/var/log/check_csr.log' | |
logging.basicConfig(filename=LOG_FILENAME, level=logging.INFO) | |
logger = logging.getLogger(__name__) | |
logger.info('Start script') | |
logger.debug("Number of arguments: %s",len(sys.argv)) | |
logger.info("Certname: %s", CERTNAME) | |
logger.debug("CSR: %s", CSR) | |
### Whitelist certnames ### | |
########################### | |
### Enter your own values ### | |
if CERTNAME == "": | |
logger.info("It's the puppetmaster, of course we'll approve it.") | |
sys.exit(0) | |
if CERTNAME == "": | |
logger.info("It's the puppetdb, of course we'll approve it.") | |
sys.exit(0) | |
### Start Duo auth request ### | |
############################## | |
INFO = { | |
'Certname': CERTNAME | |
} | |
### Start Duo auth request ### Read CSR for PSK attribute ### | |
############################################################# | |
cmd = ['/usr/bin/openssl', 'req', '-noout', '-text'] | |
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
(output, err) = proc.communicate(CSR) | |
logger.debug("CSR output: %s", output) | |
logger.debug("CSR error: %s", err) | |
lineList = output.splitlines() | |
strippedLineList = [line.lstrip() for line in lineList] | |
strippedLineList2 = [line.rstrip() for line in strippedLineList] | |
logger.debug("Stripped list: %s", strippedLineList2) | |
try: | |
psk_attribute = strippedLineList2.index("1.3.6.1.4.1.34380.1.1.4:") | |
except: | |
logger.info("No PSK in CSR. Notifing Duo.") | |
INFO['Preshared key'] = 'No PSK in CSR.' | |
psk = strippedLineList2[psk_attribute+1] | |
logger.info("Attribute: %s", psk) | |
try: | |
f = open("/etc/puppetlabs/psk/psk.txt", "r") | |
approved_key = ". %s" % f.read(32) | |
except: | |
logger.info("No approved key. Notifing Duo.") | |
INFO['Preshared key'] = 'No approved key found on Server.' | |
if psk == approved_key: | |
INFO['Preshared key'] = 'Success!' | |
else: | |
logger.info("Key mismatch. Notifing Duo.") | |
INFO['Preshared key'] = 'Key mismatch.' | |
### Send Duo auth request ### | |
############################# | |
PUSH_INFO = urllib.urlencode(INFO) | |
client = duo_client.Auth(ikey=DUO_INTEGRATION_KEY, skey=DUO_SECRET_KEY, host=DUO_API_HOSTNAME) | |
request = client.auth(factor='push', username=DUO_USERNAME, device='auto', pushinfo=PUSH_INFO, async=True) | |
txid = request['txid'] | |
time.sleep(15) | |
check_req = client.auth_status(txid) | |
if check_req['status'] == 'deny': | |
logger.info("Denied by Duo.") | |
sys.exit(1) | |
elif check_req['status'] == 'allow': | |
logger.info("Allowed by Duo.") | |
sys.exit(0) | |
elif check_req['status'] != 'timeout': | |
timeout = time.time() + 60*5 | |
while (time.time() < timeout): | |
check_req = client.auth_status(txid) | |
req_status = check_req['status'] | |
if req_status == 'allow': | |
logger.info("Allowed by Duo.") | |
sys.exit(0) | |
else: | |
logger.info("Duo request waiting for approval. Sleeping 20...") | |
time.sleep(20) | |
else: | |
logger.info("Duo request timeout: CSR for %s not approved.", CERTNAME) | |
sys.exit(1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment