converter.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  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. package rbac
  17. import (
  18. "encoding/json"
  19. "fmt"
  20. "strings"
  21. v1xdsudpatypepb "github.com/cncf/xds/go/udpa/type/v1"
  22. v3xdsxdstypepb "github.com/cncf/xds/go/xds/type/v3"
  23. v3rbacpb "github.com/envoyproxy/go-control-plane/envoy/config/rbac/v3"
  24. v3auditloggersstreampb "github.com/envoyproxy/go-control-plane/envoy/extensions/rbac/audit_loggers/stream/v3"
  25. "google.golang.org/grpc/authz/audit"
  26. "google.golang.org/grpc/authz/audit/stdout"
  27. "google.golang.org/protobuf/encoding/protojson"
  28. "google.golang.org/protobuf/types/known/anypb"
  29. "google.golang.org/protobuf/types/known/structpb"
  30. )
  31. func buildLogger(loggerConfig *v3rbacpb.RBAC_AuditLoggingOptions_AuditLoggerConfig) (audit.Logger, error) {
  32. if loggerConfig.GetAuditLogger().GetTypedConfig() == nil {
  33. return nil, fmt.Errorf("missing required field: TypedConfig")
  34. }
  35. customConfig, loggerName, err := getCustomConfig(loggerConfig.AuditLogger.TypedConfig)
  36. if err != nil {
  37. return nil, err
  38. }
  39. if loggerName == "" {
  40. return nil, fmt.Errorf("field TypedConfig.TypeURL cannot be an empty string")
  41. }
  42. factory := audit.GetLoggerBuilder(loggerName)
  43. if factory == nil {
  44. if loggerConfig.IsOptional {
  45. return nil, nil
  46. }
  47. return nil, fmt.Errorf("no builder registered for %v", loggerName)
  48. }
  49. auditLoggerConfig, err := factory.ParseLoggerConfig(customConfig)
  50. if err != nil {
  51. return nil, fmt.Errorf("custom config could not be parsed by registered factory. error: %v", err)
  52. }
  53. auditLogger := factory.Build(auditLoggerConfig)
  54. return auditLogger, nil
  55. }
  56. func getCustomConfig(config *anypb.Any) (json.RawMessage, string, error) {
  57. any, err := config.UnmarshalNew()
  58. if err != nil {
  59. return nil, "", err
  60. }
  61. switch m := any.(type) {
  62. case *v1xdsudpatypepb.TypedStruct:
  63. return convertCustomConfig(m.TypeUrl, m.Value)
  64. case *v3xdsxdstypepb.TypedStruct:
  65. return convertCustomConfig(m.TypeUrl, m.Value)
  66. case *v3auditloggersstreampb.StdoutAuditLog:
  67. return convertStdoutConfig(m)
  68. }
  69. return nil, "", fmt.Errorf("custom config not implemented for type [%v]", config.GetTypeUrl())
  70. }
  71. func convertStdoutConfig(config *v3auditloggersstreampb.StdoutAuditLog) (json.RawMessage, string, error) {
  72. json, err := protojson.Marshal(config)
  73. return json, stdout.Name, err
  74. }
  75. func convertCustomConfig(typeURL string, s *structpb.Struct) (json.RawMessage, string, error) {
  76. // The gRPC policy name will be the "type name" part of the value of the
  77. // type_url field in the TypedStruct. We get this by using the part after
  78. // the last / character. Can assume a valid type_url from the control plane.
  79. urls := strings.Split(typeURL, "/")
  80. if len(urls) == 0 {
  81. 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)
  82. }
  83. name := urls[len(urls)-1]
  84. rawJSON := []byte("{}")
  85. var err error
  86. if s != nil {
  87. rawJSON, err = json.Marshal(s)
  88. if err != nil {
  89. return nil, "", fmt.Errorf("error converting custom audit logger %v for %v: %v", typeURL, s, err)
  90. }
  91. }
  92. return rawJSON, name, nil
  93. }