mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Problem: No authorization mode without threescale (#2088)
Problem The current production deployment template uses 3scale to ensure that POST requests to the network (from anyone) only get through if they come from a client with an account (app_id and app_key). A private network wants to launch so that all HTTP requests (POST and GET) sent to the nodes in the network get be dropped unless they come from a small set of known (and unchanging) clients/sources. They don't need 3scale. They will want a modified version of the production deployment template. Solution Generate a special HTTP header and share it with all the known clients/sources. Have a single NGINX in each node which checks for that HTTP header value. If it's present, let the request pass through to the network. (HTTP headers are encrypted if HTTPS is used.) Are there other simpler or better options?
This commit is contained in:
parent
cdec60a7c0
commit
0ddfc62e3b
@ -92,6 +92,9 @@ data:
|
||||
# it will use the default cache size; i.e. max((50% RAM - 1GB), 256MB)
|
||||
storage-engine-cache-size: ""
|
||||
|
||||
# POST API authorization mode [threescale | secrete-token]
|
||||
authorization-mode: "threescale"
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
|
@ -54,6 +54,16 @@ data:
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: nginx-secret-header
|
||||
namespace: default
|
||||
type: Opaque
|
||||
data:
|
||||
# Base64-encoded secret token to authorize POST requests
|
||||
secret-token: "<b64 encoded secret token for authorization>"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: https-certs
|
||||
namespace: default
|
||||
@ -65,7 +75,7 @@ data:
|
||||
# starting with your primary SSL cert (e.g. your_domain.crt)
|
||||
# followed by all intermediate certs.
|
||||
# If cert if from DigiCert, download "Best format for nginx".
|
||||
cert.pem: "<b64 encoded HTTPS certificate chain"
|
||||
cert.pem: "<b64 encoded HTTPS certificate chain>"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
|
@ -5,6 +5,7 @@ RUN apt-get update \
|
||||
&& apt-get -y upgrade \
|
||||
&& apt-get autoremove \
|
||||
&& apt-get clean
|
||||
COPY nginx.conf.threescale.template /etc/nginx/nginx-threescale.conf
|
||||
COPY nginx.conf.template /etc/nginx/nginx.conf
|
||||
COPY nginx_entrypoint.bash /
|
||||
EXPOSE 80 443 27017 9986 46656
|
||||
|
@ -1,6 +1,7 @@
|
||||
# Frontend API server that:
|
||||
# 1. Acts as the HTTPS termination point.
|
||||
# 2. Forwards BDB HTTP requests to OpenResty backend.
|
||||
# 2. Authorizes HTTP requests with secret token header
|
||||
# and forwards to BDB backend.
|
||||
# 3. Forwards BDB WS requests to BDB backend.
|
||||
# 4. Does health check with LB.
|
||||
|
||||
@ -57,9 +58,6 @@ http {
|
||||
map $remote_addr $bdb_backend {
|
||||
default BIGCHAINDB_BACKEND_HOST;
|
||||
}
|
||||
map $remote_addr $openresty_backend {
|
||||
default OPENRESTY_BACKEND_HOST;
|
||||
}
|
||||
|
||||
# Frontend server for the external clients; acts as HTTPS termination point.
|
||||
server {
|
||||
@ -100,27 +98,27 @@ http {
|
||||
proxy_pass http://$bdb_backend:BIGCHAINDB_API_PORT;
|
||||
}
|
||||
|
||||
# POST requests get forwarded to OpenResty instance. Enable CORS too.
|
||||
if ($request_method = POST ) {
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
|
||||
add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
|
||||
|
||||
proxy_pass http://$openresty_backend:OPENRESTY_BACKEND_PORT;
|
||||
}
|
||||
|
||||
# OPTIONS requests handling for CORS.
|
||||
if ($request_method = 'OPTIONS') {
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,app_key,app_id';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-Secret-Access-Token,User-Agent';
|
||||
add_header 'Access-Control-Max-Age' 43200;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
add_header 'Content-Length' 0;
|
||||
return 204;
|
||||
}
|
||||
|
||||
# Check for security header to authorize POST requests
|
||||
if ( $http_x_secret_access_token != "SECRET_ACCESS_TOKEN" ) {
|
||||
return 403;
|
||||
}
|
||||
|
||||
# POST requests get forwarded to BDB.
|
||||
if ($request_method = POST ) {}
|
||||
proxy_pass http://$bdb_backend:BIGCHAINDB_API_PORT;
|
||||
}
|
||||
|
||||
# Only return this reponse if request_method is neither POST|GET|OPTIONS
|
||||
if ($request_method !~ ^(GET|OPTIONS|POST)$) {
|
||||
return 444;
|
||||
|
198
k8s/nginx-https/container/nginx.conf.threescale.template
Normal file
198
k8s/nginx-https/container/nginx.conf.threescale.template
Normal file
@ -0,0 +1,198 @@
|
||||
# Frontend API server that:
|
||||
# 1. Acts as the HTTPS termination point.
|
||||
# 2. Forwards BDB HTTP requests to OpenResty backend.
|
||||
# 3. Forwards BDB WS requests to BDB backend.
|
||||
# 4. Does health check with LB.
|
||||
|
||||
worker_processes 2;
|
||||
daemon off;
|
||||
user nobody nogroup;
|
||||
pid /tmp/nginx.pid;
|
||||
error_log /dev/stderr;
|
||||
|
||||
events {
|
||||
# Each worker handles up to 512 connections. Increase this for heavy
|
||||
# workloads.
|
||||
worker_connections 512;
|
||||
accept_mutex on;
|
||||
use epoll;
|
||||
}
|
||||
|
||||
http {
|
||||
access_log /dev/stdout combined buffer=16k flush=5s;
|
||||
|
||||
# Allow 10 req/sec from the same IP address, and store the counters in a
|
||||
# `zone` or shared memory location tagged as 'one'.
|
||||
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
|
||||
|
||||
# Enable logging when requests are being throttled.
|
||||
limit_req_log_level notice;
|
||||
|
||||
# HTTP status code that is returned to the client; 429 is for TooManyRequests,
|
||||
# ref. RFC 6585
|
||||
limit_req_status 429;
|
||||
|
||||
# Limit requests from the same client, allow `burst` to 20 r/s,
|
||||
# `nodelay` or drop connection immediately in case it exceeds this
|
||||
# threshold.
|
||||
limit_req zone=one burst=20 nodelay;
|
||||
|
||||
# `slowloris` attack mitigation settings.
|
||||
client_body_timeout 10s;
|
||||
client_header_timeout 10s;
|
||||
|
||||
# Do not expose nginx data/version number in error response and header
|
||||
server_tokens off;
|
||||
|
||||
# To prevent cross-site scripting
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
|
||||
# DNS resolver to use for all the backend names specified in this configuration.
|
||||
resolver DNS_SERVER valid=30s ipv6=off;
|
||||
|
||||
keepalive_timeout 60s;
|
||||
|
||||
# The following map blocks enable lazy-binding to the backend at runtime,
|
||||
# rather than binding as soon as NGINX starts.
|
||||
map $remote_addr $bdb_backend {
|
||||
default BIGCHAINDB_BACKEND_HOST;
|
||||
}
|
||||
map $remote_addr $openresty_backend {
|
||||
default OPENRESTY_BACKEND_HOST;
|
||||
}
|
||||
|
||||
# Frontend server for the external clients; acts as HTTPS termination point.
|
||||
server {
|
||||
listen CLUSTER_FRONTEND_PORT ssl;
|
||||
server_name "CLUSTER_FQDN";
|
||||
|
||||
ssl_certificate /etc/nginx/ssl/cert.pem;
|
||||
ssl_certificate_key /etc/nginx/ssl/cert.key;
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
|
||||
underscores_in_headers on;
|
||||
|
||||
# Forward websockets directly to backend BDB.
|
||||
location /api/v1/streams/valid_transactions {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
proxy_pass http://$bdb_backend:BIGCHAINDB_WS_PORT;
|
||||
proxy_read_timeout 600s;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
# Forward other URL paths as per business logic/use case to BDB or
|
||||
# OpenResty instance.
|
||||
location / {
|
||||
proxy_ignore_client_abort on;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
# max client request body size: avg transaction size.
|
||||
client_max_body_size 15k;
|
||||
|
||||
# No auth for GETs, forward directly to BDB.
|
||||
if ($request_method = GET) {
|
||||
proxy_pass http://$bdb_backend:BIGCHAINDB_API_PORT;
|
||||
}
|
||||
|
||||
# POST requests get forwarded to OpenResty instance. Enable CORS too.
|
||||
if ($request_method = POST ) {
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
|
||||
add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
|
||||
|
||||
proxy_pass http://$openresty_backend:OPENRESTY_BACKEND_PORT;
|
||||
}
|
||||
|
||||
# OPTIONS requests handling for CORS.
|
||||
if ($request_method = 'OPTIONS') {
|
||||
add_header 'Access-Control-Allow-Origin' '*';
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
|
||||
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,app_key,app_id';
|
||||
add_header 'Access-Control-Max-Age' 43200;
|
||||
add_header 'Content-Type' 'text/plain charset=UTF-8';
|
||||
add_header 'Content-Length' 0;
|
||||
return 204;
|
||||
}
|
||||
|
||||
# Only return this reponse if request_method is neither POST|GET|OPTIONS
|
||||
if ($request_method !~ ^(GET|OPTIONS|POST)$) {
|
||||
return 444;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Frontend server for the load balancer to respond to health checks.
|
||||
server {
|
||||
listen HEALTH_CHECK_PORT;
|
||||
|
||||
location = /health {
|
||||
return 200;
|
||||
}
|
||||
}
|
||||
|
||||
# Frontend server for the external clients; returns a pretty error message
|
||||
# when an HTTP request is sent instead of HTTPS.
|
||||
server {
|
||||
listen 80;
|
||||
server_name "CLUSTER_FQDN";
|
||||
|
||||
location / {
|
||||
add_header Upgrade "TLS/1.2, HTTP/1.1" always;
|
||||
default_type text/plain;
|
||||
return 426 'Consider using the HTTPS protocol next time!';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# NGINX stream block for TCP and UDP proxies.
|
||||
stream {
|
||||
log_format bdb_log '[$time_iso8601] $realip_remote_addr $remote_addr '
|
||||
'$proxy_protocol_addr $proxy_protocol_port '
|
||||
'$protocol $status $session_time $bytes_sent '
|
||||
'$bytes_received "$upstream_addr" "$upstream_bytes_sent" '
|
||||
'"$upstream_bytes_received" "$upstream_connect_time" ';
|
||||
|
||||
access_log /dev/stdout bdb_log buffer=16k flush=5s;
|
||||
|
||||
# Define a zone 'two' of size 10 megabytes to store the counters
|
||||
# that hold number of TCP connections from a specific IP address.
|
||||
limit_conn_zone $binary_remote_addr zone=two:10m;
|
||||
|
||||
# Enable logging when connections are being throttled.
|
||||
limit_conn_log_level notice;
|
||||
|
||||
# Allow 256 connections from the same IP address.
|
||||
limit_conn two 256;
|
||||
|
||||
# DNS resolver to use for all the backend names specified in this configuration.
|
||||
resolver DNS_SERVER valid=30s ipv6=off;
|
||||
|
||||
# The following map block enables lazy-binding to the backend at runtime,
|
||||
# rather than binding as soon as NGINX starts.
|
||||
map $remote_addr $tm_backend {
|
||||
default TM_BACKEND_HOST;
|
||||
}
|
||||
|
||||
# Server to forward connection to nginx instance hosting
|
||||
# tendermint node public key.
|
||||
server {
|
||||
listen TM_PUB_KEY_ACCESS_PORT;
|
||||
proxy_pass $tm_backend:TM_PUB_KEY_ACCESS_PORT;
|
||||
}
|
||||
|
||||
# Server to forward p2p connections to Tendermint instance.
|
||||
server {
|
||||
listen TM_P2P_PORT so_keepalive=3m:1m:5;
|
||||
preread_timeout 60s;
|
||||
tcp_nodelay on;
|
||||
proxy_pass $tm_backend:TM_P2P_PORT;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Authorization Modes
|
||||
threescale_auth_mode="threescale"
|
||||
secret_token_auth_mode="secret-token"
|
||||
|
||||
# Cluster vars
|
||||
cluster_fqdn=`printenv CLUSTER_FQDN`
|
||||
cluster_frontend_port=`printenv CLUSTER_FRONTEND_PORT`
|
||||
@ -9,6 +13,7 @@ cluster_frontend_port=`printenv CLUSTER_FRONTEND_PORT`
|
||||
# NGINX vars
|
||||
dns_server=`printenv DNS_SERVER`
|
||||
health_check_port=`printenv HEALTH_CHECK_PORT`
|
||||
authorization_mode=`printenv AUTHORIZATION_MODE`
|
||||
|
||||
|
||||
# MongoDB vars
|
||||
@ -47,7 +52,8 @@ if [[ -z "${cluster_frontend_port:?CLUSTER_FRONTEND_PORT not specified. Exiting!
|
||||
-z "${cluster_fqdn:?CLUSTER_FQDN not specified. Exiting!}" || \
|
||||
-z "${tm_pub_key_access_port:?TM_PUB_KEY_ACCESS_PORT not specified. Exiting!}" || \
|
||||
-z "${tm_backend_host:?TM_BACKEND_HOST not specified. Exiting!}" || \
|
||||
-z "${tm_p2p_port:?TM_P2P_PORT not specified. Exiting!}" ]]; then
|
||||
-z "${tm_p2p_port:?TM_P2P_PORT not specified. Exiting!}" || \
|
||||
-z "${authorization_mode:-threescale_auth_mode}" ]]; then # Set the default authorization mode to threescale
|
||||
echo "Missing required environment variables. Exiting!"
|
||||
exit 1
|
||||
else
|
||||
@ -68,7 +74,18 @@ else
|
||||
echo TM_P2P_PORT="$tm_p2p_port"
|
||||
fi
|
||||
|
||||
NGINX_CONF_FILE=/etc/nginx/nginx.conf
|
||||
if [[ ${authorization_mode} == ${secret_token_auth_mode} ]]; then
|
||||
NGINX_CONF_FILE=/etc/nginx/nginx.conf
|
||||
secret_access_token=`printenv SECRET_ACCESS_TOKEN`
|
||||
sed -i "s|SECRET_ACCESS_TOKEN|${secret_token_header}|g"
|
||||
elif [[ ${authorization_mode} == ${threescale_auth_mode} ]]; then
|
||||
NGINX_CONF_FILE=/etc/nginx/nginx-threescale.conf
|
||||
sed -i "s|OPENRESTY_BACKEND_PORT|${openresty_backend_port}|g" ${NGINX_CONF_FILE}
|
||||
sed -i "s|OPENRESTY_BACKEND_HOST|${openresty_backend_host}|g" ${NGINX_CONF_FILE}
|
||||
else
|
||||
echo "Unrecognised authorization mode: ${authorization_mode}. Exiting!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# configure the nginx.conf file with env variables
|
||||
sed -i "s|CLUSTER_FQDN|${cluster_fqdn}|g" ${NGINX_CONF_FILE}
|
||||
@ -76,8 +93,6 @@ sed -i "s|CLUSTER_FRONTEND_PORT|${cluster_frontend_port}|g" ${NGINX_CONF_FILE}
|
||||
sed -i "s|MONGODB_FRONTEND_PORT|${mongo_frontend_port}|g" ${NGINX_CONF_FILE}
|
||||
sed -i "s|MONGODB_BACKEND_HOST|${mongo_backend_host}|g" ${NGINX_CONF_FILE}
|
||||
sed -i "s|MONGODB_BACKEND_PORT|${mongo_backend_port}|g" ${NGINX_CONF_FILE}
|
||||
sed -i "s|OPENRESTY_BACKEND_PORT|${openresty_backend_port}|g" ${NGINX_CONF_FILE}
|
||||
sed -i "s|OPENRESTY_BACKEND_HOST|${openresty_backend_host}|g" ${NGINX_CONF_FILE}
|
||||
sed -i "s|BIGCHAINDB_BACKEND_HOST|${bdb_backend_host}|g" ${NGINX_CONF_FILE}
|
||||
sed -i "s|BIGCHAINDB_API_PORT|${bdb_api_port}|g" ${NGINX_CONF_FILE}
|
||||
sed -i "s|BIGCHAINDB_WS_PORT|${bdb_ws_port}|g" ${NGINX_CONF_FILE}
|
||||
@ -89,4 +104,4 @@ sed -i "s|TM_P2P_PORT|${tm_p2p_port}|g" ${NGINX_CONF_FILE}
|
||||
|
||||
# start nginx
|
||||
echo "INFO: starting nginx..."
|
||||
exec nginx -c /etc/nginx/nginx.conf
|
||||
exec nginx -c ${NGINX_CONF_FILE}
|
||||
|
@ -85,6 +85,11 @@ spec:
|
||||
configMapKeyRef:
|
||||
name: tendermint-config
|
||||
key: tm-p2p-port
|
||||
- name: AUTHORIZATION_MODE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: vars
|
||||
key: authorization-mode
|
||||
ports:
|
||||
# return a pretty error message on port 80, since we are expecting
|
||||
# HTTPS traffic.
|
||||
|
Loading…
x
Reference in New Issue
Block a user