Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
laurivosandi committed Jun 2, 2021
0 parents commit b03e205
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM python
RUN pip install motor sanic sanic-prometheus sanic_wtf
ADD lease.py /
CMD /lease.py
105 changes: 105 additions & 0 deletions lease.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env python

import os
import socket
from datetime import datetime
from motor.motor_asyncio import AsyncIOMotorClient
from prometheus_client import Counter
from sanic import Sanic, response
from sanic.exceptions import InvalidUsage, NotFound
from sanic_prometheus import monitor
from sanic_wtf import SanicForm
from wtforms import IntegerField, StringField
from wtforms.validators import DataRequired, IPAddress, NumberRange

submit_count = Counter("pinecrypt_lease_submit", "IP updates", ["service"])
flush_count = Counter("pinecrypt_lease_flush", "IP assignment flushes", ["service"])
not_found_count = Counter("pinecrypt_lease_not_found", "Certificate not found", ["service"])

class LeaseUpdateForm(SanicForm):
service = StringField("Service name")
internal_addr = StringField("Internal IP address", validators=[DataRequired(), IPAddress(ipv4=True, ipv6=True)])
remote_addr = StringField("Remote IP address", validators=[DataRequired(), IPAddress(ipv4=True, ipv6=True)])
remote_port = IntegerField(validators=[NumberRange(min=0, max=65534)])

app = Sanic("lease")
app.config["WTF_CSRF_ENABLED"] = False

MONGO_URI = os.getenv("MONGO_URI", "mongodb://127.0.0.1:27017/default")
FQDN = socket.getfqdn()


@app.listener('before_server_start')
async def setup_db(app, loop):
app.ctx.db = AsyncIOMotorClient(MONGO_URI).get_default_database()


async def submit(request, q):
q["status"] = "signed"
# TODO: add expiration check

form = LeaseUpdateForm(request)
if not form.validate():
raise InvalidUsage("Invalid form input")

result = await app.ctx.db.certidude_certificates.update_one(q, {
"$set": {
"last_seen": datetime.utcnow(),
"instance": "%s-%s" % (FQDN, form.service.data),
"remote.port": form.remote_port.data,
"remote.addr": form.remote_addr.data,
},
"$addToSet": {
"ip": form.internal_addr.data
}
})
if result.modified_count == 1:
submit_count.labels(form.service.data).inc()
return response.text('Lease updated')
else:
assert result.modified_count == 0
not_found_count.labels(form.service.data).inc()
raise NotFound("Node not found")


@app.route("/api/by-serial/<serial_number:int>", methods=["GET"])
async def get_by_serial(request, serial_number):
obj = await app.ctx.db.certidude_certificates.find_one({
"serial_number": "%x" % serial_number,
"status": "signed"})
# TODO: Add expiration check
if obj:
return response.text("Certificate valid")
else:
raise NotFound("Certificate not found or not valid")


@app.route("/api/by-dn/<distinguished_name:string>", methods=["POST"])
async def submit_by_dn(request, distinguished_name):
return await submit(request, {"distinguished_name": distinguished_name.replace("%20", " ")})


@app.route("/api/by-serial/<serial_number:int>", methods=["POST"])
async def submit_by_serial(request, serial_number):
return await submit(request, {"serial_number": "%x" % serial_number})


@app.route("/api/by-service/<service:string>", methods=["DELETE"])
async def flush(request, service):
"""
Flush IP addresses assigned by this instance as it was restarted
"""
await app.ctx.db.certidude_certificates.update_many({
"instance": "%s-%s" % (FQDN, service),
}, {
"$unset": {
"ip": "",
"instance": "",
}
})
flush_count.labels(service).inc()
return response.text('Leases flushed')


monitor(app).expose_endpoint()
app.run(port=2001)

0 comments on commit b03e205

Please sign in to comment.