Something went wrong. Try again.
What happens if I push all of nixpkgs
Something went wrong. Try again.
6.3 kB · 162 lines
Nix
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163let certs = import ./snakeoil-certs.nix;in{ pkgs, ... }:{ name = "nginx-proxyprotocol";
meta = { maintainers = with pkgs.lib.maintainers; [ raitobezarius ]; };
nodes = { webserver = { pkgs, lib, ... }: { environment.systemPackages = [ pkgs.netcat ]; security.pki.certificateFiles = [ certs.ca.cert ];
networking.extraHosts = '' 127.0.0.5 proxy.test.nix 127.0.0.5 noproxy.test.nix 127.0.0.3 direct-nossl.test.nix 127.0.0.4 unsecure-nossl.test.nix 127.0.0.2 direct-noproxy.test.nix 127.0.0.1 direct-proxy.test.nix ''; services.nginx = { enable = true; defaultListen = [ { addr = "127.0.0.1"; proxyProtocol = true; ssl = true; } { addr = "127.0.0.2"; } { addr = "127.0.0.3"; ssl = false; } { addr = "127.0.0.4"; ssl = false; proxyProtocol = true; } ]; commonHttpConfig = '' log_format pcombined '(proxy_protocol=$proxy_protocol_addr) - (remote_addr=$remote_addr) - (realip=$realip_remote_addr) - (upstream=) - (remote_user=$remote_user) [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"'; access_log /var/log/nginx/access.log pcombined; error_log /var/log/nginx/error.log; ''; virtualHosts = let commonConfig = { locations."/".return = "200 '$remote_addr'"; extraConfig = '' set_real_ip_from 127.0.0.5/32; real_ip_header proxy_protocol; ''; }; in { "*.test.nix" = commonConfig // { sslCertificate = certs."*.test.nix".cert; sslCertificateKey = certs."*.test.nix".key; forceSSL = true; }; "direct-nossl.test.nix" = commonConfig; "unsecure-nossl.test.nix" = commonConfig // { extraConfig = '' real_ip_header proxy_protocol; ''; }; }; };
services.sniproxy = { enable = true; config = '' error_log { syslog daemon } access_log { syslog daemon } listener 127.0.0.5:443 { protocol tls source 127.0.0.5 } table { ^proxy\.test\.nix$ 127.0.0.1 proxy_protocol ^noproxy\.test\.nix$ 127.0.0.2 } ''; }; }; };
testScript = '' def check_origin_ip(src_ip: str, dst_url: str, failure: bool = False, proxy_protocol: bool = False, expected_ip: str | None = None): check = webserver.fail if failure else webserver.succeed if expected_ip is None: expected_ip = src_ip
return check(f"curl {'--haproxy-protocol' if proxy_protocol else '''} --interface {src_ip} --fail -L {dst_url} | grep '{expected_ip}'")
webserver.wait_for_unit("nginx") webserver.wait_for_unit("sniproxy") # This should be closed by virtue of ssl = true; webserver.wait_for_closed_port(80, "127.0.0.1") # This should be open by virtue of no explicit ssl webserver.wait_for_open_port(80, "127.0.0.2") # This should be open by virtue of ssl = true; webserver.wait_for_open_port(443, "127.0.0.1") # This should be open by virtue of no explicit ssl webserver.wait_for_open_port(443, "127.0.0.2") # This should be open by sniproxy webserver.wait_for_open_port(443, "127.0.0.5") # This should be closed by sniproxy webserver.wait_for_closed_port(80, "127.0.0.5")
# Sanity checks for the NGINX module # direct-HTTP connection to NGINX without TLS, this checks that ssl = false; works well. check_origin_ip("127.0.0.10", "http://direct-nossl.test.nix/") # webserver.execute("openssl s_client -showcerts -connect direct-noproxy.test.nix:443") # direct-HTTP connection to NGINX with TLS check_origin_ip("127.0.0.10", "http://direct-noproxy.test.nix/") check_origin_ip("127.0.0.10", "https://direct-noproxy.test.nix/") # Well, sniproxy is not listening on 80 and cannot redirect check_origin_ip("127.0.0.10", "http://proxy.test.nix/", failure=True) check_origin_ip("127.0.0.10", "http://noproxy.test.nix/", failure=True)
# Actual PROXY protocol related tests # Connecting through sniproxy should passthrough the originating IP address. check_origin_ip("127.0.0.10", "https://proxy.test.nix/") # Connecting through sniproxy to a non-PROXY protocol enabled listener should not pass the originating IP address. check_origin_ip("127.0.0.10", "https://noproxy.test.nix/", expected_ip="127.0.0.5")
# Attack tests against spoofing # Let's try to spoof our IP address by connecting direct-y to the PROXY protocol listener. # FIXME(RaitoBezarius): rewrite it using Python + (Scapy|something else) as this is too much broken unfortunately. # Or wait for upstream curl patch. # def generate_attacker_request(original_ip: str, target_ip: str, dst_url: str): # return f"""PROXY TCP4 {original_ip} {target_ip} 80 80 # GET / HTTP/1.1 # Host: {dst_url}
# """ # def spoof(original_ip: str, target_ip: str, dst_url: str, tls: bool = False, expect_failure: bool = True): # method = webserver.fail if expect_failure else webserver.succeed # port = 443 if tls else 80 # print(webserver.execute(f"cat <<EOF | nc {target_ip} {port}\n{generate_attacker_request(original_ip, target_ip, dst_url)}\nEOF")) # return method(f"cat <<EOF | nc {target_ip} {port} | grep {original_ip}\n{generate_attacker_request(original_ip, target_ip, dst_url)}\nEOF")
# check_origin_ip("127.0.0.10", "http://unsecure-nossl.test.nix", proxy_protocol=True) # spoof("1.1.1.1", "127.0.0.4", "direct-nossl.test.nix") # spoof("1.1.1.1", "127.0.0.4", "unsecure-nossl.test.nix", expect_failure=False) '';}