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

authz: Rbac engine audit logging #6225

Merged
merged 106 commits into from May 17, 2023
Merged
Show file tree
Hide file tree
Changes from 102 commits
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
8b9f59a
Add conversion of json to RBAC Audit Logging config
gtcooke94 Apr 6, 2023
56ab1cd
Swap to passing around references instead of copied values
gtcooke94 Apr 14, 2023
0f3b6e7
Change v3 to v3corepb
gtcooke94 Apr 14, 2023
6bff58b
go mod tidy compat=1.17
gtcooke94 Apr 14, 2023
9b3ab47
go mod tidy in examples
gtcooke94 Apr 14, 2023
bbafb89
mod tidy
gtcooke94 Apr 14, 2023
5dad66e
go mod tidy compat=1.17
gtcooke94 Apr 14, 2023
73b1390
more tidy
gtcooke94 Apr 14, 2023
27cfe85
replace panic with t.fatal
gtcooke94 Apr 17, 2023
c8751d3
return nil when error
gtcooke94 Apr 17, 2023
441fb5c
lowercase start of error message
gtcooke94 Apr 17, 2023
2326e9f
remove redundant change
gtcooke94 Apr 17, 2023
abcb93f
Fix test logging hard-coding problem
gtcooke94 Apr 17, 2023
3f57e69
Changed behavior of missing configs per PR discussion
gtcooke94 Apr 18, 2023
b7863ee
Change parser to use map from generated proto go file
gtcooke94 Apr 18, 2023
48a875e
ALLOW and DENY filter should get separate audit logger config
gtcooke94 Apr 18, 2023
edf40f1
Small change remove and else
gtcooke94 Apr 18, 2023
551ced9
Construct and allow and denyproto from the beginning
gtcooke94 Apr 19, 2023
1718c45
Merge branch 'master' into AuditLoggingRBACTranslator
gtcooke94 Apr 19, 2023
dad7293
compat 1.17 in examples
gtcooke94 Apr 19, 2023
7b9e96e
more 1.17 compat
gtcooke94 Apr 19, 2023
1f4c0c0
Address PR comments
gtcooke94 Apr 20, 2023
2eb4512
starting work
gtcooke94 Apr 20, 2023
fd97b2c
Move audit logger to it's own package
gtcooke94 Apr 20, 2023
ca8f66c
remove audit prefixes since its the package name now
gtcooke94 Apr 21, 2023
bf571d6
Add package comment
gtcooke94 Apr 21, 2023
49f1ff3
Merge branch 'MoveAuditPackage' into RBACEngine
gtcooke94 Apr 21, 2023
066adbb
Merge branch 'master' into RBACEngine
gtcooke94 Apr 21, 2023
472d752
some work
gtcooke94 Apr 21, 2023
66fa61a
Shell for audit logging
gtcooke94 Apr 21, 2023
95a5253
Continuing impl
gtcooke94 Apr 21, 2023
67a71ff
Continuing work
gtcooke94 Apr 25, 2023
1a4e978
Adding NewChainEngine tests
gtcooke94 Apr 25, 2023
1a5b03d
Don't create a new anonymous type every time
gtcooke94 Apr 26, 2023
5490046
basic engine test
gtcooke94 Apr 26, 2023
1c4b097
Working on pushing policyname through
gtcooke94 Apr 26, 2023
0747d62
Changing NewChainEngine to include policyName
gtcooke94 Apr 26, 2023
fa5e894
new commented tests
gtcooke94 Apr 26, 2023
b95b6f1
Renamed to NewChainEngine
gtcooke94 Apr 26, 2023
9ef033b
Finish renaming
gtcooke94 Apr 26, 2023
4896f7e
More tests
gtcooke94 Apr 26, 2023
6fb2f46
more tests
gtcooke94 Apr 26, 2023
760f946
More comments
gtcooke94 Apr 26, 2023
d426edb
Add policyName to tests
gtcooke94 Apr 26, 2023
5aef84f
merge master
gtcooke94 Apr 26, 2023
1b60ec1
fix
gtcooke94 Apr 26, 2023
6287772
Cleanup
gtcooke94 Apr 26, 2023
90a1306
tests for bad cases
gtcooke94 Apr 26, 2023
bc236d9
configJson -> configJSON
gtcooke94 Apr 26, 2023
60338b3
Added feature and tests for handling IsOptional on unsupported logger…
gtcooke94 Apr 26, 2023
c4e6067
Make lines wrap shorter
gtcooke94 Apr 27, 2023
4fec2a8
Addressing PR comments
gtcooke94 Apr 27, 2023
60088e3
Addressing PR comments
gtcooke94 Apr 27, 2023
50f2673
undo rename of matchingPolicyName
gtcooke94 Apr 27, 2023
26e48ce
make builder manage the list of auditEvents
gtcooke94 Apr 27, 2023
67613d3
Add comment in internal.go
gtcooke94 Apr 27, 2023
468126a
Don't use pointer to audit.Logger interface
gtcooke94 Apr 27, 2023
4a9e3f8
Change error message
gtcooke94 Apr 27, 2023
16ea27e
Cleanup parsing custom config
gtcooke94 Apr 27, 2023
89bc833
changing a name for receiver consistency
gtcooke94 Apr 27, 2023
938b6b9
rename engine receiver -> e
gtcooke94 Apr 28, 2023
752d9e6
Refactor audit logger option parsing to it's own func
gtcooke94 Apr 28, 2023
844216c
Change to more preferred slice declaration
gtcooke94 Apr 28, 2023
a46cd2e
Merge branch 'master' into RBACEngineAuditLogging
gtcooke94 May 1, 2023
f86c660
Moving to correct TypedConfig structure for custom config
gtcooke94 May 1, 2023
cab68ba
Use TypedStruct properly for custom configs
gtcooke94 May 2, 2023
21a3788
parse out the prefix of the name
gtcooke94 May 2, 2023
5e5f9e9
Move custom config logic to it's own converter.go file, setup pattern…
gtcooke94 May 2, 2023
724e066
standardize imports
gtcooke94 May 2, 2023
89aca52
Change principal handling:
gtcooke94 May 2, 2023
1685b62
Remove extra package comment
gtcooke94 May 3, 2023
2f51981
Rename helper functions
gtcooke94 May 3, 2023
8e20f7f
fix go vet error
gtcooke94 May 3, 2023
c5798a9
Added error cases for buildLogger
gtcooke94 May 3, 2023
d35a865
Actually add the new converter_test.go file
gtcooke94 May 3, 2023
9e16b15
Remove tests that weren't being used
gtcooke94 May 4, 2023
697ad75
Add copyright
gtcooke94 May 4, 2023
2bead31
git messiness, sorry
gtcooke94 May 4, 2023
5ce64e9
combine if conditions
gtcooke94 May 4, 2023
1402f64
Addressing PR comments
gtcooke94 May 4, 2023
ac17f03
Address PR comments
gtcooke94 May 5, 2023
488c09d
Use test name for individual loggers rather than clearing the registry
gtcooke94 May 9, 2023
9fa7542
Remove internal unregister function
gtcooke94 May 9, 2023
5392f60
remove unregisterLoggerBuilder
gtcooke94 May 9, 2023
421acff
Apply punctuation suggestions from code review
gtcooke94 May 9, 2023
0960c8b
%s/typedURLPrefix/typeURLPrefix
gtcooke94 May 9, 2023
2cb5de1
More PR comments
gtcooke94 May 9, 2023
361dcba
Merge master
gtcooke94 May 9, 2023
4dd9061
Add more descriptive error in helper
gtcooke94 May 9, 2023
a81070c
Own TODO
gtcooke94 May 9, 2023
50d1699
Apply suggestions from code review
gtcooke94 May 10, 2023
1637d73
Address PR comments
gtcooke94 May 15, 2023
4c2b1bb
Change how we get SPIFFE ID
gtcooke94 May 16, 2023
218ba4b
Change missing custom config behavior
gtcooke94 May 16, 2023
1ec90ed
Merge remote-tracking branch 'origin/RBACEngineAuditLogging' into RBA…
gtcooke94 May 16, 2023
85696a7
lowercase
gtcooke94 May 16, 2023
d8777da
Change error message
gtcooke94 May 16, 2023
cfaf71d
reword other errors
gtcooke94 May 16, 2023
dd6ff8d
Fix test error strings
gtcooke94 May 16, 2023
4362f75
handle s == nil
gtcooke94 May 16, 2023
d582f2c
use value instead of pointer
gtcooke94 May 16, 2023
6908c86
Remove unnecessary spiffe scheme check
gtcooke94 May 16, 2023
ea8f50e
Make for loop use value
gtcooke94 May 16, 2023
dd2f2a6
Swap to []*auditLogger
gtcooke94 May 16, 2023
52f77b8
Add check for empty audit logger name
gtcooke94 May 16, 2023
2f0a376
Better error message
gtcooke94 May 16, 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
4 changes: 2 additions & 2 deletions authz/grpc_authz_server_interceptors.go
Expand Up @@ -44,11 +44,11 @@ type StaticInterceptor struct {
// NewStatic returns a new StaticInterceptor from a static authorization policy
// JSON string.
func NewStatic(authzPolicy string) (*StaticInterceptor, error) {
rbacs, err := translatePolicy(authzPolicy)
rbacs, policyName, err := translatePolicy(authzPolicy)
if err != nil {
return nil, err
}
chainEngine, err := rbac.NewChainEngine(rbacs)
chainEngine, err := rbac.NewChainEngine(rbacs, policyName)
if err != nil {
return nil, err
}
Expand Down
35 changes: 16 additions & 19 deletions authz/rbac_translator.go
Expand Up @@ -39,7 +39,7 @@ import (

// This is used when converting a custom config from raw JSON to a TypedStruct
// The TypeURL of the TypeStruct will be "grpc.authz.audit_logging/<name>"
const typedURLPrefix = "grpc.authz.audit_logging/"
const typeURLPrefix = "grpc.authz.audit_logging/"

type header struct {
Key string
Expand All @@ -62,9 +62,9 @@ type rule struct {
}

type auditLogger struct {
Name string `json:"name"`
Config *structpb.Struct `json:"config"`
IsOptional bool `json:"is_optional"`
Name string `json:"name"`
Config structpb.Struct `json:"config"`
IsOptional bool `json:"is_optional"`
}

type auditLoggingOptions struct {
Expand Down Expand Up @@ -304,12 +304,9 @@ func (options *auditLoggingOptions) toProtos() (allow *v3rbacpb.RBAC_AuditLoggin

for i := range options.AuditLoggers {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for _, config := range options.AuditLoggers?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed, I think this was a holdover from when this was structured differently.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is why?

range var config copies lock: google.golang.org/grpc/authz.auditLogger contains google.golang.org/protobuf/types/known/structpb.Struct contains google.golang.org/protobuf/internal/impl.MessageState contains sync.Mutex

Should this be []*auditLogger then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes, I remember now that is why I had done that - changed to []*auditLogger

config := &options.AuditLoggers[i]
if config.Config == nil {
return nil, nil, fmt.Errorf("AuditLogger Config field cannot be nil")
}
typedStruct := &v1xdsudpatypepb.TypedStruct{
TypeUrl: typedURLPrefix + config.Name,
Value: config.Config,
TypeUrl: typeURLPrefix + config.Name,
rockspore marked this conversation as resolved.
Show resolved Hide resolved
Value: &config.Config,
}
customConfig, err := anypb.New(typedStruct)
if err != nil {
Expand Down Expand Up @@ -355,30 +352,30 @@ func toDenyCondition(condition v3rbacpb.RBAC_AuditLoggingOptions_AuditCondition)

// translatePolicy translates SDK authorization policy in JSON format to two
// Envoy RBAC polices (deny followed by allow policy) or only one Envoy RBAC
// allow policy. If the input policy cannot be parsed or is invalid, an error
// will be returned.
func translatePolicy(policyStr string) ([]*v3rbacpb.RBAC, error) {
// allow policy. Also returns the overall policy name. If the input policy
// cannot be parsed or is invalid, an error will be returned.
func translatePolicy(policyStr string) ([]*v3rbacpb.RBAC, string, error) {
gtcooke94 marked this conversation as resolved.
Show resolved Hide resolved
policy := &authorizationPolicy{}
d := json.NewDecoder(bytes.NewReader([]byte(policyStr)))
d.DisallowUnknownFields()
if err := d.Decode(policy); err != nil {
return nil, fmt.Errorf("failed to unmarshal policy: %v", err)
return nil, "", fmt.Errorf("failed to unmarshal policy: %v", err)
}
if policy.Name == "" {
return nil, fmt.Errorf(`"name" is not present`)
return nil, "", fmt.Errorf(`"name" is not present`)
}
if len(policy.AllowRules) == 0 {
return nil, fmt.Errorf(`"allow_rules" is not present`)
return nil, "", fmt.Errorf(`"allow_rules" is not present`)
}
allowLogger, denyLogger, err := policy.AuditLoggingOptions.toProtos()
if err != nil {
return nil, err
return nil, "", err
}
rbacs := make([]*v3rbacpb.RBAC, 0, 2)
if len(policy.DenyRules) > 0 {
denyPolicies, err := parseRules(policy.DenyRules, policy.Name)
if err != nil {
return nil, fmt.Errorf(`"deny_rules" %v`, err)
return nil, "", fmt.Errorf(`"deny_rules" %v`, err)
}
denyRBAC := &v3rbacpb.RBAC{
Action: v3rbacpb.RBAC_DENY,
Expand All @@ -389,8 +386,8 @@ func translatePolicy(policyStr string) ([]*v3rbacpb.RBAC, error) {
}
allowPolicies, err := parseRules(policy.AllowRules, policy.Name)
if err != nil {
return nil, fmt.Errorf(`"allow_rules" %v`, err)
return nil, "", fmt.Errorf(`"allow_rules" %v`, err)
}
allowRBAC := &v3rbacpb.RBAC{Action: v3rbacpb.RBAC_ALLOW, Policies: allowPolicies, AuditLoggingOptions: allowLogger}
return append(rbacs, allowRBAC), nil
return append(rbacs, allowRBAC), policy.Name, nil
}
141 changes: 105 additions & 36 deletions authz/rbac_translator_test.go
Expand Up @@ -36,9 +36,10 @@ import (

func TestTranslatePolicy(t *testing.T) {
tests := map[string]struct {
authzPolicy string
wantErr string
wantPolicies []*v3rbacpb.RBAC
authzPolicy string
wantErr string
wantPolicies []*v3rbacpb.RBAC
wantPolicyName string
}{
"valid policy": {
authzPolicy: `{
Expand Down Expand Up @@ -210,6 +211,7 @@ func TestTranslatePolicy(t *testing.T) {
AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{},
},
},
wantPolicyName: "authz",
},
"allow authenticated": {
authzPolicy: `{
Expand Down Expand Up @@ -798,6 +800,101 @@ func TestTranslatePolicy(t *testing.T) {
},
},
},
"missing custom config audit logger": {
authzPolicy: `{
"name": "authz",
"allow_rules": [
{
"name": "allow_authenticated",
"source": {
"principals":["*", ""]
}
}],
"deny_rules": [
{
"name": "deny_policy_1",
"source": {
"principals":[
"spiffe://foo.abc"
]
}
}],
"audit_logging_options": {
"audit_condition": "ON_DENY",
"audit_loggers": [
{
"name": "stdout_logger",
"is_optional": false
}
]
}
}`,
wantPolicies: []*v3rbacpb.RBAC{
{
Action: v3rbacpb.RBAC_DENY,
Policies: map[string]*v3rbacpb.Policy{
"authz_deny_policy_1": {
Principals: []*v3rbacpb.Principal{
{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
Ids: []*v3rbacpb.Principal{
{Identifier: &v3rbacpb.Principal_Authenticated_{
Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: "spiffe://foo.abc"},
}},
}},
},
}}},
},
Permissions: []*v3rbacpb.Permission{
{Rule: &v3rbacpb.Permission_Any{Any: true}},
},
},
},
AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{
AuditCondition: v3rbacpb.RBAC_AuditLoggingOptions_ON_DENY,
LoggerConfigs: []*v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig{
{AuditLogger: &v3corepb.TypedExtensionConfig{Name: "stdout_logger", TypedConfig: anyPbHelper(t, map[string]interface{}{}, "stdout_logger")},
IsOptional: false,
},
},
},
},
{
Action: v3rbacpb.RBAC_ALLOW,
Policies: map[string]*v3rbacpb.Policy{
"authz_allow_authenticated": {
Principals: []*v3rbacpb.Principal{
{Identifier: &v3rbacpb.Principal_OrIds{OrIds: &v3rbacpb.Principal_Set{
Ids: []*v3rbacpb.Principal{
{Identifier: &v3rbacpb.Principal_Authenticated_{
Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
MatchPattern: &v3matcherpb.StringMatcher_SafeRegex{SafeRegex: &v3matcherpb.RegexMatcher{Regex: ".+"}},
}},
}},
{Identifier: &v3rbacpb.Principal_Authenticated_{
Authenticated: &v3rbacpb.Principal_Authenticated{PrincipalName: &v3matcherpb.StringMatcher{
MatchPattern: &v3matcherpb.StringMatcher_Exact{Exact: ""},
}},
}},
},
}}},
},
Permissions: []*v3rbacpb.Permission{
{Rule: &v3rbacpb.Permission_Any{Any: true}},
},
},
},
AuditLoggingOptions: &v3rbacpb.RBAC_AuditLoggingOptions{
AuditCondition: v3rbacpb.RBAC_AuditLoggingOptions_ON_DENY,
LoggerConfigs: []*v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig{
{AuditLogger: &v3corepb.TypedExtensionConfig{Name: "stdout_logger", TypedConfig: anyPbHelper(t, map[string]interface{}{}, "stdout_logger")},
IsOptional: false,
},
},
},
},
},
},
"unknown field": {
authzPolicy: `{"random": 123}`,
wantErr: "failed to unmarshal policy",
Expand Down Expand Up @@ -897,47 +994,19 @@ func TestTranslatePolicy(t *testing.T) {
}`,
wantErr: `failed to unmarshal policy`,
},
"missing custom config audit logger": {
authzPolicy: `{
"name": "authz",
"allow_rules": [
{
"name": "allow_authenticated",
"source": {
"principals":["*", ""]
}
}],
"deny_rules": [
{
"name": "deny_policy_1",
"source": {
"principals":[
"spiffe://foo.abc"
]
}
}],
"audit_logging_options": {
"audit_condition": "ON_DENY",
"audit_loggers": [
{
"name": "stdout_logger",
"is_optional": false
}
]
}
}`,
wantErr: "AuditLogger Config field cannot be nil",
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
gotPolicies, gotErr := translatePolicy(test.authzPolicy)
gotPolicies, gotPolicyName, gotErr := translatePolicy(test.authzPolicy)
if gotErr != nil && !strings.HasPrefix(gotErr.Error(), test.wantErr) {
t.Fatalf("unexpected error\nwant:%v\ngot:%v", test.wantErr, gotErr)
}
if diff := cmp.Diff(gotPolicies, test.wantPolicies, protocmp.Transform()); diff != "" {
t.Fatalf("unexpected policy\ndiff (-want +got):\n%s", diff)
}
if test.wantPolicyName != "" && gotPolicyName != test.wantPolicyName {
t.Fatalf("unexpected policy name\nwant:%v\ngot:%v", test.wantPolicyName, gotPolicyName)
}
})
}
}
Expand All @@ -946,7 +1015,7 @@ func anyPbHelper(t *testing.T, in map[string]interface{}, name string) *anypb.An
t.Helper()
pb, err := structpb.NewStruct(in)
typedStruct := &v1xdsudpatypepb.TypedStruct{
TypeUrl: typedURLPrefix + name,
TypeUrl: typeURLPrefix + name,
Value: pb,
}
if err != nil {
Expand Down
98 changes: 98 additions & 0 deletions internal/xds/rbac/converter.go
@@ -0,0 +1,98 @@
/*
* 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 rbac

import (
"encoding/json"
"fmt"
"strings"

v1xdsudpatypepb "github.com/cncf/xds/go/udpa/type/v1"
v3xdsxdstypepb "github.com/cncf/xds/go/xds/type/v3"
v3rbacpb "github.com/envoyproxy/go-control-plane/envoy/config/rbac/v3"
"google.golang.org/grpc/authz/audit"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/structpb"
)

const udpaTypedStuctType = "type.googleapis.com/udpa.type.v1.TypedStruct"
const xdsTypedStuctType = "type.googleapis.com/xds.type.v3.TypedStruct"

func buildLogger(loggerConfig *v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig) (audit.Logger, error) {
gtcooke94 marked this conversation as resolved.
Show resolved Hide resolved
if loggerConfig.GetAuditLogger().GetTypedConfig() == nil {
return nil, fmt.Errorf("missing required field: TypedConfig")
}
customConfig, loggerName, err := getCustomConfig(loggerConfig.AuditLogger.TypedConfig)
if err != nil {
return nil, err
}
if loggerName == "" {
return nil, fmt.Errorf("field TypedConfig.TypeURL cannot be an empty string")
}
factory := audit.GetLoggerBuilder(loggerName)
if factory == nil {
if loggerConfig.IsOptional {
return nil, nil
}
return nil, fmt.Errorf("no builder registered for %v", loggerName)
}
auditLoggerConfig, err := factory.ParseLoggerConfig(customConfig)
if err != nil {
return nil, fmt.Errorf("custom config could not be parsed by registered factory. error: %v", err)
}
auditLogger := factory.Build(auditLoggerConfig)
return auditLogger, nil
}

func getCustomConfig(config *anypb.Any) (json.RawMessage, string, error) {
switch config.GetTypeUrl() {
case udpaTypedStuctType:
typedStruct := &v1xdsudpatypepb.TypedStruct{}
if err := config.UnmarshalTo(typedStruct); err != nil {
return nil, "", fmt.Errorf("failed to unmarshal resource: %v", err)
}
return convertCustomConfig(typedStruct.TypeUrl, typedStruct.Value)
case xdsTypedStuctType:
typedStruct := &v3xdsxdstypepb.TypedStruct{}
if err := config.UnmarshalTo(typedStruct); err != nil {
return nil, "", fmt.Errorf("failed to unmarshal resource: %v", err)
}
return convertCustomConfig(typedStruct.TypeUrl, typedStruct.Value)
}
return nil, "", fmt.Errorf("custom config not implemented for type [%v]", config.GetTypeUrl())
}

func convertCustomConfig(typeURL string, s *structpb.Struct) (json.RawMessage, string, error) {
// The gRPC policy name will be the "type name" part of the value of the
// type_url field in the TypedStruct. We get this by using the part after
// the last / character. Can assume a valid type_url from the control plane.
urls := strings.Split(typeURL, "/")
if len(urls) == 0 {
return nil, "", fmt.Errorf("error converting custom audit logger %v for %v: typeURL must have a url-like format with the typeName being the value after the last /", typeURL, s)
}
name := urls[len(urls)-1]

rawJSON := []byte("{}")
var err error
if s != nil {
rawJSON, err = json.Marshal(s)
if err != nil {
return nil, "", fmt.Errorf("error converting custom audit logger %v for %v: %v", typeURL, s, err)
}
}
return rawJSON, name, nil
}