This is a simple server that signs CSRs and responds with the signed Client Cert.
Instructions on how to run this server:
make setup
make serve
"""
import os | |
import time | |
import socket | |
import OpenSSL | |
from flask import Flask, request | |
# set up globals | |
app = Flask(__name__) | |
HERE = os.path.abspath(os.path.curdir) | |
CA_PRV_KEY = os.path.join(HERE, os.environ['CA_PRV_KEY']) | |
CA_PUB_CRT = os.path.join(HERE, os.environ['CA_PUB_CRT']) | |
# get real IP address | |
def get_ip_address(): | |
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | |
s.connect(("8.8.8.8", 80)) | |
return s.getsockname()[0] | |
ip_address = get_ip_address() | |
# define routes | |
@app.route('/', methods=['GET','POST']) | |
def index(): | |
return """To use this server to sign CSRs, | |
curl {}:5000/csr -F csr=@<path-to-csr> > <path-to-cert> | |
""".format(ip_address) | |
@app.route('/csr', methods=['POST']) | |
def sign(): | |
""" | |
http://docs.ganeti.org/ganeti/2.7/html/design-x509-ca.html#x509-certificate-from-certificate-signing-request | |
""" | |
# get latest intermediary and load them | |
if not os.path.exists(CA_PUB_CRT) or not os.path.exists(CA_PRV_KEY): | |
return b'Intermediary not configured.\n' | |
ca_cert = OpenSSL.crypto.load_certificate( | |
OpenSSL.crypto.FILETYPE_PEM, | |
open(CA_PUB_CRT, 'r').read()) | |
ca_key = OpenSSL.crypto.load_privatekey( | |
OpenSSL.crypto.FILETYPE_PEM, | |
open(CA_PRV_KEY, 'r').read()) | |
signed = bytes(None) | |
try: | |
f_csr = request.files.get('csr') | |
csr = OpenSSL.crypto.load_certificate_request( | |
OpenSSL.crypto.FILETYPE_PEM, | |
f_csr.stream.read()) | |
cert = OpenSSL.crypto.X509() | |
cert.set_subject(csr.get_subject()) | |
cert.set_serial_number(1) | |
cert.gmtime_adj_notBefore(0) | |
cert.gmtime_adj_notAfter(365 * 24 * 60 * 60) | |
cert.set_issuer(ca_cert.get_subject()) | |
cert.set_pubkey(csr.get_pubkey()) | |
cert.sign(ca_key, "sha1") | |
signed = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert) | |
except: | |
return b'An error occurred with the csr-signer.\n' | |
return signed | |
# start server | |
if __name__ == '__main__': | |
app.run(host=ip_address, port=5000) |
.PHONY: clean-pyc clean-build docs clean | |
define BROWSER_PYSCRIPT | |
import os, webbrowser, sys | |
try: | |
from urllib import pathname2url | |
except: | |
from urllib.request import pathname2url | |
webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1]))) | |
endef | |
export BROWSER_PYSCRIPT | |
BROWSER := python -c "$$BROWSER_PYSCRIPT" | |
CA_PRV_KEY ?= ca.prv.pem | |
CA_PUB_KEY ?= ca.pub.pem | |
help: | |
@echo "setup - create python3 virtual environment, install dependencies" | |
@echo "serve - run the Certificate Authority" | |
setup: | |
python3 -m venv .venv | |
.venv/bin/pip install flask pyOpenSSL | |
serve: | |
@echo "using private key: ${CA_PRV_KEY}" | |
@echo "using public cert: ${CA_PUB_CRT}" | |
.venv/bin/python ca.py |