Fix formatting issues

This commit is contained in:
Lauri Võsandi 2021-06-05 04:50:27 +00:00
parent 22290db3bb
commit d549ab4999
7 changed files with 76 additions and 72 deletions

6
.flake8 Normal file
View File

@ -0,0 +1,6 @@
[flake8]
inline-quotes = "
multiline-quotes = """
indent-size = 4
max-line-length = 160
ignore = Q003 E128 E704 E731

9
.gitlint Normal file
View File

@ -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

11
.pre-commit-config.yaml Normal file
View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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",
],
)