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
authz: add audit logging APIs #6158
Changes from 13 commits
6e34e14
ef778ee
04cf7d5
1b869ce
4a4609c
460954c
4f77bc3
7574567
d663ad2
f13452e
538b905
5b23c35
6b8d081
bde3dff
b6221df
6a81a5d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,132 @@ | ||||||||||||||||||||||||||||||||
/* | ||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||
* 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. | ||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
package authz | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
import ( | ||||||||||||||||||||||||||||||||
"encoding/json" | ||||||||||||||||||||||||||||||||
"sync" | ||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
// loggerBuilderRegistry holds a map of audit logger builders and a mutex | ||||||||||||||||||||||||||||||||
// to facilitate thread-safe reading/writing operations. | ||||||||||||||||||||||||||||||||
type loggerBuilderRegistry struct { | ||||||||||||||||||||||||||||||||
mu sync.Mutex | ||||||||||||||||||||||||||||||||
builders map[string]AuditLoggerBuilder | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
var ( | ||||||||||||||||||||||||||||||||
registry = loggerBuilderRegistry{ | ||||||||||||||||||||||||||||||||
builders: make(map[string]AuditLoggerBuilder), | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
// RegisterAuditLoggerBuilder registers the builder in a global map | ||||||||||||||||||||||||||||||||
// using b.Name() as the key. | ||||||||||||||||||||||||||||||||
// This should only be called during initialization time (i.e. in an init() | ||||||||||||||||||||||||||||||||
// function). | ||||||||||||||||||||||||||||||||
// If multiple builders are registered with the same name, the one registered | ||||||||||||||||||||||||||||||||
// last will take effect. | ||||||||||||||||||||||||||||||||
func RegisterAuditLoggerBuilder(b AuditLoggerBuilder) { | ||||||||||||||||||||||||||||||||
registry.mu.Lock() | ||||||||||||||||||||||||||||||||
defer registry.mu.Unlock() | ||||||||||||||||||||||||||||||||
registry.builders[b.Name()] = b | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
// GetAuditLoggerBuilder returns a builder with the given name. | ||||||||||||||||||||||||||||||||
// It returns nil if the builder is not found in the registry. | ||||||||||||||||||||||||||||||||
func GetAuditLoggerBuilder(name string) AuditLoggerBuilder { | ||||||||||||||||||||||||||||||||
registry.mu.Lock() | ||||||||||||||||||||||||||||||||
defer registry.mu.Unlock() | ||||||||||||||||||||||||||||||||
return registry.builders[name] | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
// AuditEvent contains information used by the audit logger during an audit | ||||||||||||||||||||||||||||||||
// logging event. | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about?
Suggested change
|
||||||||||||||||||||||||||||||||
type AuditEvent struct { | ||||||||||||||||||||||||||||||||
// FullMethodName is the full method name of the audited RPC, in the format | ||||||||||||||||||||||||||||||||
// of "/pkg.Service/Method". For example, "/helloworld.Greeter/SayHello". | ||||||||||||||||||||||||||||||||
FullMethodName string | ||||||||||||||||||||||||||||||||
// Principal is the identity of the caller. Currently it will only be | ||||||||||||||||||||||||||||||||
// available in certificate-based TLS authentication. | ||||||||||||||||||||||||||||||||
Principal string | ||||||||||||||||||||||||||||||||
// PolicyName is the authorization policy name or the xDS RBAC filter name. | ||||||||||||||||||||||||||||||||
PolicyName string | ||||||||||||||||||||||||||||||||
// MatchedRule is the matched rule or policy name in the xDS RBAC filter. | ||||||||||||||||||||||||||||||||
// It will be empty if there is no match. | ||||||||||||||||||||||||||||||||
MatchedRule string | ||||||||||||||||||||||||||||||||
// Authorized indicates whether the audited RPC is authorized or not. | ||||||||||||||||||||||||||||||||
Authorized bool | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
// AuditLoggerConfig defines the configuration for a particular implementation | ||||||||||||||||||||||||||||||||
// of audit logger. | ||||||||||||||||||||||||||||||||
type AuditLoggerConfig interface { | ||||||||||||||||||||||||||||||||
// auditLoggerConfig is a dummy interface requiring users to embed this | ||||||||||||||||||||||||||||||||
// interface to implement it. | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: these two lines can be removed. |
||||||||||||||||||||||||||||||||
auditLoggerConfig() | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would currently show up as follows in the godoc:
Consider changing this to: // AuditLoggerConfig represents an opaque data structure holding an audit
// logger configuration. Concrete types representing configuration of specific
// audit loggers must embed this interface to implement it.
type AuditLoggerConfig interface {
// auditLoggerConfig is a dummy interface requiring users to embed this
// interface to implement it.
auditLoggerConfig()
} |
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
// AuditLogger is the interface for an audit logger. | ||||||||||||||||||||||||||||||||
easwars marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||
// An audit logger is a logger instance that can be configured to use via the | ||||||||||||||||||||||||||||||||
// authorization policy or xDS HTTP RBAC filters. When the authorization | ||||||||||||||||||||||||||||||||
// decision meets the condition for audit, all the configured audit loggers' | ||||||||||||||||||||||||||||||||
// Log() method will be invoked to log that event with the AuditInfo. | ||||||||||||||||||||||||||||||||
// The method will be executed synchronously before the authorization is | ||||||||||||||||||||||||||||||||
// complete and the call is denied or allowed. | ||||||||||||||||||||||||||||||||
// | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Skipping the line about the method being invoked inline since the same is mentioned in the docstring for |
||||||||||||||||||||||||||||||||
// TODO(lwge): Change the link to the merged gRFC once it's ready. | ||||||||||||||||||||||||||||||||
// Please refer to https://github.com/grpc/proposal/pull/346 for more details | ||||||||||||||||||||||||||||||||
// about audit logging. | ||||||||||||||||||||||||||||||||
type AuditLogger interface { | ||||||||||||||||||||||||||||||||
// Log does audit logging with the given information in the audit event. | ||||||||||||||||||||||||||||||||
// This method will be executed synchronously by gRPC so implementers must | ||||||||||||||||||||||||||||||||
// keep in mind it must not block the RPC. Specifically, time-consuming | ||||||||||||||||||||||||||||||||
// processes should be fired asynchronously such that this method can | ||||||||||||||||||||||||||||||||
// return immediately. | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about:
Suggested change
|
||||||||||||||||||||||||||||||||
Log(*AuditEvent) | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
// AuditLoggerBuilder is the interface for an audit logger builder. | ||||||||||||||||||||||||||||||||
easwars marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||
// It parses and validates a config, and builds an audit logger from the parsed | ||||||||||||||||||||||||||||||||
// config. This enables configuring and instantiating audit loggers in the | ||||||||||||||||||||||||||||||||
// runtime. Users that want to implement their own audit logging logic should | ||||||||||||||||||||||||||||||||
// implement this along with the AuditLogger interface and register this | ||||||||||||||||||||||||||||||||
// builder by calling RegisterAuditLoggerBuilder() before they start the gRPC | ||||||||||||||||||||||||||||||||
// server. | ||||||||||||||||||||||||||||||||
// | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||
// TODO(lwge): Change the link to the merged gRFC once it's ready. | ||||||||||||||||||||||||||||||||
// Please refer to https://github.com/grpc/proposal/pull/346 for more details | ||||||||||||||||||||||||||||||||
// about audit logging. | ||||||||||||||||||||||||||||||||
type AuditLoggerBuilder interface { | ||||||||||||||||||||||||||||||||
// ParseAuditLoggerConfig parses the given JSON bytes into a structured | ||||||||||||||||||||||||||||||||
// logger config this builder can use to build an audit logger. | ||||||||||||||||||||||||||||||||
// When users implement this method, its return type must embed the | ||||||||||||||||||||||||||||||||
// AuditLoggerConfig interface. | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is mentioned in the docstring of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||||||||||||||||||||||||||||||||
ParseAuditLoggerConfig(config json.RawMessage) (AuditLoggerConfig, error) | ||||||||||||||||||||||||||||||||
// Build builds an audit logger with the given logger config. | ||||||||||||||||||||||||||||||||
// This will only be called with valid configs returned from | ||||||||||||||||||||||||||||||||
// ParseAuditLoggerConfig() and any runtime issues such as failing to | ||||||||||||||||||||||||||||||||
// create a file should be handled by the logger implementation instead of | ||||||||||||||||||||||||||||||||
// failing the logger instantiation. So implementers need to make sure it | ||||||||||||||||||||||||||||||||
// can return a logger without error at this stage. | ||||||||||||||||||||||||||||||||
Build(AuditLoggerConfig) AuditLogger | ||||||||||||||||||||||||||||||||
easwars marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||
// Name returns the name of logger built by this builder. | ||||||||||||||||||||||||||||||||
// This is used to register and pick the builder. | ||||||||||||||||||||||||||||||||
Name() string | ||||||||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit