The proxy knocker can run on a hidden server (such as VPS), accept HTTPS requests, conduct identity authentication (optional), then login to the real server through SSH, and create firewall rules to allow the specified client IP to pass.
It has been tested with Python 3.6 & nginx 1.14 & ubuntu 18.04.
Prerequisites
Install
Clone from GitHub
git clone https://github.com/Binkcn/proxy-knocker.git
Install Python & pip & Paramiko
sudo apt-get update
sudo apt-get install -y python3
sudo pip3 install paramiko
Configuration
vim config.py
Running services
python3 proxy_knocker.py
Forward the request to proxy knocker through nginx
server {
listen 443 ssl;
server_name proxyknocker.yourdomain.com;
proxy_set_header X-Forwarded-For $remote_addr;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_certificate /etc/nginx/ssl/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8880;
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-Host $server_name;
proxy_read_timeout 1200s;
# used for view/edit office file via Office Online Server
client_max_body_size 0;
access_log /var/log/nginx/proxyknocker.access.log;
error_log /var/log/nginx/proxyknocker.error.log;
}
}
# Server listen
LISTEN_ADDR = '127.0.0.1'
LISTEN_PORT = 8880
# Redirect
REDIRECT_CODE = 307
REDIRECT_URL = 'https://nas.yourdomain.com:1443'
# Security header converted to get parameter sent.
REDIRECT_HEADER_TO_GET = True
REDIRECT_HEADERS = ['Authorization', 'WWW-Authenticate', 'Cookie', 'Cookie2']
# Auth method
AUTH_TYPE = 'NONE' # 'NONE', 'BASIC', 'GET', 'POST', 'COOKIE', 'HEADER'
# for BASIC
AUTH_USER = 'proxy-knocker'
AUTH_PASS = 'passwd'
# for GET/POST/COOKIE/HEADER
AUTH_FIELD = 'proxy-knocker'
AUTH_KEY = 'passwd'
# SSH
SSH_ADDR = '127.0.0.1'
SSH_PORT = 22
SSH_USER = 'root'
SSH_PASS = 'passwd'
# iptables
IPTABLES_PORT = 1443
IPTABLES_APPEND = 'sudo iptables -v -A INPUT -s {IP} -p tcp --dport ' + str(IPTABLES_PORT) + ' -j ACCEPT'
IPTABLES_DELETE = 'sudo iptables -v -D INPUT -s {IP} -p tcp --dport ' + str(IPTABLES_PORT) + ' -j ACCEPT'
IPTABLES_CONFIRM = 'sudo iptables -L -n | grep ' + str(IPTABLES_PORT) + ' | grep ACCEPT | grep {IP} | wc -l'
When the forwarded request contains secure information headers, such as Authorization, WWW-Authenticate, Cookie and other headers, if they are cross domain, these headers will not be copied to the new request. Therefore, when these headers are included in the request, change them to get parameter to send follow redirection, and then convert them to headers on nginx of receiving server.
Nginx configuration on real server:
# Restore get parameter to header send
set $Authorization $http_authorization;
set $WWWAuthenticate $http_www-authenticate;
set $Cookie $http_cookie;
if ($arg_HTTP_Authorization){
set_unescape_uri $Authorization $arg_HTTP_Authorization;
}
if ($arg_HTTP_WWW-Authenticate){
set_unescape_uri $WWWAuthenticate $arg_HTTP_WWW-Authenticate;
}
if ($arg_HTTP_Cookie){
set_unescape_uri $Cookie $arg_HTTP_Cookie;
}
proxy_set_header Authorization $Authorization;
proxy_set_header WWW-Authenticate $WWWAuthenticate;
proxy_set_header Cookie $Cookie;
_You need to set_unescape_uri
to decode the GET
parameter, but the module is not distributed with the Nginx source, so you need to compile it manually._ See ngx_set_misc#set_unescape_uri