mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
BigchainDB Web Proxy to add headers to requests
Currently, the requests from public websites (like `bigchaindb.com/getstarted` and tutorials.bigchaindb.com/crab) cannot have the app_id and app_key required to access IPDB in the web page. We pass such requests through a web proxy that adds the required headers to any POST requests from `*.bigchaindb.com`.
This commit is contained in:
parent
5fbc3f4a6c
commit
f07df50041
33
k8s/nginx-https-web-proxy/README.md
Normal file
33
k8s/nginx-https-web-proxy/README.md
Normal file
@ -0,0 +1,33 @@
|
||||
## Deploying the BigchainDB Web Proxy on a Kubernetes Cluster
|
||||
|
||||
|
||||
### Configure the Web Proxy
|
||||
|
||||
* Fill in the configuration details for the proxy in the
|
||||
`nginx-https-web-proxy-conf.yaml` file.
|
||||
|
||||
* Use the command below to create the appropriate ConfigMap and Secret:
|
||||
```
|
||||
kubectl apply -f nginx-https-web-proxy-conf.yaml
|
||||
```
|
||||
|
||||
|
||||
### Start the Kubernetes Service for BigchainDB Web Proxy
|
||||
|
||||
* Use the command below to start the Kubernetes Service:
|
||||
```
|
||||
kubectl apply -f nginx-https-web-proxy-svc.yaml
|
||||
```
|
||||
|
||||
* This will give you a public IP address tied to an Azure LB.
|
||||
|
||||
* Map this to an available domain of your choice on the Azure portal (or use
|
||||
any other DNS service provider!)
|
||||
|
||||
|
||||
### Start the Kubernetes Deployment for BigchainDB Web Proxy
|
||||
|
||||
* Use the command below to start the Kubernetes Deployment:
|
||||
```
|
||||
kubectl apply -f nginx-https-web-proxy-dep.yaml
|
||||
```
|
8
k8s/nginx-https-web-proxy/container/Dockerfile
Normal file
8
k8s/nginx-https-web-proxy/container/Dockerfile
Normal file
@ -0,0 +1,8 @@
|
||||
FROM openresty/openresty:alpine
|
||||
RUN apk update \
|
||||
&& apk upgrade \
|
||||
&& apk add bash
|
||||
COPY nginx.conf.template /etc/nginx/nginx.conf
|
||||
COPY nginx_entrypoint.bash /
|
||||
EXPOSE 443
|
||||
ENTRYPOINT ["/nginx_entrypoint.bash"]
|
5
k8s/nginx-https-web-proxy/container/docker_build_and_push.bash
Executable file
5
k8s/nginx-https-web-proxy/container/docker_build_and_push.bash
Executable file
@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker build -t bigchaindb/nginx-https-web-proxy:0.10 .
|
||||
|
||||
docker push bigchaindb/nginx-https-web-proxy:0.10
|
138
k8s/nginx-https-web-proxy/container/nginx.conf.template
Normal file
138
k8s/nginx-https-web-proxy/container/nginx.conf.template
Normal file
@ -0,0 +1,138 @@
|
||||
# Frontend Proxy server that:
|
||||
# 1. Acts as the HTTPS proxy termination point.
|
||||
# 2. Forwards BDB POST requests to OpenResty backend after appending the app_id
|
||||
# and app_key headers.
|
||||
# 3. Forwards BDB GET requests to BDB backend.
|
||||
# 4. Does health check with LB.
|
||||
|
||||
worker_processes 4;
|
||||
daemon off;
|
||||
user nobody nogroup;
|
||||
pid /tmp/nginx.pid;
|
||||
error_log /dev/stderr;
|
||||
|
||||
events {
|
||||
# Each worker handles up to 1024 connections. Increase this for heavy
|
||||
# workloads.
|
||||
worker_connections 1024;
|
||||
accept_mutex on;
|
||||
use epoll;
|
||||
}
|
||||
|
||||
http {
|
||||
access_log /dev/stdout combined buffer=16k flush=5s;
|
||||
|
||||
# Allow 2048 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=2048r/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 3072 r/s,
|
||||
# `nodelay` or drop connection immediately in case it exceeds this
|
||||
# threshold.
|
||||
limit_req zone=one burst=3072 nodelay;
|
||||
|
||||
# `slowloris` attack mitigation settings.
|
||||
client_body_timeout 30s;
|
||||
client_header_timeout 10s;
|
||||
|
||||
# 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 PROXY_FRONTEND_PORT ssl;
|
||||
server_name "PROXY_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;
|
||||
|
||||
# No websocket support for web proxy
|
||||
location /api/v1/streams/valid_transactions {
|
||||
return 403 'Websockets are not supported in the web proxy';
|
||||
}
|
||||
|
||||
# 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;
|
||||
|
||||
# Debug block for listing all the headers sent with the request
|
||||
header_filter_by_lua_block {
|
||||
local h = ngx.req.get_headers()
|
||||
for k, v in pairs(h) do
|
||||
ngx.log(ngx.ERR, "Header "..k..": "..v..";")
|
||||
end
|
||||
}
|
||||
|
||||
# check if the request originated from the required web page
|
||||
# use referer header.
|
||||
if ($http_referer !~ "PROXY_EXPECTED_REFERER_HEADER" ) {
|
||||
return 403 'Unknown referer';
|
||||
}
|
||||
|
||||
# check if the request has the expected origin header
|
||||
if ($http_origin !~ "PROXY_EXPECTED_ORIGIN_HEADER" ) {
|
||||
return 403 'Unknown origin';
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
# 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; set the correct
|
||||
# headers accordingly
|
||||
proxy_set_header app_id "PROXY_APP_ID";
|
||||
proxy_set_header app_key "PROXY_APP_KEY";
|
||||
if ($request_method = POST ) {
|
||||
proxy_pass http://$openresty_backend:OPENRESTY_BACKEND_PORT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Frontend server for the load balancer to respond to health checks.
|
||||
server {
|
||||
listen HEALTH_CHECK_PORT;
|
||||
|
||||
location = /health {
|
||||
return 200;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
74
k8s/nginx-https-web-proxy/container/nginx_entrypoint.bash
Executable file
74
k8s/nginx-https-web-proxy/container/nginx_entrypoint.bash
Executable file
@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Proxy vars
|
||||
proxy_fqdn=`printenv PROXY_FQDN`
|
||||
proxy_frontend_port=`printenv PROXY_FRONTEND_PORT`
|
||||
|
||||
proxy_app_id_file=/etc/nginx/proxy/credentials/app_id
|
||||
proxy_app_key_file=/etc/nginx/proxy/credentials/app_key
|
||||
proxy_app_id=`cat ${proxy_app_id_file}`
|
||||
proxy_app_key=`cat ${proxy_app_key_file}`
|
||||
|
||||
proxy_expected_referer_header=`printenv PROXY_EXPECTED_REFERER_HEADER`
|
||||
proxy_expected_origin_header=`printenv PROXY_EXPECTED_ORIGIN_HEADER`
|
||||
|
||||
# OpenResty vars
|
||||
openresty_backend_host=`printenv OPENRESTY_BACKEND_HOST`
|
||||
openresty_backend_port=`printenv OPENRESTY_BACKEND_PORT`
|
||||
|
||||
# NGINX vars
|
||||
dns_server=`printenv DNS_SERVER`
|
||||
health_check_port=`printenv HEALTH_CHECK_PORT`
|
||||
|
||||
# BigchainDB vars
|
||||
bdb_backend_host=`printenv BIGCHAINDB_BACKEND_HOST`
|
||||
bdb_api_port=`printenv BIGCHAINDB_API_PORT`
|
||||
|
||||
|
||||
# sanity check
|
||||
if [[ -z "${proxy_frontend_port:?PROXY_FRONTEND_PORT not specified. Exiting!}" || \
|
||||
-z "${openresty_backend_port:?OPENRESTY_BACKEND_PORT not specified. Exiting!}" || \
|
||||
-z "${openresty_backend_host:?OPENRESTY_BACKEND_HOST not specified. Exiting!}" || \
|
||||
-z "${bdb_backend_host:?BIGCHAINDB_BACKEND_HOST not specified. Exiting!}" || \
|
||||
-z "${bdb_api_port:?BIGCHAINDB_API_PORT not specified. Exiting!}" || \
|
||||
-z "${dns_server:?DNS_SERVER not specified. Exiting!}" || \
|
||||
-z "${health_check_port:?HEALTH_CHECK_PORT not specified. Exiting!}" || \
|
||||
-z "${proxy_app_id:?PROXY_APP_ID not specified. Exiting!}" || \
|
||||
-z "${proxy_app_key:?PROXY_APP_KEY not specified. Exiting!}" || \
|
||||
-z "${proxy_expected_referer_header:?PROXY_EXPECTED_REFERER_HEADER not specified. Exiting!}" || \
|
||||
-z "${proxy_expected_origin_header:?PROXY_EXPECTED_ORIGIN_HEADER not specified. Exiting!}" || \
|
||||
-z "${proxy_fqdn:?PROXY_FQDN not specified. Exiting!}" ]]; then
|
||||
exit 1
|
||||
else
|
||||
echo PROXY_FQDN="$proxy_fqdn"
|
||||
echo PROXY_FRONTEND_PORT="$proxy_frontend_port"
|
||||
echo PROXY_EXPECTED_REFERER_HEADER="$proxy_expected_referer_header"
|
||||
echo PROXY_EXPECTED_ORIGIN_HEADER="$proxy_expected_origin_header"
|
||||
echo DNS_SERVER="$dns_server"
|
||||
echo HEALTH_CHECK_PORT="$health_check_port"
|
||||
echo OPENRESTY_BACKEND_HOST="$openresty_backend_host"
|
||||
echo OPENRESTY_BACKEND_PORT="$openresty_backend_port"
|
||||
echo BIGCHAINDB_BACKEND_HOST="$bdb_backend_host"
|
||||
echo BIGCHAINDB_API_PORT="$bdb_api_port"
|
||||
fi
|
||||
|
||||
NGINX_CONF_FILE=/etc/nginx/nginx.conf
|
||||
|
||||
# configure the nginx.conf file with env variables
|
||||
sed -i "s|PROXY_FQDN|${proxy_fqdn}|g" ${NGINX_CONF_FILE}
|
||||
sed -i "s|PROXY_FRONTEND_PORT|${proxy_frontend_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|DNS_SERVER|${dns_server}|g" ${NGINX_CONF_FILE}
|
||||
sed -i "s|HEALTH_CHECK_PORT|${health_check_port}|g" ${NGINX_CONF_FILE}
|
||||
sed -i "s|PROXY_APP_ID|${proxy_app_id}|g" ${NGINX_CONF_FILE}
|
||||
sed -i "s|PROXY_APP_KEY|${proxy_app_key}|g" ${NGINX_CONF_FILE}
|
||||
sed -i "s|PROXY_EXPECTED_REFERER_HEADER|${proxy_expected_referer_header}|g" ${NGINX_CONF_FILE}
|
||||
sed -i "s|PROXY_EXPECTED_ORIGIN_HEADER|${proxy_expected_origin_header}|g" ${NGINX_CONF_FILE}
|
||||
|
||||
# start nginx
|
||||
echo "INFO: starting nginx..."
|
||||
exec nginx -c /etc/nginx/nginx.conf
|
60
k8s/nginx-https-web-proxy/nginx-https-web-proxy-conf.yaml
Normal file
60
k8s/nginx-https-web-proxy/nginx-https-web-proxy-conf.yaml
Normal file
@ -0,0 +1,60 @@
|
||||
# All secret data should be base64 encoded before embedding them in the Secret.
|
||||
# Short strings can be encoded using, e.g.
|
||||
# echo "secret string" | base64 -w 0 > secret.string.b64
|
||||
# Files (e.g. certificates) can be encoded using, e.g.
|
||||
# cat cert.pem | base64 -w 0 > cert.pem.b64
|
||||
# then copy the contents of cert.pem.b64 (for example) below.
|
||||
# Ref: https://kubernetes.io/docs/concepts/configuration/secret/
|
||||
# Unused values can be set to ""
|
||||
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: proxy-credentials
|
||||
namespace: default
|
||||
type: Opaque
|
||||
data:
|
||||
# app_id is the app id that the proxy adds to requests going to the backend
|
||||
app_id: "<b64 encoded app_id>"
|
||||
# app_key is the app key that the proxy adds to requests going to the backend
|
||||
app_key: "<b64 encoded app_key>"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: proxy-https-certs
|
||||
namespace: default
|
||||
type: Opaque
|
||||
data:
|
||||
# Base64-encoded HTTPS private key
|
||||
cert.key: "<b64 encoded HTTPS private key>"
|
||||
# Base64-encoded HTTPS certificate chain
|
||||
# starting with your primary SSL cert (e.g. your_domain.crt)
|
||||
# followed by all intermediate certs.
|
||||
# If cert is from DigiCert, download "Best format for nginx".
|
||||
cert.pem: "<b64 encoded HTTPS certificate chain"
|
||||
---
|
||||
## Note: data values do NOT have to be base64-encoded for ConfigMap.
|
||||
# proxy-vars is common environment variables for the Web Proxy.
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: proxy-vars
|
||||
namespace: default
|
||||
data:
|
||||
# proxy-fqdn is the DNS name registered for your HTTPS certificate.
|
||||
proxy-fqdn: "proxy-bdb.example.com"
|
||||
|
||||
# proxy-frontend-port is the port number on which this web proxy's services
|
||||
# are available to external clients.
|
||||
proxy-frontend-port: "4443"
|
||||
|
||||
# expected-http-referer is the expected regex expression of the Referer
|
||||
# header in the HTTP requests to the proxy.
|
||||
# The default below accepts the referrer value to be *.bigchaindb.com
|
||||
expected-http-referer: "^https://(.*)bigchaindb\\.com/(.*)"
|
||||
|
||||
# expected-http-origin is the expected regex expression of the Origin
|
||||
# header in the HTTP requests to the proxy.
|
||||
# The default below accepts the origin value to be *.bigchaindb.com
|
||||
expected-http-origin: "^https://(.*)bigchaindb\\.com"
|
92
k8s/nginx-https-web-proxy/nginx-https-web-proxy-dep.yaml
Normal file
92
k8s/nginx-https-web-proxy/nginx-https-web-proxy-dep.yaml
Normal file
@ -0,0 +1,92 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: web-proxy-instance-0-dep
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: web-proxy-instance-0-dep
|
||||
spec:
|
||||
terminationGracePeriodSeconds: 10
|
||||
containers:
|
||||
- name: web-proxy
|
||||
image: bigchaindb/nginx-https-web-proxy:0.10
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
- name: PROXY_FQDN
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: proxy-vars
|
||||
key: proxy-fqdn
|
||||
- name: PROXY_FRONTEND_PORT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: proxy-vars
|
||||
key: proxy-frontend-port
|
||||
- name: PROXY_EXPECTED_REFERER_HEADER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: proxy-vars
|
||||
key: expected-http-referer
|
||||
- name: PROXY_EXPECTED_ORIGIN_HEADER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: proxy-vars
|
||||
key: expected-http-origin
|
||||
- name: OPENRESTY_BACKEND_HOST
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: vars
|
||||
key: ngx-openresty-instance-name
|
||||
- name: OPENRESTY_BACKEND_PORT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: vars
|
||||
key: openresty-backend-port
|
||||
- name: DNS_SERVER
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: vars
|
||||
key: cluster-dns-server-ip
|
||||
- name: HEALTH_CHECK_PORT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: vars
|
||||
key: cluster-health-check-port
|
||||
- name: BIGCHAINDB_BACKEND_HOST
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: vars
|
||||
key: ngx-bdb-instance-name
|
||||
- name: BIGCHAINDB_API_PORT
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: vars
|
||||
key: bigchaindb-api-port
|
||||
ports:
|
||||
- containerPort: <port where the proxy is listening for requests>
|
||||
protocol: TCP
|
||||
resources:
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
volumeMounts:
|
||||
- name: proxy-https-certs
|
||||
mountPath: /etc/nginx/ssl/
|
||||
readOnly: true
|
||||
- name: proxy-credentials
|
||||
mountPath: /etc/nginx/proxy/credentials/
|
||||
readOnly: true
|
||||
# TODO probes!!??
|
||||
restartPolicy: Always
|
||||
volumes:
|
||||
- name: proxy-https-certs
|
||||
secret:
|
||||
secretName: proxy-https-certs
|
||||
defaultMode: 0400
|
||||
- name: proxy-credentials
|
||||
secret:
|
||||
secretName: proxy-credentials
|
||||
defaultMode: 0400
|
16
k8s/nginx-https-web-proxy/nginx-https-web-proxy-svc.yaml
Normal file
16
k8s/nginx-https-web-proxy/nginx-https-web-proxy-svc.yaml
Normal file
@ -0,0 +1,16 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: web-proxy-instance-0
|
||||
namespace: default
|
||||
labels:
|
||||
name: web-proxy-instance-0
|
||||
spec:
|
||||
selector:
|
||||
app: web-proxy-instance-0-dep
|
||||
ports:
|
||||
- port: <port where the proxy is listening for requests>
|
||||
targetPort: <port where the proxy is listening for requests>
|
||||
name: public-web-proxy-port
|
||||
protocol: TCP
|
||||
type: LoadBalancer
|
Loading…
x
Reference in New Issue
Block a user