Skip to content

api: Add log action to RBAC filter api#11705

Merged
mattklein123 merged 48 commits intoenvoyproxy:masterfrom
davidraskin:api_change
Aug 11, 2020
Merged

api: Add log action to RBAC filter api#11705
mattklein123 merged 48 commits intoenvoyproxy:masterfrom
davidraskin:api_change

Conversation

@davidraskin
Copy link
Contributor

@davidraskin davidraskin commented Jun 23, 2020

Commit Message: Add "LOG" action to RBAC filter api
Additional Description: The log action will be used to set the dynamic metadata key "envoy.log", which can be used to decide whether to log a request.
Risk Level: Low
Testing: Existing tests pass
Docs Changes: Updated RBAC configuration reference with new dynamic metadata, and updated RBAC api reference.
Release Notes: n/a
[Optional Runtime guard:]
[Optional Fixes #Issue]
[Optional Deprecated:]

@repokitteh-read-only
Copy link

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to api/.
CC @envoyproxy/api-watchers: FYI only for changes made to api/.

🐱

Caused by: #11705 was opened by davidraskin.

see: more, trace.

@davidraskin
Copy link
Contributor Author

Relates to #11594

Copy link
Member

Choose a reason for hiding this comment

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

Why is this a string and not a bool?

Copy link
Contributor

@kyessenov kyessenov Jun 24, 2020

Choose a reason for hiding this comment

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

This could be used to indicate a reason for logging and presence of the key indicates whether to log. E.g. RBAC filter would put "rbac" here.

Copy link
Member

Choose a reason for hiding this comment

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

I think I would prefer we have a dynamic metadata key for the RBAC filter and make it a bool. This is the intended use of dynamic metadata, which avoids having to coordinate on key namespace across arbitrary number of filters.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1 to make it a bool.

Copy link
Contributor

Choose a reason for hiding this comment

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

What about the scenarios where multiple filters can give a decision to logging filter to log/not. For example, we have a wasm sampling filter that also decides whether a request should be logged or not. It would be good to have a key that is generic enough and not filter specific so that the consuming filter can make a decision just based on the value of this key rather than needing to have knowledge of all filters from whom, it can get a decision of, to log or not.

Copy link
Member

Choose a reason for hiding this comment

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

Please specify in the docs how this interacts with Envoy's default file and gRPC access loggers. You might want to add a field that indicates what metadata controls logging to them potentially. I think you should also pick naming of the key space that indicates how this is supposed to be used when taking into account the variety of loggers; basically what I'm after is a solution that makes sense for Envoy independent of Istio.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good. To clarify, we'll use the same key for use in all access loggers. It will be called something like "access_log_policy", which conveys its use for determining whether to output access logs. All loggers have the option of checking this key when invoked. For envoy access loggers specifically, we'd provide an access log filter that can be specified in the logger config that checks this key.

Copy link
Member

Choose a reason for hiding this comment

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

OK, sounds good. Will this be a boolean or some string? What are the contents of this string if it's a policy?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For flexibility purposes @gargnupur and @kyessenov preferred a string. Currently I just have it set to "yes" or "no", but potential use case for a string would be instead of "yes" to put the deciding filter name, for debugging or some other reason. I could go either way on this, whatever the general consensus is.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We're going with a boolean value now.

Copy link
Member

Choose a reason for hiding this comment

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

Does this still effectively allow?

Copy link
Contributor Author

@davidraskin davidraskin Jun 23, 2020

Choose a reason for hiding this comment

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

It allows all requests. I'll make it more clear.

@davidraskin
Copy link
Contributor Author

@liminw @yangminzhu

Copy link
Contributor

Choose a reason for hiding this comment

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

same here.

@repokitteh-read-only
Copy link

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to api/envoy/.
CC @envoyproxy/api-watchers: FYI only for changes made to api/envoy/.

🐱

Caused by: #11705 was synchronize by davidraskin.

see: more, trace.

Copy link
Member

Choose a reason for hiding this comment

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

Should this key be qualified by RBAC filter?

Copy link
Member

Choose a reason for hiding this comment

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

This is probably the only comment I have still outstanding.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1. The "envoy" part in "envoy.log" does not provide much value.

Copy link
Member

Choose a reason for hiding this comment

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

I think I would prefer we have a dynamic metadata key for the RBAC filter and make it a bool. This is the intended use of dynamic metadata, which avoids having to coordinate on key namespace across arbitrary number of filters.

Copy link
Contributor Author

@davidraskin davidraskin Jun 25, 2020

Choose a reason for hiding this comment

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

I say that all requests are allowed explicitly here. I think it's clear enough right @yangminzhu ?

Copy link
Contributor

Choose a reason for hiding this comment

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

LOG action does not impact allow or deny decision. Let's remove "All requests are allowed" to avoid confusion.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To avoid confusion, I think its best for the user to know that all requests are allowed if the action is LOG rather than wonder what will happen with their request

Copy link
Contributor

Choose a reason for hiding this comment

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

+1 to make it a bool.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1. The "envoy" part in "envoy.log" does not provide much value.

@repokitteh-read-only
Copy link

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to (api/envoy[\w/]*/(v1alpha\d?|v1|v2alpha\d?|v2))|(api/envoy/type/(matcher/)?\w+.proto).

🐱

Caused by: #11705 was synchronize by davidraskin.

see: more, trace.

@davidraskin davidraskin force-pushed the api_change branch 3 times, most recently from a5ccc9c to 7f21b1e Compare July 7, 2020 03:41
* empty map should be used if there are no headers available.
* @param info the per-request or per-connection stream info with additional information
* about the action/principal.
* about the action/principal. Can be modified by an Action.
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we be more specific that it could be modified only by an LOG action.

return true;
}
default:
return true;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can replace return true with NOT_REACHED_GCOVR_EXCL_LINE;, and remove the return true below.

