1
0
mirror of https://github.com/laurivosandi/certidude synced 2025-10-31 01:19:11 +00:00

Refactor codebase

* Replace PyOpenSSL with cryptography.io
* Rename constants to const
* Drop support for uwsgi
* Use systemd to launch certidude server
* Signer automatically spawned as part of server
* Update requirements.txt
* Clean up certidude client configuration handling
* Add automatic enroll with Kerberos machine cerdentials
This commit is contained in:
2016-09-18 00:00:14 +03:00
parent 15858083b3
commit b4d006227a
35 changed files with 1181 additions and 1057 deletions

View File

@@ -12,7 +12,7 @@ from certidude.auth import login_required, authorize_admin
from certidude.user import User
from certidude.decorators import serialize, event_source, csrf_protection
from certidude.wrappers import Request, Certificate
from certidude import constants, config
from certidude import const, config
logger = logging.getLogger("api")
@@ -35,7 +35,7 @@ class CertificateAuthorityResource(object):
resp.stream = open(config.AUTHORITY_CERTIFICATE_PATH, "rb")
resp.append_header("Content-Type", "application/x-x509-ca-cert")
resp.append_header("Content-Disposition", "attachment; filename=%s.crt" %
constants.HOSTNAME.encode("ascii"))
const.HOSTNAME.encode("ascii"))
class SessionResource(object):
@@ -112,7 +112,7 @@ class NormalizeMiddleware(object):
assert not req.get_param("unicode") or req.get_param("unicode") == u"", "Unicode sanity check failed"
req.context["remote_addr"] = ipaddress.ip_address(req.env["REMOTE_ADDR"].decode("utf-8"))
def process_response(self, req, resp, resource):
def process_response(self, req, resp, resource=None):
# wtf falcon?!
if isinstance(resp.location, unicode):
resp.location = resp.location.encode("ascii")
@@ -125,7 +125,6 @@ def certidude_app():
from .request import RequestListResource, RequestDetailResource
from .lease import LeaseResource
from .whois import WhoisResource
from .log import LogResource
from .tag import TagResource, TagDetailResource
from .cfg import ConfigResource, ScriptResource
@@ -149,19 +148,6 @@ def certidude_app():
if config.USER_CERTIFICATE_ENROLLMENT:
app.add_route("/api/bundle/", BundleResource())
log_handlers = []
if config.LOGGING_BACKEND == "sql":
from certidude.mysqllog import LogHandler
uri = config.cp.get("logging", "database")
log_handlers.append(LogHandler(uri))
app.add_route("/api/log/", LogResource(uri))
elif config.LOGGING_BACKEND == "syslog":
from logging.handlers import SyslogHandler
log_handlers.append(SysLogHandler())
# Browsing syslog via HTTP is obviously not possible out of the box
elif config.LOGGING_BACKEND:
raise ValueError("Invalid logging.backend = %s" % config.LOGGING_BACKEND)
if config.TAGGING_BACKEND == "sql":
uri = config.cp.get("tagging", "database")
app.add_route("/api/tag/", TagResource(uri))
@@ -171,23 +157,5 @@ def certidude_app():
elif config.TAGGING_BACKEND:
raise ValueError("Invalid tagging.backend = %s" % config.TAGGING_BACKEND)
if config.PUSH_PUBLISH:
from certidude.push import PushLogHandler
log_handlers.append(PushLogHandler())
for facility in "api", "cli":
logger = logging.getLogger(facility)
logger.setLevel(logging.DEBUG)
for handler in log_handlers:
logger.addHandler(handler)
logging.getLogger("cli").debug("Started Certidude at %s", constants.FQDN)
import atexit
def exit_handler():
logging.getLogger("cli").debug("Shutting down Certidude")
atexit.register(exit_handler)
return app

View File

@@ -1,4 +1,5 @@
import logging
import hashlib
from certidude import config, authority

View File

@@ -36,8 +36,6 @@ join
tag on device_tag.tag_id = tag.id
join
device on device_tag.device_id = device.id
where
device.cn = %s
"""
@@ -63,7 +61,7 @@ class ConfigResource(RelationalMixin):
@login_required
@authorize_admin
def on_get(self, req, resp):
return self.iterfetch(SQL_SELECT_RULES)
return self.iterfetch(SQL_SELECT_TAGS)
class ScriptResource(RelationalMixin):

View File

@@ -10,6 +10,9 @@ from certidude.decorators import serialize, csrf_protection
from certidude.wrappers import Request, Certificate
from certidude.firewall import whitelist_subnets, whitelist_content_types
from cryptography import x509
from cryptography.hazmat.backends import default_backend
logger = logging.getLogger("api")
class RequestListResource(object):
@@ -29,6 +32,7 @@ class RequestListResource(object):
"""
body = req.stream.read(req.content_length)
csr = Request(body)
if not csr.common_name:
@@ -38,6 +42,19 @@ class RequestListResource(object):
"Bad request",
"No common name specified!")
machine = req.context.get("machine")
if machine:
if csr.common_name != machine:
raise falcon.HTTPBadRequest(
"Bad request",
"Common name %s differs from Kerberos credential %s!" % (csr.common_name, machine))
if csr.signable:
# Automatic enroll with Kerberos machine cerdentials
resp.set_header("Content-Type", "application/x-x509-user-cert")
resp.body = authority.sign(csr, overwrite=True).dump()
return
# Check if this request has been already signed and return corresponding certificte if it has been signed
try:
cert = authority.get_signed(csr.common_name)
@@ -51,8 +68,8 @@ class RequestListResource(object):
# TODO: check for revoked certificates and return HTTP 410 Gone
# Process automatic signing if the IP address is whitelisted and autosigning was requested
if req.get_param_as_bool("autosign"):
# Process automatic signing if the IP address is whitelisted, autosigning was requested and certificate can be automatically signed
if req.get_param_as_bool("autosign") and csr.signable:
for subnet in config.AUTOSIGN_SUBNETS:
if req.context.get("remote_addr") in subnet:
try:

View File

@@ -2,7 +2,7 @@
import falcon
import json
import logging
from certidude import constants
from certidude import const
from certidude.authority import export_crl, list_revoked
from certidude.decorators import MyEncoder
from cryptography import x509
@@ -21,7 +21,7 @@ class RevocationListResource(object):
resp.set_header("Content-Type", "application/x-pkcs7-crl")
resp.append_header(
"Content-Disposition",
("attachment; filename=%s.crl" % constants.HOSTNAME).encode("ascii"))
("attachment; filename=%s.crl" % const.HOSTNAME).encode("ascii"))
# Convert PEM to DER
resp.body = x509.load_pem_x509_crl(export_crl(),
default_backend()).public_bytes(Encoding.DER)
@@ -29,7 +29,7 @@ class RevocationListResource(object):
resp.set_header("Content-Type", "application/x-pem-file")
resp.append_header(
"Content-Disposition",
("attachment; filename=%s-crl.pem" % constants.HOSTNAME).encode("ascii"))
("attachment; filename=%s-crl.pem" % const.HOSTNAME).encode("ascii"))
resp.body = export_crl()
elif req.accept.startswith("application/json"):
resp.set_header("Content-Type", "application/json")