diff --git a/facade-poc/README.md b/facade-poc/README.md new file mode 100644 index 0000000..2657647 --- /dev/null +++ b/facade-poc/README.md @@ -0,0 +1,87 @@ +# Motivation + This set up shows a simple 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 successful request 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..f331126 --- /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 "/certificates/nginx.crt"; + ssl_certificate_key "/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..4c3c9ea --- /dev/null +++ b/facade-poc/server.py @@ -0,0 +1,36 @@ +from flask import Flask, jsonify, request +import ssl + +app = Flask(__name__) + +# Hardcoded API key +API_KEY = "TEST-API-KEY" +HEADER_NAME = "X-API-Key" + +# Unsecured 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) + + # API key is invalid, return send unauthorized + if provided_api_key != API_KEY: + return jsonify({'error': 'Unauthorized access. Invalid API key.'}), 401 + + + 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)