1 //
2 // Copyright 2023 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include <grpc/support/port_platform.h>
18
19 #include "src/core/ext/xds/xds_audit_logger_registry.h"
20
21 #include <string>
22 #include <utility>
23
24 #include "absl/status/status.h"
25 #include "absl/status/statusor.h"
26 #include "absl/strings/string_view.h"
27 #include "absl/types/optional.h"
28 #include "envoy/config/core/v3/extension.upb.h"
29 #include "envoy/config/rbac/v3/rbac.upb.h"
30
31 #include "src/core/ext/xds/xds_common_types.h"
32 #include "src/core/lib/gprpp/match.h"
33 #include "src/core/lib/gprpp/validation_errors.h"
34 #include "src/core/lib/security/authorization/audit_logging.h"
35
36 namespace grpc_core {
37
38 namespace {
39
40 using experimental::AuditLoggerRegistry;
41
42 class StdoutLoggerConfigFactory : public XdsAuditLoggerRegistry::ConfigFactory {
43 public:
ConvertXdsAuditLoggerConfig(const XdsResourceType::DecodeContext &,absl::string_view,ValidationErrors *)44 Json::Object ConvertXdsAuditLoggerConfig(
45 const XdsResourceType::DecodeContext& /*context*/,
46 absl::string_view /*configuration*/,
47 ValidationErrors* /*errors*/) override {
48 // Stdout logger has no configuration right now. So we don't process the
49 // config protobuf.
50 return {};
51 }
52
type()53 absl::string_view type() override { return Type(); }
name()54 absl::string_view name() override { return "stdout_logger"; }
55
Type()56 static absl::string_view Type() {
57 return "envoy.extensions.rbac.audit_loggers.stream.v3.StdoutAuditLog";
58 }
59 };
60
61 } // namespace
62
XdsAuditLoggerRegistry()63 XdsAuditLoggerRegistry::XdsAuditLoggerRegistry() {
64 audit_logger_config_factories_.emplace(
65 StdoutLoggerConfigFactory::Type(),
66 std::make_unique<StdoutLoggerConfigFactory>());
67 }
68
ConvertXdsAuditLoggerConfig(const XdsResourceType::DecodeContext & context,const envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditLoggerConfig * logger_config,ValidationErrors * errors) const69 Json XdsAuditLoggerRegistry::ConvertXdsAuditLoggerConfig(
70 const XdsResourceType::DecodeContext& context,
71 const envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditLoggerConfig*
72 logger_config,
73 ValidationErrors* errors) const {
74 const auto* typed_extension_config =
75 envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditLoggerConfig_audit_logger(
76 logger_config);
77 ValidationErrors::ScopedField field(errors, ".audit_logger");
78 if (typed_extension_config == nullptr) {
79 errors->AddError("field not present");
80 return Json(); // A null Json object.
81 }
82 ValidationErrors::ScopedField field2(errors, ".typed_config");
83 const auto* typed_config =
84 envoy_config_core_v3_TypedExtensionConfig_typed_config(
85 typed_extension_config);
86 auto extension = ExtractXdsExtension(context, typed_config, errors);
87 if (!extension.has_value()) return Json();
88 absl::string_view name;
89 Json config;
90 Match(
91 extension->value,
92 // Built-in logger types.
93 [&](absl::string_view serialized_value) {
94 auto it = audit_logger_config_factories_.find(extension->type);
95 if (it == audit_logger_config_factories_.end()) return;
96 name = it->second->name();
97 config = Json::FromObject(it->second->ConvertXdsAuditLoggerConfig(
98 context, serialized_value, errors));
99 },
100 // Custom logger types.
101 [&](Json json) {
102 if (!AuditLoggerRegistry::FactoryExists(extension->type)) return;
103 name = extension->type;
104 config = json;
105 });
106 // Config not found in either case if name is empty.
107 if (name.empty()) {
108 if (!envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditLoggerConfig_is_optional(
109 logger_config)) {
110 errors->AddError("unsupported audit logger type");
111 }
112 return Json();
113 }
114 // Validate the converted config.
115 auto result = AuditLoggerRegistry::ParseConfig(name, config);
116 if (!result.ok()) {
117 errors->AddError(result.status().message());
118 return Json();
119 }
120 return Json::FromObject({{std::string(name), std::move(config)}});
121 }
122 } // namespace grpc_core
123