deploy: add notification proxy
This commit is contained in:
parent
6408f5a15c
commit
a747ed293e
8 changed files with 196 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
||||||
*_secret.txt
|
*_secret.txt
|
||||||
|
*_apikey.txt
|
||||||
playbook.retry
|
playbook.retry
|
||||||
|
|
|
||||||
38
nginx.conf
38
nginx.conf
|
|
@ -129,6 +129,44 @@ http {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
listen [::]:443 ssl http2;
|
||||||
|
server_name automation.jaseg.de;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
|
||||||
|
ssl_certificate "/etc/letsencrypt/live/automation.jaseg.de/fullchain.pem";
|
||||||
|
ssl_certificate_key "/etc/letsencrypt/live/automation.jaseg.de/privkey.pem";
|
||||||
|
ssl_dhparam "/etc/letsencrypt/ssl-dhparams.pem";
|
||||||
|
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||||
|
|
||||||
|
ssl_stapling on;
|
||||||
|
ssl_stapling_verify on;
|
||||||
|
|
||||||
|
resolver 67.207.67.2 67.207.67.3 valid=300s;
|
||||||
|
resolver_timeout 10s;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=86400";
|
||||||
|
|
||||||
|
# Load configuration files for the default server block.
|
||||||
|
include /etc/nginx/default.d/*.conf;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
include uwsgi_params;
|
||||||
|
uwsgi_pass unix:/run/uwsgi/notification-proxy.socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 404 /404.html;
|
||||||
|
location = /40x.html {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 500 502 503 504 /50x.html;
|
||||||
|
location = /50x.html {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
listen 443 ssl http2;
|
listen 443 ssl http2;
|
||||||
listen [::]:443 ssl http2;
|
listen [::]:443 ssl http2;
|
||||||
|
|
|
||||||
89
notification_proxy.py
Normal file
89
notification_proxy.py
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
import smtplib
|
||||||
|
import ssl
|
||||||
|
import email.utils
|
||||||
|
import hmac
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
from datetime import datetime
|
||||||
|
import functools
|
||||||
|
import json
|
||||||
|
import binascii
|
||||||
|
|
||||||
|
from flask import Flask, request, abort
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config.from_pyfile('config.py')
|
||||||
|
|
||||||
|
smtp_server = "smtp.sendgrid.net"
|
||||||
|
port = 465
|
||||||
|
|
||||||
|
mail_routes = {}
|
||||||
|
def mail_route(name, receiver, subject):
|
||||||
|
def wrap(func):
|
||||||
|
global routes
|
||||||
|
mail_routes[name] = (receiver, subject, func)
|
||||||
|
return func
|
||||||
|
return wrap
|
||||||
|
|
||||||
|
|
||||||
|
def authenticate(secret):
|
||||||
|
def wrap(func):
|
||||||
|
func.last_seqnum = 0
|
||||||
|
@functools.wraps(func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
if not request.is_json:
|
||||||
|
abort(400)
|
||||||
|
|
||||||
|
if not 'auth' in request.json and 'payload' in request.json:
|
||||||
|
abort(400)
|
||||||
|
|
||||||
|
if not isinstance(request.json['auth'], str):
|
||||||
|
abort(400)
|
||||||
|
their_digest = binascii.unhexlify(request.json['auth'])
|
||||||
|
|
||||||
|
our_digest = hmac.digest(secret.encode('utf-8'), request.json['payload'].encode('utf-8'), 'sha256')
|
||||||
|
if not hmac.compare_digest(their_digest, our_digest):
|
||||||
|
abort(403)
|
||||||
|
|
||||||
|
try:
|
||||||
|
payload = json.loads(request.json['payload'])
|
||||||
|
except:
|
||||||
|
abort(400)
|
||||||
|
|
||||||
|
if not isinstance(payload['seq'], int) or payload['seq'] <= func.last_seqnum:
|
||||||
|
abort(400)
|
||||||
|
|
||||||
|
func.last_seqnum = payload['seq']
|
||||||
|
del payload['seq']
|
||||||
|
return func(payload)
|
||||||
|
return wrapper
|
||||||
|
return wrap
|
||||||
|
|
||||||
|
@mail_route('klingel', 'computerstuff@jaseg.de', 'It rang!')
|
||||||
|
@authenticate(app.config['SECRET_KLINGEL'])
|
||||||
|
def klingel(_):
|
||||||
|
return f'Date: {datetime.utcnow().isoformat()}'
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/notify/<route_name>', methods=['POST'])
|
||||||
|
def notify(route_name):
|
||||||
|
try:
|
||||||
|
context = ssl.create_default_context()
|
||||||
|
smtp = smtplib.SMTP_SSL(smtp_server, port)
|
||||||
|
smtp.login('apikey', app.config['SENDGRID_APIKEY'])
|
||||||
|
|
||||||
|
sender = f'{route_name}@{app.config["DOMAIN"]}'
|
||||||
|
|
||||||
|
receiver, subject, func = mail_routes[route_name]
|
||||||
|
|
||||||
|
msg = MIMEText(func() or subject)
|
||||||
|
msg['Subject'] = subject
|
||||||
|
msg['From'] = sender
|
||||||
|
msg['To'] = receiver
|
||||||
|
msg['Date'] = email.utils.formatdate()
|
||||||
|
smtp.sendmail(sender, receiver, msg.as_string())
|
||||||
|
finally:
|
||||||
|
smtp.quit()
|
||||||
|
return 'success'
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run()
|
||||||
5
notification_proxy_config.py.j2
Normal file
5
notification_proxy_config.py.j2
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
SENDGRID_APIKEY = '{{lookup('file', 'notification_proxy_sendgrid_apikey.txt')}}'
|
||||||
|
DOMAIN = 'automation.jaseg.de'
|
||||||
|
|
||||||
|
SECRET_KLINGEL = '{{lookup('password', 'notification_proxy_klingel_secret.txt length=32')}}'
|
||||||
|
|
@ -71,3 +71,6 @@
|
||||||
- name: Setup pogojig
|
- name: Setup pogojig
|
||||||
include_tasks: setup_pogojig.yml
|
include_tasks: setup_pogojig.yml
|
||||||
|
|
||||||
|
- name: Setup notification proxy
|
||||||
|
include_tasks: setup_notification_proxy.yml
|
||||||
|
|
||||||
|
|
|
||||||
48
setup_notification_proxy.yml
Normal file
48
setup_notification_proxy.yml
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
---
|
||||||
|
- name: Create notification proxy worker user and group
|
||||||
|
user:
|
||||||
|
name: uwsgi-notification-proxy
|
||||||
|
create_home: no
|
||||||
|
group: uwsgi
|
||||||
|
password: '!'
|
||||||
|
shell: /sbin/nologin
|
||||||
|
system: yes
|
||||||
|
|
||||||
|
- name: Create webapp dir
|
||||||
|
file:
|
||||||
|
path: /var/lib/notification-proxy
|
||||||
|
state: directory
|
||||||
|
owner: uwsgi-notification-proxy
|
||||||
|
group: uwsgi
|
||||||
|
mode: 0550
|
||||||
|
|
||||||
|
- name: Copy webapp sources
|
||||||
|
copy:
|
||||||
|
src: notification_proxy.py
|
||||||
|
dest: /var/lib/notification-proxy/
|
||||||
|
owner: uwsgi-notification-proxy
|
||||||
|
group: uwsgi
|
||||||
|
mode: 0440
|
||||||
|
|
||||||
|
- name: Template webapp config
|
||||||
|
template:
|
||||||
|
src: notification_proxy_config.py.j2
|
||||||
|
dest: /var/lib/notification-proxy/config.py
|
||||||
|
owner: uwsgi-notification-proxy
|
||||||
|
group: root
|
||||||
|
mode: 0660
|
||||||
|
|
||||||
|
- name: Copy uwsgi config
|
||||||
|
copy:
|
||||||
|
src: uwsgi-notification-proxy.ini
|
||||||
|
dest: /etc/uwsgi.d/notification-proxy.ini
|
||||||
|
owner: uwsgi-notification-proxy
|
||||||
|
group: uwsgi
|
||||||
|
mode: 0440
|
||||||
|
|
||||||
|
- name: Enable uwsgi systemd socket
|
||||||
|
systemd:
|
||||||
|
daemon-reload: yes
|
||||||
|
name: uwsgi-app@notification-proxy.socket
|
||||||
|
enabled: yes
|
||||||
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
- kochbuch.jaseg.net
|
- kochbuch.jaseg.net
|
||||||
- tracespace.jaseg.net
|
- tracespace.jaseg.net
|
||||||
- openjscad.jaseg.net
|
- openjscad.jaseg.net
|
||||||
|
- automation.jaseg.de
|
||||||
|
|
||||||
- name: Copy uwsgi systemd socket config
|
- name: Copy uwsgi systemd socket config
|
||||||
copy:
|
copy:
|
||||||
|
|
@ -54,6 +55,7 @@
|
||||||
- tracespace.jaseg.net
|
- tracespace.jaseg.net
|
||||||
- openjscad.jaseg.net
|
- openjscad.jaseg.net
|
||||||
- pogojig.jaseg.net
|
- pogojig.jaseg.net
|
||||||
|
- automation.jaseg.de
|
||||||
|
|
||||||
- name: Copy final nginx config
|
- name: Copy final nginx config
|
||||||
copy:
|
copy:
|
||||||
|
|
|
||||||
10
uwsgi-notification-proxy.ini
Normal file
10
uwsgi-notification-proxy.ini
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
[uwsgi]
|
||||||
|
master = True
|
||||||
|
cheap = True
|
||||||
|
die-on-idle = False
|
||||||
|
manage-script-name = True
|
||||||
|
log-format = [pid: %(pid)|app: -|req: -/-] %(addr) (%(user)) {%(vars) vars in %(pktsize) bytes} [%(ctime)] %(method) [URI hidden] => generated %(rsize) bytes in %(msecs) msecs (%(proto) %(status)) %(headers) headers in %(hsize) bytes (%(switches) switches on core %(core))
|
||||||
|
plugins = python3
|
||||||
|
chdir = /var/lib/notification-proxy
|
||||||
|
mount = /=notification_proxy:app
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue