Skip to content

Instantly share code, notes, and snippets.

@willcharlton
Last active June 8, 2022 01:14
Show Gist options
  • Save willcharlton/9b7f26449dd3b37cf3975ae5b9e61511 to your computer and use it in GitHub Desktop.
Save willcharlton/9b7f26449dd3b37cf3975ae5b9e61511 to your computer and use it in GitHub Desktop.
A simple flask server that functions as a very basic Certificate Authority.

Basic Certificate Authority

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment