From d549ab499906e0303b94b5f800a6725c6f609fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauri=20V=C3=B5sandi?= Date: Sat, 5 Jun 2021 04:50:27 +0000 Subject: [PATCH] Fix formatting issues --- .flake8 | 6 +++ .gitlint | 9 ++++ .pre-commit-config.yaml | 11 +++++ README.md | 4 +- pinecrypt/client/cli.py | 86 ++++++++++++++++----------------------- pinecrypt/client/const.py | 14 +++---- setup.py | 18 ++++---- 7 files changed, 76 insertions(+), 72 deletions(-) create mode 100644 .flake8 create mode 100644 .gitlint create mode 100644 .pre-commit-config.yaml diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..ff6c948 --- /dev/null +++ b/.flake8 @@ -0,0 +1,6 @@ +[flake8] +inline-quotes = " +multiline-quotes = """ +indent-size = 4 +max-line-length = 160 +ignore = Q003 E128 E704 E731 diff --git a/.gitlint b/.gitlint new file mode 100644 index 0000000..e3f0c82 --- /dev/null +++ b/.gitlint @@ -0,0 +1,9 @@ +[general] +ignore=body-is-missing,T3 +ignore-stdin=true + +[title-match-regex] +regex=[A-Z] + +[author-valid-email] +regex=[^@]+@pinecrypt.com diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..a60b2ae --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,11 @@ +repos: +- repo: https://github.com/PyCQA/flake8 + rev: 3.9.2 + hooks: + - id: flake8 + additional_dependencies: [flake8-typing-imports==1.10.0,flake8-quotes==3.2.0] + +- repo: https://github.com/jorisroovers/gitlint + rev: v0.15.1 + hooks: + - id: gitlint diff --git a/README.md b/README.md index 20e209f..2a0ffc1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # Background -Certidude is the VPN connectivity client for Pinecrypt Gateway +Certidude is the VPN connectivity client for Pinecrypt Gateway. +Code snippet for installing the utility and provisioning the +connection is exposed in the Pinecrypt Gateway user interface diff --git a/pinecrypt/client/cli.py b/pinecrypt/client/cli.py index 6f92eb3..ca4b1b2 100644 --- a/pinecrypt/client/cli.py +++ b/pinecrypt/client/cli.py @@ -2,24 +2,17 @@ import click import hashlib -import logging import ipsecparse import json import os -import random import re import signal -import string -import socket import subprocess -import sys import requests from asn1crypto import pem, x509 from asn1crypto.csr import CertificationRequest -from certbuilder import CertificateBuilder, pem_armor_certificate from csrbuilder import CSRBuilder, pem_armor_csr from configparser import ConfigParser, NoOptionError -from datetime import datetime, timedelta from email.utils import formatdate from oscrypto import asymmetric from pinecrypt.client import const @@ -37,8 +30,9 @@ retry = Retry( status_forcelist=(500, 502, 504), ) adapter = HTTPAdapter(max_retries=retry) -session.mount('http://', adapter) -session.mount('https://', adapter) +session.mount("http://", adapter) +session.mount("https://", adapter) + def selinux_fixup(path): """ @@ -87,19 +81,19 @@ def certidude_provision(authority, method): client_config.set(authority, "request path", os.path.join(b, "host_req.pem")) client_config.set(authority, "key path", os.path.join(b, "host_key.pem")) client_config.set(authority, "certificate path", os.path.join(b, "host_cert.pem")) - client_config.set(authority, "authority path", os.path.join(b, "ca_cert.pem")) + client_config.set(authority, "authority path", os.path.join(b, "ca_cert.pem")) if method: client_config.set(authority, "method", method) - with open(const.CLIENT_CONFIG_PATH + ".part", 'w') as fh: + with open(const.CLIENT_CONFIG_PATH + ".part", "w") as fh: client_config.write(fh) os.rename(const.CLIENT_CONFIG_PATH + ".part", const.CLIENT_CONFIG_PATH) os.system("certidude enroll") + @click.command("enroll", help="Run processes for requesting certificates and configuring services") @click.option("-k", "--kerberos", default=False, is_flag=True, help="Offer system keytab for auth") @click.option("-f", "--fork", default=False, is_flag=True, help="Fork to background") @click.option("-nw", "--no-wait", default=False, is_flag=True, help="Return immediately if server doesn't autosign") - def certidude_enroll(fork, no_wait, kerberos): try: os.makedirs(const.RUN_DIR) @@ -128,10 +122,9 @@ def certidude_enroll(fork, no_wait, kerberos): else: raise - - ######################### - ### Fork if requested ### - ######################### + ##################### + # Fork if requested # + ##################### pid_path = os.path.join(const.RUN_DIR, authority_name + ".pid") @@ -233,10 +226,9 @@ def certidude_enroll(fork, no_wait, kerberos): if not re.match(const.RE_COMMON_NAME, common_name): raise ValueError("Supplied common name %s doesn't match the expression %s" % (common_name, const.RE_COMMON_NAME)) - - ################################ - ### Generate keypair and CSR ### - ################################ + ############################ + # Generate keypair and CSR # + ############################ try: key_path = clients.get(authority_name, "key path") @@ -266,19 +258,18 @@ def certidude_enroll(fork, no_wait, kerberos): builder = CSRBuilder({"common_name": common_name}, self_public_key) request = builder.build(private_key) - with open(key_partial, 'wb') as f: + with open(key_partial, "wb") as f: f.write(asymmetric.dump_private_key(private_key, None)) - with open(request_partial, 'wb') as f: + with open(request_partial, "wb") as f: f.write(pem_armor_csr(request)) selinux_fixup(key_partial) selinux_fixup(request_partial) os.rename(key_partial, key_path) os.rename(request_partial, request_path) - - ############################################## - ### Submit CSR and save signed certificate ### - ############################################## + ########################################## + # Submit CSR and save signed certificate # + ########################################## try: certificate_path = clients.get(authority_name, "certificate path") @@ -314,7 +305,7 @@ def certidude_enroll(fork, no_wait, kerberos): except ImportError: click.echo("Kerberos bindings not available, please install requests-kerberos") else: - os.environ["KRB5CCNAME"]="/tmp/ca.ticket" + os.environ["KRB5CCNAME"] = "/tmp/ca.ticket" # Mac OS X has keytab with lowercase hostname cmd = "kinit -S HTTP/%s -k %s$" % (authority_name, const.HOSTNAME.lower()) @@ -348,14 +339,15 @@ def certidude_enroll(fork, no_wait, kerberos): if submission.status_code == requests.codes.ok: pass if submission.status_code == requests.codes.accepted: - click.echo("Server accepted the request, but refused to sign immediately (%s). Waiting was not requested, hence quitting for now" % submission.text) + click.echo("Server accepted the request, but refused to sign immediately (%s). " + "Waiting was not requested, hence quitting for now" % submission.text) os.unlink(pid_path) continue if submission.status_code == requests.codes.conflict: raise ValueError("Different signing request with same CN is already present on server, server refuses to overwrite") elif submission.status_code == requests.codes.gone: # Should the client retry or disable request submission? - raise ValueError("Server refused to sign the request") # TODO: Raise proper exception + raise ValueError("Server refused to sign the request") # TODO: Raise proper exception elif submission.status_code == requests.codes.bad_request: raise ValueError("Server said following, likely current certificate expired/revoked? %s" % submission.text) else: @@ -363,8 +355,8 @@ def certidude_enroll(fork, no_wait, kerberos): try: header, _, certificate_der_bytes = pem.unarmor(submission.content) - cert = x509.Certificate.load(certificate_der_bytes) - except: # TODO: catch correct exceptions + x509.Certificate.load(certificate_der_bytes) + except ValueError: raise ValueError("Failed to parse PEM: %s" % submission.text) os.umask(0o022) @@ -380,10 +372,9 @@ def certidude_enroll(fork, no_wait, kerberos): else: click.echo("Certificate found at %s and no renewal requested" % certificate_path) - - ################################## - ### Configure related services ### - ################################## + ############################## + # Configure related services # + ############################## endpoint = authority_name @@ -429,12 +420,7 @@ def certidude_enroll(fork, no_wait, kerberos): if os.path.exists("/bin/systemctl"): click.echo("Re-running systemd generators for OpenVPN...") os.system("systemctl daemon-reload") -# if not os.path.exists("/etc/systemd/system/openvpn-reconnect.service"): -# with open("/etc/systemd/system/openvpn-reconnect.service.part", "w") as fh: -# fh.write(env.get_template("client/openvpn-reconnect.service").render(context)) -# os.rename("/etc/systemd/system/openvpn-reconnect.service.part", -# "/etc/systemd/system/openvpn-reconnect.service") -# click.echo("Created /etc/systemd/system/openvpn-reconnect.service") + # TODO: Restore openvpn-reconnect.service here os.system("systemctl restart openvpn") continue @@ -458,14 +444,12 @@ def certidude_enroll(fork, no_wait, kerberos): config["conn", endpoint]["esp"] = "%s!" % bootstrap["strongswan"]["esp"] config["conn", endpoint]["leftsourceip"] = "%config,%config6" config["conn", endpoint]["leftcert"] = certificate_path -# leftca="$AUTHORITY_CERTIFICATE_DISTINGUISHED_NAME" -# rightca="$AUTHORITY_CERTIFICATE_DISTINGUISHED_NAME" - + # TODO: Assert DN values here? with open(strongswan_secrets_path + ".part", "w") as fh: fh.write(": %s %s\n" % ( - "ECDSA" if authority_public_key.algorithm == "ec" else "RSA", - key_path + "ECDSA" if authority_public_key.algorithm == "ec" else "RSA", + key_path )) with open(strongswan_config_path + ".part", "w") as fh: @@ -481,7 +465,7 @@ def certidude_enroll(fork, no_wait, kerberos): fh.write(certificate_path + " r,\n") # Attempt to reload config or start if it's not running - if os.path.exists("/usr/sbin/strongswan"): # wtf fedora + if os.path.exists("/usr/sbin/strongswan"): # wtf fedora if os.system("strongswan update"): os.system("strongswan start") else: @@ -509,7 +493,7 @@ def certidude_enroll(fork, no_wait, kerberos): nm_config.set("vpn", "comp-lzo", "no") nm_config.set("vpn", "cert-pass-flags", "0") nm_config.set("vpn", "tap-dev", "no") - nm_config.set("vpn", "remote-cert-tls", "server") # Assert TLS Server flag of X.509 certificate + nm_config.set("vpn", "remote-cert-tls", "server") # Assert TLS Server flag of X.509 certificate nm_config.set("vpn", "remote", endpoint) nm_config.set("vpn", "key", key_path) nm_config.set("vpn", "cert", certificate_path) @@ -537,10 +521,8 @@ def certidude_enroll(fork, no_wait, kerberos): os.system("nmcli con up %s" % uuid) continue - # IPSec set up with NetworkManager if method == "network-manager/strongswan": - client_config = ConfigParser() nm_config = ConfigParser() nm_config.add_section("connection") nm_config.set("connection", "certidude managed", "true") @@ -557,7 +539,7 @@ def certidude_enroll(fork, no_wait, kerberos): nm_config.set("vpn", "userkey", key_path) nm_config.set("vpn", "usercert", certificate_path) nm_config.set("vpn", "certificate", authority_path) - nm_config.set("vpn", "ike", bootstrap["strongswan"]["ike"]) + nm_config.set("vpn", "ike", bootstrap["strongswan"]["ike"]) # TODO: Check if the ! syntax is used nm_config.set("vpn", "esp", bootstrap["strongswan"]["esp"]) nm_config.set("vpn", "proposal", "yes") @@ -576,7 +558,7 @@ def certidude_enroll(fork, no_wait, kerberos): os.system("nmcli con up %s" % uuid) continue - click.echo("Unknown service: %s" % service_config.get(endpoint, "service")) + click.echo("Unknown provisioning method: %s" % method) os.unlink(pid_path) diff --git a/pinecrypt/client/const.py b/pinecrypt/client/const.py index a05a46a..2932dbc 100644 --- a/pinecrypt/client/const.py +++ b/pinecrypt/client/const.py @@ -4,20 +4,16 @@ import socket RUN_DIR = "/run/certidude" CONFIG_DIR = "/etc/certidude" CLIENT_CONFIG_PATH = os.path.join(CONFIG_DIR, "client.conf") -SERVICES_CONFIG_PATH = os.path.join(CONFIG_DIR, "services.conf") -RE_FQDN = "^(([a-z0-9]|[a-z0-9][a-z0-9\-_]*[a-z0-9])\.)+([a-z0-9]|[a-z0-9][a-z0-9\-_]*[a-z0-9])?$" -RE_HOSTNAME = "^[a-z0-9]([a-z0-9\-_]{0,61}[a-z0-9])?$" -RE_COMMON_NAME = "^[A-Za-z0-9\-\.\_@]+$" +RE_FQDN = r"^(([a-z0-9]|[a-z0-9][a-z0-9\-_]*[a-z0-9])\.)+([a-z0-9]|[a-z0-9][a-z0-9\-_]*[a-z0-9])?$" +RE_HOSTNAME = r"^[a-z0-9]([a-z0-9\-_]{0,61}[a-z0-9])?$" +RE_COMMON_NAME = r"^[A-Za-z0-9\-\.\_@]+$" -try: - FQDN = socket.getaddrinfo(socket.gethostname(), 0, socket.AF_INET, 0, 0, socket.AI_CANONNAME)[0][3] -except socket.gaierror: - FQDN = socket.gethostname() +FQDN = socket.getfqdn() try: HOSTNAME, DOMAIN = FQDN.split(".", 1) -except ValueError: # If FQDN is not configured +except ValueError: # If FQDN is not configured HOSTNAME = FQDN DOMAIN = None diff --git a/setup.py b/setup.py index b1e92b2..c942d8b 100644 --- a/setup.py +++ b/setup.py @@ -1,17 +1,16 @@ #!/usr/bin/env python3 # coding: utf-8 -import os from setuptools import setup setup( - name = "certidude", - version = "0.2.1", - author = u"Pinecrypt Labs", - author_email = "lauri@pinecrypt.com", - description = "Certidude provisions VPN connections to Pinecrypt Gateway", - license = "MIT", - keywords = "falcon http jinja2 x509 pkcs11 webcrypto kerberos ldap", - url = "https://git.k-space.ee/pinecrypt/certidude", + name="certidude", + version="0.2.1", + author=u"Pinecrypt Labs", + author_email="lauri@pinecrypt.com", + description="Certidude provisions VPN connections to Pinecrypt Gateway", + license="MIT", + keywords="falcon http jinja2 x509 pkcs11 webcrypto kerberos ldap", + url="https://git.k-space.ee/pinecrypt/certidude", packages=[ "pinecrypt.client", ], @@ -40,4 +39,3 @@ setup( "Programming Language :: Python :: 3 :: Only", ], ) -