google.golang.org/grpc@v1.74.2/credentials/tls/certprovider/pemfile/builder.go (about) 1 /* 2 * 3 * Copyright 2020 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package pemfile 20 21 import ( 22 "encoding/json" 23 "fmt" 24 "time" 25 26 "google.golang.org/grpc/credentials/tls/certprovider" 27 "google.golang.org/grpc/internal/envconfig" 28 "google.golang.org/protobuf/encoding/protojson" 29 "google.golang.org/protobuf/types/known/durationpb" 30 ) 31 32 const ( 33 // PluginName is the name of the PEM file watcher plugin. 34 PluginName = "file_watcher" 35 defaultRefreshInterval = 10 * time.Minute 36 ) 37 38 func init() { 39 certprovider.Register(&pluginBuilder{}) 40 } 41 42 type pluginBuilder struct{} 43 44 func (p *pluginBuilder) ParseConfig(c any) (*certprovider.BuildableConfig, error) { 45 data, ok := c.(json.RawMessage) 46 if !ok { 47 return nil, fmt.Errorf("meshca: unsupported config type: %T", c) 48 } 49 opts, err := pluginConfigFromJSON(data) 50 if err != nil { 51 return nil, err 52 } 53 return certprovider.NewBuildableConfig(PluginName, opts.canonical(), func(certprovider.BuildOptions) certprovider.Provider { 54 return newProvider(opts) 55 }), nil 56 } 57 58 func (p *pluginBuilder) Name() string { 59 return PluginName 60 } 61 62 func pluginConfigFromJSON(jd json.RawMessage) (Options, error) { 63 // The only difference between this anonymous struct and the Options struct 64 // is that the refresh_interval is represented here as a duration proto, 65 // while in the latter a time.Duration is used. 66 cfg := &struct { 67 CertificateFile string `json:"certificate_file,omitempty"` 68 PrivateKeyFile string `json:"private_key_file,omitempty"` 69 CACertificateFile string `json:"ca_certificate_file,omitempty"` 70 SPIFFETrustBundleMapFile string `json:"spiffe_trust_bundle_map_file,omitempty"` 71 RefreshInterval json.RawMessage `json:"refresh_interval,omitempty"` 72 }{} 73 if err := json.Unmarshal(jd, cfg); err != nil { 74 return Options{}, fmt.Errorf("pemfile: json.Unmarshal(%s) failed: %v", string(jd), err) 75 } 76 if !envconfig.XDSSPIFFEEnabled { 77 cfg.SPIFFETrustBundleMapFile = "" 78 } 79 80 opts := Options{ 81 CertFile: cfg.CertificateFile, 82 KeyFile: cfg.PrivateKeyFile, 83 RootFile: cfg.CACertificateFile, 84 SPIFFEBundleMapFile: cfg.SPIFFETrustBundleMapFile, 85 // Refresh interval is the only field in the configuration for which we 86 // support a default value. We cannot possibly have valid defaults for 87 // file paths to watch. Also, it is valid to specify an empty path for 88 // some of those fields if the user does not want to watch them. 89 RefreshDuration: defaultRefreshInterval, 90 } 91 if cfg.RefreshInterval != nil { 92 dur := &durationpb.Duration{} 93 if err := protojson.Unmarshal(cfg.RefreshInterval, dur); err != nil { 94 return Options{}, fmt.Errorf("pemfile: protojson.Unmarshal(%+v) failed: %v", cfg.RefreshInterval, err) 95 } 96 opts.RefreshDuration = dur.AsDuration() 97 } 98 99 if err := opts.validate(); err != nil { 100 return Options{}, err 101 } 102 return opts, nil 103 }