Skip to content

Commit

Permalink
wasm: capability restriction (#13911)
Browse files Browse the repository at this point in the history
Defines the configuration for capability restriction and propagates the configuration to `proxy-wasm-cpp-host`.
Risk Level: Medium
Testing: Unit tests ([`wasm_test.cc`](https://github.com/envoyproxy/envoy/pull/13911/files#diff-bc05b247c9a740af67a404a40498f96ced6bfc5911a2695f36bd60f0d348eadd)), configuration tests ([`config_test`](https://github.com/envoyproxy/envoy/pull/13911/files#diff-d743e0cfc1194f55ff4d936715cae872062265816c13d47c7db218cb9c3266ea)), and integration tests ([`wasm_filter_test.cc`](https://github.com/envoyproxy/envoy/pull/13911/files#diff-2ed9d95165b50294925d720defe225098c88b58381637c6457a0ea975a607d07)). Test that capabilities can be restricted selectively and are unrestricted by default.
Docs Changes: Add documentation for the new `messages` created in `wasm.proto`.
Release notes: N/A

Signed-off-by: Ryan Apilado <rapilado@google.com>
  • Loading branch information
ryanapilado authored Feb 9, 2021
1 parent 0f3663f commit 47ad8ee
Show file tree
Hide file tree
Showing 26 changed files with 755 additions and 87 deletions.
27 changes: 26 additions & 1 deletion api/envoy/extensions/wasm/v3/wasm.proto
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,28 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// [#protodoc-title: Wasm]
// [#extension: envoy.bootstrap.wasm]

// Configuration for restricting Proxy-Wasm capabilities available to modules.
message CapabilityRestrictionConfig {
// The Proxy-Wasm capabilities which will be allowed. Capabilities are mapped by
// name. The *SanitizationConfig* which each capability maps to is currently unimplemented and ignored,
// and so should be left empty.
//
// The capability names are given in the
// `Proxy-Wasm ABI <https://github.com/proxy-wasm/spec/tree/master/abi-versions/vNEXT>`_.
// Additionally, the following WASI capabilities from
// `this list <https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/docs.md#modules>`_
// are implemented and can be allowed:
// *fd_write*, *fd_read*, *fd_seek*, *fd_close*, *fd_fdstat_get*, *environ_get*, *environ_sizes_get*,
// *args_get*, *args_sizes_get*, *proc_exit*, *clock_time_get*, *random_get*.
map<string, SanitizationConfig> allowed_capabilities = 1;
}

// Configuration for sanitization of inputs to an allowed capability.
//
// NOTE: This is currently unimplemented.
message SanitizationConfig {
}

// Configuration for a Wasm VM.
// [#next-free-field: 7]
message VmConfig {
Expand Down Expand Up @@ -73,7 +95,7 @@ message VmConfig {
}

// Base Configuration for Wasm Plugins e.g. filters and services.
// [#next-free-field: 6]
// [#next-free-field: 7]
message PluginConfig {
// A unique name for a filters/services in a VM for use in identifying the filter/service if
// multiple filters/services are handled by the same *vm_id* and *root_id* and for
Expand Down Expand Up @@ -104,6 +126,9 @@ message PluginConfig {
// during xDS updates the xDS configuration will be rejected and when on_start or on_configuration return false on initial
// startup the proxy will not start.
bool fail_open = 5;

// Configuration for restricting Proxy-Wasm capabilities available to modules.
CapabilityRestrictionConfig capability_restriction_config = 6;
}

// WasmService is configured as a built-in *envoy.wasm_service* :ref:`WasmService
Expand Down
6 changes: 3 additions & 3 deletions bazel/repository_locations.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -907,8 +907,8 @@ REPOSITORY_LOCATIONS_SPEC = dict(
project_name = "WebAssembly for Proxies (C++ host implementation)",
project_desc = "WebAssembly for Proxies (C++ host implementation)",
project_url = "https://github.com/proxy-wasm/proxy-wasm-cpp-host",
version = "6dab125d7a668c7158848b6f48c67fd827c952e6",
sha256 = "b5c73ed053a7079bd8bf53b14c4811e87ae521d9fcf4769ec5b248202a27600d",
version = "5a53cf4b231599e1d2a1f2f4598fdfbb727ff948",
sha256 = "600dbc651a2837e6f1db964eb7e1078e5e338049a34c9ab47415dfa7f3de5478",
strip_prefix = "proxy-wasm-cpp-host-{version}",
urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-host/archive/{version}.tar.gz"],
use_category = ["dataplane_ext"],
Expand All @@ -923,7 +923,7 @@ REPOSITORY_LOCATIONS_SPEC = dict(
"envoy.wasm.runtime.wavm",
"envoy.wasm.runtime.wasmtime",
],
release_date = "2020-12-16",
release_date = "2021-01-12",
cpe = "N/A",
),
proxy_wasm_rust_sdk = dict(
Expand Down
27 changes: 26 additions & 1 deletion generated_api_shadow/envoy/extensions/wasm/v3/wasm.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions source/extensions/access_loggers/wasm/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ WasmAccessLogFactory::createAccessLogInstance(const Protobuf::Message& proto_con
};

if (!Common::Wasm::createWasm(
config.config().vm_config(), plugin, context.scope().createScope(""),
context.clusterManager(), context.initManager(), context.dispatcher(), context.api(),
context.lifecycleNotifier(), remote_data_provider_, std::move(callback))) {
config.config().vm_config(), config.config().capability_restriction_config(), plugin,
context.scope().createScope(""), context.clusterManager(), context.initManager(),
context.dispatcher(), context.api(), context.lifecycleNotifier(), remote_data_provider_,
std::move(callback))) {
throw Common::Wasm::WasmException(
fmt::format("Unable to create Wasm access log {}", plugin->name_));
}
Expand Down
7 changes: 4 additions & 3 deletions source/extensions/bootstrap/wasm/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ void WasmServiceExtension::createWasm(Server::Configuration::ServerFactoryContex
};

if (!Common::Wasm::createWasm(
config_.config().vm_config(), plugin, context.scope().createScope(""),
context.clusterManager(), context.initManager(), context.dispatcher(), context.api(),
context.lifecycleNotifier(), remote_data_provider_, std::move(callback))) {
config_.config().vm_config(), config_.config().capability_restriction_config(), plugin,
context.scope().createScope(""), context.clusterManager(), context.initManager(),
context.dispatcher(), context.api(), context.lifecycleNotifier(), remote_data_provider_,
std::move(callback))) {
// NB: throw if we get a synchronous configuration failures as this is how such failures are
// reported to xDS.
throw Common::Wasm::WasmException(
Expand Down
2 changes: 2 additions & 0 deletions source/extensions/common/wasm/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ using proxy_wasm::WasmResult;
using proxy_wasm::WasmStreamType;

using VmConfig = envoy::extensions::wasm::v3::VmConfig;
using CapabilityRestrictionConfig = envoy::extensions::wasm::v3::CapabilityRestrictionConfig;
using SanitizationConfig = envoy::extensions::wasm::v3::SanitizationConfig;
using GrpcService = envoy::config::core::v3::GrpcService;

class Wasm;
Expand Down
40 changes: 22 additions & 18 deletions source/extensions/common/wasm/wasm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,11 @@ void Wasm::initializeLifecycle(Server::ServerLifecycleNotifier& lifecycle_notifi
}

Wasm::Wasm(absl::string_view runtime, absl::string_view vm_id, absl::string_view vm_configuration,
absl::string_view vm_key, const Stats::ScopeSharedPtr& scope,
Upstream::ClusterManager& cluster_manager, Event::Dispatcher& dispatcher)
: WasmBase(createWasmVm(runtime), vm_id, vm_configuration, vm_key), scope_(scope),
cluster_manager_(cluster_manager), dispatcher_(dispatcher),
absl::string_view vm_key, proxy_wasm::AllowedCapabilitiesMap allowed_capabilities,
const Stats::ScopeSharedPtr& scope, Upstream::ClusterManager& cluster_manager,
Event::Dispatcher& dispatcher)
: WasmBase(createWasmVm(runtime), vm_id, vm_configuration, vm_key, allowed_capabilities),
scope_(scope), cluster_manager_(cluster_manager), dispatcher_(dispatcher),
time_source_(dispatcher.timeSource()),
wasm_stats_(WasmStats{
ALL_WASM_STATS(POOL_COUNTER_PREFIX(*scope_, absl::StrCat("wasm.", runtime, ".")),
Expand Down Expand Up @@ -312,8 +313,9 @@ WasmEvent toWasmEvent(const std::shared_ptr<WasmHandleBase>& wasm) {
NOT_IMPLEMENTED_GCOVR_EXCL_LINE;
}

static bool createWasmInternal(const VmConfig& vm_config, const PluginSharedPtr& plugin,
const Stats::ScopeSharedPtr& scope,
static bool createWasmInternal(const VmConfig& vm_config,
const CapabilityRestrictionConfig& capability_restriction_config,
const PluginSharedPtr& plugin, const Stats::ScopeSharedPtr& scope,
Upstream::ClusterManager& cluster_manager,
Init::Manager& init_manager, Event::Dispatcher& dispatcher,
Api::Api& api, Server::ServerLifecycleNotifier& lifecycle_notifier,
Expand Down Expand Up @@ -380,8 +382,8 @@ static bool createWasmInternal(const VmConfig& vm_config, const PluginSharedPtr&
.value_or(code.empty() ? EMPTY_STRING : INLINE_STRING);
}

auto complete_cb = [cb, vm_config, plugin, scope, &cluster_manager, &dispatcher,
&lifecycle_notifier, create_root_context_for_testing,
auto complete_cb = [cb, vm_config, capability_restriction_config, plugin, scope, &cluster_manager,
&dispatcher, &lifecycle_notifier, create_root_context_for_testing,
wasm_extension](std::string code) -> bool {
if (code.empty()) {
cb(nullptr);
Expand All @@ -391,10 +393,10 @@ static bool createWasmInternal(const VmConfig& vm_config, const PluginSharedPtr&
proxy_wasm::makeVmKey(vm_config.vm_id(), anyToBytes(vm_config.configuration()), code);
auto wasm_factory = wasm_extension->wasmFactory();
proxy_wasm::WasmHandleFactory proxy_wasm_factory =
[&vm_config, scope, &cluster_manager, &dispatcher, &lifecycle_notifier,
wasm_factory](absl::string_view vm_key) -> WasmHandleBaseSharedPtr {
return wasm_factory(vm_config, scope, cluster_manager, dispatcher, lifecycle_notifier,
vm_key);
[&vm_config, &capability_restriction_config, scope, &cluster_manager, &dispatcher,
&lifecycle_notifier, wasm_factory](absl::string_view vm_key) -> WasmHandleBaseSharedPtr {
return wasm_factory(vm_config, capability_restriction_config, scope, cluster_manager,
dispatcher, lifecycle_notifier, vm_key);
};
auto wasm = proxy_wasm::createWasm(
vm_key, code, plugin, proxy_wasm_factory,
Expand Down Expand Up @@ -469,15 +471,17 @@ static bool createWasmInternal(const VmConfig& vm_config, const PluginSharedPtr&
return true;
}

bool createWasm(const VmConfig& vm_config, const PluginSharedPtr& plugin,
const Stats::ScopeSharedPtr& scope, Upstream::ClusterManager& cluster_manager,
Init::Manager& init_manager, Event::Dispatcher& dispatcher, Api::Api& api,
bool createWasm(const VmConfig& vm_config,
const CapabilityRestrictionConfig& capability_restriction_config,
const PluginSharedPtr& plugin, const Stats::ScopeSharedPtr& scope,
Upstream::ClusterManager& cluster_manager, Init::Manager& init_manager,
Event::Dispatcher& dispatcher, Api::Api& api,
Envoy::Server::ServerLifecycleNotifier& lifecycle_notifier,
Config::DataSource::RemoteAsyncDataProviderPtr& remote_data_provider,
CreateWasmCallback&& cb, CreateContextFn create_root_context_for_testing) {
return createWasmInternal(vm_config, plugin, scope, cluster_manager, init_manager, dispatcher,
api, lifecycle_notifier, remote_data_provider, std::move(cb),
create_root_context_for_testing);
return createWasmInternal(vm_config, capability_restriction_config, plugin, scope,
cluster_manager, init_manager, dispatcher, api, lifecycle_notifier,
remote_data_provider, std::move(cb), create_root_context_for_testing);
}

PluginHandleSharedPtr
Expand Down
13 changes: 8 additions & 5 deletions source/extensions/common/wasm/wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ struct WasmStats {
class Wasm : public WasmBase, Logger::Loggable<Logger::Id::wasm> {
public:
Wasm(absl::string_view runtime, absl::string_view vm_id, absl::string_view vm_configuration,
absl::string_view vm_key, const Stats::ScopeSharedPtr& scope,
Upstream::ClusterManager& cluster_manager, Event::Dispatcher& dispatcher);
absl::string_view vm_key, proxy_wasm::AllowedCapabilitiesMap allowed_capabilities,
const Stats::ScopeSharedPtr& scope, Upstream::ClusterManager& cluster_manager,
Event::Dispatcher& dispatcher);
Wasm(std::shared_ptr<WasmHandle> other, Event::Dispatcher& dispatcher);
~Wasm() override;

Expand Down Expand Up @@ -160,9 +161,11 @@ using CreateWasmCallback = std::function<void(WasmHandleSharedPtr)>;
// all failures synchronously as it has no facility to report configuration update failures
// asynchronously. Callers should throw an exception if they are part of a synchronous xDS update
// because that is the mechanism for reporting configuration errors.
bool createWasm(const VmConfig& vm_config, const PluginSharedPtr& plugin,
const Stats::ScopeSharedPtr& scope, Upstream::ClusterManager& cluster_manager,
Init::Manager& init_manager, Event::Dispatcher& dispatcher, Api::Api& api,
bool createWasm(const VmConfig& vm_config,
const CapabilityRestrictionConfig& capability_restriction_config,
const PluginSharedPtr& plugin, const Stats::ScopeSharedPtr& scope,
Upstream::ClusterManager& cluster_manager, Init::Manager& init_manager,
Event::Dispatcher& dispatcher, Api::Api& api,
Envoy::Server::ServerLifecycleNotifier& lifecycle_notifier,
Config::DataSource::RemoteAsyncDataProviderPtr& remote_data_provider,
CreateWasmCallback&& callback,
Expand Down
16 changes: 11 additions & 5 deletions source/extensions/common/wasm/wasm_extension.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,19 @@ PluginHandleExtensionFactory EnvoyWasm::pluginFactory() {
}

WasmHandleExtensionFactory EnvoyWasm::wasmFactory() {
return [](const VmConfig vm_config, const Stats::ScopeSharedPtr& scope,
Upstream::ClusterManager& cluster_manager, Event::Dispatcher& dispatcher,
Server::ServerLifecycleNotifier& lifecycle_notifier,
return [](const VmConfig vm_config,
const CapabilityRestrictionConfig capability_restriction_config,
const Stats::ScopeSharedPtr& scope, Upstream::ClusterManager& cluster_manager,
Event::Dispatcher& dispatcher, Server::ServerLifecycleNotifier& lifecycle_notifier,
absl::string_view vm_key) -> WasmHandleBaseSharedPtr {
proxy_wasm::AllowedCapabilitiesMap allowed_capabilities;
for (auto& capability : capability_restriction_config.allowed_capabilities()) {
// TODO(rapilado): Set the SanitizationConfig fields once sanitization is implemented.
allowed_capabilities[capability.first] = proxy_wasm::SanitizationConfig();
}
auto wasm = std::make_shared<Wasm>(vm_config.runtime(), vm_config.vm_id(),
anyToBytes(vm_config.configuration()), vm_key, scope,
cluster_manager, dispatcher);
anyToBytes(vm_config.configuration()), vm_key,
allowed_capabilities, scope, cluster_manager, dispatcher);
wasm->initializeLifecycle(lifecycle_notifier);
return std::static_pointer_cast<WasmHandleBase>(std::make_shared<WasmHandle>(std::move(wasm)));
};
Expand Down
7 changes: 4 additions & 3 deletions source/extensions/common/wasm/wasm_extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ using CreateContextFn =
using PluginHandleExtensionFactory = std::function<PluginHandleBaseSharedPtr(
const WasmHandleSharedPtr& base_wasm, absl::string_view plugin_key)>;
using WasmHandleExtensionFactory = std::function<WasmHandleBaseSharedPtr(
const VmConfig& vm_config, const Stats::ScopeSharedPtr& scope,
Upstream::ClusterManager& cluster_manager, Event::Dispatcher& dispatcher,
Server::ServerLifecycleNotifier& lifecycle_notifier, absl::string_view vm_key)>;
const VmConfig& vm_config, const CapabilityRestrictionConfig& capability_restriction_config,
const Stats::ScopeSharedPtr& scope, Upstream::ClusterManager& cluster_manager,
Event::Dispatcher& dispatcher, Server::ServerLifecycleNotifier& lifecycle_notifier,
absl::string_view vm_key)>;
using WasmHandleExtensionCloneFactory = std::function<WasmHandleBaseSharedPtr(
const WasmHandleSharedPtr& base_wasm, Event::Dispatcher& dispatcher,
CreateContextFn create_root_context_for_testing)>;
Expand Down
7 changes: 4 additions & 3 deletions source/extensions/filters/http/wasm/wasm_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ FilterConfig::FilterConfig(const envoy::extensions::filters::http::wasm::v3::Was
};

if (!Common::Wasm::createWasm(
config.config().vm_config(), plugin_, context.scope().createScope(""),
context.clusterManager(), context.initManager(), context.dispatcher(), context.api(),
context.lifecycleNotifier(), remote_data_provider_, std::move(callback))) {
config.config().vm_config(), config.config().capability_restriction_config(), plugin_,
context.scope().createScope(""), context.clusterManager(), context.initManager(),
context.dispatcher(), context.api(), context.lifecycleNotifier(), remote_data_provider_,
std::move(callback))) {
throw Common::Wasm::WasmException(
fmt::format("Unable to create Wasm HTTP filter {}", plugin->name_));
}
Expand Down
7 changes: 4 additions & 3 deletions source/extensions/filters/network/wasm/wasm_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ FilterConfig::FilterConfig(const envoy::extensions::filters::network::wasm::v3::
};

if (!Common::Wasm::createWasm(
config.config().vm_config(), plugin_, context.scope().createScope(""),
context.clusterManager(), context.initManager(), context.dispatcher(), context.api(),
context.lifecycleNotifier(), remote_data_provider_, std::move(callback))) {
config.config().vm_config(), config.config().capability_restriction_config(), plugin_,
context.scope().createScope(""), context.clusterManager(), context.initManager(),
context.dispatcher(), context.api(), context.lifecycleNotifier(), remote_data_provider_,
std::move(callback))) {
throw Common::Wasm::WasmException(
fmt::format("Unable to create Wasm network filter {}", plugin->name_));
}
Expand Down
7 changes: 4 additions & 3 deletions source/extensions/stat_sinks/wasm/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ WasmSinkFactory::createStatsSink(const Protobuf::Message& proto_config,
};

if (!Common::Wasm::createWasm(
config.config().vm_config(), plugin, context.scope().createScope(""),
context.clusterManager(), context.initManager(), context.dispatcher(), context.api(),
context.lifecycleNotifier(), remote_data_provider_, std::move(callback))) {
config.config().vm_config(), config.config().capability_restriction_config(), plugin,
context.scope().createScope(""), context.clusterManager(), context.initManager(),
context.dispatcher(), context.api(), context.lifecycleNotifier(), remote_data_provider_,
std::move(callback))) {
throw Common::Wasm::WasmException(
fmt::format("Unable to create Wasm Stat Sink {}", plugin->name_));
}
Expand Down
Loading

0 comments on commit 47ad8ee

Please sign in to comment.