From b749078069bd3e4e2c55226a41c4ea9a588964d2 Mon Sep 17 00:00:00 2001 From: Uwinator Date: Thu, 21 Mar 2024 13:04:26 +0100 Subject: [PATCH 1/4] add basic facade example --- facade-poc/README.md | 87 +++++++++++++++++++++++++++++++++++++++++++ facade-poc/nginx.conf | 73 ++++++++++++++++++++++++++++++++++++ facade-poc/server.py | 34 +++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 facade-poc/README.md create mode 100644 facade-poc/nginx.conf create mode 100644 facade-poc/server.py diff --git a/facade-poc/README.md b/facade-poc/README.md new file mode 100644 index 0000000..b7c57ee --- /dev/null +++ b/facade-poc/README.md @@ -0,0 +1,87 @@ +# Motivation + This repository shows a simple set up for a facade implementation with re-authentication. + +## Components +* server +* nginx +* client call + +# Requirements +* python (tested with version 3.12.2) +* nginx (tested with version 1.25.4) + +# Server +1) Create a Virtual Environment for Python + +`python3 -m venv venv` + +2) Install Flask + +`pip3 install flask` + +3) Activate the virtual environment for python + +`source venv/bin/activate` + +4) Create Private Key + +`openssl genrsa -aes256 -out server.key 2048` + +5) Create Certificate Signing Request + +`openssl req -new -key server.key -out server.csr` + +6) Create the Certificate + +`openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt` + +7) Start the server + +`python server.py` + +8) Test the server + +`curl https://127.0.0.1:5000/unsecured --insecure` + +9) Test passing an API Key + +`curl https://localhost:5000/secured -H "X-API-Key:TEST-API-KEY" --insecure` + +# NGINX +Apply the right configuration, found in this repository in `nginx.conf` +On MacOS it is located in `/usr/local/etc/nginx` + +## Create Certificates and Adjust NGINX Configuration + +1) Create Private Key + +`openssl genrsa -aes256 -out server.key 2048` + +2) Create Certificate Signing Request + +`openssl req -new -key nginx.key -out nginx.csr` + +3) Create the Certificate + +`openssl x509 -req -days 365 -in nginx.csr -signkey nginx.key -out nginx.crt` + +4) Adjust paths in nginx.conf + + +5) Start nginx + +`nginx` + +# Start Testing + +Test for forbidden on unsecured endpoint + +`curl https://localhost/unsecured --insecure` + +Test for forbidden on secured endpoint with enriched credentials + +`curl https://localhost/secured --insecure` + +# Troubleshooting + +Beware of the nginx state. Sometimes, a reload via `nginx -s reload` is not enough. If it behaves not as expected, try `nginx -s quit` and restart using `nginx`. diff --git a/facade-poc/nginx.conf b/facade-poc/nginx.conf new file mode 100644 index 0000000..abf7a7d --- /dev/null +++ b/facade-poc/nginx.conf @@ -0,0 +1,73 @@ + +#user nobody; +worker_processes 1; + +error_log /var/log/nginx/error.log; +error_log /var/log/nginx/error.log notice; +error_log /var/log/nginx/error.log info; + +#pid logs/nginx.pid; + +events { + worker_connections 1024; +} + + +http { + include mime.types; + default_type application/octet-stream; + + #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + # '$status $body_bytes_sent "$http_referer" ' + # '"$http_user_agent" "$http_x_forwarded_for"'; + + #access_log logs/access.log main; + + sendfile on; + #tcp_nopush on; + + #keepalive_timeout 0; + keepalive_timeout 65; + + #gzip on; + + # HTTPS server + + server { + listen 443 ssl; + server_name localhost; + ssl_certificate "/Users/uwe/Projects/Facade-PoC/certificates/nginx.crt"; + ssl_certificate_key "/Users/uwe/Projects/Facade-PoC/certificates/nginx.key"; + ssl_session_cache shared:SSL:1m; + ssl_session_timeout 5m; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + + location /secured { + # Hardcoded API key + set $api_key "TEST-API-KEY"; + + # Add the API key as a custom HTTP header + proxy_set_header X-API-Key $api_key; + + proxy_pass https://127.0.0.1:5000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_ssl_verify off; + } + + # Allow access to other locations + location / { + # Define your access permissions here + deny all; + # Additional configurations for other locations if needed + } + + + } + include servers/*; +} diff --git a/facade-poc/server.py b/facade-poc/server.py new file mode 100644 index 0000000..5f68ecf --- /dev/null +++ b/facade-poc/server.py @@ -0,0 +1,34 @@ +from flask import Flask, jsonify, request +import ssl + +app = Flask(__name__) + +# Hardcoded API key +API_KEY = "TEST-API-KEY" +HEADER_NAME = "X-API-Key" +# First endpoint +@app.route('/unsecured', methods=['GET']) +def unsecured(): + data = {'message': 'This is an unsecured endpoint.'} + return jsonify(data) + +# Secured endpoint +@app.route('/secured', methods=['GET']) +def endpoint2(): + # Check if API key is provided in the request headers + provided_api_key = request.headers.get(HEADER_NAME) + + if provided_api_key != API_KEY: + return jsonify({'error': 'Unauthorized access. Invalid API key.'}), 401 + + # API key is valid, return data + data = {'message': 'This is a secured endpoint.'} + return jsonify(data) + +if __name__ == '__main__': + # Generate SSL context + context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + context.load_cert_chain('certificates/server.crt', 'certificates/server.key') # Provide paths to your certificate and private key files + + # Run Flask app with TLS/SSL enabled + app.run(debug=True, ssl_context=context) From 78bdfa8e5b82f85ef2c94061a4d94546606d409b Mon Sep 17 00:00:00 2001 From: Uwinator <16160551+Uwinator@users.noreply.github.com> Date: Thu, 21 Mar 2024 13:20:37 +0100 Subject: [PATCH 2/4] remove user-specific paths --- facade-poc/nginx.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/facade-poc/nginx.conf b/facade-poc/nginx.conf index abf7a7d..f331126 100644 --- a/facade-poc/nginx.conf +++ b/facade-poc/nginx.conf @@ -36,8 +36,8 @@ http { server { listen 443 ssl; server_name localhost; - ssl_certificate "/Users/uwe/Projects/Facade-PoC/certificates/nginx.crt"; - ssl_certificate_key "/Users/uwe/Projects/Facade-PoC/certificates/nginx.key"; + ssl_certificate "/certificates/nginx.crt"; + ssl_certificate_key "/certificates/nginx.key"; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; From b6707900598c505981056531bda6379b0aaef44e Mon Sep 17 00:00:00 2001 From: Uwinator <16160551+Uwinator@users.noreply.github.com> Date: Thu, 21 Mar 2024 14:24:02 +0100 Subject: [PATCH 3/4] minor docu fixes --- facade-poc/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/facade-poc/README.md b/facade-poc/README.md index b7c57ee..2657647 100644 --- a/facade-poc/README.md +++ b/facade-poc/README.md @@ -1,5 +1,5 @@ # Motivation - This repository shows a simple set up for a facade implementation with re-authentication. + This set up shows a simple facade implementation with re-authentication. ## Components * server @@ -78,7 +78,7 @@ Test for forbidden on unsecured endpoint `curl https://localhost/unsecured --insecure` -Test for forbidden on secured endpoint with enriched credentials +Test for successful request on secured endpoint with enriched credentials `curl https://localhost/secured --insecure` From 433e8e55cf143c582ffffa0f3574e7ca17d294aa Mon Sep 17 00:00:00 2001 From: Uwinator <16160551+Uwinator@users.noreply.github.com> Date: Thu, 21 Mar 2024 14:26:47 +0100 Subject: [PATCH 4/4] polishing --- facade-poc/server.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/facade-poc/server.py b/facade-poc/server.py index 5f68ecf..4c3c9ea 100644 --- a/facade-poc/server.py +++ b/facade-poc/server.py @@ -6,7 +6,8 @@ # Hardcoded API key API_KEY = "TEST-API-KEY" HEADER_NAME = "X-API-Key" -# First endpoint + +# Unsecured endpoint @app.route('/unsecured', methods=['GET']) def unsecured(): data = {'message': 'This is an unsecured endpoint.'} @@ -18,10 +19,11 @@ def endpoint2(): # Check if API key is provided in the request headers provided_api_key = request.headers.get(HEADER_NAME) + # API key is invalid, return send unauthorized if provided_api_key != API_KEY: return jsonify({'error': 'Unauthorized access. Invalid API key.'}), 401 - # API key is valid, return data + data = {'message': 'This is a secured endpoint.'} return jsonify(data)