[Audit Logging] Stdout logger implementation (#33026)

The logger uses `absl::FPrintF` to write to stdout. After reading a
number of sources online, I got the impression that `std::fwrite` which
is used by `absl::FPrintF` is atomic so there is no locking required
here.

---------

Co-authored-by: rockspore <rockspore@users.noreply.github.com>
pull/33147/head
Luwei Ge 2 years ago committed by GitHub
parent 7c98b91091
commit 6df358cf6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CMakeLists.txt
  2. 2
      Makefile
  3. 4
      build_autogenerated.yaml
  4. 1
      config.m4
  5. 1
      config.w32
  6. 2
      gRPC-C++.podspec
  7. 3
      gRPC-Core.podspec
  8. 2
      grpc.gemspec
  9. 2
      grpc.gyp
  10. 2
      package.xml
  11. 3
      src/core/BUILD
  12. 8
      src/core/lib/security/authorization/audit_logging.cc
  13. 3
      src/core/lib/security/authorization/audit_logging.h
  14. 75
      src/core/lib/security/authorization/stdout_logger.cc
  15. 60
      src/core/lib/security/authorization/stdout_logger.h
  16. 1
      src/python/grpcio/grpc_core_dependencies.py
  17. 60
      test/core/security/grpc_audit_logging_test.cc
  18. 2
      tools/doxygen/Doxyfile.c++.internal
  19. 2
      tools/doxygen/Doxyfile.core.internal

2
CMakeLists.txt generated

@ -2211,6 +2211,7 @@ add_library(grpc
src/core/lib/security/authorization/grpc_server_authz_filter.cc
src/core/lib/security/authorization/matchers.cc
src/core/lib/security/authorization/rbac_policy.cc
src/core/lib/security/authorization/stdout_logger.cc
src/core/lib/security/certificate_provider/certificate_provider_registry.cc
src/core/lib/security/context/security_context.cc
src/core/lib/security/credentials/alts/alts_credentials.cc
@ -4438,6 +4439,7 @@ add_library(grpc_authorization_provider
src/core/lib/security/authorization/matchers.cc
src/core/lib/security/authorization/rbac_policy.cc
src/core/lib/security/authorization/rbac_translator.cc
src/core/lib/security/authorization/stdout_logger.cc
src/core/lib/security/certificate_provider/certificate_provider_registry.cc
src/core/lib/security/context/security_context.cc
src/core/lib/security/credentials/alts/check_gcp_environment.cc

2
Makefile generated

@ -1592,6 +1592,7 @@ LIBGRPC_SRC = \
src/core/lib/security/authorization/grpc_server_authz_filter.cc \
src/core/lib/security/authorization/matchers.cc \
src/core/lib/security/authorization/rbac_policy.cc \
src/core/lib/security/authorization/stdout_logger.cc \
src/core/lib/security/certificate_provider/certificate_provider_registry.cc \
src/core/lib/security/context/security_context.cc \
src/core/lib/security/credentials/alts/alts_credentials.cc \
@ -3372,6 +3373,7 @@ 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)
src/core/lib/security/authorization/stdout_logger.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/alts/alts_credentials.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/channel_creds_registry_init.cc: $(OPENSSL_DEP)
src/core/lib/security/credentials/external/aws_external_account_credentials.cc: $(OPENSSL_DEP)

@ -881,6 +881,7 @@ libs:
- src/core/lib/security/authorization/grpc_server_authz_filter.h
- src/core/lib/security/authorization/matchers.h
- src/core/lib/security/authorization/rbac_policy.h
- src/core/lib/security/authorization/stdout_logger.h
- src/core/lib/security/certificate_provider/certificate_provider_factory.h
- src/core/lib/security/certificate_provider/certificate_provider_registry.h
- src/core/lib/security/context/security_context.h
@ -1639,6 +1640,7 @@ libs:
- src/core/lib/security/authorization/grpc_server_authz_filter.cc
- src/core/lib/security/authorization/matchers.cc
- src/core/lib/security/authorization/rbac_policy.cc
- src/core/lib/security/authorization/stdout_logger.cc
- src/core/lib/security/certificate_provider/certificate_provider_registry.cc
- src/core/lib/security/context/security_context.cc
- src/core/lib/security/credentials/alts/alts_credentials.cc
@ -3742,6 +3744,7 @@ libs:
- src/core/lib/security/authorization/matchers.h
- src/core/lib/security/authorization/rbac_policy.h
- src/core/lib/security/authorization/rbac_translator.h
- src/core/lib/security/authorization/stdout_logger.h
- src/core/lib/security/certificate_provider/certificate_provider_factory.h
- src/core/lib/security/certificate_provider/certificate_provider_registry.h
- src/core/lib/security/context/security_context.h
@ -3995,6 +3998,7 @@ libs:
- src/core/lib/security/authorization/matchers.cc
- src/core/lib/security/authorization/rbac_policy.cc
- src/core/lib/security/authorization/rbac_translator.cc
- src/core/lib/security/authorization/stdout_logger.cc
- src/core/lib/security/certificate_provider/certificate_provider_registry.cc
- src/core/lib/security/context/security_context.cc
- src/core/lib/security/credentials/alts/check_gcp_environment.cc

1
config.m4 generated

@ -717,6 +717,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/security/authorization/grpc_server_authz_filter.cc \
src/core/lib/security/authorization/matchers.cc \
src/core/lib/security/authorization/rbac_policy.cc \
src/core/lib/security/authorization/stdout_logger.cc \
src/core/lib/security/certificate_provider/certificate_provider_registry.cc \
src/core/lib/security/context/security_context.cc \
src/core/lib/security/credentials/alts/alts_credentials.cc \

1
config.w32 generated

@ -682,6 +682,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\security\\authorization\\grpc_server_authz_filter.cc " +
"src\\core\\lib\\security\\authorization\\matchers.cc " +
"src\\core\\lib\\security\\authorization\\rbac_policy.cc " +
"src\\core\\lib\\security\\authorization\\stdout_logger.cc " +
"src\\core\\lib\\security\\certificate_provider\\certificate_provider_registry.cc " +
"src\\core\\lib\\security\\context\\security_context.cc " +
"src\\core\\lib\\security\\credentials\\alts\\alts_credentials.cc " +

2
gRPC-C++.podspec generated

@ -974,6 +974,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/authorization/grpc_server_authz_filter.h',
'src/core/lib/security/authorization/matchers.h',
'src/core/lib/security/authorization/rbac_policy.h',
'src/core/lib/security/authorization/stdout_logger.h',
'src/core/lib/security/certificate_provider/certificate_provider_factory.h',
'src/core/lib/security/certificate_provider/certificate_provider_registry.h',
'src/core/lib/security/context/security_context.h',
@ -2010,6 +2011,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/authorization/grpc_server_authz_filter.h',
'src/core/lib/security/authorization/matchers.h',
'src/core/lib/security/authorization/rbac_policy.h',
'src/core/lib/security/authorization/stdout_logger.h',
'src/core/lib/security/certificate_provider/certificate_provider_factory.h',
'src/core/lib/security/certificate_provider/certificate_provider_registry.h',
'src/core/lib/security/context/security_context.h',

3
gRPC-Core.podspec generated

@ -1581,6 +1581,8 @@ Pod::Spec.new do |s|
'src/core/lib/security/authorization/matchers.h',
'src/core/lib/security/authorization/rbac_policy.cc',
'src/core/lib/security/authorization/rbac_policy.h',
'src/core/lib/security/authorization/stdout_logger.cc',
'src/core/lib/security/authorization/stdout_logger.h',
'src/core/lib/security/certificate_provider/certificate_provider_factory.h',
'src/core/lib/security/certificate_provider/certificate_provider_registry.cc',
'src/core/lib/security/certificate_provider/certificate_provider_registry.h',
@ -2735,6 +2737,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/authorization/grpc_server_authz_filter.h',
'src/core/lib/security/authorization/matchers.h',
'src/core/lib/security/authorization/rbac_policy.h',
'src/core/lib/security/authorization/stdout_logger.h',
'src/core/lib/security/certificate_provider/certificate_provider_factory.h',
'src/core/lib/security/certificate_provider/certificate_provider_registry.h',
'src/core/lib/security/context/security_context.h',

2
grpc.gemspec generated

@ -1487,6 +1487,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/authorization/matchers.h )
s.files += %w( src/core/lib/security/authorization/rbac_policy.cc )
s.files += %w( src/core/lib/security/authorization/rbac_policy.h )
s.files += %w( src/core/lib/security/authorization/stdout_logger.cc )
s.files += %w( src/core/lib/security/authorization/stdout_logger.h )
s.files += %w( src/core/lib/security/certificate_provider/certificate_provider_factory.h )
s.files += %w( src/core/lib/security/certificate_provider/certificate_provider_registry.cc )
s.files += %w( src/core/lib/security/certificate_provider/certificate_provider_registry.h )

2
grpc.gyp generated

@ -895,6 +895,7 @@
'src/core/lib/security/authorization/grpc_server_authz_filter.cc',
'src/core/lib/security/authorization/matchers.cc',
'src/core/lib/security/authorization/rbac_policy.cc',
'src/core/lib/security/authorization/stdout_logger.cc',
'src/core/lib/security/certificate_provider/certificate_provider_registry.cc',
'src/core/lib/security/context/security_context.cc',
'src/core/lib/security/credentials/alts/alts_credentials.cc',
@ -1900,6 +1901,7 @@
'src/core/lib/security/authorization/matchers.cc',
'src/core/lib/security/authorization/rbac_policy.cc',
'src/core/lib/security/authorization/rbac_translator.cc',
'src/core/lib/security/authorization/stdout_logger.cc',
'src/core/lib/security/certificate_provider/certificate_provider_registry.cc',
'src/core/lib/security/context/security_context.cc',
'src/core/lib/security/credentials/alts/check_gcp_environment.cc',

2
package.xml generated

@ -1469,6 +1469,8 @@
<file baseinstalldir="/" name="src/core/lib/security/authorization/matchers.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/rbac_policy.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/rbac_policy.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/stdout_logger.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/authorization/stdout_logger.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/certificate_provider/certificate_provider_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/certificate_provider/certificate_provider_registry.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/certificate_provider/certificate_provider_registry.h" role="src" />

@ -2777,9 +2777,11 @@ grpc_cc_library(
name = "grpc_audit_logging",
srcs = [
"lib/security/authorization/audit_logging.cc",
"lib/security/authorization/stdout_logger.cc",
],
hdrs = [
"lib/security/authorization/audit_logging.h",
"lib/security/authorization/stdout_logger.h",
],
external_deps = [
"absl/base:core_headers",
@ -2787,6 +2789,7 @@ grpc_cc_library(
"absl/status:statusor",
"absl/strings",
"absl/strings:str_format",
"absl/time",
],
deps = [
"//:gpr",

@ -31,9 +31,11 @@
#include "absl/strings/string_view.h"
#include <grpc/grpc_audit_logging.h>
#include <grpc/support/json.h>
#include <grpc/support/log.h>
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/security/authorization/stdout_logger.h"
namespace grpc_core {
namespace experimental {
@ -42,6 +44,12 @@ Mutex* AuditLoggerRegistry::mu = new Mutex();
AuditLoggerRegistry* AuditLoggerRegistry::registry = new AuditLoggerRegistry();
AuditLoggerRegistry::AuditLoggerRegistry() {
auto factory = std::make_unique<StdoutAuditLoggerFactory>();
absl::string_view name = factory->name();
GPR_ASSERT(logger_factories_map_.emplace(name, std::move(factory)).second);
}
void AuditLoggerRegistry::RegisterFactory(
std::unique_ptr<AuditLoggerFactory> factory) {
GPR_ASSERT(factory != nullptr);

@ -56,8 +56,7 @@ class AuditLoggerRegistry {
static void TestOnlyResetRegistry();
private:
// TODO(lwge): Add built-in logger registrations once avaialble.
AuditLoggerRegistry() = default;
AuditLoggerRegistry();
static Mutex* mu;

@ -0,0 +1,75 @@
// Copyright 2023 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <grpc/support/port_platform.h>
#include "src/core/lib/security/authorization/stdout_logger.h"
#include <cstdio>
#include <initializer_list>
#include <memory>
#include <string>
#include "absl/status/statusor.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include <grpc/grpc_audit_logging.h>
#include <grpc/support/json.h>
#include <grpc/support/log.h>
namespace grpc_core {
namespace experimental {
namespace {
constexpr absl::string_view kName = "stdout_logger";
constexpr char kLogFormat[] =
"{\"grpc_audit_log\":{\"timestamp\":\"%s\",\"rpc_method\":\"%s\","
"\"principal\":\"%s\",\"policy_name\":\"%s\",\"matched_rule\":\"%s\","
"\"authorized\":%s}}\n";
} // namespace
void StdoutAuditLogger::Log(const AuditContext& context) {
absl::FPrintF(stdout, kLogFormat, absl::FormatTime(absl::Now()),
context.rpc_method(), context.principal(),
context.policy_name(), context.matched_rule(),
context.authorized() ? "true" : "false");
}
absl::string_view StdoutAuditLoggerFactory::Config::name() const {
return kName;
}
std::string StdoutAuditLoggerFactory::Config::ToString() const { return "{}"; }
absl::string_view StdoutAuditLoggerFactory::name() const { return kName; }
absl::StatusOr<std::unique_ptr<AuditLoggerFactory::Config>>
StdoutAuditLoggerFactory::ParseAuditLoggerConfig(const Json&) {
return std::make_unique<StdoutAuditLoggerFactory::Config>();
}
std::unique_ptr<AuditLogger> StdoutAuditLoggerFactory::CreateAuditLogger(
std::unique_ptr<AuditLoggerFactory::Config> config) {
// Sanity check.
GPR_ASSERT(config != nullptr && config->name() == name());
return std::make_unique<StdoutAuditLogger>();
}
} // namespace experimental
} // namespace grpc_core

@ -0,0 +1,60 @@
// Copyright 2023 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_SRC_CORE_LIB_SECURITY_AUTHORIZATION_STDOUT_LOGGER_H
#define GRPC_SRC_CORE_LIB_SECURITY_AUTHORIZATION_STDOUT_LOGGER_H
#include <grpc/support/port_platform.h>
#include <memory>
#include <string>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include <grpc/grpc_audit_logging.h>
#include <grpc/support/json.h>
namespace grpc_core {
namespace experimental {
class StdoutAuditLogger : public AuditLogger {
public:
StdoutAuditLogger() = default;
void Log(const AuditContext&) override;
};
class StdoutAuditLoggerFactory : public AuditLoggerFactory {
public:
class Config : public AuditLoggerFactory::Config {
public:
Config() = default;
absl::string_view name() const override;
std::string ToString() const override;
};
StdoutAuditLoggerFactory() = default;
absl::string_view name() const override;
absl::StatusOr<std::unique_ptr<AuditLoggerFactory::Config>>
ParseAuditLoggerConfig(const Json& json) override;
std::unique_ptr<AuditLogger> CreateAuditLogger(
std::unique_ptr<AuditLoggerFactory::Config>) override;
};
} // namespace experimental
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_SECURITY_AUTHORIZATION_STDOUT_LOGGER_H

@ -691,6 +691,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/security/authorization/grpc_server_authz_filter.cc',
'src/core/lib/security/authorization/matchers.cc',
'src/core/lib/security/authorization/rbac_policy.cc',
'src/core/lib/security/authorization/stdout_logger.cc',
'src/core/lib/security/certificate_provider/certificate_provider_registry.cc',
'src/core/lib/security/context/security_context.cc',
'src/core/lib/security/credentials/alts/alts_credentials.cc',

@ -25,11 +25,16 @@
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/numbers.h"
#include "absl/strings/string_view.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include <grpc/grpc_audit_logging.h>
#include "src/core/lib/json/json.h"
#include "src/core/lib/json/json_reader.h"
#include "src/core/lib/json/json_writer.h"
#include "src/core/lib/security/authorization/audit_logging.h"
#include "test/core/util/test_config.h"
#include "test/core/util/tls_utils.h"
@ -71,7 +76,7 @@ class TestAuditLoggerFactory : public AuditLoggerFactory {
}
};
class AuditLoggingTest : public ::testing::Test {
class AuditLoggerRegistryTest : public ::testing::Test {
protected:
void SetUp() override {
RegisterAuditLoggerFactory(std::make_unique<TestAuditLoggerFactory>());
@ -81,14 +86,18 @@ class AuditLoggingTest : public ::testing::Test {
} // namespace
TEST_F(AuditLoggingTest, SuccessfulLoggerCreation) {
//
// AuditLoggerRegistryTest
//
TEST_F(AuditLoggerRegistryTest, SuccessfulLoggerCreation) {
auto result = AuditLoggerRegistry::ParseConfig(kName, Json());
ASSERT_TRUE(result.ok());
ASSERT_NE(AuditLoggerRegistry::CreateAuditLogger(std::move(result.value())),
nullptr);
}
TEST_F(AuditLoggingTest, UnknownLogger) {
TEST_F(AuditLoggerRegistryTest, UnknownLogger) {
auto result = AuditLoggerRegistry::ParseConfig("unknown_logger", Json());
EXPECT_EQ(result.status().code(), absl::StatusCode::kNotFound);
EXPECT_EQ(result.status().message(),
@ -96,11 +105,54 @@ TEST_F(AuditLoggingTest, UnknownLogger) {
<< result.status();
}
TEST_F(AuditLoggingTest, AuditLoggerFactoryExistenceChecks) {
TEST_F(AuditLoggerRegistryTest, LoggerFactoryExistenceChecks) {
EXPECT_TRUE(AuditLoggerRegistry::FactoryExists(kName));
EXPECT_FALSE(AuditLoggerRegistry::FactoryExists("unknown_logger"));
}
//
// StdoutLoggerTest
//
TEST(StdoutLoggerTest, LoggerFactoryExistenceChecks) {
EXPECT_TRUE(AuditLoggerRegistry::FactoryExists("stdout_logger"));
}
TEST(StdoutLoggerTest, StdoutLoggerCreationAndLogInvocation) {
auto result =
AuditLoggerRegistry::ParseConfig("stdout_logger", Json::FromObject({}));
ASSERT_TRUE(result.ok());
auto logger =
AuditLoggerRegistry::CreateAuditLogger(std::move(result.value()));
AuditContext context("method", "spiffe", "policy", "rule", true);
::testing::internal::CaptureStdout();
absl::Time time_before_log = absl::Now();
logger->Log(context);
absl::Time time_after_log = absl::Now();
auto log_or = JsonParse(::testing::internal::GetCapturedStdout());
ASSERT_TRUE(log_or.ok());
ASSERT_EQ(log_or->type(), Json::Type::kObject);
auto it = log_or->object().find("grpc_audit_log");
ASSERT_NE(it, log_or->object().end());
ASSERT_EQ(it->second.type(), Json::Type::kObject);
auto& object = it->second.object();
ASSERT_NE(object.find("timestamp"), object.end());
EXPECT_EQ(object.find("timestamp")->second.type(), Json::Type::kString);
absl::Time time_at_log;
ASSERT_TRUE(absl::ParseTime(absl::RFC3339_full,
object.find("timestamp")->second.string(),
&time_at_log, nullptr));
// Check if the recorded timestamp is in between the recorded interval.
EXPECT_GE(time_at_log, time_before_log);
EXPECT_LE(time_at_log, time_after_log);
// Check exact values of everything else.
Json::Object json_object = object;
json_object.erase("timestamp");
EXPECT_EQ(JsonDump(Json::FromObject(json_object)),
"{\"authorized\":true,\"matched_rule\":\"rule\",\"policy_name\":"
"\"policy\",\"principal\":\"spiffe\",\"rpc_method\":\"method\"}");
}
} // namespace testing
} // namespace grpc_core

@ -2483,6 +2483,8 @@ src/core/lib/security/authorization/matchers.cc \
src/core/lib/security/authorization/matchers.h \
src/core/lib/security/authorization/rbac_policy.cc \
src/core/lib/security/authorization/rbac_policy.h \
src/core/lib/security/authorization/stdout_logger.cc \
src/core/lib/security/authorization/stdout_logger.h \
src/core/lib/security/certificate_provider/certificate_provider_factory.h \
src/core/lib/security/certificate_provider/certificate_provider_registry.cc \
src/core/lib/security/certificate_provider/certificate_provider_registry.h \

@ -2264,6 +2264,8 @@ src/core/lib/security/authorization/matchers.cc \
src/core/lib/security/authorization/matchers.h \
src/core/lib/security/authorization/rbac_policy.cc \
src/core/lib/security/authorization/rbac_policy.h \
src/core/lib/security/authorization/stdout_logger.cc \
src/core/lib/security/authorization/stdout_logger.h \
src/core/lib/security/certificate_provider/certificate_provider_factory.h \
src/core/lib/security/certificate_provider/certificate_provider_registry.cc \
src/core/lib/security/certificate_provider/certificate_provider_registry.h \

Loading…
Cancel
Save