config_->engine(callbacks_->route(), Filters::Common::RBAC::EnforcementMode::Enforced);
if (engine != nullptr) {
if (engine->allowed(*callbacks_->connection(), headers, callbacks_->streamInfo(), nullptr)) {
// Check authorization decision and do Action operations
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment seems a bit redundant.

checkEngine(engine, expected, empty_info, connection, headers);
}

void checkEngineLog(
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we remove this function and combine the check into the checkEngine()? You can still pass the LogResult to it. This gives us more coverage with less code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That would probably mean having every test check log metadata even when its an Allow or Deny test

Copy link
Contributor

Choose a reason for hiding this comment

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

isn't that better? we make sure the Allow/Deny doesn't write to the metadata accidentally.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah I guess that's true.

checkEngineLog(engine, RBAC::LogResult::Undecided, info, conn, headers);
}

TEST(RoleBasedAccessControlEngineImpl, LogAllowAll) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This would be duplicated and can be removed if you combine checkEngineLog() to checkEngine(), see the comment above.

EXPECT_EQ(Http::FilterHeadersStatus::Continue, log_filter_.decodeHeaders(headers, false));
auto filter_meta = req_info_.dynamicMetadata().filter_metadata().at(
Filters::Common::RBAC::DynamicMetadataKeysSingleton::get().CommonNamespace);
EXPECT_EQ(false, filter_meta.fields()
Copy link
Contributor

Choose a reason for hiding this comment

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

You can just use EXPECT_FALSE.

EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_.decodeTrailers(trailers_));

// Check Log
setMetadata();
Copy link
Contributor

Choose a reason for hiding this comment

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

Call the setMetadata() in the beginning, also remove the extra call of EXPECT_EQ(Http::FilterHeadersStatus::Continue, ...) which is already called above.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This checks the log action in the same test as the regular action. After refactoring some stuff from before, it might make sense to do all log tests this way. Do you think its better to combine log tests with Allow tests or should we keep them separate?

Copy link
Contributor

Choose a reason for hiding this comment

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

let's combine them together so that we also cover the case that non-LOG action will not write to the metadata accidentally.

Copy link
Contributor Author

@davidraskin davidraskin Aug 5, 2020

Choose a reason for hiding this comment

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

I meant testing that LOG action will log whenever ALLOW action allows. So I'm using two separate configs in these tests. This allows me to easily add checks for log action for other cases like Path and RequestedServerName. Do you think that's too confusing?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is unnecessary and complicates the tests with two configs. Like I said before, just initialize the config to the action you want to test, and then check the behavior:

  • for ALLOW action, it should allow the request and deny by default, the metadata should not change
  • for DENY action, it should deny if explicitly matched and allow if not, the metadata should not change
  • for LOG action, it should always allow, and the metadata should change if matched

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure sounds good.

};
EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_.decodeHeaders(headers, false));

