Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement a capability restriction system. #89

Merged
merged 27 commits into from
Dec 22, 2020

Conversation

ryanapilado
Copy link
Contributor

@ryanapilado ryanapilado commented Nov 5, 2020

Implement a mechanism to restrict which proxy-wasm ABI functions are made available to the module. Functions which are restricted are replaced with a stub.

Envoy-side implementation and tests.

Signed-off-by: Ryan Apilado [email protected]

@ryanapilado ryanapilado force-pushed the capability-restriction branch 4 times, most recently from 21a78ee to 05a3bca Compare November 5, 2020 16:39
@ryanapilado ryanapilado force-pushed the capability-restriction branch from 05a3bca to 0b28799 Compare November 5, 2020 16:51
@ryanapilado ryanapilado changed the title implement a capability restriction mechanism implement an abi restriction system Nov 18, 2020
@ryanapilado ryanapilado marked this pull request as ready for review November 18, 2020 22:57
@ryanapilado ryanapilado marked this pull request as draft November 19, 2020 03:33
Signed-off-by: Ryan Apilado <[email protected]>
Copy link
Member

@PiotrSikora PiotrSikora left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies for the late review.

BUILD Outdated
@@ -9,6 +9,7 @@ cc_library(
hdrs = glob(["include/proxy-wasm/**/*.h"]),
deps = [
"@proxy_wasm_cpp_sdk//:common_lib",
"@com_google_absl//absl/container:flat_hash_set",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't recall the reason, but John removed all uses of absl from this repo. Is there any reason why we need absl::flat_hash_set here instead of using std::unordered_map?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to create allowed_capabilities on the Envoy side and pass it to the WasmBase constructor, but the Envoy formatter complains when I use unordered_set or unordered_map. So I had to switch it to absl::flat_hash_set in both Envoy and here.

But I see that there is some code in Envoy that uses unordered_set anyways, like here. Should I do the same?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, OK. Let's leave it then.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any thoughts on absl::flat_hash_set, @mathetake? Should we completely remove it? Removing it from V8 would be trivial.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re: #89 (comment)

Should I change it to a std::unordered_map then? Again, it goes against Envoy style guidelines, and at the moment, there are no uses of std::unordered_map in Envoy.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK then, let's follow Envoy's style guide and stick to absl everywhere in this repo too. What I wanted was consistency. After merging, could you please replace std::unordered_** with abls ones?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, sounds good!

Copy link
Member

@PiotrSikora PiotrSikora Dec 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason for no absl is that proxy-wasm-cpp-host can be used (at least in theory) by other proxies, not only Envoy, and we didn't want to force absl as a dependency for them when the same containers are available in std.

You should be able to "fix" the formatter warnings by adding relevant files to a whitelist (there are many of those for various formatter exclusions). Envoy has no business enforcing argument types in 3rd-party libraries.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, makes sense. Changed to std::unordered_map here and in Envoy PR.

@PiotrSikora
Copy link
Member

@mathetake @kyessenov could you take a look as well?

@ryanapilado ryanapilado force-pushed the capability-restriction branch 3 times, most recently from 77aa7f6 to 3ef808d Compare November 19, 2020 16:43
@ryanapilado ryanapilado changed the title implement an abi restriction system implement a capability restriction system Nov 19, 2020
Signed-off-by: Ryan Apilado <[email protected]>
@ryanapilado ryanapilado force-pushed the capability-restriction branch from eeb98b8 to 0e09b31 Compare November 19, 2020 18:04
Signed-off-by: Ryan Apilado <[email protected]>
@ryanapilado ryanapilado force-pushed the capability-restriction branch from 0e09b31 to a180877 Compare November 19, 2020 18:05
@mathetake
Copy link
Contributor

👍 to 2) because it’s more independent of ABI versions and developer friendly.

@mathetake
Copy link
Contributor

But then should we discuss this in proxy-wasm/spec first? I think we would better have more comments from the folks including SDK developers

@ryanapilado
Copy link
Contributor Author

I think (2) definitely needs to be done, eventually. There are dependencies between some of the capabilities which aren't obvious (e.g. proxy_on_vm_start won't work without proxy_get_property and proxy_on_context_create), so we should be bundling them together into functional packages to make it developer-friendly.

