@@ -579,8 +579,7 @@ func NewRoundTripperFromConfig(cfg HTTPClientConfig, name string, optFuncs ...HT
579
579
// No need for a RoundTripper that reloads the CA file automatically.
580
580
return newRT (tlsConfig )
581
581
}
582
-
583
- return NewTLSRoundTripper (tlsConfig , cfg .TLSConfig .CAFile , cfg .TLSConfig .CertFile , cfg .TLSConfig .KeyFile , newRT )
582
+ return NewTLSRoundTripper (tlsConfig , cfg .TLSConfig .roundTripperSettings (), newRT )
584
583
}
585
584
586
585
type authorizationCredentialsRoundTripper struct {
@@ -750,7 +749,7 @@ func (rt *oauth2RoundTripper) RoundTrip(req *http.Request) (*http.Response, erro
750
749
if len (rt .config .TLSConfig .CAFile ) == 0 {
751
750
t , _ = tlsTransport (tlsConfig )
752
751
} else {
753
- t , err = NewTLSRoundTripper (tlsConfig , rt .config .TLSConfig .CAFile , rt . config . TLSConfig . CertFile , rt . config . TLSConfig . KeyFile , tlsTransport )
752
+ t , err = NewTLSRoundTripper (tlsConfig , rt .config .TLSConfig .roundTripperSettings () , tlsTransport )
754
753
if err != nil {
755
754
return nil , err
756
755
}
@@ -817,6 +816,10 @@ func cloneRequest(r *http.Request) *http.Request {
817
816
818
817
// NewTLSConfig creates a new tls.Config from the given TLSConfig.
819
818
func NewTLSConfig (cfg * TLSConfig ) (* tls.Config , error ) {
819
+ if err := cfg .Validate (); err != nil {
820
+ return nil , err
821
+ }
822
+
820
823
tlsConfig := & tls.Config {
821
824
InsecureSkipVerify : cfg .InsecureSkipVerify ,
822
825
MinVersion : uint16 (cfg .MinVersion ),
@@ -831,7 +834,11 @@ func NewTLSConfig(cfg *TLSConfig) (*tls.Config, error) {
831
834
832
835
// If a CA cert is provided then let's read it in so we can validate the
833
836
// scrape target's certificate properly.
834
- if len (cfg .CAFile ) > 0 {
837
+ if len (cfg .CA ) > 0 {
838
+ if ! updateRootCA (tlsConfig , []byte (cfg .CA )) {
839
+ return nil , fmt .Errorf ("unable to use inline CA cert" )
840
+ }
841
+ } else if len (cfg .CAFile ) > 0 {
835
842
b , err := readCAFile (cfg .CAFile )
836
843
if err != nil {
837
844
return nil , err
@@ -844,12 +851,9 @@ func NewTLSConfig(cfg *TLSConfig) (*tls.Config, error) {
844
851
if len (cfg .ServerName ) > 0 {
845
852
tlsConfig .ServerName = cfg .ServerName
846
853
}
854
+
847
855
// If a client cert & key is provided then configure TLS config accordingly.
848
- if len (cfg .CertFile ) > 0 && len (cfg .KeyFile ) == 0 {
849
- return nil , fmt .Errorf ("client cert file %q specified without client key file" , cfg .CertFile )
850
- } else if len (cfg .KeyFile ) > 0 && len (cfg .CertFile ) == 0 {
851
- return nil , fmt .Errorf ("client key file %q specified without client cert file" , cfg .KeyFile )
852
- } else if len (cfg .CertFile ) > 0 && len (cfg .KeyFile ) > 0 {
856
+ if cfg .usingClientCert () && cfg .usingClientKey () {
853
857
// Verify that client cert and key are valid.
854
858
if _ , err := cfg .getClientCertificate (nil ); err != nil {
855
859
return nil , err
@@ -862,6 +866,12 @@ func NewTLSConfig(cfg *TLSConfig) (*tls.Config, error) {
862
866
863
867
// TLSConfig configures the options for TLS connections.
864
868
type TLSConfig struct {
869
+ // Text of the CA cert to use for the targets.
870
+ CA string `yaml:"ca,omitempty" json:"ca,omitempty"`
871
+ // Text of the client cert file for the targets.
872
+ Cert string `yaml:"cert,omitempty" json:"cert,omitempty"`
873
+ // Text of the client key file for the targets.
874
+ Key Secret `yaml:"key,omitempty" json:"key,omitempty"`
865
875
// The CA cert to use for the targets.
866
876
CAFile string `yaml:"ca_file,omitempty" json:"ca_file,omitempty"`
867
877
// The client cert file for the targets.
@@ -891,29 +901,77 @@ func (c *TLSConfig) SetDirectory(dir string) {
891
901
// UnmarshalYAML implements the yaml.Unmarshaler interface.
892
902
func (c * TLSConfig ) UnmarshalYAML (unmarshal func (interface {}) error ) error {
893
903
type plain TLSConfig
894
- return unmarshal ((* plain )(c ))
904
+ if err := unmarshal ((* plain )(c )); err != nil {
905
+ return err
906
+ }
907
+ return c .Validate ()
895
908
}
896
909
897
- // readCertAndKey reads the cert and key files from the disk.
898
- func readCertAndKey (certFile , keyFile string ) ([]byte , []byte , error ) {
899
- certData , err := os .ReadFile (certFile )
900
- if err != nil {
901
- return nil , nil , err
910
+ // Validate validates the TLSConfig to check that only one of the inlined or
911
+ // file-based fields for the TLS CA, client certificate, and client key are
912
+ // used.
913
+ func (c * TLSConfig ) Validate () error {
914
+ if len (c .CA ) > 0 && len (c .CAFile ) > 0 {
915
+ return fmt .Errorf ("at most one of ca and ca_file must be configured" )
916
+ }
917
+ if len (c .Cert ) > 0 && len (c .CertFile ) > 0 {
918
+ return fmt .Errorf ("at most one of cert and cert_file must be configured" )
919
+ }
920
+ if len (c .Key ) > 0 && len (c .KeyFile ) > 0 {
921
+ return fmt .Errorf ("at most one of key and key_file must be configured" )
902
922
}
903
923
904
- keyData , err := os .ReadFile (keyFile )
905
- if err != nil {
906
- return nil , nil , err
924
+ if c .usingClientCert () && ! c .usingClientKey () {
925
+ return fmt .Errorf ("exactly one of key or key_file must be configured when a client certificate is configured" )
926
+ } else if c .usingClientKey () && ! c .usingClientCert () {
927
+ return fmt .Errorf ("exactly one of cert or cert_file must be configured when a client key is configured" )
907
928
}
908
929
909
- return certData , keyData , nil
930
+ return nil
931
+ }
932
+
933
+ func (c * TLSConfig ) usingClientCert () bool {
934
+ return len (c .Cert ) > 0 || len (c .CertFile ) > 0
935
+ }
936
+
937
+ func (c * TLSConfig ) usingClientKey () bool {
938
+ return len (c .Key ) > 0 || len (c .KeyFile ) > 0
939
+ }
940
+
941
+ func (c * TLSConfig ) roundTripperSettings () TLSRoundTripperSettings {
942
+ return TLSRoundTripperSettings {
943
+ CA : c .CA ,
944
+ CAFile : c .CAFile ,
945
+ Cert : c .Cert ,
946
+ CertFile : c .CertFile ,
947
+ Key : string (c .Key ),
948
+ KeyFile : c .KeyFile ,
949
+ }
910
950
}
911
951
912
952
// getClientCertificate reads the pair of client cert and key from disk and returns a tls.Certificate.
913
953
func (c * TLSConfig ) getClientCertificate (_ * tls.CertificateRequestInfo ) (* tls.Certificate , error ) {
914
- certData , keyData , err := readCertAndKey (c .CertFile , c .KeyFile )
915
- if err != nil {
916
- return nil , fmt .Errorf ("unable to read specified client cert (%s) & key (%s): %s" , c .CertFile , c .KeyFile , err )
954
+ var (
955
+ certData , keyData []byte
956
+ err error
957
+ )
958
+
959
+ if c .CertFile != "" {
960
+ certData , err = os .ReadFile (c .CertFile )
961
+ if err != nil {
962
+ return nil , fmt .Errorf ("unable to read specified client cert (%s): %s" , c .CertFile , err )
963
+ }
964
+ } else {
965
+ certData = []byte (c .Cert )
966
+ }
967
+
968
+ if c .KeyFile != "" {
969
+ keyData , err = os .ReadFile (c .KeyFile )
970
+ if err != nil {
971
+ return nil , fmt .Errorf ("unable to read specified client key (%s): %s" , c .KeyFile , err )
972
+ }
973
+ } else {
974
+ keyData = []byte (c .Key )
917
975
}
918
976
919
977
cert , err := tls .X509KeyPair (certData , keyData )
@@ -946,30 +1004,32 @@ func updateRootCA(cfg *tls.Config, b []byte) bool {
946
1004
// tlsRoundTripper is a RoundTripper that updates automatically its TLS
947
1005
// configuration whenever the content of the CA file changes.
948
1006
type tlsRoundTripper struct {
949
- caFile string
950
- certFile string
951
- keyFile string
1007
+ settings TLSRoundTripperSettings
952
1008
953
1009
// newRT returns a new RoundTripper.
954
1010
newRT func (* tls.Config ) (http.RoundTripper , error )
955
1011
956
1012
mtx sync.RWMutex
957
1013
rt http.RoundTripper
958
- hashCAFile []byte
959
- hashCertFile []byte
960
- hashKeyFile []byte
1014
+ hashCAData []byte
1015
+ hashCertData []byte
1016
+ hashKeyData []byte
961
1017
tlsConfig * tls.Config
962
1018
}
963
1019
1020
+ type TLSRoundTripperSettings struct {
1021
+ CA , CAFile string
1022
+ Cert , CertFile string
1023
+ Key , KeyFile string
1024
+ }
1025
+
964
1026
func NewTLSRoundTripper (
965
1027
cfg * tls.Config ,
966
- caFile , certFile , keyFile string ,
1028
+ settings TLSRoundTripperSettings ,
967
1029
newRT func (* tls.Config ) (http.RoundTripper , error ),
968
1030
) (http.RoundTripper , error ) {
969
1031
t := & tlsRoundTripper {
970
- caFile : caFile ,
971
- certFile : certFile ,
972
- keyFile : keyFile ,
1032
+ settings : settings ,
973
1033
newRT : newRT ,
974
1034
tlsConfig : cfg ,
975
1035
}
@@ -979,44 +1039,74 @@ func NewTLSRoundTripper(
979
1039
return nil , err
980
1040
}
981
1041
t .rt = rt
982
- _ , t .hashCAFile , t .hashCertFile , t .hashKeyFile , err = t .getTLSFilesWithHash ()
1042
+ _ , t .hashCAData , t .hashCertData , t .hashKeyData , err = t .getTLSDataWithHash ()
983
1043
if err != nil {
984
1044
return nil , err
985
1045
}
986
1046
987
1047
return t , nil
988
1048
}
989
1049
990
- func (t * tlsRoundTripper ) getTLSFilesWithHash () ([]byte , []byte , []byte , []byte , error ) {
991
- b1 , err := readCAFile (t .caFile )
992
- if err != nil {
993
- return nil , nil , nil , nil , err
1050
+ func (t * tlsRoundTripper ) getTLSDataWithHash () ([]byte , []byte , []byte , []byte , error ) {
1051
+ var (
1052
+ caBytes , certBytes , keyBytes []byte
1053
+
1054
+ err error
1055
+ )
1056
+
1057
+ if t .settings .CAFile != "" {
1058
+ caBytes , err = os .ReadFile (t .settings .CAFile )
1059
+ if err != nil {
1060
+ return nil , nil , nil , nil , err
1061
+ }
1062
+ } else if t .settings .CA != "" {
1063
+ caBytes = []byte (t .settings .CA )
1064
+ }
1065
+
1066
+ if t .settings .CertFile != "" {
1067
+ certBytes , err = os .ReadFile (t .settings .CertFile )
1068
+ if err != nil {
1069
+ return nil , nil , nil , nil , err
1070
+ }
1071
+ } else if t .settings .Cert != "" {
1072
+ certBytes = []byte (t .settings .Cert )
994
1073
}
995
- h1 := sha256 .Sum256 (b1 )
996
1074
997
- var h2 , h3 [32 ]byte
998
- if t .certFile != "" {
999
- b2 , b3 , err := readCertAndKey (t .certFile , t .keyFile )
1075
+ if t .settings .KeyFile != "" {
1076
+ keyBytes , err = os .ReadFile (t .settings .KeyFile )
1000
1077
if err != nil {
1001
1078
return nil , nil , nil , nil , err
1002
1079
}
1003
- h2 , h3 = sha256 .Sum256 (b2 ), sha256 .Sum256 (b3 )
1080
+ } else if t .settings .Key != "" {
1081
+ keyBytes = []byte (t .settings .Key )
1082
+ }
1083
+
1084
+ var caHash , certHash , keyHash [32 ]byte
1085
+
1086
+ if len (caBytes ) > 0 {
1087
+ caHash = sha256 .Sum256 (caBytes )
1088
+ }
1089
+ if len (certBytes ) > 0 {
1090
+ certHash = sha256 .Sum256 (certBytes )
1091
+ }
1092
+ if len (keyBytes ) > 0 {
1093
+ keyHash = sha256 .Sum256 (keyBytes )
1004
1094
}
1005
1095
1006
- return b1 , h1 [:], h2 [:], h3 [:], nil
1096
+ return caBytes , caHash [:], certHash [:], keyHash [:], nil
1007
1097
}
1008
1098
1009
1099
// RoundTrip implements the http.RoundTrip interface.
1010
1100
func (t * tlsRoundTripper ) RoundTrip (req * http.Request ) (* http.Response , error ) {
1011
- caData , caHash , certHash , keyHash , err := t .getTLSFilesWithHash ()
1101
+ caData , caHash , certHash , keyHash , err := t .getTLSDataWithHash ()
1012
1102
if err != nil {
1013
1103
return nil , err
1014
1104
}
1015
1105
1016
1106
t .mtx .RLock ()
1017
- equal := bytes .Equal (caHash [:], t .hashCAFile ) &&
1018
- bytes .Equal (certHash [:], t .hashCertFile ) &&
1019
- bytes .Equal (keyHash [:], t .hashKeyFile )
1107
+ equal := bytes .Equal (caHash [:], t .hashCAData ) &&
1108
+ bytes .Equal (certHash [:], t .hashCertData ) &&
1109
+ bytes .Equal (keyHash [:], t .hashKeyData )
1020
1110
rt := t .rt
1021
1111
t .mtx .RUnlock ()
1022
1112
if equal {
@@ -1029,7 +1119,7 @@ func (t *tlsRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
1029
1119
// using GetClientCertificate.
1030
1120
tlsConfig := t .tlsConfig .Clone ()
1031
1121
if ! updateRootCA (tlsConfig , caData ) {
1032
- return nil , fmt .Errorf ("unable to use specified CA cert %s" , t .caFile )
1122
+ return nil , fmt .Errorf ("unable to use specified CA cert %s" , t .settings . CAFile )
1033
1123
}
1034
1124
rt , err = t .newRT (tlsConfig )
1035
1125
if err != nil {
@@ -1039,9 +1129,9 @@ func (t *tlsRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
1039
1129
1040
1130
t .mtx .Lock ()
1041
1131
t .rt = rt
1042
- t .hashCAFile = caHash [:]
1043
- t .hashCertFile = certHash [:]
1044
- t .hashKeyFile = keyHash [:]
1132
+ t .hashCAData = caHash [:]
1133
+ t .hashCertData = certHash [:]
1134
+ t .hashKeyData = keyHash [:]
1045
1135
t .mtx .Unlock ()
1046
1136
1047
1137
return rt .RoundTrip (req )
0 commit comments