Repository navigation
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: gorkem The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
An embedder that runs untrusted workloads in the guest needs to decide,
per connection, whether the host may open it on the guest's behalf, for
example to keep the guest to an allow list of destinations. The TCP, UDP
and ICMP forwarders open those connections with no point where the
embedder can refuse one.
Configuration gains DialFilter. When it is set, each forwarder calls it
with the network ("tcp", "udp" or "icmp") and the destination after NAT
translation before it dials, and a non-nil error refuses the connection:
TCP answers the guest with a reset, UDP and ICMP are dropped. When it is
nil, nothing changes.
Signed-off-by: Gorkem Ercan <gorkem.ercan@gmail.com>
An embedder that limits the guest to named destinations needs the addresses those names resolve to, so it can allow connections to them. The embedded DNS server answers the guest from its upstream resolver without exposing those answers. Configuration gains DNSObserver. When it is set, the DNS server calls it with the name, without its trailing dot, and the addresses of every A or AAAA answer it takes from the upstream resolver, before the answer is sent, so a connection the guest opens after the lookup already finds its address allowed. When it is nil, nothing changes. Signed-off-by: Gorkem Ercan <gorkem.ercan@gmail.com>
70159b9 to
a3159d4
Compare
Thanks @evidolob, and no worries. I went through #687 to see if it covers what I need. Unfortunately it doesn't quite fit. My use case: a program embeds gvisor-tap-vsock as a Go library to give a VM networking, and that VM runs untrusted workloads. The host process decides which destinations the guest may reach. The allowed set comes from the embedding program's own configuration, not from gvproxy's YAML, and it changes while the VM is running. To enforce that on the host side, I need things #687's policy doesn't express:
That's why #750 adds two hooks rather than a policy: a dial filter called with the destination after NAT, and an observer for upstream DNS answers. The embedding program decides what's allowed, and when both hooks are nil, nothing changes. The two could fit together if #687's allowlist, blocklist and SNI checks were built on top of the same hooks. #687's policy would then be one implementation, and gvproxy users would get it from config and the REST API as you've designed it. Library users with their own policy could plug in theirs. For TLS, the hook would need to be called with the SNI once it's been peeked. I'd be happy to extend #750's filter signature for that, or rebase onto yours if it lands first. |
An embedder that runs untrusted workloads in the guest, and wants to hold them to an allow list of destinations on the host side, has no point where it can refuse a connection the forwarders open for the guest, or learn the addresses the embedded DNS server resolved. This adds two optional hooks to
types.Configuration:DialFilter func(network, address string) erroris called by the TCP, UDP and ICMP forwarders with the destination after NAT translation, before they dial. A non-nil error refuses the connection: TCP answers the guest with a reset, UDP and ICMP are dropped.DNSObserver func(name string, ips []net.IP)is called by the DNS server with the addresses of every A or AAAA answer it takes from the upstream resolver, before the answer is sent, so a connection the guest opens after the lookup already finds its address allowed.Both are
yaml:"-"and nil by default, which leaves current behaviour unchanged. One thing to note for review:forwarder.TCP,forwarder.UDPandforwarder.ICMPtake the filter as a new trailing parameter, so a caller of those functions outsidepkg/virtualnetworkneeds to passnil. If an options struct or a setter would suit the project better, I can change it.The change is split in two commits, one per hook, each building on its own.
pkg/services/forwarderandpkg/services/dnsgain tests for the refusal and the observed answers.make cross-lintandgo test ./pkg/...pass; the VM-based suites were not run locally.