spin
spin copied to clipboard
Socket Runtime Support
The following is an attempt to describe what socket support in the Spin runtime would look like both from a user's perspective. This does not touch on guest support for Sockets as that generally would fall to language standard libraries nor does it attempt to talk through implementation details.
Controlling Socket Usage
Adding basic socket support to Spin is extremely easy. We just need to configure the wasmtime runtime to support sockets (a one line change) and guests can start targeting the wasi:sockets interface. However, this is not what we want as giving guests the ability to use sockets in an unconstrained manner does not fit into the "secure-by-default" philosophy of Spin. Therefore, Spin needs to limit socket usage both in ways that the end user can control and in some hard coded ways.
Hard coded limits
The following are ways that we want to limit socket usage that cannot be controlled by the end user (with the possible future exception of some --unsafe-sockets option that is beyond the scope of this proposal):
- listening and accepting connections on a socket on any address and port
These constraints cannot be removed by the operator running Spin.
Runtime Controlled Limits
By default, the runtime will additionally block the following behavior:
- Connecting to
127.0.0.0/8orlocalhoston any port 1-1023 - Usage of UDP
These constraints may be lifted by the operator running Spin, but the actual mechanism for how this is done is left to a future proposal.
Besides the hardcoded and deny-by-default limits, operators of Spin can opt into even more constrained control. This is done through a --disallowed-outbound-hosts that uses the same syntax as allowed_outbound_hosts but has the opposite semantics (i.e., any matching hosts are not allowed by any guest running in that instance of Spin).
User Controlled Limits
Besides the hard coded and runtime limits, users can opt into hosts that components can connect to through the allowed_outbound_hosts configuration. In order to allow for this, allowed_outbound_hosts syntax will be expanded to support IP address CIDR ranges.
Spin will only allow a host to be used with sockets if the corresponding entry in the allowed_outbound_hosts list allows all schemes regardless if the socket is only being used for a specific scheme. For example, imagine the user specifies allowed_outbound_hosts = ["http://192.168.0.1"] for a Spin component. That component will not be permitted to connect to a socket at that address even if that socket will only be used for HTTP. In order for socket usage to be permitted for 192.168.0.1, allowed_outbound_hosts would need to specify a * scheme like so allowed_outbound_hosts = ["*://192.168.0.1:80"].
DNS
allowed_outbound_hosts allow-listed domains are allowed at domain resolution time and will continue to be allowed until the domain is resolved again. For example, imagine the user specifies allowed_outbound_hosts = ["*://example.com:80"], when example.com is resolved by calling wasi:sockets/ip-name-lookup, the IP addresses that name resolves to will be permitted until wasi:sockets/ip-name-lookup is called again.
127.0.0.1/8
...and ::1; or use https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_loopback
...IP addresses that name resolves to will be permitted until wasi:sockets/ip-name-lookup is called again.
called again with the same hostname?
Regarding the proposed --disallowed-outbound-hosts:
If a component says it needs *://example.com:8080, and this is disallowed, that should be a "can't satisfy requirements" failure, caught at validation time, correct?
If a component says it needs *://example.com:*, and *//example.com:8080 is disallowed, will that also be a "can't satisfy requirements" failure? (On the basis that we cannot meet the component's requirement for ALL THE PORTS.)
Given that we don't enforce allowed_outbound_hosts until runtime, maybe the validation step would only be a warning, e.g. allowed_outbound_hosts = [...] overlaps with disallowed_outbound_hosts or something.
...IP addresses that name resolves to will be permitted until wasi:sockets/ip-name-lookup is called again.
called again with the same hostname?
Correct
Regarding the proposed
--disallowed-outbound-hosts:If a component says it needs
*://example.com:8080, and this is disallowed, that should be a "can't satisfy requirements" failure, caught at validation time, correct?If a component says it needs
*://example.com:*, and*//example.com:8080is disallowed, will that also be a "can't satisfy requirements" failure? (On the basis that we cannot meet the component's requirement for ALL THE PORTS.)
Yes, I think we'll want to do our best to try to warn against this. I don't think we should necessarily fail since just because a component claims it needs permission for something does not mean it always does.
@rylev is some of this work in progress? @dicej thinks some initial support has been added since this ticket was created.
Initial support has indeed been added through the likes of https://github.com/fermyon/spin/pull/2156. We might be ok to close this in favor of more specific tickets.
@rylev are we OK to close this and open up specific tickets?
Yes, I think we should close this in favor of more targeted PRs.