-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Tom Doyle
authored and
Tom Doyle
committed
Aug 18, 2021
0 parents
commit ed643b5
Showing
13 changed files
with
340 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[app] | ||
secret_key = |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
bind = '0.0.0.0:5005' | ||
workers = 1 | ||
accesslog = '-' | ||
loglevel = 'debug' | ||
capture_output = True | ||
enable_stdio_inheritance = True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
src/config/ | ||
src/api.keys | ||
letsencrypt/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
FROM python:3.9 | ||
|
||
ENV FLASK_APP app.py | ||
|
||
COPY requirements.txt ./ | ||
RUN pip install -r requirements.txt | ||
|
||
COPY . ./ | ||
|
||
EXPOSE 5005 | ||
WORKDIR src/ | ||
CMD ["gunicorn", "--config", "config/gunicorn-cfg.py", "app:app"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
config: | ||
./configure | ||
|
||
build: | ||
./configure | ||
docker-compose up -d --build | ||
|
||
traefik: | ||
./configure | ||
docker-compose --file docker-compose-traefik.yml up -d --build | ||
|
||
clean: | ||
rm -rf src/config/ | ||
rm -rf api.keys | ||
|
||
local: | ||
./configure local | ||
docker-compose --file docker-compose-traefik-local.yml up -d --build | ||
|
||
stop: | ||
docker-compose down |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
## Python API Template | ||
|
||
This repo is a template for a python api with Flask | ||
|
||
|
||
### Configure & Install | ||
|
||
Configure `config.yml` | ||
|
||
**Optional** To generate only the configuration files | ||
|
||
```bash | ||
make config | ||
``` | ||
|
||
To run container on port 5005 | ||
|
||
```bash | ||
make build | ||
``` | ||
|
||
To run the container with traefik proxy and letsencrypt | ||
|
||
```bash | ||
make traefik | ||
``` | ||
|
||
**Note:** If you are running this locally you won't be able to get a cert from letsencrypt | ||
You should then build for local | ||
|
||
```bash | ||
make local | ||
``` | ||
|
||
If you want to stop all containers | ||
|
||
```bash | ||
make stop | ||
``` | ||
|
||
If you want to remove all generated config files | ||
```bash | ||
make clean | ||
``` | ||
|
||
|
||
### Issues | ||
|
||
If you have any questions or issues please open an issue on this repo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
gunicorn: | ||
bind: '0.0.0.0:5005' | ||
workers: 1 | ||
accesslog: '-' | ||
loglevel: 'debug' | ||
capture_output: True | ||
enable_stdio_inheritance: True | ||
api: | ||
example_key: 'w8iqHcy4p1a9xlQL4dQZkxA7Qo8EmcWFretixnvSPzm1iF2wUh' | ||
app: | ||
secret_key: WfQ2mha43Pfzwu1qYu3k4eBaKVDMV6dA9cD54cef | ||
traefik: | ||
letsencrypt: | ||
email: [email protected] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
#!/bin/bash | ||
|
||
# | ||
# Configure script | ||
# | ||
|
||
|
||
# | ||
# Parse config.yml | ||
# | ||
|
||
parse_yaml() { | ||
local prefix=$2 | ||
local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034') | ||
sed -ne "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \ | ||
-e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" $1 | | ||
awk -F$fs '{ | ||
indent = length($1)/2; | ||
vname[indent] = $2; | ||
for (i in vname) {if (i > indent) {delete vname[i]}} | ||
if (length($3) > 0) { | ||
vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")} | ||
printf("%s%s%s=\"%s\"\n", "'$prefix'",vn, $2, $3); | ||
} | ||
}' | ||
} | ||
|
||
if [[ ! -d "src/config" ]]; then | ||
mkdir src/config | ||
fi | ||
|
||
# | ||
# Generate gunicorn.cnf | ||
# | ||
|
||
eval $(parse_yaml config.yml "config_") | ||
|
||
echo "bind = $config_gunicorn_bind" > src/config/gunicorn-cfg.py | ||
echo "workers = $config_gunicorn_workers" >> src/config/gunicorn-cfg.py | ||
echo "accesslog = $config_gunicorn_accesslog" >> src/config/gunicorn-cfg.py | ||
echo "loglevel = $config_gunicorn_loglevel" >> src/config/gunicorn-cfg.py | ||
echo "capture_output = $config_gunicorn_capture_output" >> src/config/gunicorn-cfg.py | ||
echo "enable_stdio_inheritance = $config_gunicorn_enable_stdio_inheritance" >> src/config/gunicorn-cfg.py | ||
|
||
# | ||
# Generate api.keys | ||
# | ||
|
||
printf "{\n $config_api_example_key : \"example_key\"\n}" > src/api.keys | ||
|
||
# | ||
# Generate config.ini | ||
# | ||
|
||
cp .config/config.ini src/config/config.ini | ||
sed -i "s/secret_key = /secret_key = ${config_app_secret_key}/" src/config/config.ini | ||
|
||
|
||
# | ||
# Generate traefik config | ||
# | ||
|
||
sed -i -e "s/- \"--certificatesresolvers.myresolver.acme.email=.*\"/- \"--certificatesresolvers.myresolver.acme.email=${config_traefik_letsencrypt_email}\"/" docker-compose-traefik.yml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
version: '3' | ||
services: | ||
example_app: | ||
container_name: example_app | ||
restart: always | ||
build: . | ||
networks: | ||
- web | ||
labels: | ||
- "traefik.http.routers.example.rule=Host(`app.internal`)" | ||
- "traefik.http.routers.example.entrypoints=web" | ||
- "traefik.http.routers.example.service=example" | ||
- "traefik.http.services.example.loadbalancer.server.port=5005" | ||
- "traefik.docker.network=web" | ||
- "traefik.http.routers.example.tls=false" | ||
|
||
example_traefik: | ||
container_name: "example_traefik" | ||
image: "traefik:latest" | ||
restart: always | ||
command: | ||
- "--entrypoints.web.address=:80" | ||
- "--entrypoints.websecure.address=:443" | ||
- "--providers.docker=true" | ||
- "--providers.docker.exposedbydefault=true" | ||
- "--api.dashboard=true" | ||
- "--certificatesresolvers.myresolver.acme.httpchallenge=true" | ||
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web" | ||
- "--certificatesresolvers.myresolver.acme.caserver=https://acme-v01.api.letsencrypt.org/directory" | ||
- "--certificatesresolvers.myresolver.acme.email=thomas.doyle9@mail.dcu.ie" | ||
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" | ||
ports: | ||
- "80:80" | ||
- "443:443" | ||
networks: | ||
- web | ||
volumes: | ||
- "./letsencrypt:/letsencrypt" | ||
- "/var/run/docker.sock:/var/run/docker.sock:ro" | ||
labels: | ||
# Dashboard | ||
- "traefik.http.routers.traefik.rule=Host(`traefik.internal`)" | ||
- "traefik.http.routers.traefik.service=api@internal" | ||
- "traefik.http.routers.traefik.entrypoints=web" | ||
- "traefik.http.routers.traefik.tls=false" | ||
- "traefik.http.routers.traefik.tls.certresolver=myresolver" | ||
|
||
# global redirect to https | ||
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)" | ||
- "traefik.http.routers.http-catchall.entrypoints=web" | ||
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https" | ||
|
||
networks: | ||
web: | ||
external: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
version: '3' | ||
services: | ||
example_app: | ||
container_name: example_app | ||
restart: always | ||
build: . | ||
networks: | ||
- web | ||
labels: | ||
- "traefik.http.routers.example.rule=Host(`app.your.domain`)" | ||
- "traefik.http.routers.example.entrypoints=websecure" | ||
- "traefik.http.routers.example.service=example" | ||
- "traefik.http.services.example.loadbalancer.server.port=5005" | ||
- "traefik.docker.network=web" | ||
- "traefik.http.routers.example.tls=true" | ||
|
||
example_traefik: | ||
container_name: "example_traefik" | ||
image: "traefik:latest" | ||
restart: always | ||
command: | ||
- "--entrypoints.web.address=:80" | ||
- "--entrypoints.websecure.address=:443" | ||
- "--providers.docker=true" | ||
- "--providers.docker.exposedbydefault=true" | ||
- "--api.dashboard=true" | ||
- "--certificatesresolvers.myresolver.acme.httpchallenge=true" | ||
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web" | ||
- "--certificatesresolvers.myresolver.acme.caserver=https://acme-v01.api.letsencrypt.org/directory" | ||
- "--certificatesresolvers.myresolver.acme.email=thomas.doyle9@mail.dcu.ie" | ||
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json" | ||
ports: | ||
- "80:80" | ||
- "443:443" | ||
networks: | ||
- web | ||
volumes: | ||
- "./letsencrypt:/letsencrypt" | ||
- "/var/run/docker.sock:/var/run/docker.sock:ro" | ||
labels: | ||
# Dashboard | ||
- "traefik.http.routers.traefik.rule=Host(`your.domain`)" | ||
- "traefik.http.routers.traefik.service=api@internal" | ||
- "traefik.http.routers.traefik.entrypoints=websecure" | ||
- "traefik.http.routers.traefik.tls=true" | ||
- "traefik.http.routers.traefik.tls.certresolver=myresolver" | ||
|
||
# global redirect to https | ||
- "traefik.http.routers.http-catchall.rule=hostregexp(`{host:.+}`)" | ||
- "traefik.http.routers.http-catchall.entrypoints=web" | ||
- "traefik.http.routers.http-catchall.middlewares=redirect-to-https" | ||
|
||
networks: | ||
web: | ||
external: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
version: '3' | ||
services: | ||
example_app: | ||
container_name: example_app | ||
restart: always | ||
build: . | ||
ports: | ||
- "5005:5005" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
flask | ||
flask_login | ||
flask_migrate | ||
flask_wtf | ||
flask_sqlalchemy==2.* | ||
email_validator | ||
python-decouple | ||
gunicorn |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
#!/usr/local/env python3.9 | ||
|
||
import json | ||
import configparser | ||
from flask import Blueprint, Flask, render_template, redirect, url_for, request, jsonify, abort | ||
from flask_login import LoginManager, login_user, logout_user, UserMixin, current_user, login_required | ||
from flask import render_template_string, redirect | ||
from functools import wraps | ||
|
||
config = configparser.ConfigParser() | ||
config.read('config/config.ini') | ||
|
||
app = Flask(__name__) | ||
app.secret_key = config['app']['secret_key'] | ||
|
||
def is_validkey(key): | ||
with open('api.keys', 'r') as f: | ||
keys = json.load(f) | ||
if key in keys: | ||
return True | ||
return False | ||
|
||
def require_appkey(view_function): | ||
@wraps(view_function) | ||
def decorated_function(*args, **kwargs): | ||
if request.headers.get('x-api-key') and is_validkey(request.headers.get('x-api-key')): | ||
return view_function(*args, **kwargs) | ||
else: | ||
abort(401) | ||
return decorated_function | ||
|
||
@app.route('/', methods=['GET']) | ||
def index(): | ||
return {"msg": "No auth needed"} | ||
|
||
@app.route('/auth/', methods=['POST', 'GET']) | ||
@require_appkey | ||
def auth(): | ||
if request.method == 'GET': | ||
return {"msg": "API key Valid"} | ||
return {"msg": "API key Not Valid"} | ||
|
||
if __name__ == '__main__': | ||
app.run(debug=True) |