diff --git a/cmd/adapter/adapter.go b/cmd/adapter/adapter.go index 19731222..7fa37858 100644 --- a/cmd/adapter/adapter.go +++ b/cmd/adapter/adapter.go @@ -17,8 +17,11 @@ limitations under the License. package main import ( + "crypto/tls" + "crypto/x509" "flag" "fmt" + "io/ioutil" "net/http" "net/url" "os" @@ -49,6 +52,8 @@ type PrometheusAdapter struct { PrometheusAuthInCluster bool // PrometheusAuthConf is the kubeconfig file that contains auth details used to connect to Prometheus PrometheusAuthConf string + // PrometheusCAFile points to the file containing the ca-root for connecting with Prometheus + PrometheusCAFile string // AdapterConfigFile points to the file containing the metrics discovery configuration. AdapterConfigFile string // MetricsRelistInterval is the interval at which to relist the set of available metrics @@ -62,11 +67,26 @@ func (cmd *PrometheusAdapter) makePromClient() (prom.Client, error) { if err != nil { return nil, fmt.Errorf("invalid Prometheus URL %q: %v", baseURL, err) } - promHTTPClient, err := makeHTTPClient(cmd.PrometheusAuthInCluster, cmd.PrometheusAuthConf) - if err != nil { - return nil, err + + var httpClient *http.Client + + if cmd.PrometheusCAFile != "" { + prometheusCAClient, err := makePrometheusCAClient(cmd.PrometheusCAFile) + if err != nil { + return nil, err + } + httpClient = prometheusCAClient + glog.Info("successfully loaded ca from file") + } else { + kubeconfigHTTPClient, err := makeKubeconfigHTTPClient(cmd.PrometheusAuthInCluster, cmd.PrometheusAuthConf) + if err != nil { + return nil, err + } + httpClient = kubeconfigHTTPClient + glog.Info("successfully using in-cluster auth") } - genericPromClient := prom.NewGenericAPIClient(promHTTPClient, baseURL) + + genericPromClient := prom.NewGenericAPIClient(httpClient, baseURL) instrumentedGenericPromClient := mprom.InstrumentGenericAPIClient(genericPromClient, baseURL.String()) return prom.NewClientForAPI(instrumentedGenericPromClient), nil } @@ -78,6 +98,8 @@ func (cmd *PrometheusAdapter) addFlags() { "use auth details from the in-cluster kubeconfig when connecting to prometheus.") cmd.Flags().StringVar(&cmd.PrometheusAuthConf, "prometheus-auth-config", cmd.PrometheusAuthConf, "kubeconfig file used to configure auth when connecting to Prometheus.") + cmd.Flags().StringVar(&cmd.PrometheusCAFile, "prometheus-ca-file", cmd.PrometheusCAFile, + "Optional CA file to use when connecting with Prometheus") cmd.Flags().StringVar(&cmd.AdapterConfigFile, "config", cmd.AdapterConfigFile, "Configuration file containing details of how to transform between Prometheus metrics "+ "and custom metrics API resources") @@ -177,7 +199,9 @@ func main() { cmd.Name = "prometheus-metrics-adapter" cmd.addFlags() cmd.Flags().AddGoFlagSet(flag.CommandLine) // make sure we get the glog flags - cmd.Flags().Parse(os.Args) + if err := cmd.Flags().Parse(os.Args); err != nil { + glog.Fatalf("unable to parse flags: %v", err) + } // make the prometheus client promClient, err := cmd.makePromClient() @@ -212,8 +236,8 @@ func main() { } } -// makeHTTPClient constructs an HTTP for connecting with the given auth options. -func makeHTTPClient(inClusterAuth bool, kubeConfigPath string) (*http.Client, error) { +// makeKubeconfigHTTPClient constructs an HTTP for connecting with the given auth options. +func makeKubeconfigHTTPClient(inClusterAuth bool, kubeConfigPath string) (*http.Client, error) { // make sure we're not trying to use two different sources of auth if inClusterAuth && kubeConfigPath != "" { return nil, fmt.Errorf("may not use both in-cluster auth and an explicit kubeconfig at the same time") @@ -246,3 +270,23 @@ func makeHTTPClient(inClusterAuth bool, kubeConfigPath string) (*http.Client, er } return &http.Client{Transport: tr}, nil } + +func makePrometheusCAClient(caFilename string) (*http.Client, error) { + data, err := ioutil.ReadFile(caFilename) + if err != nil { + return nil, fmt.Errorf("failed to read prometheus-ca-file: %v", err) + } + + pool := x509.NewCertPool() + if !pool.AppendCertsFromPEM(data) { + return nil, fmt.Errorf("no certs found in prometheus-ca-file") + } + + return &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: pool, + }, + }, + }, nil +}