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

rbac: support to configure the shadow rule stat with a custom prefix. #15323

Merged
merged 3 commits into from
Mar 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions api/envoy/extensions/filters/http/rbac/v3/rbac.proto
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ message RBAC {
// but will emit stats and logs and can be used for rule testing.
// If absent, no shadow RBAC policy will be applied.
config.rbac.v3.RBAC shadow_rules = 2;

// If specified, shadow rules will emit stats with the given prefix.
// This is useful to distinguish the stat when there are more than 1 RBAC filter configured with
// shadow rules.
string shadow_rules_stat_prefix = 3;
}

message RBACPerRoute {
Expand Down
5 changes: 5 additions & 0 deletions api/envoy/extensions/filters/http/rbac/v4alpha/rbac.proto

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

6 changes: 6 additions & 0 deletions api/envoy/extensions/filters/network/rbac/v3/rbac.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
//
// Header should not be used in rules/shadow_rules in RBAC network filter as
// this information is only available in :ref:`RBAC http filter <config_http_filters_rbac>`.
// [#next-free-field: 6]
message RBAC {
option (udpa.annotations.versioning).previous_message_type =
"envoy.config.filter.network.rbac.v2.RBAC";
Expand All @@ -45,6 +46,11 @@ message RBAC {
// If absent, no shadow RBAC policy will be applied.
config.rbac.v3.RBAC shadow_rules = 2;

// If specified, shadow rules will emit stats with the given prefix.
// This is useful to distinguish the stat when there are more than 1 RBAC filter configured with
// shadow rules.
string shadow_rules_stat_prefix = 5;

// The prefix to use when emitting statistics.
string stat_prefix = 3 [(validate.rules).string = {min_len: 1}];

Expand Down
6 changes: 6 additions & 0 deletions api/envoy/extensions/filters/network/rbac/v4alpha/rbac.proto

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

1 change: 1 addition & 0 deletions docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ New Features
* original_dst: added support for :ref:`Original Destination <config_listener_filters_original_dst>` on Windows. This enables the use of Envoy as a sidecar proxy on Windows.
* overload: add support for scaling :ref:`transport connection timeouts<envoy_v3_api_enum_value_config.overload.v3.ScaleTimersOverloadActionConfig.TimerType.TRANSPORT_SOCKET_CONNECT>`. This can be used to reduce the TLS handshake timeout in response to overload.
* postgres: added ability to :ref:`terminate SSL<envoy_v3_api_field_extensions.filters.network.postgres_proxy.v3alpha.PostgresProxy.terminate_ssl>`.
* rbac: added :ref:`shadow_rules_stat_prefix <envoy_v3_api_field_extensions.filters.http.rbac.v3.RBAC.shadow_rules_stat_prefix>` to allow adding custom prefix to the stats emitted by shadow rules.
* route config: added :ref:`allow_post field <envoy_v3_api_field_config.route.v3.RouteAction.UpgradeConfig.ConnectConfig.allow_post>` for allowing POST payload as raw TCP.
* route config: added :ref:`max_direct_response_body_size_bytes <envoy_v3_api_field_config.route.v3.RouteConfiguration.max_direct_response_body_size_bytes>` to set maximum :ref:`direct response body <envoy_v3_api_field_config.route.v3.DirectResponseAction.body>` size in bytes. If not specified the default remains 4096 bytes.
* server: added *fips_mode* to :ref:`server compilation settings <server_compilation_settings_statistics>` related statistic.
Expand Down

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

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

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

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

9 changes: 3 additions & 6 deletions source/extensions/filters/http/rbac/rbac_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ RoleBasedAccessControlFilterConfig::RoleBasedAccessControlFilterConfig(
const envoy::extensions::filters::http::rbac::v3::RBAC& proto_config,
const std::string& stats_prefix, Stats::Scope& scope)
: stats_(Filters::Common::RBAC::generateStats(stats_prefix, scope)),
shadow_rules_stat_prefix_(proto_config.shadow_rules_stat_prefix()),
engine_(Filters::Common::RBAC::createEngine(proto_config)),
shadow_engine_(Filters::Common::RBAC::createShadowEngine(proto_config)) {}

Expand Down Expand Up @@ -91,14 +92,10 @@ RoleBasedAccessControlFilter::decodeHeaders(Http::RequestHeaderMap& headers, boo

auto& fields = *metrics.mutable_fields();
if (!effective_policy_id.empty()) {
*fields[Filters::Common::RBAC::DynamicMetadataKeysSingleton::get()
.ShadowEffectivePolicyIdField]
.mutable_string_value() = effective_policy_id;
*fields[config_->shadowEffectivePolicyIdField()].mutable_string_value() = effective_policy_id;
}

*fields[Filters::Common::RBAC::DynamicMetadataKeysSingleton::get().ShadowEngineResultField]
.mutable_string_value() = shadow_resp_code;

*fields[config_->shadowEngineResultField()].mutable_string_value() = shadow_resp_code;
callbacks_->streamInfo().setDynamicMetadata(HttpFilterNames::get().Rbac, metrics);
}

Expand Down
9 changes: 9 additions & 0 deletions source/extensions/filters/http/rbac/rbac_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ class RoleBasedAccessControlFilterConfig {
const std::string& stats_prefix, Stats::Scope& scope);

Filters::Common::RBAC::RoleBasedAccessControlFilterStats& stats() { return stats_; }
std::string shadowEffectivePolicyIdField() const {
return shadow_rules_stat_prefix_ +
Filters::Common::RBAC::DynamicMetadataKeysSingleton::get().ShadowEffectivePolicyIdField;
}
std::string shadowEngineResultField() const {
return shadow_rules_stat_prefix_ +
Filters::Common::RBAC::DynamicMetadataKeysSingleton::get().ShadowEngineResultField;
}

const Filters::Common::RBAC::RoleBasedAccessControlEngineImpl*
engine(const Router::RouteConstSharedPtr route,
Expand All @@ -56,6 +64,7 @@ class RoleBasedAccessControlFilterConfig {
}

Filters::Common::RBAC::RoleBasedAccessControlFilterStats stats_;
const std::string shadow_rules_stat_prefix_;

std::unique_ptr<const Filters::Common::RBAC::RoleBasedAccessControlEngineImpl> engine_;
std::unique_ptr<const Filters::Common::RBAC::RoleBasedAccessControlEngineImpl> shadow_engine_;
Expand Down
7 changes: 3 additions & 4 deletions source/extensions/filters/network/rbac/rbac_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace RBACFilter {
RoleBasedAccessControlFilterConfig::RoleBasedAccessControlFilterConfig(
const envoy::extensions::filters::network::rbac::v3::RBAC& proto_config, Stats::Scope& scope)
: stats_(Filters::Common::RBAC::generateStats(proto_config.stat_prefix(), scope)),
shadow_rules_stat_prefix_(proto_config.shadow_rules_stat_prefix()),
engine_(Filters::Common::RBAC::createEngine(proto_config)),
shadow_engine_(Filters::Common::RBAC::createShadowEngine(proto_config)),
enforcement_type_(proto_config.enforcement_type()) {}
Expand Down Expand Up @@ -86,11 +87,9 @@ void RoleBasedAccessControlFilter::setDynamicMetadata(std::string shadow_engine_
ProtobufWkt::Struct metrics;
auto& fields = *metrics.mutable_fields();
if (!shadow_policy_id.empty()) {
*fields[Filters::Common::RBAC::DynamicMetadataKeysSingleton::get().ShadowEffectivePolicyIdField]
.mutable_string_value() = shadow_policy_id;
*fields[config_->shadowEffectivePolicyIdField()].mutable_string_value() = shadow_policy_id;
}
*fields[Filters::Common::RBAC::DynamicMetadataKeysSingleton::get().ShadowEngineResultField]
.mutable_string_value() = shadow_engine_result;
*fields[config_->shadowEngineResultField()].mutable_string_value() = shadow_engine_result;
callbacks_->connection().streamInfo().setDynamicMetadata(NetworkFilterNames::get().Rbac, metrics);
}

Expand Down
13 changes: 11 additions & 2 deletions source/extensions/filters/network/rbac/rbac_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ class RoleBasedAccessControlFilterConfig {
const envoy::extensions::filters::network::rbac::v3::RBAC& proto_config, Stats::Scope& scope);

Filters::Common::RBAC::RoleBasedAccessControlFilterStats& stats() { return stats_; }
std::string shadowEffectivePolicyIdField() const {
return shadow_rules_stat_prefix_ +
Filters::Common::RBAC::DynamicMetadataKeysSingleton::get().ShadowEffectivePolicyIdField;
}
std::string shadowEngineResultField() const {
return shadow_rules_stat_prefix_ +
Filters::Common::RBAC::DynamicMetadataKeysSingleton::get().ShadowEngineResultField;
}

const Filters::Common::RBAC::RoleBasedAccessControlEngineImpl*
engine(Filters::Common::RBAC::EnforcementMode mode) const {
Expand All @@ -44,9 +52,10 @@ class RoleBasedAccessControlFilterConfig {

private:
Filters::Common::RBAC::RoleBasedAccessControlFilterStats stats_;
const std::string shadow_rules_stat_prefix_;

std::unique_ptr<Filters::Common::RBAC::RoleBasedAccessControlEngineImpl> engine_;
std::unique_ptr<Filters::Common::RBAC::RoleBasedAccessControlEngineImpl> shadow_engine_;
std::unique_ptr<const Filters::Common::RBAC::RoleBasedAccessControlEngineImpl> engine_;
std::unique_ptr<const Filters::Common::RBAC::RoleBasedAccessControlEngineImpl> shadow_engine_;
const envoy::extensions::filters::network::rbac::v3::RBAC::EnforcementType enforcement_type_;
};

Expand Down
5 changes: 3 additions & 2 deletions test/extensions/filters/http/rbac/rbac_filter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class RoleBasedAccessControlFilterTest : public testing::Test {
shadow_policy.add_principals()->set_any(true);
config.mutable_shadow_rules()->set_action(action);
(*config.mutable_shadow_rules()->mutable_policies())["bar"] = shadow_policy;
config.set_shadow_rules_stat_prefix("prefix_");

return std::make_shared<RoleBasedAccessControlFilterConfig>(config, "test", store_);
}
Expand Down Expand Up @@ -184,8 +185,8 @@ TEST_F(RoleBasedAccessControlFilterTest, Denied) {
EXPECT_EQ(1U, config_->stats().shadow_allowed_.value());

auto filter_meta = req_info_.dynamicMetadata().filter_metadata().at(HttpFilterNames::get().Rbac);
EXPECT_EQ("allowed", filter_meta.fields().at("shadow_engine_result").string_value());
EXPECT_EQ("bar", filter_meta.fields().at("shadow_effective_policy_id").string_value());
EXPECT_EQ("allowed", filter_meta.fields().at("prefix_shadow_engine_result").string_value());
EXPECT_EQ("bar", filter_meta.fields().at("prefix_shadow_effective_policy_id").string_value());
EXPECT_EQ("rbac_access_denied_matched_policy[none]", callbacks_.details());
checkAccessLogMetadata(LogResult::Undecided);
}
Expand Down
5 changes: 3 additions & 2 deletions test/extensions/filters/network/rbac/filter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class RoleBasedAccessControlNetworkFilterTest : public testing::Test {
shadow_policy_rules->add_rules()->set_destination_port(456);
shadow_policy.add_principals()->set_any(true);
config.mutable_shadow_rules()->set_action(action);
config.set_shadow_rules_stat_prefix("prefix_");
(*config.mutable_shadow_rules()->mutable_policies())["bar"] = shadow_policy;
}

Expand Down Expand Up @@ -189,8 +190,8 @@ TEST_F(RoleBasedAccessControlNetworkFilterTest, Denied) {

auto filter_meta =
stream_info_.dynamicMetadata().filter_metadata().at(NetworkFilterNames::get().Rbac);
EXPECT_EQ("bar", filter_meta.fields().at("shadow_effective_policy_id").string_value());
EXPECT_EQ("allowed", filter_meta.fields().at("shadow_engine_result").string_value());
EXPECT_EQ("bar", filter_meta.fields().at("prefix_shadow_effective_policy_id").string_value());
EXPECT_EQ("allowed", filter_meta.fields().at("prefix_shadow_engine_result").string_value());
}

// Log Tests
Expand Down