headers = Http::TestRequestHeaderMapImpl{
Copy link
Contributor

Choose a reason for hiding this comment

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

what's the purpose of this and the next line?

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 added an extra test to Path, I thought it could maybe use a verify false test? I'll remove it. It's probably not necessary.

Copy link
Contributor

Choose a reason for hiding this comment

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

isn't it duplicate with the above one?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

":path" is set to "prefix/suffix/next" for the first one and "/suffix#seg?param=value" for the second one.

EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_.decodeHeaders(headers, false));

// Check Log
setMetadata();
Copy link
Contributor

Choose a reason for hiding this comment

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

same here, move the setMetadata() to the above, and remove the extra EXPECT_EQ() in the next line.

RoleBasedAccessControlFilterConfigSharedPtr config_;

RoleBasedAccessControlFilter filter_;
RoleBasedAccessControlFilterConfigSharedPtr log_config_;
Copy link
Contributor

Choose a reason for hiding this comment

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

no, let's use only one filter_ and config_ otherwise it gets really complicated of which one is being tested in a test case.

You can have a custom setUp(envoy::config::rbac::v3::RBAC::Action action) that creates a new config/filter and assign to the config_/filter_ in the beginning of each test case, it also combine the SetUp().

Similar to what you are doing in the network/rbac/filter_test.cc

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This makes more verbose to check log and non-log actions in the same test, which I do a couple times, but for clarity I can change it.

Copy link
Contributor

Choose a reason for hiding this comment

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

why more verbose? they are testing different things, for a non-LOG action, we also need to make sure it doesn't write to the metadata.

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'm testing both configs in some tests, see below comment.

Signed-off-by: davidraskin <draskin@google.com>
Signed-off-by: davidraskin <draskin@google.com>
@davidraskin
Copy link
Contributor Author

@mattklein123 @yangminzhu does this look good now? Thanks.

yangminzhu
yangminzhu previously approved these changes Aug 6, 2020
Copy link
Contributor

@yangminzhu yangminzhu left a comment

Choose a reason for hiding this comment

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

Thanks! Looks good to me and only 1 small comment.

NOT_REACHED_GCOVR_EXCL_LINE;
}

return true;
Copy link
Contributor

Choose a reason for hiding this comment

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

could this be removed since all cases are handled in the switch?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep. Thanks.

Signed-off-by: davidraskin <draskin@google.com>
@davidraskin
Copy link
Contributor Author

@mattklein123 Could you please take a look? Thanks!

@davidraskin
Copy link
Contributor Author

@mattklein123 Does this PR look okay now or is there more that needs to be done? Thanks.

@mattklein123
Copy link
Member

@mattklein123 Does this PR look okay now or is there more that needs to be done? Thanks.

This is in my review queue. Asking me repeatedly to review it is doing the opposite of what you are hoping for. Thank you for your understanding!

@davidraskin
Copy link
Contributor Author

Apologies, and sorry for being obnoxious. This was just a blocking PR on my end and I just wanted to make sure you hadn't missed it for whatever reason. I fully understand that there's other PRs that are higher priority and need to be reviewed first. Thanks!

Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

LGTM with small merge issue. Thank you!

/wait

* lua: added Lua APIs to access :ref:`SSL connection info <config_http_filters_lua_ssl_socket_info>` object.
* postgres network filter: :ref:`metadata <config_network_filters_postgres_proxy_dynamic_metadata>` is produced based on SQL query.
* ratelimit: added :ref:`enable_x_ratelimit_headers <envoy_v3_api_msg_extensions.filters.http.ratelimit.v3.RateLimit>` option to enable `X-RateLimit-*` headers as defined in `draft RFC <https://tools.ietf.org/id/draft-polli-ratelimit-headers-03.html>`_.
* ratelimit: added :ref:`enable_x_ratelimit_headers <envoy_v3_api_msg_extensions.filters.http.ratelimit.v3.RateLimit>` option to enable `X-RateLimit-*` headers as defined in `draft RFC <https://tools.ietf.org/id/draft-polli-ratelimit-headers-02.html>`_.
Copy link
Member

Choose a reason for hiding this comment

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

merge issue on this line

Copy link
Member

Choose a reason for hiding this comment

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

You didn't actually fix the issue. This line needs to get reverted.

/wait

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops, should be good now.

Signed-off-by: davidraskin <draskin@google.com>
Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Thanks!

@davidraskin
Copy link
Contributor Author

Thank you!

@mattklein123 mattklein123 merged commit 89b594e into envoyproxy:master Aug 11, 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.

7 participants