summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPiotr Dobrowolski <admin@tastycode.pl>2017-03-12 19:55:05 +0100
committerPiotr Dobrowolski <admin@tastycode.pl>2017-03-12 19:55:28 +0100
commit2a217b5a82ea165f2d5c1bc2b1d0ccef036f12f8 (patch)
tree0b1e5a4358c9923d5fc16ded0fe313ca8a29e518
downloadlocal-letsencrypt-2a217b5a82ea165f2d5c1bc2b1d0ccef036f12f8.tar.gz
local-letsencrypt-2a217b5a82ea165f2d5c1bc2b1d0ccef036f12f8.tar.bz2
local-letsencrypt-2a217b5a82ea165f2d5c1bc2b1d0ccef036f12f8.zip
Initial commit
-rw-r--r--.gitignore4
-rw-r--r--README.md20
-rwxr-xr-xclient/cleanup-hook.sh5
-rw-r--r--client/hook-config.dist2
-rwxr-xr-xclient/install-hook.sh11
-rw-r--r--server/backends.py45
-rw-r--r--server/config.cfg.dist7
-rw-r--r--server/master.py26
-rw-r--r--server/utils.py18
9 files changed, 138 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..88f2278
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.py[co]
+config.cfg
+ovh.conf
+hook-config
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c28c57f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,20 @@
+local-letsencrypt
+=================
+
+PoC for letsencrypt SSL certificates, as public, as local hswaw DNS zone is.
+
+Usage
+-----
+ cp server/config.cfg.dist server/config.cfg
+ vim server/config.cfg
+
+ cp client/hook-config.dist client/hook-config
+ vim client/hook-config
+
+ (cd server && python master.py) &
+
+ certbot-auto certonly --manual --preferred-challenges=dns \
+ --manual-auth-hook `pwd`/client/install-hook.sh \
+ --manual-cleanup-hook `pwd`/client/cleanup-hook.sh \
+ --manual-public-ip-logging-ok \
+ -d testing2.waw.inf.re
diff --git a/client/cleanup-hook.sh b/client/cleanup-hook.sh
new file mode 100755
index 0000000..23fe60a
--- /dev/null
+++ b/client/cleanup-hook.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+. $(dirname $(realpath $0))/hook-config
+
+curl "$API_URL/api/1/remove?token=$API_TOKEN&record=$CERTBOT_DOMAIN"
diff --git a/client/hook-config.dist b/client/hook-config.dist
new file mode 100644
index 0000000..ae9ed7a
--- /dev/null
+++ b/client/hook-config.dist
@@ -0,0 +1,2 @@
+API_URL="http://localhost:5000" # you may want to keep it on ssl...
+API_TOKEN="testtoken"
diff --git a/client/install-hook.sh b/client/install-hook.sh
new file mode 100755
index 0000000..08576dd
--- /dev/null
+++ b/client/install-hook.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+. $(dirname $(realpath $0))/hook-config
+
+curl "$API_URL/api/1/add?token=$API_TOKEN&record=$CERTBOT_DOMAIN&value=$CERTBOT_VALIDATION"
+
+# FIXME: ovh is shit
+while [ "$(dig _acme-challenge.$CERTBOT_DOMAIN TXT +short | wc -l)" -lt 1 ]; do
+ echo 'still waiting...' >&2
+ sleep 5;
+done
diff --git a/server/backends.py b/server/backends.py
new file mode 100644
index 0000000..be95f8c
--- /dev/null
+++ b/server/backends.py
@@ -0,0 +1,45 @@
+class Backend(object):
+ def __init__(self, config):
+ self.config = config
+
+ def add(self, name, value):
+ raise NotImplemented
+
+ def remove(self, name):
+ raise NotImplemented
+
+
+class OVHBackend(Backend):
+ def __init__(self, config):
+ import ovh
+ import ovh.exceptions
+
+ self.config = config
+ self.client = ovh.Client()
+ try:
+ self.client.get('/auth/currentCredential')
+ except (ovh.exceptions.InvalidKey, ovh.exceptions.InvalidCredential):
+ req = ovh.Client().request_consumerkey([
+ {'method': 'GET', 'path': '/domain/zone/*/record'},
+ {'method': 'POST', 'path': '/domain/zone/*/record'},
+ {'method': 'POST', 'path': '/domain/zone/*/refresh'},
+ {'method': 'DELETE', 'path': '/domain/zone/*/record/*'},
+ ])
+ print(req)
+
+ def add(self, name, value):
+ if not name.endswith(self.config['OVH_ZONE']):
+ raise Exception()
+
+ v = self.client.post('/domain/zone/%s/record' % (self.config['OVH_ZONE'],),
+ fieldType='TXT', subDomain=name+'.', target=value)
+ print(v)
+ self.client.post('/domain/zone/%s/refresh' % (self.config['OVH_ZONE'],))
+
+ def remove(self, name):
+ ids = self.client.get(
+ '/domain/zone/%s/record' % (self.config['OVH_ZONE'],), fieldType='TXT', subDomain=name+'.')
+ for i in ids:
+ print('Removing', i)
+ self.client.delete('/domain/zone/%s/record/%d' % (self.config['OVH_ZONE'], i))
+ self.client.post('/domain/zone/%s/refresh' % (self.config['OVH_ZONE'],))
diff --git a/server/config.cfg.dist b/server/config.cfg.dist
new file mode 100644
index 0000000..964eb19
--- /dev/null
+++ b/server/config.cfg.dist
@@ -0,0 +1,7 @@
+# Global configuration
+TOKENS = {
+ 'testing3.waw.inf.re': 'testtoken',
+}
+
+# OVH-specific backend configuration
+OVH_ZONE = 'inf.re'
diff --git a/server/master.py b/server/master.py
new file mode 100644
index 0000000..bcb3076
--- /dev/null
+++ b/server/master.py
@@ -0,0 +1,26 @@
+import flask
+from flask import request
+
+from backends import OVHBackend
+from utils import verify_token
+
+app = flask.Flask(__name__)
+app.config.from_pyfile('config.cfg')
+
+app.backend = OVHBackend(app.config)
+
+@app.route('/api/1/add')
+@verify_token
+def add():
+ app.backend.add('_acme-challenge.'+request.args['record'], request.args['value'])
+ return 'ok'
+
+@app.route('/api/1/remove')
+@verify_token
+def remove():
+ app.backend.remove('_acme-challenge.'+request.args['record'])
+ return 'ok'
+
+
+if __name__ == "__main__":
+ app.run(debug=True)
diff --git a/server/utils.py b/server/utils.py
new file mode 100644
index 0000000..5536290
--- /dev/null
+++ b/server/utils.py
@@ -0,0 +1,18 @@
+from functools import wraps
+from flask import current_app, request, abort
+
+
+def verify_token(f):
+ """Verifies request token"""
+
+ @wraps(f)
+ def wrapped(*args, **kwargs):
+ rec = request.args.get('record', None)
+ token = request.args.get('token', None)
+
+ if rec in current_app.config['TOKENS'] and current_app.config['TOKENS'][rec] == token:
+ return f(*args, **kwargs)
+
+ abort(403)
+
+ return wrapped