Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature_proxy #39

Merged
merged 1 commit into from
Nov 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,6 @@ confidence=
# --disable=W".
disable=missing-docstring,
missing-module-docstring,
unused-argument,
unused-variable,
pointless-string-statement,
too-many-arguments,
too-few-public-methods,
bad-continuation, # bad-continuation doesn't comply with yapf, so lets
# yapf correct indentation continuation issue
useless-object-inheritance,
Expand Down
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ PIP_FILE_LOCK = Pipfile.lock
# default configuration
ENV_FILE ?= .env.local
HTTP_PORT ?= 5000
ROUTE_PREFIX ?= /api/$(SERVICE_NAME)

# Commands
PIPENV_RUN := pipenv run
Expand Down Expand Up @@ -145,7 +146,7 @@ serve: clean_logs $(LOGS_DIR)

.PHONY: gunicornserve
gunicornserve: clean_logs $(LOGS_DIR)
ENV_FILE=$(ENV_FILE) LOGS_DIR=$(LOGS_DIR) $(PYTHON) wsgi.py
SCRIPT_NAME=$(ROUTE_PREFIX) ENV_FILE=$(ENV_FILE) LOGS_DIR=$(LOGS_DIR) $(PYTHON) wsgi.py


# Docker related functions.
Expand Down Expand Up @@ -177,6 +178,7 @@ dockerrun: clean_logs dockerbuild $(LOGS_DIR)
-it -p $(HTTP_PORT):8080 \
--env-file=${PWD}/${ENV_FILE} \
--env LOGS_DIR=/logs \
--env SCRIPT_NAME=$(ROUTE_PREFIX) \
--mount type=bind,source="${LOGS_DIR}",target=/logs \
$(DOCKER_IMG_LOCAL_TAG)

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,5 @@ The service is configured by Environment Variable:
| Env | Default | Description |
| ----------- | --------------------- | -------------------------- |
| LOGGING_CFG | logging-cfg-local.yml | Logging configuration file |
| FORWARED_ALLOW_IPS | `*` | Sets the gunicorn `forwarded_allow_ips` (see https://docs.gunicorn.org/en/stable/settings.html#forwarded-allow-ips). This is required in order to `secure_scheme_headers` to works. |
| FORWARDED_PROTO_HEADER_NAME | `X-Forwarded-Proto` | Sets gunicorn `secure_scheme_headers` parameter to `{FORWARDED_PROTO_HEADER_NAME: 'https'}`, see https://docs.gunicorn.org/en/stable/settings.html#secure-scheme-headers. |
6 changes: 0 additions & 6 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@

from app import settings
from app.helpers.utils import ALLOWED_DOMAINS_PATTERN
from app.helpers.utils import init_logging
from app.helpers.utils import make_error_msg
from app.middleware import ReverseProxy

logger = logging.getLogger(__name__)
route_logger = logging.getLogger('app.routes')
Expand All @@ -23,10 +21,6 @@

app = Flask(__name__)
app.config.from_object(settings)
# this middleware is useful if this micro-service will return URLs to itself
# otherwise, for simpler services (such as only returning a simple raw data / JSON / image)
# this can be removed
app.wsgi_app = ReverseProxy(app.wsgi_app, script_name='/')


# NOTE it is better to have this method registered first (before validate_origin) otherwise
Expand Down
60 changes: 0 additions & 60 deletions app/middleware.py

This file was deleted.

2 changes: 1 addition & 1 deletion app/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@


@app.route('/checker', methods=['GET'])
def check():
def checker():
return make_response(jsonify({'success': True, 'message': 'OK', 'version': APP_VERSION}))
4 changes: 4 additions & 0 deletions app/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@
raise RuntimeError("Environment variable $ALLOWED_DOMAINS was not set")

ALLOWED_DOMAINS = ALLOWED_DOMAINS_STRING.split(',')

# Proxy settings
FORWARED_ALLOW_IPS = os.getenv('FORWARED_ALLOW_IPS', '*')
FORWARDED_PROTO_HEADER_NAME = os.getenv('FORWARDED_PROTO_HEADER_NAME', 'X-Forwarded-Proto')
37 changes: 37 additions & 0 deletions tests/unit_tests/test_route.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import logging
import unittest

from flask import url_for

from app import app
from app.version import APP_VERSION

logger = logging.getLogger(__name__)


class CheckerTests(unittest.TestCase):

def setUp(self):
self.context = app.test_request_context()
self.context.push()
self.app = app.test_client()
self.app.testing = True
self.origin_headers = {
"allowed": {
"Origin": "some_random_domain"
}, "bad": {
"Origin": "big-bad-wolf.com"
}
}

def test_checker(self):
response = self.app.get(url_for('checker'), headers=self.origin_headers["allowed"])
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content_type, "application/json")
self.assertEqual(response.json, {"message": "OK", "success": True, "version": APP_VERSION})

def test_checker_non_allowed_origin(self):
response = self.app.get(url_for('checker'), headers=self.origin_headers["bad"])
self.assertEqual(response.status_code, 403)
self.assertEqual(response.content_type, "application/json")
self.assertEqual(response.json["error"]["message"], "Not allowed")
8 changes: 7 additions & 1 deletion wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from app import app as application
from app.helpers.utils import get_logging_cfg
from app.settings import FORWARDED_PROTO_HEADER_NAME
from app.settings import FORWARED_ALLOW_IPS
from app.settings import HTTP_PORT


Expand Down Expand Up @@ -32,6 +34,10 @@ def load(self):
'worker_class': 'gevent',
'workers': 2, # scaling horizontally is left to Kubernetes
'timeout': 60,
'logconfig_dict': get_logging_cfg()
'logconfig_dict': get_logging_cfg(),
'forwarded_allow_ips': FORWARED_ALLOW_IPS,
'secure_scheme_headers': {
FORWARDED_PROTO_HEADER_NAME.upper(): 'https'
}
}
StandaloneApplication(application, options).run()