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

[Audit Logging] Custom audit logger parsing in xDS registry. #32970

Merged
merged 35 commits into from
May 17, 2023
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
4e6e356
Add third_party logger config conversion in xDS audit logger registry.
rockspore Apr 28, 2023
4aec3b7
Automated change: Fix sanity tests
rockspore Apr 28, 2023
13f4442
Merge pull request #17 from rockspore/create-pull-request/patch-4e6e356
rockspore Apr 28, 2023
6d37605
return empty json on error
rockspore Apr 28, 2023
16bd834
stdout audit logger impl
rockspore May 5, 2023
f8f5ee1
generate projects
rockspore May 5, 2023
195f90f
Automated change: Fix sanity tests
rockspore May 5, 2023
1c224f3
Merge pull request #21 from rockspore/create-pull-request/patch-f8f5ee1
rockspore May 5, 2023
5cb67df
address PR comments
rockspore May 5, 2023
fc13177
constexpr
rockspore May 5, 2023
3cbd452
Merge branch 'master' of github.com:grpc/grpc into stdout-logger
rockspore May 12, 2023
1064479
switch to public json hdr
rockspore May 12, 2023
db15d5c
sanity
rockspore May 12, 2023
4ecbc71
Automated change: Fix sanity tests
rockspore May 12, 2023
5c0fc5b
Merge pull request #23 from rockspore/create-pull-request/patch-db15d5c
rockspore May 12, 2023
defee80
address PR comments
rockspore May 12, 2023
6092130
fix build
rockspore May 12, 2023
eedd236
Automated change: Fix sanity tests
rockspore May 12, 2023
2738e47
log in seconds
rockspore May 15, 2023
f6427bb
Merge pull request #24 from rockspore/create-pull-request/patch-6092130
rockspore May 15, 2023
7c765ee
address PR comments
rockspore May 15, 2023
aca75f2
nanosecond
rockspore May 15, 2023
82a2406
allow equal time
rockspore May 16, 2023
ebddd57
Merge branch 'master' of github.com:grpc/grpc into xds-registry
rockspore May 16, 2023
f333b8b
Merge branch 'stdout-logger' of github.com:rockspore/grpc into xds-re…
rockspore May 16, 2023
a89fa3f
use new Json APIs
rockspore May 16, 2023
fc994c5
Merge branch 'master' of github.com:grpc/grpc into xds-registry
rockspore May 16, 2023
b5e1962
validate config for built-in loggers
rockspore May 16, 2023
e9e96b6
Automated change: Fix sanity tests
rockspore May 16, 2023
803e4da
Merge pull request #26 from rockspore/create-pull-request/patch-b5e1962
rockspore May 16, 2023
1f58adf
use match
rockspore May 17, 2023
e76be97
Merge branch 'xds-registry' of github.com:rockspore/grpc into xds-reg…
rockspore May 17, 2023
8a0fa4e
fix test
rockspore May 17, 2023
9b21f69
Automated change: Fix sanity tests
rockspore May 17, 2023
cf7d08c
Merge pull request #27 from rockspore/create-pull-request/patch-8a0fa4e
rockspore May 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/core/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -4067,6 +4067,7 @@ grpc_cc_library(
"envoy_type_upb",
"error",
"google_rpc_status_upb",
"grpc_audit_logging",
"grpc_fake_credentials",
"grpc_fault_injection_filter",
"grpc_lb_xds_channel_args",
Expand Down
41 changes: 30 additions & 11 deletions src/core/ext/xds/xds_audit_logger_registry.cc
markdroth marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -18,34 +18,40 @@

#include "src/core/ext/xds/xds_audit_logger_registry.h"

#include <string>
#include <utility>

#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "absl/types/variant.h"
#include "envoy/config/core/v3/extension.upb.h"
#include "envoy/config/rbac/v3/rbac.upb.h"

#include <grpc/support/json.h>

#include "src/core/ext/xds/xds_common_types.h"
#include "src/core/lib/gprpp/validation_errors.h"
#include "src/core/lib/json/json.h"
#include "src/core/lib/security/authorization/audit_logging.h"

namespace grpc_core {

namespace {

using experimental::AuditLoggerRegistry;

class StdoutLoggerConfigFactory : public XdsAuditLoggerRegistry::ConfigFactory {
public:
Json::Object ConvertXdsAuditLoggerConfig(
const XdsResourceType::DecodeContext& /*context*/,
absl::string_view /*configuration*/,
ValidationErrors* /*errors*/) override {
return Json::Object{{"stdout_logger", Json::FromObject({})}};
// Stdout logger has no configuration right now. So we don't process the
// config protobuf.
return {};
}

absl::string_view type() override { return Type(); }
absl::string_view name() override { return "stdout_logger"; }

static absl::string_view Type() {
return "envoy.extensions.rbac.audit_loggers.stream.v3.StdoutAuditLog";
Expand Down Expand Up @@ -86,17 +92,30 @@ Json XdsAuditLoggerRegistry::ConvertXdsAuditLoggerConfig(
auto config_factory_it =
audit_logger_config_factories_.find(extension->type);
if (config_factory_it != audit_logger_config_factories_.end()) {
// TODO(lwge): Parse the config with the gRPC audit logger registry.
return Json::FromObject(
auto json_config = Json::FromObject(
config_factory_it->second->ConvertXdsAuditLoggerConfig(
context, *serialized_value, errors));
auto result = AuditLoggerRegistry::ParseConfig(
markdroth marked this conversation as resolved.
Show resolved Hide resolved
config_factory_it->second->name(), json_config);
if (!result.ok()) {
errors->AddError(result.status().message());
return Json();
}
return Json::FromObject(
{{std::string(config_factory_it->second->name()), json_config}});
}
}
// TODO(lwge): Check for third-party audit logger type. For now, we disallow
// it by rejecting TypedStruct entries.
if (absl::get_if<Json>(&extension->value) != nullptr) {
errors->AddError("third-party audit logger is not supported");
return Json();
// Check for custom audit logger type.
Json* json = absl::get_if<Json>(&extension->value);
if (json != nullptr &&
AuditLoggerRegistry::FactoryExists(extension->type)) {
auto result = AuditLoggerRegistry::ParseConfig(extension->type, *json);
if (!result.ok()) {
errors->AddError(result.status().message());
return Json();
}
return Json::FromObject(
{{std::string(extension->type), std::move(*json)}});
}
}
// Add validation error only if the config is not marked optional.
Expand Down
3 changes: 3 additions & 0 deletions src/core/ext/xds/xds_audit_logger_registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ class XdsAuditLoggerRegistry {
virtual Json::Object ConvertXdsAuditLoggerConfig(
const XdsResourceType::DecodeContext& context,
absl::string_view configuration, ValidationErrors* errors) = 0;
// The full proto message name for the logger config.
virtual absl::string_view type() = 0;
// The logger name used for the gRPC registry.
virtual absl::string_view name() = 0;
};

XdsAuditLoggerRegistry();
Expand Down
1 change: 1 addition & 0 deletions test/core/xds/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ grpc_cc_test(
deps = [
"//:gpr",
"//:grpc",
"//src/core:grpc_audit_logging",
"//src/proto/grpc/testing/xds/v3:audit_logger_stream_proto",
"//src/proto/grpc/testing/xds/v3:rbac_proto",
"//src/proto/grpc/testing/xds/v3:typed_struct_proto",
Expand Down
75 changes: 66 additions & 9 deletions test/core/xds/xds_audit_logger_registry_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,32 @@

#include "src/core/ext/xds/xds_audit_logger_registry.h"

#include <stdint.h>

#include <initializer_list>
#include <memory>
#include <string>

#include <google/protobuf/any.pb.h>

#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "envoy/config/rbac/v3/rbac.upb.h"
#include "google/protobuf/struct.pb.h"
#include "gtest/gtest.h"
#include "upb/reflection/def.hpp"
#include "upb/upb.hpp"

#include <grpc/grpc.h>
#include <grpc/grpc_audit_logging.h>

#include "src/core/ext/xds/xds_bootstrap_grpc.h"
#include "src/core/lib/gprpp/crash.h"
#include "src/core/lib/json/json.h"
#include "src/core/lib/json/json_writer.h"
#include "src/core/lib/security/authorization/audit_logging.h"
#include "src/proto/grpc/testing/xds/v3/audit_logger_stream.pb.h"
#include "src/proto/grpc/testing/xds/v3/extension.pb.h"
#include "src/proto/grpc/testing/xds/v3/rbac.pb.h"
Expand All @@ -43,11 +54,16 @@ namespace grpc_core {
namespace testing {
namespace {

using experimental::AuditLogger;
using experimental::AuditLoggerFactory;
using experimental::AuditLoggerRegistry;
using AuditLoggerConfigProto =
::envoy::config::rbac::v3::RBAC::AuditLoggingOptions::AuditLoggerConfig;
using ::envoy::extensions::rbac::audit_loggers::stream::v3::StdoutAuditLog;
using ::xds::type::v3::TypedStruct;

constexpr absl::string_view kName = "test_logger";

absl::StatusOr<std::string> ConvertAuditLoggerConfig(
const AuditLoggerConfigProto& config) {
std::string serialized_config = config.SerializeAsString();
Expand All @@ -69,11 +85,38 @@ absl::StatusOr<std::string> ConvertAuditLoggerConfig(
return JsonDump(config_json);
}

class TestAuditLoggerFactory : public AuditLoggerFactory {
public:
absl::string_view name() const override { return kName; }
absl::StatusOr<std::unique_ptr<AuditLoggerFactory::Config>>
ParseAuditLoggerConfig(const Json& json) override {
if (json.object().find("bad") != json.object().end()) {
return absl::InvalidArgumentError("invalid test_logger config");
}
return nullptr;
}
std::unique_ptr<AuditLogger> CreateAuditLogger(
std::unique_ptr<AuditLoggerFactory::Config>) override {
Crash("unreachable");
return nullptr;
}
};

class XdsAuditLoggerRegistryTest : public ::testing::Test {
protected:
void SetUp() override {
AuditLoggerRegistry::RegisterFactory(
std::make_unique<TestAuditLoggerFactory>());
}

void TearDown() override { AuditLoggerRegistry::TestOnlyResetRegistry(); }
};

//
// StdoutLoggerTest
//

TEST(StdoutLoggerTest, Basic) {
TEST(StdoutLoggerTest, BasicStdoutLogger) {
AuditLoggerConfigProto config;
config.mutable_audit_logger()->mutable_typed_config()->PackFrom(
StdoutAuditLog());
Expand All @@ -86,34 +129,48 @@ TEST(StdoutLoggerTest, Basic) {
// ThirdPartyLoggerTest
//

TEST(XdsAuditLoggerRegistryTest, ThirdPartyLogger) {
TEST_F(XdsAuditLoggerRegistryTest, ValidThirdPartyLogger) {
AuditLoggerConfigProto config;
TypedStruct logger;
logger.set_type_url(absl::StrFormat("myorg/foo/bar/%s", kName));
auto* fields = logger.mutable_value()->mutable_fields();
(*fields)["foo"].set_string_value("bar");
config.mutable_audit_logger()->mutable_typed_config()->PackFrom(logger);
auto result = ConvertAuditLoggerConfig(config);
ASSERT_TRUE(result.ok()) << result.status();
EXPECT_EQ(*result, "{\"test_logger\":{\"foo\":\"bar\"}}");
}

TEST_F(XdsAuditLoggerRegistryTest, InvalidThirdPartyLoggerConfig) {
AuditLoggerConfigProto config;
TypedStruct logger;
logger.set_type_url("myorg/foo/bar/test.UnknownAuditLogger");
logger.set_type_url(absl::StrFormat("myorg/foo/bar/%s", kName));
auto* fields = logger.mutable_value()->mutable_fields();
(*fields)["bad"].set_string_value("true");
config.mutable_audit_logger()->mutable_typed_config()->PackFrom(logger);
auto result = ConvertAuditLoggerConfig(config);
EXPECT_EQ(result.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(result.status().message(),
"validation errors: "
"[field:audit_logger.typed_config.value"
"[xds.type.v3.TypedStruct].value[test.UnknownAuditLogger] "
"error:third-party audit logger is not supported]")
"[xds.type.v3.TypedStruct].value[test_logger] "
"error:invalid test_logger config]")
<< result.status();
}

//
// XdsAuditLoggerRegistryTest
//

TEST(XdsAuditLoggerRegistryTest, EmptyAuditLoggerConfig) {
TEST_F(XdsAuditLoggerRegistryTest, EmptyAuditLoggerConfig) {
auto result = ConvertAuditLoggerConfig(AuditLoggerConfigProto());
EXPECT_EQ(result.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(result.status().message(),
"validation errors: [field:audit_logger error:field not present]")
<< result.status();
}

TEST(XdsAuditLoggerRegistryTest, MissingTypedConfig) {
TEST_F(XdsAuditLoggerRegistryTest, MissingTypedConfig) {
AuditLoggerConfigProto config;
config.mutable_audit_logger();
auto result = ConvertAuditLoggerConfig(config);
Expand All @@ -124,7 +181,7 @@ TEST(XdsAuditLoggerRegistryTest, MissingTypedConfig) {
<< result.status();
}

TEST(XdsAuditLoggerRegistryTest, NoSupportedType) {
TEST_F(XdsAuditLoggerRegistryTest, NoSupportedType) {
AuditLoggerConfigProto config;
config.mutable_audit_logger()->mutable_typed_config()->PackFrom(
AuditLoggerConfigProto());
Expand All @@ -136,7 +193,7 @@ TEST(XdsAuditLoggerRegistryTest, NoSupportedType) {
<< result.status();
}

TEST(XdsAuditLoggerRegistryTest, NoSupportedTypeButIsOptional) {
TEST_F(XdsAuditLoggerRegistryTest, NoSupportedTypeButIsOptional) {
AuditLoggerConfigProto config;
config.mutable_audit_logger()->mutable_typed_config()->PackFrom(
AuditLoggerConfigProto());
Expand Down