|
7 | 7 | "bytes"
|
8 | 8 | "context"
|
9 | 9 | "fmt"
|
| 10 | + "io" |
| 11 | + "net/http" |
| 12 | + "regexp" |
10 | 13 | "strconv"
|
11 | 14 | "strings"
|
12 | 15 | "time"
|
@@ -470,6 +473,160 @@ func (clusterWatcher *ClusterWatcher) deployControllerDeployment(deployment *app
|
470 | 473 | return nil
|
471 | 474 | }
|
472 | 475 |
|
| 476 | +func (clusterWatcher *ClusterWatcher) getProvider(providerHostname, providerEndpoint string) (string, string, string) { |
| 477 | + nodes, err := clusterWatcher.Client.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}) |
| 478 | + if err != nil { |
| 479 | + clusterWatcher.Log.Warnf("Error listing nodes: %s\n", err.Error()) |
| 480 | + } |
| 481 | + |
| 482 | + for _, node := range nodes.Items { |
| 483 | + for key, label := range node.Labels { |
| 484 | + if strings.Contains(key, "gke") || strings.Contains(label, "gke") { |
| 485 | + if providerHostname != "" && providerEndpoint == "" { |
| 486 | + providerEndpoint = "/computeMetadata/v1/instance/attributes/cluster-name" |
| 487 | + } else if providerHostname == "" && providerEndpoint != "" { |
| 488 | + providerHostname = "http://metadata.google.internal" |
| 489 | + } else if providerHostname == "" && providerEndpoint == "" { |
| 490 | + providerHostname = "http://metadata.google.internal" |
| 491 | + providerEndpoint = "/computeMetadata/v1/instance/attributes/cluster-name" |
| 492 | + } |
| 493 | + return "gke", providerHostname, providerEndpoint |
| 494 | + } else if strings.Contains(key, "eks") || strings.Contains(label, "eks") { |
| 495 | + if providerHostname != "" && providerEndpoint == "" { |
| 496 | + providerEndpoint = "/latest/user-data" |
| 497 | + } else if providerHostname == "" && providerEndpoint != "" { |
| 498 | + providerHostname = "http://169.254.169.254" |
| 499 | + } else if providerHostname == "" && providerEndpoint == "" { |
| 500 | + providerHostname = "http://169.254.169.254" |
| 501 | + providerEndpoint = "/latest/user-data" |
| 502 | + } |
| 503 | + return "eks", providerHostname, providerEndpoint |
| 504 | + } |
| 505 | + } |
| 506 | + } |
| 507 | + return "default", "", "" |
| 508 | +} |
| 509 | + |
| 510 | +func (clusterWatcher *ClusterWatcher) fetchClusterNameFromGKE(providerHostname, providerEndpoint string) (string, error) { |
| 511 | + url := providerHostname + providerEndpoint |
| 512 | + req, err := http.NewRequest("GET", url, nil) |
| 513 | + if err != nil { |
| 514 | + clusterWatcher.Log.Warnf("failed to create request: %w, check provider host name and endpoint", err) |
| 515 | + return "", err |
| 516 | + } |
| 517 | + |
| 518 | + // Set the required header |
| 519 | + req.Header.Set("Metadata-Flavor", "Google") |
| 520 | + |
| 521 | + // Create an HTTP client and make the request |
| 522 | + client := &http.Client{} |
| 523 | + resp, err := client.Do(req) |
| 524 | + if err != nil { |
| 525 | + clusterWatcher.Log.Warnf("error making request: %w, check provider host name and endpoint", err) |
| 526 | + return "", err |
| 527 | + } |
| 528 | + defer resp.Body.Close() |
| 529 | + |
| 530 | + // Check for a successful response |
| 531 | + if resp.StatusCode != http.StatusOK { |
| 532 | + clusterWatcher.Log.Warnf("failed to fetch from metadata, status code: %d", resp.StatusCode) |
| 533 | + return "", err |
| 534 | + } |
| 535 | + |
| 536 | + // Read the response body |
| 537 | + body, err := io.ReadAll(resp.Body) |
| 538 | + if err != nil { |
| 539 | + clusterWatcher.Log.Warnf("error reading response body: %w", err) |
| 540 | + return "", err |
| 541 | + } |
| 542 | + |
| 543 | + return string(body), nil |
| 544 | +} |
| 545 | + |
| 546 | +func (clusterWatcher *ClusterWatcher) fetchClusterNameFromAWS(providerHostname, providerEndpoint string) (string, error) { |
| 547 | + var token []byte |
| 548 | + client := &http.Client{Timeout: 2 * time.Second} |
| 549 | + req, err := http.NewRequest("PUT", providerHostname+"/latest/api/token", nil) |
| 550 | + if err != nil { |
| 551 | + clusterWatcher.Log.Warnf("failed to create request for fetching token: %w, check provider host name", err) |
| 552 | + return "", err |
| 553 | + } |
| 554 | + req.Header.Set("X-aws-ec2-metadata-token-ttl-seconds", "21600") |
| 555 | + |
| 556 | + resp, err := client.Do(req) |
| 557 | + if err != nil { |
| 558 | + clusterWatcher.Log.Warnf("error making request: %w", err) |
| 559 | + return "", err |
| 560 | + } |
| 561 | + defer resp.Body.Close() |
| 562 | + |
| 563 | + if resp.StatusCode == http.StatusOK { |
| 564 | + token, err = io.ReadAll(resp.Body) |
| 565 | + if err != nil { |
| 566 | + clusterWatcher.Log.Warnf("failed to read token: %d", err) |
| 567 | + return "", err |
| 568 | + } |
| 569 | + } |
| 570 | + |
| 571 | + // Fetch the EKS cluster name from user data |
| 572 | + url := providerHostname + providerEndpoint |
| 573 | + req, err = http.NewRequest("GET", url, nil) |
| 574 | + client = &http.Client{Timeout: 2 * time.Second} |
| 575 | + if err != nil { |
| 576 | + clusterWatcher.Log.Warnf("failed to create request for fetching metadata: %w, check provider host name and endpoint", err) |
| 577 | + return "", err |
| 578 | + } |
| 579 | + req.Header.Set("X-aws-ec2-metadata-token", string(token)) |
| 580 | + |
| 581 | + resp, err = client.Do(req) |
| 582 | + if err != nil { |
| 583 | + clusterWatcher.Log.Warnf("error making request: %w", err) |
| 584 | + return "", err |
| 585 | + } |
| 586 | + defer resp.Body.Close() |
| 587 | + |
| 588 | + if resp.StatusCode != http.StatusOK { |
| 589 | + clusterWatcher.Log.Warnf("failed to fetch from metadata, status code: %d", resp.StatusCode) |
| 590 | + return "", err |
| 591 | + } |
| 592 | + |
| 593 | + body, err := io.ReadAll(resp.Body) |
| 594 | + if err != nil { |
| 595 | + clusterWatcher.Log.Warnf("failed to read metadata: %d", err) |
| 596 | + return "", err |
| 597 | + } |
| 598 | + |
| 599 | + // Extract EKS cluster name |
| 600 | + re := regexp.MustCompile(`/etc/eks/bootstrap\.sh (\S+)`) |
| 601 | + match := re.FindStringSubmatch(string(body)) |
| 602 | + if len(match) > 0 { |
| 603 | + return match[1], nil |
| 604 | + } |
| 605 | + |
| 606 | + return "", err |
| 607 | +} |
| 608 | + |
| 609 | +func (clusterWatcher *ClusterWatcher) GetClusterName(providerHostname, providerEndpoint string) string { |
| 610 | + provider, pHostname, pEndpoint := clusterWatcher.getProvider(ProviderHostname, providerEndpoint) |
| 611 | + if provider == "gke" { |
| 612 | + clusterWatcher.Log.Infof("Provider is GKE") |
| 613 | + if clusterName, err := clusterWatcher.fetchClusterNameFromGKE(pHostname, pEndpoint); err != nil { |
| 614 | + clusterWatcher.Log.Warnf("Cannot fetch cluster name for GKE %s", err.Error()) |
| 615 | + } else { |
| 616 | + return clusterName |
| 617 | + } |
| 618 | + } else if provider == "eks" { |
| 619 | + clusterWatcher.Log.Infof("Provider is EKS") |
| 620 | + if clusterName, err := clusterWatcher.fetchClusterNameFromAWS(pHostname, pEndpoint); err != nil { |
| 621 | + clusterWatcher.Log.Warnf("Cannot fetch cluster name for EKS %s", err.Error()) |
| 622 | + } else { |
| 623 | + return clusterName |
| 624 | + } |
| 625 | + } |
| 626 | + |
| 627 | + return "default" |
| 628 | +} |
| 629 | + |
473 | 630 | func (clusterWatcher *ClusterWatcher) WatchRequiredResources() {
|
474 | 631 | var caCert, tlsCrt, tlsKey *bytes.Buffer
|
475 | 632 | var kGenErr, err, installErr error
|
@@ -653,6 +810,7 @@ func (clusterWatcher *ClusterWatcher) WatchRequiredResources() {
|
653 | 810 | // kubearmor configmap
|
654 | 811 | configmap := addOwnership(deployments.GetKubearmorConfigMap(common.Namespace, deployments.KubeArmorConfigMapName)).(*corev1.ConfigMap)
|
655 | 812 | configmap.Data = common.ConfigMapData
|
| 813 | + configmap.Data["cluster"] = clusterWatcher.GetClusterName(ProviderHostname, ProviderEndpoint) |
656 | 814 |
|
657 | 815 | for {
|
658 | 816 | caCert, tlsCrt, tlsKey, kGenErr = common.GeneratePki(common.Namespace, deployments.KubeArmorControllerWebhookServiceName)
|
|
0 commit comments