[Audit Logging] Audit logging support in authorization engines. (#32995)

1. `GrpcAuthorizationEngine` creates the logger from the given config in
its ctor.
2. `Evaluate()` invokes audit logging when needed.

---------

Co-authored-by: rockspore <rockspore@users.noreply.github.com>
pull/33006/head
Luwei Ge 2 years ago committed by GitHub
parent 18c1cc5a51
commit abc82b9e19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      CMakeLists.txt
  2. 2
      Makefile
  3. 20
      build_autogenerated.yaml
  4. 1
      config.m4
  5. 1
      config.w32
  6. 1
      gRPC-C++.podspec
  7. 3
      gRPC-Core.podspec
  8. 2
      grpc.gemspec
  9. 2
      grpc.gyp
  10. 2
      package.xml
  11. 1
      src/core/BUILD
  12. 3
      src/core/ext/filters/rbac/rbac_service_config_parser.cc
  13. 49
      src/core/lib/security/authorization/grpc_authorization_engine.cc
  14. 11
      src/core/lib/security/authorization/grpc_authorization_engine.h
  15. 5
      src/core/lib/security/authorization/rbac_policy.cc
  16. 1
      src/python/grpcio/grpc_core_dependencies.py
  17. 310
      test/core/security/grpc_authorization_engine_test.cc
  18. 2
      tools/doxygen/Doxyfile.core.internal

9
CMakeLists.txt generated

@ -2196,6 +2196,7 @@ add_library(grpc
src/core/lib/resource_quota/resource_quota.cc
src/core/lib/resource_quota/thread_quota.cc
src/core/lib/resource_quota/trace.cc
src/core/lib/security/authorization/audit_logging.cc
src/core/lib/security/authorization/authorization_policy_provider_vtable.cc
src/core/lib/security/authorization/evaluate_args.cc
src/core/lib/security/authorization/grpc_authorization_engine.cc
@ -3222,7 +3223,6 @@ add_library(grpc++
src/core/ext/transport/binder/wire_format/transaction.cc
src/core/ext/transport/binder/wire_format/wire_reader_impl.cc
src/core/ext/transport/binder/wire_format/wire_writer.cc
src/core/lib/security/authorization/audit_logging.cc
src/cpp/client/channel_cc.cc
src/cpp/client/client_callback.cc
src/cpp/client/client_context.cc
@ -6854,7 +6854,6 @@ add_executable(binder_transport_test
src/core/ext/transport/binder/wire_format/transaction.cc
src/core/ext/transport/binder/wire_format/wire_reader_impl.cc
src/core/ext/transport/binder/wire_format/wire_writer.cc
src/core/lib/security/authorization/audit_logging.cc
src/cpp/client/channel_cc.cc
src/cpp/client/client_callback.cc
src/cpp/client/client_context.cc
@ -9928,7 +9927,6 @@ add_executable(endpoint_binder_pool_test
src/core/ext/transport/binder/wire_format/transaction.cc
src/core/ext/transport/binder/wire_format/wire_reader_impl.cc
src/core/ext/transport/binder/wire_format/wire_writer.cc
src/core/lib/security/authorization/audit_logging.cc
src/cpp/client/channel_cc.cc
src/cpp/client/client_callback.cc
src/cpp/client/client_context.cc
@ -10621,7 +10619,6 @@ add_executable(fake_binder_test
src/core/ext/transport/binder/wire_format/transaction.cc
src/core/ext/transport/binder/wire_format/wire_reader_impl.cc
src/core/ext/transport/binder/wire_format/wire_writer.cc
src/core/lib/security/authorization/audit_logging.cc
src/cpp/client/channel_cc.cc
src/cpp/client/client_callback.cc
src/cpp/client/client_context.cc
@ -11960,7 +11957,6 @@ endif()
if(gRPC_BUILD_TESTS)
add_executable(grpc_audit_logging_test
src/core/lib/security/authorization/audit_logging.cc
test/core/security/grpc_audit_logging_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
@ -21834,7 +21830,6 @@ add_executable(transport_stream_receiver_test
src/core/ext/transport/binder/wire_format/transaction.cc
src/core/ext/transport/binder/wire_format/wire_reader_impl.cc
src/core/ext/transport/binder/wire_format/wire_writer.cc
src/core/lib/security/authorization/audit_logging.cc
src/cpp/client/channel_cc.cc
src/cpp/client/client_callback.cc
src/cpp/client/client_context.cc
@ -22549,7 +22544,6 @@ add_executable(wire_reader_test
src/core/ext/transport/binder/wire_format/transaction.cc
src/core/ext/transport/binder/wire_format/wire_reader_impl.cc
src/core/ext/transport/binder/wire_format/wire_writer.cc
src/core/lib/security/authorization/audit_logging.cc
src/cpp/client/channel_cc.cc
src/cpp/client/client_callback.cc
src/cpp/client/client_context.cc
@ -22651,7 +22645,6 @@ add_executable(wire_writer_test
src/core/ext/transport/binder/wire_format/transaction.cc
src/core/ext/transport/binder/wire_format/wire_reader_impl.cc
src/core/ext/transport/binder/wire_format/wire_writer.cc
src/core/lib/security/authorization/audit_logging.cc
src/cpp/client/channel_cc.cc
src/cpp/client/client_callback.cc
src/cpp/client/client_context.cc

2
Makefile generated

@ -1579,6 +1579,7 @@ LIBGRPC_SRC = \
src/core/lib/resource_quota/resource_quota.cc \
src/core/lib/resource_quota/thread_quota.cc \
src/core/lib/resource_quota/trace.cc \
src/core/lib/security/authorization/audit_logging.cc \
src/core/lib/security/authorization/authorization_policy_provider_vtable.cc \
src/core/lib/security/authorization/evaluate_args.cc \
src/core/lib/security/authorization/grpc_authorization_engine.cc \
@ -3354,6 +3355,7 @@ src/core/ext/xds/xds_transport_grpc.cc: $(OPENSSL_DEP)
src/core/lib/http/httpcli_security_connector.cc: $(OPENSSL_DEP)
src/core/lib/json/json_util.cc: $(OPENSSL_DEP)
src/core/lib/matchers/matchers.cc: $(OPENSSL_DEP)
src/core/lib/security/authorization/audit_logging.cc: $(OPENSSL_DEP)
src/core/lib/security/authorization/grpc_authorization_engine.cc: $(OPENSSL_DEP)
src/core/lib/security/authorization/matchers.cc: $(OPENSSL_DEP)
src/core/lib/security/authorization/rbac_policy.cc: $(OPENSSL_DEP)

@ -863,6 +863,7 @@ libs:
- src/core/lib/resource_quota/resource_quota.h
- src/core/lib/resource_quota/thread_quota.h
- src/core/lib/resource_quota/trace.h
- src/core/lib/security/authorization/audit_logging.h
- src/core/lib/security/authorization/authorization_engine.h
- src/core/lib/security/authorization/authorization_policy_provider.h
- src/core/lib/security/authorization/evaluate_args.h
@ -1616,6 +1617,7 @@ libs:
- src/core/lib/resource_quota/resource_quota.cc
- src/core/lib/resource_quota/thread_quota.cc
- src/core/lib/resource_quota/trace.cc
- src/core/lib/security/authorization/audit_logging.cc
- src/core/lib/security/authorization/authorization_policy_provider_vtable.cc
- src/core/lib/security/authorization/evaluate_args.cc
- src/core/lib/security/authorization/grpc_authorization_engine.cc
@ -2960,7 +2962,6 @@ libs:
- src/core/ext/transport/binder/wire_format/wire_reader.h
- src/core/ext/transport/binder/wire_format/wire_reader_impl.h
- src/core/ext/transport/binder/wire_format/wire_writer.h
- src/core/lib/security/authorization/audit_logging.h
- src/cpp/client/client_stats_interceptor.h
- src/cpp/client/create_channel_internal.h
- src/cpp/client/secure_credentials.h
@ -2992,7 +2993,6 @@ libs:
- src/core/ext/transport/binder/wire_format/transaction.cc
- src/core/ext/transport/binder/wire_format/wire_reader_impl.cc
- src/core/ext/transport/binder/wire_format/wire_writer.cc
- src/core/lib/security/authorization/audit_logging.cc
- src/cpp/client/channel_cc.cc
- src/cpp/client/client_callback.cc
- src/cpp/client/client_context.cc
@ -4981,7 +4981,6 @@ targets:
- src/core/ext/transport/binder/wire_format/wire_reader.h
- src/core/ext/transport/binder/wire_format/wire_reader_impl.h
- src/core/ext/transport/binder/wire_format/wire_writer.h
- src/core/lib/security/authorization/audit_logging.h
- src/cpp/client/client_stats_interceptor.h
- src/cpp/client/create_channel_internal.h
- src/cpp/client/secure_credentials.h
@ -5014,7 +5013,6 @@ targets:
- src/core/ext/transport/binder/wire_format/transaction.cc
- src/core/ext/transport/binder/wire_format/wire_reader_impl.cc
- src/core/ext/transport/binder/wire_format/wire_writer.cc
- src/core/lib/security/authorization/audit_logging.cc
- src/cpp/client/channel_cc.cc
- src/cpp/client/client_callback.cc
- src/cpp/client/client_context.cc
@ -6463,7 +6461,6 @@ targets:
- src/core/ext/transport/binder/wire_format/wire_reader.h
- src/core/ext/transport/binder/wire_format/wire_reader_impl.h
- src/core/ext/transport/binder/wire_format/wire_writer.h
- src/core/lib/security/authorization/audit_logging.h
- src/cpp/client/client_stats_interceptor.h
- src/cpp/client/create_channel_internal.h
- src/cpp/client/secure_credentials.h
@ -6496,7 +6493,6 @@ targets:
- src/core/ext/transport/binder/wire_format/transaction.cc
- src/core/ext/transport/binder/wire_format/wire_reader_impl.cc
- src/core/ext/transport/binder/wire_format/wire_writer.cc
- src/core/lib/security/authorization/audit_logging.cc
- src/cpp/client/channel_cc.cc
- src/cpp/client/client_callback.cc
- src/cpp/client/client_context.cc
@ -6887,7 +6883,6 @@ targets:
- src/core/ext/transport/binder/wire_format/wire_reader.h
- src/core/ext/transport/binder/wire_format/wire_reader_impl.h
- src/core/ext/transport/binder/wire_format/wire_writer.h
- src/core/lib/security/authorization/audit_logging.h
- src/cpp/client/client_stats_interceptor.h
- src/cpp/client/create_channel_internal.h
- src/cpp/client/secure_credentials.h
@ -6920,7 +6915,6 @@ targets:
- src/core/ext/transport/binder/wire_format/transaction.cc
- src/core/ext/transport/binder/wire_format/wire_reader_impl.cc
- src/core/ext/transport/binder/wire_format/wire_writer.cc
- src/core/lib/security/authorization/audit_logging.cc
- src/cpp/client/channel_cc.cc
- src/cpp/client/client_callback.cc
- src/cpp/client/client_context.cc
@ -8012,10 +8006,8 @@ targets:
gtest: true
build: test
language: c++
headers:
- src/core/lib/security/authorization/audit_logging.h
headers: []
src:
- src/core/lib/security/authorization/audit_logging.cc
- test/core/security/grpc_audit_logging_test.cc
deps:
- grpc_test_util
@ -12281,7 +12273,6 @@ targets:
- src/core/ext/transport/binder/wire_format/wire_reader.h
- src/core/ext/transport/binder/wire_format/wire_reader_impl.h
- src/core/ext/transport/binder/wire_format/wire_writer.h
- src/core/lib/security/authorization/audit_logging.h
- src/cpp/client/client_stats_interceptor.h
- src/cpp/client/create_channel_internal.h
- src/cpp/client/secure_credentials.h
@ -12313,7 +12304,6 @@ targets:
- src/core/ext/transport/binder/wire_format/transaction.cc
- src/core/ext/transport/binder/wire_format/wire_reader_impl.cc
- src/core/ext/transport/binder/wire_format/wire_writer.cc
- src/core/lib/security/authorization/audit_logging.cc
- src/cpp/client/channel_cc.cc
- src/cpp/client/client_callback.cc
- src/cpp/client/client_context.cc
@ -12596,7 +12586,6 @@ targets:
- src/core/ext/transport/binder/wire_format/wire_reader.h
- src/core/ext/transport/binder/wire_format/wire_reader_impl.h
- src/core/ext/transport/binder/wire_format/wire_writer.h
- src/core/lib/security/authorization/audit_logging.h
- src/cpp/client/client_stats_interceptor.h
- src/cpp/client/create_channel_internal.h
- src/cpp/client/secure_credentials.h
@ -12629,7 +12618,6 @@ targets:
- src/core/ext/transport/binder/wire_format/transaction.cc
- src/core/ext/transport/binder/wire_format/wire_reader_impl.cc
- src/core/ext/transport/binder/wire_format/wire_writer.cc
- src/core/lib/security/authorization/audit_logging.cc
- src/cpp/client/channel_cc.cc
- src/cpp/client/client_callback.cc
- src/cpp/client/client_context.cc
@ -12705,7 +12693,6 @@ targets:
- src/core/ext/transport/binder/wire_format/wire_reader.h
- src/core/ext/transport/binder/wire_format/wire_reader_impl.h
- src/core/ext/transport/binder/wire_format/wire_writer.h
- src/core/lib/security/authorization/audit_logging.h
- src/cpp/client/client_stats_interceptor.h
- src/cpp/client/create_channel_internal.h
- src/cpp/client/secure_credentials.h
@ -12738,7 +12725,6 @@ targets:
- src/core/ext/transport/binder/wire_format/transaction.cc
- src/core/ext/transport/binder/wire_format/wire_reader_impl.cc
- src/core/ext/transport/binder/wire_format/wire_writer.cc
- src/core/lib/security/authorization/audit_logging.cc
- src/cpp/client/channel_cc.cc
- src/cpp/client/client_callback.cc
- src/cpp/client/client_context.cc

1
config.m4 generated

@ -705,6 +705,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/resource_quota/resource_quota.cc \
src/core/lib/resource_quota/thread_quota.cc \
src/core/lib/resource_quota/trace.cc \
src/core/lib/security/authorization/audit_logging.cc \
src/core/lib/security/authorization/authorization_policy_provider_vtable.cc \
src/core/lib/security/authorization/evaluate_args.cc \
src/core/lib/security/authorization/grpc_authorization_engine.cc \

1
config.w32 generated

@ -670,6 +670,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\resource_quota\\resource_quota.cc " +
"src\\core\\lib\\resource_quota\\thread_quota.cc " +
"src\\core\\lib\\resource_quota\\trace.cc " +
"src\\core\\lib\\security\\authorization\\audit_logging.cc " +
"src\\core\\lib\\security\\authorization\\authorization_policy_provider_vtable.cc " +
"src\\core\\lib\\security\\authorization\\evaluate_args.cc " +
"src\\core\\lib\\security\\authorization\\grpc_authorization_engine.cc " +

1
gRPC-C++.podspec generated

@ -958,7 +958,6 @@ Pod::Spec.new do |s|
'src/core/lib/resource_quota/resource_quota.h',
'src/core/lib/resource_quota/thread_quota.h',
'src/core/lib/resource_quota/trace.h',
'src/core/lib/security/authorization/audit_logging.cc',
'src/core/lib/security/authorization/audit_logging.h',
'src/core/lib/security/authorization/authorization_engine.h',
'src/core/lib/security/authorization/authorization_policy_provider.h',

3
gRPC-Core.podspec generated

@ -1552,6 +1552,8 @@ Pod::Spec.new do |s|
'src/core/lib/resource_quota/thread_quota.h',
'src/core/lib/resource_quota/trace.cc',
'src/core/lib/resource_quota/trace.h',
'src/core/lib/security/authorization/audit_logging.cc',
'src/core/lib/security/authorization/audit_logging.h',
'src/core/lib/security/authorization/authorization_engine.h',
'src/core/lib/security/authorization/authorization_policy_provider.h',
'src/core/lib/security/authorization/authorization_policy_provider_vtable.cc',
@ -2701,6 +2703,7 @@ Pod::Spec.new do |s|
'src/core/lib/resource_quota/resource_quota.h',
'src/core/lib/resource_quota/thread_quota.h',
'src/core/lib/resource_quota/trace.h',
'src/core/lib/security/authorization/audit_logging.h',
'src/core/lib/security/authorization/authorization_engine.h',
'src/core/lib/security/authorization/authorization_policy_provider.h',
'src/core/lib/security/authorization/evaluate_args.h',

2
grpc.gemspec generated

@ -1458,6 +1458,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/resource_quota/thread_quota.h )
s.files += %w( src/core/lib/resource_quota/trace.cc )
s.files += %w( src/core/lib/resource_quota/trace.h )
s.files += %w( src/core/lib/security/authorization/audit_logging.cc )
s.files += %w( src/core/lib/security/authorization/audit_logging.h )
s.files += %w( src/core/lib/security/authorization/authorization_engine.h )
s.files += %w( src/core/lib/security/authorization/authorization_policy_provider.h )
s.files += %w( src/core/lib/security/authorization/authorization_policy_provider_vtable.cc )

2
grpc.gyp generated

@ -883,6 +883,7 @@
'src/core/lib/resource_quota/resource_quota.cc',
'src/core/lib/resource_quota/thread_quota.cc',
'src/core/lib/resource_quota/trace.cc',
'src/core/lib/security/authorization/audit_logging.cc',
'src/core/lib/security/authorization/authorization_policy_provider_vtable.cc',
'src/core/lib/security/authorization/evaluate_args.cc',
'src/core/lib/security/authorization/grpc_authorization_engine.cc',
@ -1506,7 +1507,6 @@
'src/core/ext/transport/binder/wire_format/transaction.cc',
'src/core/ext/transport/binder/wire_format/wire_reader_impl.cc',
'src/core/ext/transport/binder/wire_format/wire_writer.cc',
'src/core/lib/security/authorization/audit_logging.cc',
'src/cpp/client/channel_cc.cc',
'src/cpp/client/client_callback.cc',
'src/cpp/client/client_context.cc',

2
package.xml generated

@ -1440,6 +1440,8 @@
<file baseinstalldir="/" name="src/core/lib/resource_quota/thread_quota.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/resource_quota/trace.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/resource_quota/trace.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/audit_logging.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/audit_logging.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/authorization_engine.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/authorization_policy_provider.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/authorization_policy_provider_vtable.cc" role="src" />

@ -3292,6 +3292,7 @@ grpc_cc_library(
],
language = "c++",
deps = [
"grpc_audit_logging",
"grpc_authorization_base",
"grpc_matchers",
"resolved_address",

@ -722,6 +722,9 @@ const JsonLoaderInterface* RbacConfig::RbacPolicy::Rules::Policy::JsonLoader(
Rbac RbacConfig::RbacPolicy::Rules::TakeAsRbac() {
Rbac rbac;
// TODO(lwge): This is to fix msan failure for now. Add proper conversion once
// audit logging support is added.
rbac.audit_condition = Rbac::AuditCondition::kNone;
rbac.action = static_cast<Rbac::Action>(action);
for (auto& p : policies) {
rbac.policies.emplace(p.first, p.second.TakeAsRbacPolicy());

@ -20,10 +20,35 @@
#include <map>
#include <utility>
#include <grpc/support/log.h>
#include "src/core/lib/security/authorization/audit_logging.h"
#include "src/core/lib/security/authorization/authorization_engine.h"
namespace grpc_core {
using experimental::AuditContext;
using experimental::AuditLoggerRegistry;
namespace {
using Decision = AuthorizationEngine::Decision;
bool ShouldLog(const Decision& decision,
const Rbac::AuditCondition& condition) {
return condition == Rbac::AuditCondition::kOnDenyAndAllow ||
(decision.type == Decision::Type::kAllow &&
condition == Rbac::AuditCondition::kOnAllow) ||
(decision.type == Decision::Type::kDeny &&
condition == Rbac::AuditCondition::kOnDeny);
}
} // namespace
GrpcAuthorizationEngine::GrpcAuthorizationEngine(Rbac policy)
: action_(policy.action) {
: name_(std::move(policy.name)),
action_(policy.action),
audit_condition_(policy.audit_condition) {
for (auto& sub_policy : policy.policies) {
Policy policy;
policy.name = sub_policy.first;
@ -31,16 +56,29 @@ GrpcAuthorizationEngine::GrpcAuthorizationEngine(Rbac policy)
std::move(sub_policy.second));
policies_.push_back(std::move(policy));
}
for (auto& logger_config : policy.logger_configs) {
auto logger =
AuditLoggerRegistry::CreateAuditLogger(std::move(logger_config));
GPR_ASSERT(logger != nullptr);
audit_loggers_.push_back(std::move(logger));
}
}
GrpcAuthorizationEngine::GrpcAuthorizationEngine(
GrpcAuthorizationEngine&& other) noexcept
: action_(other.action_), policies_(std::move(other.policies_)) {}
: name_(std::move(other.name_)),
action_(other.action_),
policies_(std::move(other.policies_)),
audit_condition_(other.audit_condition_),
audit_loggers_(std::move(other.audit_loggers_)) {}
GrpcAuthorizationEngine& GrpcAuthorizationEngine::operator=(
GrpcAuthorizationEngine&& other) noexcept {
name_ = std::move(other.name_);
action_ = other.action_;
policies_ = std::move(other.policies_);
audit_condition_ = other.audit_condition_;
audit_loggers_ = std::move(other.audit_loggers_);
return *this;
}
@ -58,6 +96,13 @@ AuthorizationEngine::Decision GrpcAuthorizationEngine::Evaluate(
decision.type = (matches == (action_ == Rbac::Action::kAllow))
? Decision::Type::kAllow
: Decision::Type::kDeny;
if (ShouldLog(decision, audit_condition_)) {
for (auto& logger : audit_loggers_) {
logger->Log(AuditContext(args.GetPath(), args.GetSpiffeId(), name_,
decision.matching_policy_name,
decision.type == Decision::Type::kAllow));
}
}
return decision;
}

@ -23,6 +23,8 @@
#include <string>
#include <vector>
#include <grpc/grpc_audit_logging.h>
#include "src/core/lib/security/authorization/authorization_engine.h"
#include "src/core/lib/security/authorization/evaluate_args.h"
#include "src/core/lib/security/authorization/matchers.h"
@ -30,6 +32,8 @@
namespace grpc_core {
using experimental::AuditLogger;
// GrpcAuthorizationEngine can be either an Allow engine or Deny engine. This
// engine makes authorization decisions to Allow or Deny incoming RPC request
// based on permission and principal configs in the provided RBAC policy and the
@ -39,7 +43,8 @@ namespace grpc_core {
class GrpcAuthorizationEngine : public AuthorizationEngine {
public:
// Builds GrpcAuthorizationEngine without any policies.
explicit GrpcAuthorizationEngine(Rbac::Action action) : action_(action) {}
explicit GrpcAuthorizationEngine(Rbac::Action action)
: action_(action), audit_condition_(Rbac::AuditCondition::kNone) {}
// Builds GrpcAuthorizationEngine with allow/deny RBAC policy.
explicit GrpcAuthorizationEngine(Rbac policy);
@ -60,8 +65,12 @@ class GrpcAuthorizationEngine : public AuthorizationEngine {
std::string name;
std::unique_ptr<AuthorizationMatcher> matcher;
};
std::string name_;
Rbac::Action action_;
std::vector<Policy> policies_;
Rbac::AuditCondition audit_condition_;
std::vector<std::unique_ptr<AuditLogger>> audit_loggers_;
};
} // namespace grpc_core

@ -32,7 +32,10 @@ namespace grpc_core {
Rbac::Rbac(std::string name, Rbac::Action action,
std::map<std::string, Policy> policies)
: name(std::move(name)), action(action), policies(std::move(policies)) {}
: name(std::move(name)),
action(action),
policies(std::move(policies)),
audit_condition(Rbac::AuditCondition::kNone) {}
Rbac::Rbac(Rbac&& other) noexcept
: name(std::move(other.name)),

@ -679,6 +679,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/resource_quota/resource_quota.cc',
'src/core/lib/resource_quota/thread_quota.cc',
'src/core/lib/resource_quota/trace.cc',
'src/core/lib/security/authorization/audit_logging.cc',
'src/core/lib/security/authorization/authorization_policy_provider_vtable.cc',
'src/core/lib/security/authorization/evaluate_args.cc',
'src/core/lib/security/authorization/grpc_authorization_engine.cc',

@ -16,12 +16,107 @@
#include "src/core/lib/security/authorization/grpc_authorization_engine.h"
#include <memory>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <grpc/grpc_audit_logging.h>
#include <grpc/grpc_security_constants.h>
#include "src/core/lib/security/authorization/audit_logging.h"
#include "test/core/util/evaluate_args_test_util.h"
namespace grpc_core {
TEST(GrpcAuthorizationEngineTest, AllowEngineWithMatchingPolicy) {
namespace {
constexpr absl::string_view kLoggerName = "test_logger";
constexpr absl::string_view kPolicyName = "authz";
constexpr absl::string_view kSpiffeId = "spiffe://foo";
constexpr absl::string_view kRpcMethod = "/foo.Bar/Echo";
using experimental::AuditContext;
using experimental::AuditLogger;
using experimental::AuditLoggerFactory;
using experimental::AuditLoggerRegistry;
using experimental::RegisterAuditLoggerFactory;
// This test class copies the audit context.
struct TestAuditContext {
explicit TestAuditContext(const AuditContext& context)
: rpc_method(context.rpc_method()),
principal(context.principal()),
policy_name(context.policy_name()),
matched_rule(context.matched_rule()),
authorized(context.authorized()) {}
std::string rpc_method;
std::string principal;
std::string policy_name;
std::string matched_rule;
bool authorized;
};
class TestAuditLogger : public AuditLogger {
public:
explicit TestAuditLogger(
std::vector<std::unique_ptr<TestAuditContext>>* contexts)
: contexts_(contexts) {}
void Log(const AuditContext& context) override {
contexts_->push_back(std::make_unique<TestAuditContext>(context));
}
private:
std::vector<std::unique_ptr<TestAuditContext>>* contexts_;
};
class TestAuditLoggerFactory : public AuditLoggerFactory {
public:
class TestAuditLoggerConfig : public AuditLoggerFactory::Config {
absl::string_view name() const override { return kLoggerName; }
std::string ToString() const override { return ""; }
};
explicit TestAuditLoggerFactory(
std::vector<std::unique_ptr<TestAuditContext>>* contexts)
: contexts_(contexts) {}
absl::string_view name() const override { return kLoggerName; }
absl::StatusOr<std::unique_ptr<AuditLoggerFactory::Config>>
ParseAuditLoggerConfig(const Json&) override {
Crash("unreachable");
return nullptr;
}
std::unique_ptr<AuditLogger> CreateAuditLogger(
std::unique_ptr<AuditLoggerFactory::Config>) override {
return std::make_unique<TestAuditLogger>(contexts_);
}
private:
std::vector<std::unique_ptr<TestAuditContext>>* contexts_;
};
class GrpcAuthorizationEngineTest : public ::testing::Test {
protected:
void SetUp() override {
RegisterAuditLoggerFactory(
std::make_unique<TestAuditLoggerFactory>(&contexts_));
evaluate_args_util_.AddPairToMetadata(":path", kRpcMethod.data());
evaluate_args_util_.AddPropertyToAuthContext(
GRPC_PEER_SPIFFE_ID_PROPERTY_NAME, kSpiffeId.data());
}
void TearDown() override { AuditLoggerRegistry::TestOnlyResetRegistry(); }
std::vector<std::unique_ptr<TestAuditContext>> contexts_;
EvaluateArgsTestUtil evaluate_args_util_;
};
} // namespace
TEST_F(GrpcAuthorizationEngineTest, AllowEngineWithMatchingPolicy) {
Rbac::Policy policy1(
Rbac::Permission::MakeNotPermission(
Rbac::Permission::MakeAnyPermission()),
@ -39,7 +134,7 @@ TEST(GrpcAuthorizationEngineTest, AllowEngineWithMatchingPolicy) {
EXPECT_EQ(decision.matching_policy_name, "policy2");
}
TEST(GrpcAuthorizationEngineTest, AllowEngineWithNoMatchingPolicy) {
TEST_F(GrpcAuthorizationEngineTest, AllowEngineWithNoMatchingPolicy) {
Rbac::Policy policy1(
Rbac::Permission::MakeNotPermission(
Rbac::Permission::MakeAnyPermission()),
@ -54,7 +149,7 @@ TEST(GrpcAuthorizationEngineTest, AllowEngineWithNoMatchingPolicy) {
EXPECT_TRUE(decision.matching_policy_name.empty());
}
TEST(GrpcAuthorizationEngineTest, AllowEngineWithEmptyPolicies) {
TEST_F(GrpcAuthorizationEngineTest, AllowEngineWithEmptyPolicies) {
GrpcAuthorizationEngine engine(Rbac::Action::kAllow);
AuthorizationEngine::Decision decision =
engine.Evaluate(EvaluateArgs(nullptr, nullptr));
@ -62,7 +157,7 @@ TEST(GrpcAuthorizationEngineTest, AllowEngineWithEmptyPolicies) {
EXPECT_TRUE(decision.matching_policy_name.empty());
}
TEST(GrpcAuthorizationEngineTest, DenyEngineWithMatchingPolicy) {
TEST_F(GrpcAuthorizationEngineTest, DenyEngineWithMatchingPolicy) {
Rbac::Policy policy1(
Rbac::Permission::MakeNotPermission(
Rbac::Permission::MakeAnyPermission()),
@ -80,7 +175,7 @@ TEST(GrpcAuthorizationEngineTest, DenyEngineWithMatchingPolicy) {
EXPECT_EQ(decision.matching_policy_name, "policy2");
}
TEST(GrpcAuthorizationEngineTest, DenyEngineWithNoMatchingPolicy) {
TEST_F(GrpcAuthorizationEngineTest, DenyEngineWithNoMatchingPolicy) {
Rbac::Policy policy1(
Rbac::Permission::MakeNotPermission(
Rbac::Permission::MakeAnyPermission()),
@ -95,7 +190,7 @@ TEST(GrpcAuthorizationEngineTest, DenyEngineWithNoMatchingPolicy) {
EXPECT_TRUE(decision.matching_policy_name.empty());
}
TEST(GrpcAuthorizationEngineTest, DenyEngineWithEmptyPolicies) {
TEST_F(GrpcAuthorizationEngineTest, DenyEngineWithEmptyPolicies) {
GrpcAuthorizationEngine engine(Rbac::Action::kDeny);
AuthorizationEngine::Decision decision =
engine.Evaluate(EvaluateArgs(nullptr, nullptr));
@ -103,6 +198,209 @@ TEST(GrpcAuthorizationEngineTest, DenyEngineWithEmptyPolicies) {
EXPECT_TRUE(decision.matching_policy_name.empty());
}
TEST_F(GrpcAuthorizationEngineTest, AuditLoggerNoneNotInvokedOnAllowedRequest) {
Rbac::Policy policy1(Rbac::Permission::MakeAnyPermission(),
Rbac::Principal::MakeAnyPrincipal());
std::map<std::string, Rbac::Policy> policies;
policies["policy1"] = std::move(policy1);
Rbac rbac(std::string(kPolicyName), Rbac::Action::kAllow,
std::move(policies));
rbac.audit_condition = Rbac::AuditCondition::kNone;
rbac.logger_configs.push_back(
std::make_unique<TestAuditLoggerFactory::TestAuditLoggerConfig>());
GrpcAuthorizationEngine engine(std::move(rbac));
AuthorizationEngine::Decision decision =
engine.Evaluate(evaluate_args_util_.MakeEvaluateArgs());
EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kAllow);
EXPECT_EQ(decision.matching_policy_name, "policy1");
EXPECT_EQ(contexts_.size(), 0);
}
TEST_F(GrpcAuthorizationEngineTest, AuditLoggerNoneNotInvokedOnDeniedRequest) {
Rbac::Policy policy1(
Rbac::Permission::MakeNotPermission(
Rbac::Permission::MakeAnyPermission()),
Rbac::Principal::MakeNotPrincipal(Rbac::Principal::MakeAnyPrincipal()));
std::map<std::string, Rbac::Policy> policies;
policies["policy1"] = std::move(policy1);
Rbac rbac(std::string(kPolicyName), Rbac::Action::kAllow,
std::move(policies));
rbac.audit_condition = Rbac::AuditCondition::kNone;
rbac.logger_configs.push_back(
std::make_unique<TestAuditLoggerFactory::TestAuditLoggerConfig>());
GrpcAuthorizationEngine engine(std::move(rbac));
AuthorizationEngine::Decision decision =
engine.Evaluate(evaluate_args_util_.MakeEvaluateArgs());
EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny);
EXPECT_EQ(decision.matching_policy_name, "");
EXPECT_EQ(contexts_.size(), 0);
}
TEST_F(GrpcAuthorizationEngineTest, AuditLoggerOnDenyNotInvoked) {
Rbac::Policy policy1(Rbac::Permission::MakeAnyPermission(),
Rbac::Principal::MakeAnyPrincipal());
std::map<std::string, Rbac::Policy> policies;
policies["policy1"] = std::move(policy1);
Rbac rbac(std::string(kPolicyName), Rbac::Action::kAllow,
std::move(policies));
rbac.audit_condition = Rbac::AuditCondition::kOnDeny;
rbac.logger_configs.push_back(
std::make_unique<TestAuditLoggerFactory::TestAuditLoggerConfig>());
GrpcAuthorizationEngine engine(std::move(rbac));
AuthorizationEngine::Decision decision =
engine.Evaluate(evaluate_args_util_.MakeEvaluateArgs());
EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kAllow);
EXPECT_EQ(decision.matching_policy_name, "policy1");
EXPECT_EQ(contexts_.size(), 0);
}
TEST_F(GrpcAuthorizationEngineTest, AuditLoggerOnAllowNotInvoked) {
Rbac::Policy policy1(
Rbac::Permission::MakeNotPermission(
Rbac::Permission::MakeAnyPermission()),
Rbac::Principal::MakeNotPrincipal(Rbac::Principal::MakeAnyPrincipal()));
std::map<std::string, Rbac::Policy> policies;
policies["policy1"] = std::move(policy1);
Rbac rbac(std::string(kPolicyName), Rbac::Action::kAllow,
std::move(policies));
rbac.audit_condition = Rbac::AuditCondition::kOnAllow;
rbac.logger_configs.push_back(
std::make_unique<TestAuditLoggerFactory::TestAuditLoggerConfig>());
GrpcAuthorizationEngine engine(std::move(rbac));
AuthorizationEngine::Decision decision =
engine.Evaluate(evaluate_args_util_.MakeEvaluateArgs());
EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny);
EXPECT_EQ(decision.matching_policy_name, "");
EXPECT_EQ(contexts_.size(), 0);
}
TEST_F(GrpcAuthorizationEngineTest, AuditLoggerOnAllowInvoked) {
Rbac::Policy policy1(Rbac::Permission::MakeAnyPermission(),
Rbac::Principal::MakeAnyPrincipal());
std::map<std::string, Rbac::Policy> policies;
policies["policy1"] = std::move(policy1);
Rbac rbac(std::string(kPolicyName), Rbac::Action::kAllow,
std::move(policies));
rbac.audit_condition = Rbac::AuditCondition::kOnAllow;
rbac.logger_configs.push_back(
std::make_unique<TestAuditLoggerFactory::TestAuditLoggerConfig>());
GrpcAuthorizationEngine engine(std::move(rbac));
AuthorizationEngine::Decision decision =
engine.Evaluate(evaluate_args_util_.MakeEvaluateArgs());
EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kAllow);
EXPECT_EQ(decision.matching_policy_name, "policy1");
ASSERT_EQ(contexts_.size(), 1);
EXPECT_EQ(contexts_[0]->rpc_method, kRpcMethod);
EXPECT_EQ(contexts_[0]->principal, kSpiffeId);
EXPECT_EQ(contexts_[0]->policy_name, kPolicyName);
EXPECT_EQ(contexts_[0]->matched_rule, "policy1");
EXPECT_EQ(contexts_[0]->authorized, true);
}
TEST_F(GrpcAuthorizationEngineTest,
AuditLoggerOnDenyAndAllowInvokedWithAllowedRequest) {
Rbac::Policy policy1(Rbac::Permission::MakeAnyPermission(),
Rbac::Principal::MakeAnyPrincipal());
std::map<std::string, Rbac::Policy> policies;
policies["policy1"] = std::move(policy1);
Rbac rbac(std::string(kPolicyName), Rbac::Action::kAllow,
std::move(policies));
rbac.audit_condition = Rbac::AuditCondition::kOnDenyAndAllow;
rbac.logger_configs.push_back(
std::make_unique<TestAuditLoggerFactory::TestAuditLoggerConfig>());
GrpcAuthorizationEngine engine(std::move(rbac));
AuthorizationEngine::Decision decision =
engine.Evaluate(evaluate_args_util_.MakeEvaluateArgs());
EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kAllow);
EXPECT_EQ(decision.matching_policy_name, "policy1");
ASSERT_EQ(contexts_.size(), 1);
EXPECT_EQ(contexts_[0]->rpc_method, kRpcMethod);
EXPECT_EQ(contexts_[0]->principal, kSpiffeId);
EXPECT_EQ(contexts_[0]->policy_name, kPolicyName);
EXPECT_EQ(contexts_[0]->matched_rule, "policy1");
EXPECT_EQ(contexts_[0]->authorized, true);
}
TEST_F(GrpcAuthorizationEngineTest, AuditLoggerOnDenyInvoked) {
Rbac::Policy policy1(
Rbac::Permission::MakeNotPermission(
Rbac::Permission::MakeAnyPermission()),
Rbac::Principal::MakeNotPrincipal(Rbac::Principal::MakeAnyPrincipal()));
std::map<std::string, Rbac::Policy> policies;
policies["policy1"] = std::move(policy1);
Rbac rbac(std::string(kPolicyName), Rbac::Action::kAllow,
std::move(policies));
rbac.audit_condition = Rbac::AuditCondition::kOnDeny;
rbac.logger_configs.push_back(
std::make_unique<TestAuditLoggerFactory::TestAuditLoggerConfig>());
GrpcAuthorizationEngine engine(std::move(rbac));
AuthorizationEngine::Decision decision =
engine.Evaluate(evaluate_args_util_.MakeEvaluateArgs());
EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny);
EXPECT_EQ(decision.matching_policy_name, "");
ASSERT_EQ(contexts_.size(), 1);
EXPECT_EQ(contexts_[0]->rpc_method, kRpcMethod);
EXPECT_EQ(contexts_[0]->principal, kSpiffeId);
EXPECT_EQ(contexts_[0]->policy_name, kPolicyName);
EXPECT_EQ(contexts_[0]->matched_rule, "");
EXPECT_EQ(contexts_[0]->authorized, false);
}
TEST_F(GrpcAuthorizationEngineTest,
AuditLoggerOnDenyAndAllowInvokedWithDeniedRequest) {
Rbac::Policy policy1(
Rbac::Permission::MakeNotPermission(
Rbac::Permission::MakeAnyPermission()),
Rbac::Principal::MakeNotPrincipal(Rbac::Principal::MakeAnyPrincipal()));
std::map<std::string, Rbac::Policy> policies;
policies["policy1"] = std::move(policy1);
Rbac rbac(std::string(kPolicyName), Rbac::Action::kAllow,
std::move(policies));
rbac.audit_condition = Rbac::AuditCondition::kOnDenyAndAllow;
rbac.logger_configs.push_back(
std::make_unique<TestAuditLoggerFactory::TestAuditLoggerConfig>());
GrpcAuthorizationEngine engine(std::move(rbac));
AuthorizationEngine::Decision decision =
engine.Evaluate(evaluate_args_util_.MakeEvaluateArgs());
EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny);
EXPECT_EQ(decision.matching_policy_name, "");
ASSERT_EQ(contexts_.size(), 1);
EXPECT_EQ(contexts_[0]->rpc_method, kRpcMethod);
EXPECT_EQ(contexts_[0]->principal, kSpiffeId);
EXPECT_EQ(contexts_[0]->policy_name, kPolicyName);
EXPECT_EQ(contexts_[0]->matched_rule, "");
EXPECT_EQ(contexts_[0]->authorized, false);
}
TEST_F(GrpcAuthorizationEngineTest, MultipleAuditLoggerInvoked) {
Rbac::Policy policy1(
Rbac::Permission::MakeNotPermission(
Rbac::Permission::MakeAnyPermission()),
Rbac::Principal::MakeNotPrincipal(Rbac::Principal::MakeAnyPrincipal()));
std::map<std::string, Rbac::Policy> policies;
policies["policy1"] = std::move(policy1);
Rbac rbac(std::string(kPolicyName), Rbac::Action::kAllow,
std::move(policies));
rbac.audit_condition = Rbac::AuditCondition::kOnDenyAndAllow;
rbac.logger_configs.push_back(
std::make_unique<TestAuditLoggerFactory::TestAuditLoggerConfig>());
rbac.logger_configs.push_back(
std::make_unique<TestAuditLoggerFactory::TestAuditLoggerConfig>());
GrpcAuthorizationEngine engine(std::move(rbac));
AuthorizationEngine::Decision decision =
engine.Evaluate(evaluate_args_util_.MakeEvaluateArgs());
EXPECT_EQ(decision.type, AuthorizationEngine::Decision::Type::kDeny);
EXPECT_EQ(decision.matching_policy_name, "");
ASSERT_EQ(contexts_.size(), 2);
for (const auto& context : contexts_) {
EXPECT_EQ(context->rpc_method, kRpcMethod);
EXPECT_EQ(context->principal, kSpiffeId);
EXPECT_EQ(context->policy_name, kPolicyName);
EXPECT_EQ(context->matched_rule, "");
EXPECT_EQ(context->authorized, false);
}
}
} // namespace grpc_core
int main(int argc, char** argv) {

@ -2235,6 +2235,8 @@ src/core/lib/resource_quota/thread_quota.cc \
src/core/lib/resource_quota/thread_quota.h \
src/core/lib/resource_quota/trace.cc \
src/core/lib/resource_quota/trace.h \
src/core/lib/security/authorization/audit_logging.cc \
src/core/lib/security/authorization/audit_logging.h \
src/core/lib/security/authorization/authorization_engine.h \
src/core/lib/security/authorization/authorization_policy_provider.h \
src/core/lib/security/authorization/authorization_policy_provider_vtable.cc \

Loading…
Cancel
Save