Skip to content

Commit

Permalink
Allow communicating with summary API via authenticated kubelet port
Browse files Browse the repository at this point in the history
using certificate.
  • Loading branch information
olagacek committed May 31, 2021
1 parent 693a7ec commit 801f85f
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 18 deletions.
1 change: 1 addition & 0 deletions hack/verify-flags/known-flags.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ batch-url
block-path-config
blunderbuss-config
blunderbuss-reassign
certificate-location
change-permissions
chart-url
cla-status-context
Expand Down
8 changes: 6 additions & 2 deletions kubelet-to-gcm/monitor/config/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const (

// NewConfigs returns the SourceConfigs for all monitored endpoints, and
// hits the GCE Metadata server if required.
func NewConfigs(zone, projectID, cluster, clusterLocation, host, instance, schemaPrefix string, monitoredResourceLabels map[string]string, kubeletPort, ctrlPort uint, resolution time.Duration) (*monitor.SourceConfig, *monitor.SourceConfig, error) {
func NewConfigs(zone, projectID, cluster, clusterLocation, host, instance, schemaPrefix, certificateLocation string, monitoredResourceLabels map[string]string, kubeletPort, ctrlPort uint, resolution time.Duration) (*monitor.SourceConfig, *monitor.SourceConfig, error) {
zone, err := getZone(zone)
if err != nil {
return nil, nil, err
Expand Down Expand Up @@ -81,6 +81,7 @@ func NewConfigs(zone, projectID, cluster, clusterLocation, host, instance, schem
MonitoredResourceLabels: monitoredResourceLabels,
Port: kubeletPort,
Resolution: resolution,
CertificateLocation: certificateLocation,
}, &monitor.SourceConfig{
Zone: zone,
Project: projectID,
Expand Down Expand Up @@ -172,7 +173,7 @@ func getClusterLocation(clusterLocation string) (string, error) {
return clusterLocation, nil
}

// getKubeletHost returns the kubelet host if given, or gets ip of network interface 0 from gce.
// getKubeletHost returns the kubelet host if given, or gets ip of network interface 0 from gce, or gets instance name if set to use-instance-name.
func getKubeletHost(kubeletHost string) (string, error) {
if kubeletHost == "use-gce" {
body, err := getGCEMetaData(metaDataURI("/instance/network-interfaces/0/ip"))
Expand All @@ -181,6 +182,9 @@ func getKubeletHost(kubeletHost string) (string, error) {
}
kubeletHost = string(body)
}
if kubeletHost == "use-instance-name" {
return getInstance("use-gce")
}
return kubeletHost, nil
}

Expand Down
8 changes: 6 additions & 2 deletions kubelet-to-gcm/monitor/kubelet/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,13 @@ type Client struct {
}

// NewClient returns a new Client.
func NewClient(host string, port uint, client *http.Client) (*Client, error) {
func NewClient(host string, port uint, client *http.Client, useAuthPort bool) (*Client, error) {
// Parse our URL upfront, so we can fail fast.
urlStr := fmt.Sprintf("http://%s:%d/stats/summary", host, port)
protocol := "http"
if useAuthPort {
protocol = "https"
}
urlStr := fmt.Sprintf("%s://%s:%d/stats/summary", protocol, host, port)
summaryURL, err := url.Parse(urlStr)
if err != nil {
return nil, err
Expand Down
34 changes: 33 additions & 1 deletion kubelet-to-gcm/monitor/kubelet/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ limitations under the License.
package kubelet

import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"

v3 "google.golang.org/api/monitoring/v3"
Expand All @@ -38,7 +41,17 @@ func NewSource(cfg *monitor.SourceConfig) (*Source, error) {
trans := NewTranslator(cfg.Zone, cfg.Project, cfg.Cluster, cfg.ClusterLocation, cfg.Instance, cfg.InstanceID, cfg.SchemaPrefix, cfg.MonitoredResourceLabels, cfg.Resolution)

// NewClient validates its own inputs.
client, err := NewClient(cfg.Host, cfg.Port, &http.Client{})
httpClient := &http.Client{}
var err error
useAuthPort := false
if cfg.CertificateLocation != "" {
httpClient, err = getSecuredHttpClient(cfg.CertificateLocation)
if err != nil {
return nil, fmt.Errorf("failed to create secure http client: %s", err)
}
useAuthPort = true
}
client, err := NewClient(cfg.Host, cfg.Port, httpClient, useAuthPort)
if err != nil {
return nil, fmt.Errorf("Failed to create a kubelet client with config %v: %v", cfg, err)
}
Expand Down Expand Up @@ -76,3 +89,22 @@ func (s *Source) Name() string {
func (s *Source) ProjectPath() string {
return s.projectPath
}

func getSecuredHttpClient(certLocation string) (*http.Client, error) {
cert, err := ioutil.ReadFile(certLocation)
if err != nil {
return nil, fmt.Errorf("failed to read file with kubelet certificate: %s", err)
}
certPool := x509.NewCertPool()
ok := certPool.AppendCertsFromPEM(cert)
if !ok {
return nil, fmt.Errorf("failed to parse kubelet certificate")
}
return &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: certPool,
},
},
}, nil
}
19 changes: 10 additions & 9 deletions kubelet-to-gcm/monitor/main/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,15 @@ var (
"When empty, old resource model (gke_container) is used. k8s_ prefix uses new model, with separate pod/container/node.")
monitoredResourceLabels = flag.String("monitored-resource-labels", "", "Manually specified MonitoredResource labels.")
// Flags to identify the Kubelet.
zone = flag.String("zone", "use-gce", "The zone where this kubelet lives.")
project = flag.String("project", "use-gce", "The project where this kubelet's host lives.")
cluster = flag.String("cluster", "use-gce", "The cluster where this kubelet holds membership.")
clusterLocation = flag.String("cluster-location", "use-gce", "The location of the cluster where this kubelet holds membership.")
kubeletInstance = flag.String("kubelet-instance", "use-gce", "The instance name the kubelet resides on.")
kubeletHost = flag.String("kubelet-host", "use-gce", "The kubelet's host name.")
kubeletPort = flag.Uint("kubelet-port", 10255, "The kubelet's port.")
ctrlPort = flag.Uint("controller-manager-port", 10252, "The kube-controller's port. Can be set to 0 to disable kube-controller-manager metrics collection.")
zone = flag.String("zone", "use-gce", "The zone where this kubelet lives.")
project = flag.String("project", "use-gce", "The project where this kubelet's host lives.")
cluster = flag.String("cluster", "use-gce", "The cluster where this kubelet holds membership.")
clusterLocation = flag.String("cluster-location", "use-gce", "The location of the cluster where this kubelet holds membership.")
kubeletInstance = flag.String("kubelet-instance", "use-gce", "The instance name the kubelet resides on.")
kubeletHost = flag.String("kubelet-host", "use-gce", "The kubelet's host name.")
kubeletPort = flag.Uint("kubelet-port", 10255, "The kubelet's port.")
ctrlPort = flag.Uint("controller-manager-port", 10252, "The kube-controller's port. Can be set to 0 to disable kube-controller-manager metrics collection.")
certificateLocation = flag.String("certificate-location", "", "Location under which kubelet certificate is available, needed when using secure kubelet port.")
// Flags to control runtime behavior.
res = flag.Uint("resolution", 10, "The time, in seconds, to poll the Kubelet.")
gcmEndpoint = flag.String("gcm-endpoint", "", "The GCM endpoint to hit. Defaults to the default endpoint.")
Expand All @@ -73,7 +74,7 @@ func main() {

monitoredResourceLabels := parseMonitoredResourceLabels(*monitoredResourceLabels)
// Initialize the configuration.
kubeletCfg, ctrlCfg, err := config.NewConfigs(*zone, *project, *cluster, *clusterLocation, *kubeletHost, *kubeletInstance, *schemaPrefix, monitoredResourceLabels, *kubeletPort, *ctrlPort, resolution)
kubeletCfg, ctrlCfg, err := config.NewConfigs(*zone, *project, *cluster, *clusterLocation, *kubeletHost, *kubeletInstance, *schemaPrefix, *certificateLocation, monitoredResourceLabels, *kubeletPort, *ctrlPort, resolution)
if err != nil {
log.Fatalf("Failed to initialize configuration: %v", err)
}
Expand Down
8 changes: 4 additions & 4 deletions kubelet-to-gcm/monitor/poll.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ const maxTimeSeriesPerRequest = 200
// SourceConfig is the set of data required to configure a kubernetes
// data source (e.g., kubelet or kube-controller).
type SourceConfig struct {
Zone, Project, Cluster, ClusterLocation, Host, Instance, InstanceID, SchemaPrefix string
MonitoredResourceLabels map[string]string
Port uint
Resolution time.Duration
Zone, Project, Cluster, ClusterLocation, Host, Instance, InstanceID, SchemaPrefix, CertificateLocation string
MonitoredResourceLabels map[string]string
Port uint
Resolution time.Duration
}

// MetricsSource is an object that provides kubernetes metrics in
Expand Down

0 comments on commit 801f85f

Please sign in to comment.