But maybe also having (1) could also be useful, for cases where more granular restriction is needed? (do such cases exist, or could we cover all reasonable restriction policies with the groups defined in (2)? I don't know). For example, maybe a user only wants to allow a subset of the gRPC capabilities, not all of them. And there are capabilities like proxy_log, proxy_get_shared_data which seem to be standalone, so they should be allowed individually. In principle, it also seems good to give the developer access to low-level control if they want it. So maybe it makes sense to have both (1) and (2)?

So maybe allowed_capabilities should just be a mix of both single capabilities (1) and groups of capabilities (2):

capability_restriction_config:
  allowed_capabilities:
    - http_request_headers_read,     // implies: on_http_request_headers, get_header_map(HttpRequestHeaders), get_header_map_value(HttpRequestHeaders), 
    - http_request_headers_write,    // implies: on_http_request_headers, get_header_map(HttpRequestHeaders), get_header_map_value(HttpRequestHeaders), set_header_map(HttpRequestHeaders), set_header_map_value(HttpRequestHeaders), 
    - http_request_body_write,       // implies: on_http_request_body, get_buffer_bytes(HttpRequest), set_buffer_bytes(HttpRequest)
    - grpc_call: ["www.google.com"], // implies: grpc_call, grpc_stream, grpc_close, grpc_cancel, grpc_send
    - proxy_log
    - proxy_get_shared_data

Internally, the capability bundles (http_request_headers_read etc.) are translated to single capabilities and used to construct the Wasm.

Signed-off-by: Ryan Apilado <[email protected]>
@ryanapilado ryanapilado force-pushed the capability-restriction branch from 8de28c7 to 254328b Compare November 21, 2020 07:31
Signed-off-by: Ryan Apilado <[email protected]>
@ryanapilado
Copy link
Contributor Author

Updated to make allowed_capabilities a map. The key is the capability name, and the value is a vector of strings, as above. The map value is ignored for now, but in later PRs can be used to implement either (1) or (2).

Also updated the Envoy PR to match.

Copy link
Member

@PiotrSikora PiotrSikora left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ryanapilado could you merge master to resolve conflicts? Thanks!

Regarding the (1) vs (2), WASI uses rights that pretty much map 1:1 with function names (although, there are a few rights that grant permission to call multiple functions), which is much closer to (1) than (2). Unfortunately, they don't limit parameters, so we need to diverge from them.

Also, (2) can be always built on top of (1), but not the vice-versa, so let's get this in, and we can worry about (2) later.

@mathetake could you review this?

auto context = exports::ContextOrEffectiveContext( \
static_cast<ContextBase *>((void)raw_context, current_context_)); \
context->wasmVm()->error("Attempted call to restricted capability: " #_fn); \
return WasmResult::InternalFailure; \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: @PiotrSikora we should have a new Wasm result like Unauthorized as WASI's acces Permission denied. (hopefully in the next ABI ). https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/docs.md#variants-1

@ryanapilado
Copy link
Contributor Author

Resolved conflicts, merged master.

@ryanapilado ryanapilado force-pushed the capability-restriction branch from 03c170a to f37f375 Compare December 17, 2020 06:59
@ryanapilado
Copy link
Contributor Author

Adding a small change in anticipation of implementing (1), PTAL. It's not enough to have a vector of strings, we also need a parameter to control whether it behaves as an allowlist or denylist. So the capabilities now map to a struct SanitizationConfig, which contains a vector of strings argument_list but also an enum ListType which determines if the former is an allowlist or a denylist. This sets up the implementation of (1) and also makes the Envoy PR cleaner.

Copy link
Member

@PiotrSikora PiotrSikora left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM sans the nit.

@ryanapilado could you fix the Envoy PR? I would like to merge this, but Envoy PR doesn't even build right now. Thanks.

@ryanapilado
Copy link
Contributor Author

ryanapilado commented Dec 22, 2020

LGTM sans the nit.

@ryanapilado could you fix the Envoy PR? I would like to merge this, but Envoy PR doesn't even build right now. Thanks.

My bad, Envoy PR seems ok now.

};
FOR_ALL_HOST_FUNCTIONS(_CREATE_EXPORT_STUB)
FOR_ALL_HOST_FUNCTIONS_ABI_SPECIFIC(_CREATE_EXPORT_STUB)
FOR_ALL_WASI_FUNCTIONS(_CREATE_EXPORT_STUB)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For WASI, I think it would be better if we had a dedicated stub that returns __WASI_ENOTCAPABLE (76), since WASI modules should be aware of that error code, and they know nothing about Proxy-Wasm return values.

@PiotrSikora PiotrSikora changed the title implement a capability restriction system Implement a capability restriction system. Dec 22, 2020
@PiotrSikora PiotrSikora merged commit 9937669 into proxy-wasm:master Dec 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants