From 2373f428bbc72725f322c159a7b0528e45535762 Mon Sep 17 00:00:00 2001 From: Erik Brakkee Date: Wed, 29 Jan 2025 21:08:42 +0100 Subject: [PATCH] now processing relabeling rules for prometheus obtaining all required monitoring endpoints now seems to work. --- cmd/policygen/cluster.go | 385 +++++++++++++++++- cmd/policygen/configvalidator.go | 4 +- cmd/policygen/kubernetes.go | 11 +- cmd/policygen/main.go | 9 +- cmd/policygen/prometheus.go | 150 +++++++ .../linkerd/namespace/monitored.yaml | 2 + .../linkerd/namespace/namespace.yaml | 20 + go.mod | 3 +- 8 files changed, 568 insertions(+), 16 deletions(-) create mode 100644 cmd/policygen/prometheus.go create mode 100644 cmd/policygen/templates/linkerd/namespace/monitored.yaml create mode 100644 cmd/policygen/templates/linkerd/namespace/namespace.yaml diff --git a/cmd/policygen/cluster.go b/cmd/policygen/cluster.go index 101b6ea..682aa08 100644 --- a/cmd/policygen/cluster.go +++ b/cmd/policygen/cluster.go @@ -6,40 +6,409 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/json" + "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" "log" + "os" "slices" "strconv" + "strings" ) +type ServiceMonitor struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec ServiceMonitorSpec `json:"spec"` +} + +type ServiceMonitorSpec struct { + NamespaceSelector NamespaceSelector `json:"namespaceSelector"` + Selector metav1.LabelSelector `json:"selector"` + Endpoints []Endpoint `json:"endpoints"` +} + +type Endpoint struct { + Path string `json:"path,omitempty"` + Port string `json:"port"` + TargetPort string `json:"targetPort"` + Scheme string `json:"scheme,omitempty"` + Relabelings []RelabelConfig `json:"relabelings,omitempty"` +} + +type PodMonitor struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec PodMonitorSpec `json:"spec"` +} + +type PodMonitorSpec struct { + NamespaceSelector NamespaceSelector `json:"namespaceSelector"` + Selector metav1.LabelSelector `json:"selector"` + PodMetricsEndpoints []Endpoint `json:"podMetricsEndpoints"` +} + +type NamespaceSelector struct { + Any bool `json:"any,omitempty"` + MatchNames []string `json:"matchNames,omitempty"` +} + +type RelabelConfig struct { + Action string `json:"action,omitempty"` + SourceLabels []string `json:"sourceLabels,omitempty"` + Separator string `json:"separator,omitempty"` + TargetLabel string `json:"targetLabel,omitempty"` + Regex string `json:"regex,omitempty"` + Modulus uint64 `json:"modulus,omitempty"` + Replacement string `json:"replacement,omitempty"` +} + type Cluster struct { namespaces map[string]v1.Namespace clientset *kubernetes.Clientset + dynClient *dynamic.DynamicClient // map of namespace to list of all pods - pods map[string][]v1.Pod + pods map[string][]v1.Pod + services map[string][]v1.Service + + // map of namespace/podname ->: ScrapingEndpoints + endpoints map[string]MonitoringEndpoints } -func NewCluster(clientset *kubernetes.Clientset) (*Cluster, error) { +type MonitoringEndpoint struct { + Port string + Path string +} + +type MonitoringEndpoints []MonitoringEndpoint + +func (s MonitoringEndpoint) CompareTo(e MonitoringEndpoint) int { + if res := strings.Compare(s.Port, e.Port); res != 0 { + return res + } + return strings.Compare(s.Path, e.Path) +} + +func (s *MonitoringEndpoints) Merge(endpoints MonitoringEndpoints) { + *s = append(*s, endpoints...) + slices.SortFunc(*s, func(a, b MonitoringEndpoint) int { + return a.CompareTo(b) + }) + *s = slices.CompactFunc(*s, func(a, b MonitoringEndpoint) bool { + return a.CompareTo(b) == 0 + }) +} + +func NewCluster(clientset *kubernetes.Clientset, dynClient *dynamic.DynamicClient) (*Cluster, error) { cluster := &Cluster{ - clientset: clientset, + clientset: clientset, + dynClient: dynClient, + namespaces: make(map[string]v1.Namespace), pods: make(map[string][]v1.Pod), + services: make(map[string][]v1.Service), + endpoints: make(map[string]MonitoringEndpoints), } nslist, err := cluster.clientset.CoreV1().Namespaces().List(context.Background(), metav1.ListOptions{}) if err != nil { return nil, err } + fmt.Fprintf(os.Stderr, "Getting pods, services\n") for _, ns := range nslist.Items { cluster.namespaces[ns.Name] = ns - podList, err := cluster.clientset.CoreV1().Pods(ns.Name).List(context.Background(), metav1.ListOptions{}) - if err != nil { - return nil, err - } - cluster.pods[ns.Name] = podList.Items } + podList, err := cluster.clientset.CoreV1().Pods("").List(context.Background(), metav1.ListOptions{}) + if err != nil { + return nil, err + } + for _, pod := range podList.Items { + cluster.pods[pod.Namespace] = append(cluster.pods[pod.Namespace], pod) + } + + svcList, err := cluster.clientset.CoreV1().Services("").List(context.Background(), metav1.ListOptions{}) + if err != nil { + return nil, err + } + for _, svc := range svcList.Items { + cluster.services[svc.Namespace] = append(cluster.services[svc.Namespace], svc) + } + err = cluster.processServiceMonitors() + if err != nil { + return nil, err + } + err = cluster.procewssPodMonitors() + if err != nil { + return nil, err + } + + podkeys := MapKeys(cluster.endpoints) + slices.Sort(podkeys) + for _, pod := range podkeys { + monitors := cluster.endpoints[pod] + slices.SortFunc(monitors, + func(m1, m2 MonitoringEndpoint) int { + return m1.CompareTo(m2) + }) + monitors = slices.CompactFunc(monitors, + func(m1, m2 MonitoringEndpoint) bool { + return m1.CompareTo(m2) == 0 + }) + cluster.endpoints[pod] = monitors + fmt.Fprintf(os.Stderr, "monitoring endpoint: %s: %v\n", pod, monitors) + } + return cluster, nil } +func (c *Cluster) processPodMonitor(podMonitor PodMonitor) error { + selector, err := metav1.LabelSelectorAsSelector(&podMonitor.Spec.Selector) + if err != nil { + return err + } + + namespaces := c.getNamespacesForMonitor(podMonitor.Spec.NamespaceSelector, podMonitor.Namespace) + for _, endpoint := range podMonitor.Spec.PodMetricsEndpoints { + for _, relabeling := range endpoint.Relabelings { + if relabeling.Action != "keep" { + continue + } + fmt.Fprintf(os.Stderr, "WARNING: podmonitor %s/%s contains relabeling which are currently not processed\n", + podMonitor.Namespace, podMonitor.Name) + } + } + for _, namespace := range namespaces { + pods := slices.DeleteFunc(slices.Clone(c.pods[namespace]), func(pod v1.Pod) bool { + return !selector.Matches(labels.Set(pod.Labels)) + }) + for _, pod := range pods { + podkey := pod.Namespace + "/" + pod.Name + klog.V(3).Infof(" match %s/%s\n", pod.Namespace, pod.Name) + for _, container := range pod.Spec.Containers { + for _, endpoint := range podMonitor.Spec.PodMetricsEndpoints { + ep, err := c.getEndpointSpec(endpoint, &pod, &container, container.Ports) + if err != nil { + // TODO generate warning? + // this container did not match + continue + } + c.endpoints[podkey] = append(c.endpoints[podkey], ep...) + } + } + if len(c.endpoints[podkey]) > 0 { + klog.V(3).Infof(" POD %s/%s :%v\n", pod.Namespace, pod.Name, + c.endpoints[podkey]) + } + } + } + return nil +} + +func (c *Cluster) getNamespacesForMonitor(namespaceSelector NamespaceSelector, defaultNamespace string) []string { + namespaces := MapKeys(c.namespaces) + if !namespaceSelector.Any { + namespaces = namespaceSelector.MatchNames + if len(namespaces) == 0 { + namespaces = []string{defaultNamespace} + } + } + return namespaces +} + +func (c *Cluster) processServiceMonitor(serviceMonitor ServiceMonitor) error { + selector, err := metav1.LabelSelectorAsSelector(&serviceMonitor.Spec.Selector) + if err != nil { + return err + } + + namespaces := c.getNamespacesForMonitor(serviceMonitor.Spec.NamespaceSelector, + serviceMonitor.Namespace) + + for _, endpoint := range serviceMonitor.Spec.Endpoints { + for _, relabeling := range endpoint.Relabelings { + if relabeling.Action != "keep" { + continue + } + fmt.Fprintf(os.Stderr, "WARNING: servicemonitor %s/%s contains relabeling which are currently not processed\n", + serviceMonitor.Namespace, serviceMonitor.Name) + } + } + for _, namespace := range namespaces { + svcs := slices.DeleteFunc(slices.Clone(c.services[namespace]), func(svc v1.Service) bool { + return !selector.Matches(labels.Set(svc.Labels)) + }) + for _, svc := range svcs { + klog.V(3).Infof(" match %s/%s\n", svc.Namespace, svc.Name) + if svc.Spec.Selector == nil { + fmt.Fprintf(os.Stderr, " service does not have a selector, skippingit, probably configured using endpoints\n") + continue + } + // Now we need to obtain the pod port. + // 1. Port specified + // service targetPort is used (equal to port if not specified) + // a. lookup pods matched by the service using the service selector + // b. path is /metics or the metric defined in the service selector + // c. port, path is defined and poss are known. + // 2. Target port specified + // a, b, c see above. + svcSelector := labels.SelectorFromSet(labels.Set(svc.Spec.Selector)) + // find pods + pods := slices.DeleteFunc(slices.Clone(c.pods[svc.Namespace]), func(pod v1.Pod) bool { + return !svcSelector.Matches(labels.Set(pod.Labels)) + }) + for _, endpoint := range serviceMonitor.Spec.Endpoints { + for _, pod := range pods { + podkey := pod.Namespace + "/" + pod.Name + for _, container := range pod.Spec.Containers { + ep, err := c.getEndpointSpec(endpoint, &pod, &container, container.Ports) + if err != nil { + // TODO: generate warning? + // this wervice did not match + } + + c.endpoints[podkey] = append(c.endpoints[podkey], ep...) + } + if len(c.endpoints[podkey]) > 0 { + klog.V(3).Infof(" POD %s/%s :%v\n", pod.Namespace, pod.Name, + c.endpoints[podkey]) + } + } + } + } + } + return nil +} + +type GeneralizedPort struct { + Name string + TargetPort string + Protocol string +} + +func MapServicePorts(ports []v1.ServicePort) []GeneralizedPort { + return Map(ports, func(p v1.ServicePort) GeneralizedPort { + return GeneralizedPort{ + Name: p.Name, + TargetPort: p.TargetPort.String(), + Protocol: string(p.Protocol), + } + }) +} + +func MapConteinerPorts(ports []v1.ContainerPort) []GeneralizedPort { + return Map(ports, func(p v1.ContainerPort) GeneralizedPort { + return GeneralizedPort{ + Name: p.Name, + TargetPort: strconv.Itoa(int(p.ContainerPort)), + Protocol: string(p.Protocol), + } + }) +} + +func (c *Cluster) getEndpointSpec(endpoint Endpoint, pod *v1.Pod, container *v1.Container, ports []v1.ContainerPort) ([]MonitoringEndpoint, error) { + klog.V(4).Infof(" analyzing %s/%s container %s/%s %v\n", + endpoint.Port, endpoint.TargetPort, pod.Name, container.Name, ports) + res := []MonitoringEndpoint{} +portLoop: + for _, port := range ports { + targetPort := "" + switch { + case endpoint.Port != "": + //fmt.Fprintf(os.Stderr, "Checking %v %s\n", port.Port, endpoint.Port) + if port.Name != endpoint.Port { + continue + } + case endpoint.TargetPort != "": + if strconv.Itoa(int(port.ContainerPort)) != endpoint.TargetPort { + continue + } + } + if targetPort == "" { + if port.Name != "" { + targetPort = port.Name + } else { + targetPort = strconv.Itoa(int(port.ContainerPort)) + } + } + // check relabeling configs + for _, relabeling := range endpoint.Relabelings { + match, err := MatchRelabeling(relabeling, pod, container, &port) + if err != nil { + return nil, err + } + if !match { + continue portLoop + } + } + // port matches all criteria + path := "/metrics" + if endpoint.Path != "" { + path = endpoint.Path + } + ep := MonitoringEndpoint{ + Port: targetPort, + Path: path, + } + res = append(res, ep) + } + return res, nil +} + +func (c *Cluster) processServiceMonitors() error { + fmt.Fprintf(os.Stderr, "Getting service monitors\n") + serviceMonitorGVR := schema.GroupVersionResource{ + Group: "monitoring.coreos.com", + Version: "v1", + Resource: "servicemonitors", + } + list, err := c.dynClient.Resource(serviceMonitorGVR). + Namespace(""). + List(context.Background(), metav1.ListOptions{}) + if err != nil { + return err + } + for _, item := range list.Items { + var sm ServiceMonitor + bytes, _ := json.Marshal(item.Object) + if err := json.Unmarshal(bytes, &sm); err != nil { + return fmt.Errorf("Error unmarshalling %s: %w", bytes, err) + } + klog.V(2).Infof("Found servicemonitor: %s/%s\n", sm.ObjectMeta.Namespace, sm.ObjectMeta.Name) + if err := c.processServiceMonitor(sm); err != nil { + return err + } + } + return nil +} + +func (c *Cluster) procewssPodMonitors() error { + fmt.Fprintf(os.Stderr, "Getting pod monitors\n") + podMonitorGVR := schema.GroupVersionResource{ + Group: "monitoring.coreos.com", + Version: "v1", + Resource: "podmonitors", + } + list, err := c.dynClient.Resource(podMonitorGVR). + Namespace(""). + List(context.Background(), metav1.ListOptions{}) + if err != nil { + return err + } + for _, item := range list.Items { + var pm PodMonitor + bytes, _ := json.Marshal(item.Object) + if err := json.Unmarshal(bytes, &pm); err != nil { + return fmt.Errorf("Error unmarshalling %s: %w", bytes, err) + } + klog.V(2).Infof("Found podmonitor: %s/%s\n", pm.ObjectMeta.Namespace, pm.ObjectMeta.Name) + if err := c.processPodMonitor(pm); err != nil { + return err + } + } + return nil +} + func (c *Cluster) Pods(application *Application) []v1.Pod { selector, err := metav1.LabelSelectorAsSelector(application.Selector()) if err != nil { diff --git a/cmd/policygen/configvalidator.go b/cmd/policygen/configvalidator.go index f6f6c43..2c7d1e6 100644 --- a/cmd/policygen/configvalidator.go +++ b/cmd/policygen/configvalidator.go @@ -35,13 +35,13 @@ func IterToSlice[K any](i iter.Seq[K]) []K { } func validate(files []string, options *Options) error { - clientset, _ := GetKubernetesConnection() + clientset, dynClient, _ := GetKubernetesConnection() config, err := readConfig(files) if err != nil { return err } - cluster, err := NewCluster(clientset) + cluster, err := NewCluster(clientset, dynClient) if err != nil { return err } diff --git a/cmd/policygen/kubernetes.go b/cmd/policygen/kubernetes.go index b7514f1..09c82da 100644 --- a/cmd/policygen/kubernetes.go +++ b/cmd/policygen/kubernetes.go @@ -1,12 +1,13 @@ package main import ( + "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "log" ) -func GetKubernetesConnection() (*kubernetes.Clientset, string) { +func GetKubernetesConnection() (*kubernetes.Clientset, *dynamic.DynamicClient, string) { loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() configOverrides := &clientcmd.ConfigOverrides{} kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides) @@ -20,12 +21,16 @@ func GetKubernetesConnection() (*kubernetes.Clientset, string) { clientset, err := kubernetes.NewForConfig(config) if err != nil { - log.Panicln(err.Error()) + panic(err) + } + dynamicClient, err := dynamic.NewForConfig(config) + if err != nil { + panic(err) } namespace, _, err := kubeConfig.Namespace() if err != nil { log.Panicf("Could not get namespace") } - return clientset, namespace + return clientset, dynamicClient, namespace } diff --git a/cmd/policygen/main.go b/cmd/policygen/main.go index 0c35fac..a832474 100644 --- a/cmd/policygen/main.go +++ b/cmd/policygen/main.go @@ -1,8 +1,10 @@ package main import ( + goflags "flag" "fmt" "github.com/spf13/cobra" + "k8s.io/klog/v2" "os" ) @@ -59,11 +61,12 @@ func generateLinkerdPolicies(files []string, options *Options) error { if err != nil { return err } - clientset, _ := GetKubernetesConnection() - cluster, err := NewCluster(clientset) + clientset, dynClient, _ := GetKubernetesConnection() + cluster, err := NewCluster(clientset, dynClient) if err != nil { return err } + fmt.Fprintf(os.Stderr, "Enhancing configuration based on running cluster\n") config.Infer(cluster) policyTemplates, err := NewPolicyTemplates() @@ -81,6 +84,8 @@ func generateLinkerdPolicies(files []string, options *Options) error { } func main() { + klogFlags := goflags.NewFlagSet("", goflags.PanicOnError) + klog.InitFlags(klogFlags) options := Options{ cni: "cilium", diff --git a/cmd/policygen/prometheus.go b/cmd/policygen/prometheus.go new file mode 100644 index 0000000..e78012a --- /dev/null +++ b/cmd/policygen/prometheus.go @@ -0,0 +1,150 @@ +package main + +import ( + "fmt" + v1 "k8s.io/api/core/v1" + "k8s.io/klog/v2" + "regexp" + "slices" + "strconv" + "strings" +) + +var standardPodLabels = map[string]func(pod *v1.Pod) string{ + "__meta_kubernetes_pod_name": func(pod *v1.Pod) string { return pod.Name }, + "__meta_kubernetes_pod_ip": func(pod *v1.Pod) string { return pod.Status.PodIP }, + "__meta_kubernetes_pod_node_name": func(pod *v1.Pod) string { return pod.Spec.NodeName }, + "__meta_kubernetes_pod_uid": func(pod *v1.Pod) string { return string(pod.UID) }, + "__meta_kubernetes_pod_phase": func(pod *v1.Pod) string { return string(pod.Status.Phase) }, + "__meta_kubernetes_pod_ready": func(pod *v1.Pod) string { return getPodReadyCondition(pod) }, + "__meta_kubernetes_pod_host_ip": func(pod *v1.Pod) string { return pod.Status.HostIP }, + "__meta_kubernetes_namespace": func(pod *v1.Pod) string { return pod.Namespace }, + "__meta_kubernetes_pod_container_init": func(pod *v1.Pod) string { return "false" }, + "__meta_kubernetes_pod_service_account": func(pod *v1.Pod) string { return pod.Spec.ServiceAccountName }, + "__meta_kubernetes_pod_controller_kind": func(pod *v1.Pod) string { return getControllerKind(pod) }, + "__meta_kubernetes_pod_controller_name": func(pod *v1.Pod) string { return getControllerName(pod) }, +} + +var containerLabels = map[string]func(pod *v1.Pod, container *v1.Container) string{ + "__meta_kubernetes_pod_container_name": func(pod *v1.Pod, container *v1.Container) string { + return container.Name + }, + "__meta_kubernetes_pod_container_id": func(pod *v1.Pod, container *v1.Container) string { + return getContainerID(pod, container) + }, +} + +func metadataPodLabels(pod *v1.Pod) map[string]string { + labels := make(map[string]string) + for name, value := range pod.Labels { + key := "__meta_kubernetes_pod_label_" + strings.ReplaceAll(name, ".", "_") + key = strings.ReplaceAll(key, "/", "_") + key = strings.ReplaceAll(key, "-", "_") + labels[key] = value + } + for name, value := range pod.Annotations { + key := "__meta_kubernetes_pod_annotation_" + strings.ReplaceAll(name, ".", "_") + key = strings.ReplaceAll(key, "/", "_") + key = strings.ReplaceAll(key, "-", "_") + labels[key] = value + } + klog.V(6).Infof("METADATA LABELS %v\n", labels) + return labels +} + +func getContainerPortSourceLabels(port *v1.ContainerPort) map[string]string { + labels := make(map[string]string) + labels["__meta_kubernetes_pod_container_port_name"] = port.Name + labels["__meta_kubernetes_pod_container_port_number"] = strconv.FormatInt(int64(port.ContainerPort), 10) + labels["__meta_kubernetes_pod_container_port_protocol"] = string(port.Protocol) + return labels +} + +type RelabelingMatcher func(pod *v1.Pod) ([]v1.ContainerPort, error) + +func MatchRelabeling(config RelabelConfig, pod *v1.Pod, container *v1.Container, + port *v1.ContainerPort) (bool, error) { + if config.Action != "keep" { + return true, nil + } + labelValues := make([]string, len(config.SourceLabels)) + for isource, sourceLabel := range config.SourceLabels { + if podLabelFunc, ok := standardPodLabels[sourceLabel]; ok { + labelValues[isource] = podLabelFunc(pod) + continue + } + metadataLabels := metadataPodLabels(pod) + if metadataLabelValue, ok := metadataLabels[sourceLabel]; ok { + labelValues[isource] = metadataLabelValue + continue + } + if containerLabelFunc, ok := containerLabels[sourceLabel]; ok { + labelValues[isource] = containerLabelFunc(pod, container) + continue + } + containerPortSourceLabels := getContainerPortSourceLabels(port) + if containerPortValue, ok := containerPortSourceLabels[sourceLabel]; ok { + labelValues[isource] = containerPortValue + continue + } + } + // concatenate the label values + labelstring := strings.Join(labelValues, ";") + matched, err := regexp.MatchString(config.Regex, labelstring) + if err != nil { + return false, err + } + klog.V(5).Infof(" relabeling '%s' ~ '%s': %v\n", labelstring, config.Regex, matched) + return matched, err +} + +func combinations(s [][]string, i int, sequence []string) { + if i == len(s) { + fmt.Printf("COMBINATION %v\n", sequence) + return + } + for _, v := range s[i] { + sequence[i] = v + combinations(s, i+1, sequence) + } +} + +// Helper functions +func getPodReadyCondition(pod *v1.Pod) string { + for _, condition := range pod.Status.Conditions { + if condition.Type == v1.PodReady { + if condition.Status == v1.ConditionTrue { + return "true" + } + return "false" + } + } + return "unknown" +} + +func getContainerID(pod *v1.Pod, container *v1.Container) string { + containerIndex := slices.IndexFunc(pod.Spec.Containers, func(c v1.Container) bool { + return c.Name == container.Name + }) + id := pod.Status.ContainerStatuses[containerIndex].ContainerID + // Strip the docker:// prefix if present + return strings.TrimPrefix(id, "docker://") +} + +func getControllerKind(pod *v1.Pod) string { + for _, owner := range pod.OwnerReferences { + if owner.Controller != nil && *owner.Controller { + return owner.Kind + } + } + return "" +} + +func getControllerName(pod *v1.Pod) string { + for _, owner := range pod.OwnerReferences { + if owner.Controller != nil && *owner.Controller { + return owner.Name + } + } + return "" +} diff --git a/cmd/policygen/templates/linkerd/namespace/monitored.yaml b/cmd/policygen/templates/linkerd/namespace/monitored.yaml new file mode 100644 index 0000000..6c60cb6 --- /dev/null +++ b/cmd/policygen/templates/linkerd/namespace/monitored.yaml @@ -0,0 +1,2 @@ + +# a rule that allows ingress from monitoring \ No newline at end of file diff --git a/cmd/policygen/templates/linkerd/namespace/namespace.yaml b/cmd/policygen/templates/linkerd/namespace/namespace.yaml new file mode 100644 index 0000000..b13ceff --- /dev/null +++ b/cmd/policygen/templates/linkerd/namespace/namespace.yaml @@ -0,0 +1,20 @@ +--- +# a Server matching all pods +# 1. must scan podmonitors and service monitoros +# must scan for all applicable podmonitor and servicemonitor resources +# Based on namespaceSelector: any (bool), matchNames ([]string) +# spec.selector determines the pods. +# +# 2. determine pods targeted +# 2. for each targeted pod, determine the port number +# 3. for each targeted pod determine the application it belongs to (so we know the labels to use) +# 4. create a rule for the given port to the given application to allow access by monitoring. +# +# Build mapping of application -> pod +# pod -> podmonitors -> port(s) +# pod -> endpoint +# +# linkerd scraping port +# linkerd-admin port on linkerd-proxy containers in any namespace, as long as they have the label linkerd.io/control-plane-ns=linkerd. + +# a MeshTlsAuthentication matching all pods \ No newline at end of file diff --git a/go.mod b/go.mod index 0049dba..6ad244d 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,8 @@ require ( k8s.io/api v0.32.0 k8s.io/apimachinery v0.32.0 k8s.io/client-go v0.32.0 + k8s.io/klog/v2 v2.130.1 + ) require ( @@ -59,7 +61,6 @@ require ( gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect