def prepare(dhparamConfig, dhparamState, statedir, dhparamSecName): if 'openssl' != dhparamConfig['handler'].split('/')[0]: return keysize = 2048 if 'keysize' in dhparamConfig: keysize = dhparamConfig['keysize'] path = os.path.realpath(os.path.join(statedir, 'dhparams', dhparamSecName)) makeDir(os.path.dirname(path)) dhparamState.setOpStateRunning() try: rv = check_output( ('openssl', 'dhparam', '-out', str(path), str(int(keysize)))) log.info(rv) except CalledProcessError as e: log.error(e.output) time.sleep(1) raise (e) resDict = {} resDict['tmpfile'] = path if 'running' == dhparamState.opstate: dhparamState.registerResult(resDict) dhparamState.setOpStateDone() return rv
def rollover(serviceConfig, serviceState, state): serviceState.setOpStateWaiting() if not isReady(serviceConfig, state, ['dhparam', 'cert']): return serviceState.setOpStateRunning() certNames = serviceConfig['cert'] if 'auto' == serviceConfig['dirext'] or 'auto' == serviceConfig['dirint']: client = docker.DockerClient(base_url=serviceConfig['dockersock']) containers = [c for c in client.containers.list() if c.attrs['Name'][1:] == serviceConfig['container']] if len(containers) == 0: log.error("container does not exist") container = containers[0] log.info("Updating traefik container: {}".format(container.attrs['Name'])) destinations = [e.replace(' ','').split('=')[1] for e in container.attrs['Args'] if e.replace(' ','').split('=')[0] == '--providers.file.directory'] if len(destinations) == 0: log.error("traefik container misses providers.file.directory argument") destination = destinations[0] traefikProvidersFileDirectory = dch.dockerPathMap('/'+serviceConfig['container'], destination)[0] #traefikProvidersFileDirectory = mount['Source'] if 'auto' == serviceConfig['dirext'] else serviceConfig['dirext'] #'./configuration' traefikConfigFilename = os.path.join(traefikProvidersFileDirectory,'files/configuration.toml') traefikCertDir = os.path.join(traefikProvidersFileDirectory,'certs') traefikProvidersFileDirectoryMount = os.path.normpath(destination) if 'auto' == serviceConfig['dirint'] else serviceConfig['dirint'] # '/configuration' traefikConfigFilenameMount = os.path.join(traefikProvidersFileDirectoryMount,'files/configuration.toml') traefikCertDirMount = os.path.join(traefikProvidersFileDirectoryMount,'certs') log.info(" -> Volume: {}:{}".format(traefikProvidersFileDirectory, traefikProvidersFileDirectoryMount)) tcfc = '' for certName in certNames: certState = state.getSubstate('cert').getSubstate(certName).result certPath = os.path.join(traefikCertDir,certName,'cert.pem') keyPath = os.path.join(traefikCertDir,certName,'key.pem') certPathMount = os.path.join(traefikCertDirMount,certName,'cert.pem') keyPathMount = os.path.join(traefikCertDirMount,certName,'key.pem') makeDir(os.path.dirname(certPath)) copyfile(certState['fullchainfile'], certPath) log.info(' {} -> {}'.format(certState['fullchainfile'], certPath)) copyfile(certState['keyfile'], keyPath) log.info(' {} -> {}'.format(certState['keyfile'], keyPath)) tcfc += '[[tls.certificates]]\n certFile = "{}"\n keyFile = "{}"\n\n'.format(certPathMount, keyPathMount) makeDir(os.path.dirname(traefikConfigFilename)) with open(traefikConfigFilename,'w') as f: f.write(tcfc) # traefik reloads config and certs only if a random file is written in # traefik's config root directory specified by: # --providers.file.directory = <config root directory> with open(os.path.join(traefikProvidersFileDirectory,'reloadtrigger'), 'w') as f: f.write('') log.info(' -> Traefik reload') serviceState.setOpStateDone()
def copyCert(certConfig, certState): src = os.path.dirname(certState.result['fullchainfile']) for name in certState.result['san']: dest = os.path.join(certConfig['destination'], name) log.info(' {} -> {}'.format(src, dest)) try: rv = check_output(('cp', '-rfLT', str(src), str(dest))) except CalledProcessError as e: log.error(e.output) raise (e)
def copyDKIM(dkimConfig, dkimState): src = dkimState.result['keyfile'] dest = os.path.join(dkimConfig['keylocation'], dkimConfig['keyname']) log.info(' {} -> {}'.format(src, dest)) try: rv = check_output(('cp', '-rfLT', str(src), str(dest))) rv = check_output(('chown', '_rspamd:_rspamd', str(dest))) except CalledProcessError as e: log.error(e.output) raise (e)
def copyConf(dkimConfig, dkimState): src = dkimState.result['signingconftemporaryfile'] dest = dkimConfig['signingconfdestinationfile'] log.info(' {} -> {}'.format(src, dest)) try: rv = check_output(('cp', '-rfLT', str(src), str(dest))) rv = check_output(('chown', '_rspamd:_rspamd', str(dest))) except CalledProcessError as e: log.error(e.output) raise (e)
def rollover(serviceConfig, serviceState, state): serviceState.setOpStateWaiting() if not isReady(serviceConfig, state, 'dkim'): return serviceState.setOpStateRunning() log.info(' -> Rspamd reload') try: rv = check_output(('sudo', 'systemctl', 'reload', 'rspamd')) # this is now working with newer version of rspamd except CalledProcessError as e: log.error(e.output) raise(e) serviceState.setOpStateDone()
def rollover(serviceConfig, serviceState, state): serviceState.setOpStateWaiting() if not isReady(serviceConfig, state, ['cert', 'dhparam']): return serviceState.setOpStateRunning() log.info(' -> Postfix reload') try: rv = check_output(('systemctl', 'start', 'postfix')) rv = check_output(('systemctl', 'reload', 'postfix')) except CalledProcessError as e: log.error(e.output) raise (e) serviceState.setOpStateDone()
def createDKIM(keysize, destination): makeDir(os.path.dirname(str(destination))) try: keyTxt = str( check_output( ('rspamadm', 'dkim_keygen', '-b', str(int(keysize)), '-s', str('dkimkey'), '-k', str(destination)))) except CalledProcessError as e: log.error(e.output) raise (e) v = keyTxt.split('v=')[1].split(';')[0] k = keyTxt.split('k=')[1].split(';')[0] p = keyTxt.split('p=')[1].split('\"')[0] return {'v': v, 'k': k, 'p': p, 'keyfile': str(destination)}
def copyDH(dhparamConfig, dhparamState): if 'tmpfile' not in dhparamState.result: return src = os.path.realpath(dhparamState.result['tmpfile']) dest = os.path.realpath(dhparamConfig['filename']) try: os.makedirs(os.path.dirname(dest)) except: pass log.info(' {} -> {}'.format(src, dest)) try: rv = check_output(('cp', '-rfLT', str(src), str(dest))) except CalledProcessError as e: log.error(e.output) raise(e)
def createDKIM(keysize, destination): makeDir(os.path.dirname(str(destination))) try: keyTxt = str( check_output( ('sudo', 'rspamadm', 'dkim_keygen', '-b', str(int(keysize)), '-s', str('dkimkey'), '-k', str(destination)))) except CalledProcessError as e: log.error(e.output) raise (e) v = keyTxt.split('v=')[1].split(';')[0] k = keyTxt.split('k=')[1].split(';')[0] pL = keyTxt.split('p=')[1].split('\"') p = "".join([e for e in pL if ")" not in e and "\n" not in e]) p = p.replace("\\n", "").replace("\\t", "") return {'v': v, 'k': k, 'p': p, 'keyfile': str(destination)}
def delOldCert(certConfig, certState): preserve = ['fullchainfile', 'certfile', 'keyfile', 'chainfile'] preserveFiles = set([certState.result[e] for e in preserve]) preserveFiles.update(set([os.path.realpath(e) for e in preserveFiles])) dirs = set([os.path.dirname(e) for e in preserveFiles]) dirs = [e for e in dirs if os.path.isdir(e)] allFiles = set([os.path.join(d, f) for d in dirs for f in os.listdir(d)]) allFiles = set([e for e in allFiles if os.path.isfile(e)]) removeFiles = allFiles - preserveFiles for e in removeFiles: log.info(' rm {}'.format(e)) try: rv = check_output(('rm', str(e))) except CalledProcessError as e: log.error(e.output) raise (e)
def copyCert(certConfig, certState): src = os.path.dirname(certState.result['fullchainfile']) for name in certState.result['san']: dest = os.path.join(certConfig['destination'], name) log.info(' {} -> {}'.format(src, dest)) try: makeDir(str(dest)) for k in ['fullchainfile', 'chainfile', 'certfile', 'keyfile']: lnksrc = certState.result[k] lnkdst = os.path.join(os.path.dirname(lnksrc), os.readlink(lnksrc)) shutil.copy2(lnkdst, os.path.join(dest, os.path.basename(lnksrc))) except CalledProcessError as e: log.error(e.output) raise (e)
def rollover(serviceConfig, serviceState, state): serviceState.setOpStateWaiting() if not isReady(serviceConfig, state, 'dkim'): return serviceState.setOpStateRunning() log.info(' -> Rspamd reload') try: rv = check_output(('systemctl', 'start', 'rspamd')) #rv = check_output(('systemctl', 'reload', 'rspamd')) # this is not working with rspamd #rv = check_output(('rspamadm', 'control', 'reload')) # only restart works - bug in rspamd rv = check_output(('systemctl', 'restart', 'rspamd')) except CalledProcessError as e: log.error(e.output) raise (e) serviceState.setOpStateDone()
def setTLSA(domainConfig, domainState, domainSecName, dnsup, state, add=True, delete=True): rrState = domainState.getSubstate('settlsa') if rrState.isDone(): return True if 'cert' in domainConfig and ('tlsaAggrAdd' in domainConfig or 'tlsaAggrDel' in domainConfig): rrState.setOpStateWaiting() tlsaPres = [] for certSec in domainConfig['cert']: if not isCertReady(state, certSec): return False rrState.setOpStateRunning() cert = getFullchain(state, certSec) if cert is None: log.info( 'not deploying TLSA record for {} (no certificate)'.format( domainSecName)) else: log.info( 'deploying TLSA record for {} (certificate found)'.format( domainSecName)) sanList = getCertSAN(cert) log.info(' -> found certificate: {} for: {}'.format( cert, b', '.join(sanList))) if domainSecName.encode() not in sanList: log.error('{} not in certificate {}'.format( domainSecName, cert)) tlsaAdd = [ dict(e, filename=cert) for e in domainConfig['tlsaAggrAdd'] if 'op' in e if 'auto' == e['op'] ] tlsaPres.extend(tlsaAdd) if add is True: dnsup.addTLSA(domainSecName, tlsaAdd) log.info('removing old TLSA record for {}'.format(domainSecName)) if delete is True: tlsaDel = domainConfig['tlsaAggrDel'] dnsup.delTLSA(domainSecName, tlsaDel, tlsaPres) rrState.setOpStateDone() return True
def list2rrType(rrType, entry, hasContent=True): if 'mx' == rrType: return list2MX(entry, hasContent) elif 'srv' == rrType: return list2SRV(entry, hasContent) elif 'ip4' == rrType: return list2ip(entry, hasContent) elif 'ip6' == rrType: return list2ip(entry, hasContent) elif 'dkim' == rrType: return list2dkim(entry, hasContent) elif 'tlsa' == rrType: return list2tlsa(entry, hasContent) elif 'caa' == rrType: return list2CAA(entry, hasContent) elif 'spf' == rrType: return list2SPF(entry, hasContent) log.error('rrType not supported') assert TypeError('rrType not supported')
def callAPI(self, method, params): for i in range(10): if i > 0: log.info('INWX api wait {} s before retry'.format(i**3)) time.sleep(i**3) rv = self.__conn.call_api(api_method=method, method_params=params) if 2400 == rv['code']: log.info('INWX api error code: {}'.format(rv['code'])) continue if 2500 == rv['code']: log.info('INWX api error code: {}'.format(rv['code'])) continue if 2502 == rv['code']: log.info('INWX api error code: {}'.format(rv['code'])) continue return rv log.error('INWX api retry limit exceeded!') log.error('INWX api error code was: {}'.format(rv['code'])) return rv
def serviceAction(serviceName, action): try: return check_output(('sudo', 'systemctl', action, serviceName)) except Exception as e: log.error(e) try: return check_output(('systemctl', action, serviceName)) except Exception as e: log.error(e) if 'reload' == action: try: return check_output(('killall', serviceName, '-s', 'SIGHUP')) except Exception as e: log.error(e) log.error("reload failed") raise("reload failed")
def copyDKIM(dkimConfig, dkimState): src = dkimState.result['keyfile'] dest = os.path.join(dkimConfig['keylocation'], dkimConfig['keyname']) log.info(' {} -> {}'.format(src, dest)) try: rv = check_output(('mkdir', '-p', os.path.dirname(str(dest)))) except CalledProcessError as e: log.error("Failed to create directory path for {}".format(str(dest))) try: rv = check_output(('cp', '-rfLT', str(src), str(dest))) except CalledProcessError as e: log.error("Failed to copy file") log.error(" {} -> {}".format(str(src), str(dest))) try: rv = check_output(('chown', '_rspamd:_rspamd', str(dest))) except CalledProcessError as e: log.error("Failed to change ownership of {}".format(str(dest)))
def copyConf(dkimConfig, dkimState): src = dkimState.result['signingconftemporaryfile'] dest = dkimConfig['signingconfdestinationfile'] log.info(' {} -> {}'.format(src, dest)) try: rv = check_output(('sudo', 'mkdir', '-p', os.path.dirname(str(dest)))) except CalledProcessError as e: log.error("Failed to create directory path for {}".format(str(dest))) try: rv = check_output(('sudo', 'cp', '-rfLT', str(src), str(dest))) except CalledProcessError as e: log.error("Failed to copy file") log.error(" {} -> {}".format(str(src), str(dest))) try: rv = check_output(('sudo', 'chown', '_rspamd:_rspamd', str(dest))) except CalledProcessError as e: log.error("Failed to change ownership of {}".format(str(dest)))
def prepare(certConfig, certState, statedir, domainList, domainAccessTable): if 'dehydrated' != certConfig['handler'].split('/')[0]: return if 0 == len(domainList): return email = certConfig['email'] keysize = 4096 if 'keysize' in certConfig: keysize = certConfig['keysize'] if 'extraflags' in certConfig: extraFlags = certConfig['extraflags'] extraFlags = [e if '-' == e[0] else '--' + e for e in extraFlags] if '--staging' in extraFlags: ca = "https://acme-staging.api.letsencrypt.org/directory" extraFlags.remove('--staging') if 'staging' in extraFlags: extraFlags.remove('staging') elif 'ca' in certConfig: ca = certConfig['ca'] else: ca = "https://acme-v02.api.letsencrypt.org/directory" makeDir(os.path.realpath(statedir)) confFilename = os.path.normpath(os.path.join(statedir, 'dehydrated.conf')) confFile = open(confFilename, 'w') confFile.write('CA={}\n'.format(str(ca))) confFile.write('CONTACT_EMAIL={}\n'.format(str(email))) confFile.write('KEYSIZE={}\n'.format(int(keysize))) confFile.write('CERTDIR={}\n'.format(os.path.join(statedir, 'certs'))) confFile.write('\n') confFile.close() here = os.path.dirname(os.path.realpath(__file__)) args = [ os.path.join(here, 'dehydrated/dehydrated'), '-f', confFilename, '--accept-terms', '-c', '-t', 'dns-01', '-k', os.path.join(here, 'hook.sh') ] log.debug(extraFlags) args.extend(extraFlags) for d in domainList: args.extend(['-d', str(d)]) log.debug(args) certState.setOpStateRunning() for i in range(10): try: rv = check_output(args, env=dict(os.environ, DOMAINACCESSTABLE=domainAccessTable)) log.info(rv) break except CalledProcessError as e: log.error(e.output) time.sleep(1) if 9 == i: raise (e) res = [] rv = rv.splitlines() for s, e in enumerate(rv): if '---- DEPLOYMENTRESULT ----' == e[:len('---- DEPLOYMENTRESULT ----' )]: break for i, e in enumerate(rv[s + 1:]): if '---- END DEPLOYMENTRESULT ----' == e[:len( '---- END DEPLOYMENTRESULT ----')]: break res.append(e) resDict = {e.split('=')[0].lower(): e.split('=')[1] for e in res} resDict['san'] = list(domainList) if 'running' == certState.opstate: certState.registerResult(resDict) certState.setOpStateDone() return rv