isolation/Start-DpProxy.ps1
|
[CmdletBinding()] param([Parameter(Mandatory)][string]$PolicyBase64) $ErrorActionPreference = 'Stop' $PSNativeCommandUseErrorActionPreference = $true $policy = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($PolicyBase64)) | ConvertFrom-Json -AsHashtable $root = '/run/deskpilot' $null = New-Item -Path $root -ItemType Directory -Force foreach ($program in @('/usr/sbin/iptables', '/usr/sbin/ip6tables')) { & $program -w -P OUTPUT DROP & $program -w -P INPUT DROP & $program -w -P FORWARD DROP } & /usr/sbin/iptables -w -A OUTPUT -o lo -p tcp -d 127.0.0.1 --dport 3128 -m owner --uid-owner 10001 -j ACCEPT & /usr/sbin/iptables -w -A OUTPUT -o lo -p tcp -s 127.0.0.1 --sport 3128 -m owner --uid-owner 10002 -j ACCEPT & /usr/sbin/iptables -w -A INPUT -i lo -p tcp --dport 3128 -j ACCEPT & /usr/sbin/iptables -w -A INPUT -i lo -p tcp --sport 3128 -m conntrack --ctstate ESTABLISHED -j ACCEPT $hosts = [Collections.Generic.List[string]]::new() $names = [Collections.Generic.List[string]]::new() foreach ($entry in $policy.hosts) { if ($entry.name -notmatch '^[a-z0-9.-]+$') { throw 'Invalid proxy name.' } $names.Add([string]$entry.name) foreach ($address in $entry.addresses) { $parsed = [Net.IPAddress]::Parse([string]$address) if ($parsed.AddressFamily -ne [Net.Sockets.AddressFamily]::InterNetwork) { throw 'IPv6 is not enabled.' } $hosts.Add("$parsed $($entry.name)") & /usr/sbin/iptables -w -A OUTPUT -p tcp -d "$parsed" --dport 443 -m owner --uid-owner 10002 -j ACCEPT & /usr/sbin/iptables -w -A INPUT -p tcp -s "$parsed" --sport 443 -m conntrack --ctstate ESTABLISHED -j ACCEPT } } if ($names.Count -eq 0) { throw 'A proxy requires an explicit host allow-list.' } [IO.File]::WriteAllLines("$root/hosts", $hosts) & /usr/bin/openssl req -x509 -newkey rsa:2048 -nodes -keyout "$root/ca.key" -out "$root/ca.crt" -days 1 -subj '/CN=DeskPilot disposable Terminal CA' 2>$null $authorityPattern = '^(' + (($names | ForEach-Object { [regex]::Escape($_) }) -join '|') + ')(:443)?$' $configuration = @" visible_hostname deskpilot-terminal http_port 127.0.0.1:3128 ssl-bump cert=$root/ca.crt key=$root/ca.key generate-host-certificates=on dynamic_cert_mem_cache_size=4MB acl connect method CONNECT acl inspected_tls connections_encrypted acl https_request proto HTTPS acl secure_port port 443 acl allowed dstdomain -n $($names -join ' ') acl has_host req_header Host .+ acl allowed_authority req_header Host -i $authorityPattern acl upgrade req_header Upgrade .+ acl step_one at_step SslBump1 http_access deny !connect !inspected_tls http_access deny !connect !https_request http_access deny !secure_port http_access deny !allowed http_access deny !has_host http_access deny !allowed_authority http_access deny upgrade http_access allow allowed http_access deny all ssl_bump bump step_one ssl_bump terminate all sslcrtd_program /usr/lib/squid/security_file_certgen -s $root/certificates -M 4MB sslcrtd_children 2 startup=1 idle=1 sslproxy_cert_error deny all tls_outgoing_options min-version=1.2 host_verify_strict on client_dst_passthru off hosts_file $root/hosts dns_nameservers 127.0.0.1 dns_timeout 2 seconds connect_timeout 10 seconds request_timeout 20 seconds read_timeout 20 seconds cache deny all cache_mem 8 MB pinger_enable off access_log none cache_log /dev/null cache_store_log none pid_filename $root/squid.pid cache_effective_user dp-proxy cache_effective_group dp-proxy shutdown_lifetime 0 seconds forwarded_for delete via off request_header_access Proxy-Authorization deny all "@ [IO.File]::WriteAllText("$root/squid.conf", $configuration) & /usr/bin/chmod 0700 $root & /usr/bin/chmod 0600 "$root/ca.key" & /usr/bin/chown -R 10002:10002 $root & /usr/bin/setpriv --reuid=10002 --regid=10002 --clear-groups /usr/lib/squid/security_file_certgen -c -s "$root/certificates" -M 4MB & /usr/bin/setpriv --reuid=10002 --regid=10002 --clear-groups /usr/sbin/squid -k parse -f "$root/squid.conf" [IO.File]::WriteAllText("$root/prepared", 'prepared') |