Skip to content

NimTechnology

Trình bày các công nghệ CLOUD một cách dễ hiểu.

  • Kubernetes & Container
    • Docker
    • Kubernetes
      • Ingress
      • Pod
    • Helm Chart
    • OAuth2 Proxy
    • Isito-EnvoyFilter
    • Apache Kafka
      • Kafka
      • Kafka Connect
      • Lenses
    • Vault
    • Longhorn – Storage
    • VictoriaMetrics
    • MetalLB
    • Kong Gateway
  • CI/CD
    • ArgoCD
    • ArgoWorkflows
    • Argo Events
    • Spinnaker
    • Jenkins
    • Harbor
    • TeamCity
    • Git
      • Bitbucket
  • Coding
    • DevSecOps
    • Terraform
      • GCP – Google Cloud
      • AWS – Amazon Web Service
      • Azure Cloud
    • Golang
    • Laravel
    • Python
    • Jquery & JavaScript
    • Selenium
  • Log, Monitor & Tracing
    • DataDog
    • Prometheus
    • Grafana
    • ELK
      • Kibana
      • Logstash
  • BareMetal
    • NextCloud
  • Toggle search form

[Golang / EKS] Accessing AWS EKS with Go: A Comprehensive Guide to Interacting with Kubernetes APIs

Posted on March 7, 2025March 7, 2025 By nim No Comments on [Golang / EKS] Accessing AWS EKS with Go: A Comprehensive Guide to Interacting with Kubernetes APIs

Mình đang câng viết 1 tool golang và sẽ access vào EKS để call tiếp các API của K8S

Chúng ta đi sơ qua 1 chút về

Đây là kubeconfig mà bạn hay sử dụng để access vào eks cluster.

Bạn có thể thấy khi access vào eks cluster thì kubeclt sẽ cần gõ một lệnh bắng aws cli để get token
Vậy là máy tính của bạn cần cài kubeclt and aws cli.

OK bậy giờ chúng ta sẽ code như thế nào?

package main

import (
    "context"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/eks"
    "github.com/aws/aws-sdk-go/service/sts"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/tools/clientcmd/api"
    "log"
    "os/exec"
    "sigs.k8s.io/aws-iam-authenticator/pkg/token"
)

// getEksToken retrieves the authentication token and CA data from the EKS cluster
func getEksToken(region, clusterName string) (string, string, []byte, error) {
    // Create an AWS session (SDK v1)
    sess, err := session.NewSession(&aws.Config{
        Region: aws.String(region),
    })
    if err != nil {
        return "", "", nil, fmt.Errorf("unable to create AWS session, %v", err)
    }

    // Create an EKS client (SDK v1)
    eksClient := eks.New(sess)

    // Get cluster details to retrieve the API server URL and certificate authority data
    clusterDetails, err := eksClient.DescribeCluster(&eks.DescribeClusterInput{
        Name: aws.String(clusterName),
    })
    if err != nil {
        return "", "", nil, fmt.Errorf("unable to describe cluster: %v", err)
    }

    // Extract API server URL and certificate authority data
    apiServer := *clusterDetails.Cluster.Endpoint
    caDataBase64 := *clusterDetails.Cluster.CertificateAuthority.Data // Dereference *string to string

    // Decode the base64-encoded CA data to []byte
    caData, err := base64.StdEncoding.DecodeString(caDataBase64)
    if err != nil {
        return "", "", nil, fmt.Errorf("unable to decode CA data: %v", err)
    }

    // Use the AWS CLI to get the authentication token
    token, err := getAWSTokenUsingCLI(region, clusterName)
    if err != nil {
        return "", "", nil, fmt.Errorf("unable to get authentication token: %v", err)
    }

    return token, apiServer, caData, nil
}

// getAWSTokenUsingIAMAuthenticator generates the authentication token using the AWS IAM Authenticator
func getAWSTokenUsingIAMAuthenticator(region, clusterName string) (string, error) {
    // Create an AWS session (SDK v1)
    sess, err := session.NewSession(&aws.Config{
        Region: aws.String(region),
    })
    if err != nil {
        return "", fmt.Errorf("unable to create AWS session: %v", err)
    }

    // Create an STS client (SDK v1)
    stsClient := sts.New(sess)

    // Create a token generator
    generator, err := token.NewGenerator(false, false)
    if err != nil {
        return "", fmt.Errorf("failed to create token generator: %v", err)
    }

    // Generate a token using the STS client to authenticate with the EKS cluster
    tk, err := generator.GetWithSTS(clusterName, stsClient)
    if err != nil {
        return "", fmt.Errorf("unable to generate token using IAM Authenticator: %v", err)
    }

    // Return the generated token
    return tk.Token, nil
}

// getAWSTokenUsingCLI runs `aws eks get-token` to retrieve the authentication token for EKS
func getAWSTokenUsingCLI(region, clusterName string) (string, error) {
    // Run the AWS CLI command to get the token
    cmd := exec.Command("aws", "eks", "get-token", "--region", region, "--cluster-name", clusterName)
    output, err := cmd.Output()
    if err != nil {
        return "", fmt.Errorf("failed to run AWS CLI: %v", err)
    }

    // The output will be in JSON format, we need to extract the token from it
    var tokenResp struct {
        Status struct {
            Token string `json:"token"`
        } `json:"status"`
    }

    // Decode the JSON response into the struct
    err = json.Unmarshal(output, &tokenResp)
    if err != nil {
        return "", fmt.Errorf("failed to parse AWS CLI output: %v", err)
    }

    // Return the token
    return tokenResp.Status.Token, nil
}

func getK8sClient(token, apiServer string, caData []byte) (*kubernetes.Clientset, error) {
    // Dynamically create a kubeconfig in memory, including the CA data
    kubeconfig := clientcmd.NewDefaultClientConfig(api.Config{
        Clusters: map[string]*api.Cluster{
            "elearning-eks": {
                Server:                   apiServer,
                CertificateAuthorityData: caData,
            },
        },
        Contexts: map[string]*api.Context{
            "elearning-eks": {
                Cluster:  "elearning-eks",
                AuthInfo: "elearning-eks",
            },
        },
        CurrentContext: "elearning-eks",
        AuthInfos: map[string]*api.AuthInfo{
            "elearning-eks": {
                Token: token,
            },
        },
    }, nil)

    // Create the Kubernetes client from the in-memory kubeconfig
    config, err := kubeconfig.ClientConfig()
    if err != nil {
        return nil, fmt.Errorf("unable to create Kubernetes config: %v", err)
    }

    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        return nil, fmt.Errorf("unable to create Kubernetes client: %v", err)
    }
    return clientset, nil
}

func main() {
    // Specify the EKS cluster name and region
    clusterName := "elearning-eks"
    region := "eu-central-1"

    // Step 1: Get EKS authentication token and API server endpoint, along with CA data
    token, apiServer, caData, err := getEksToken(region, clusterName)
    if err != nil {
        log.Fatalf("Error getting EKS token: %v", err)
    }

    // Step 2: Set up the Kubernetes client dynamically using the token, API server URL, and CA certificate
    clientset, err := getK8sClient(token, apiServer, caData)
    if err != nil {
        log.Fatalf("Error creating Kubernetes client: %v", err)
    }

    // Step 3: Use the clientset to interact with Kubernetes
    // Example: List pods
    pods, err := clientset.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{})
    if err != nil {
        log.Fatalf("Error listing pods: %v", err)
    }
    fmt.Println("Pods in cluster:")
    for _, pod := range pods.Items {
        fmt.Println(pod.Name)
    }

    // Example: List nodes
    nodes, err := clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
    if err != nil {
        log.Fatalf("Error listing nodes: %v", err)
    }
    fmt.Println("Nodes in cluster:")
    for _, node := range nodes.Items {
        fmt.Println(node.Name)
    }
}

Bạn có thể thấy đầu tiên thì tool sẽ thự hiện Get EKS authentication token and API server endpoint, along with CA data

explain the code easily to understand:
// getEksToken retrieves the authentication token and CA data from the EKS cluster
func getEksToken(region, clusterName string) (string, string, []byte, error) {
    // Create an AWS session (SDK v1)
    sess, err := session.NewSession(&aws.Config{
        Region: aws.String(region),
    })
    if err != nil {
        return "", "", nil, fmt.Errorf("unable to create AWS session, %v", err)
    }

    // Create an EKS client (SDK v1)
    eksClient := eks.New(sess)

    // Get cluster details to retrieve the API server URL and certificate authority data
    clusterDetails, err := eksClient.DescribeCluster(&eks.DescribeClusterInput{
        Name: aws.String(clusterName),
    })
    if err != nil {
        return "", "", nil, fmt.Errorf("unable to describe cluster: %v", err)
    }

    // Extract API server URL and certificate authority data
    apiServer := *clusterDetails.Cluster.Endpoint
    caDataBase64 := *clusterDetails.Cluster.CertificateAuthority.Data // Dereference *string to string

    // Decode the base64-encoded CA data to []byte
    caData, err := base64.StdEncoding.DecodeString(caDataBase64)
    if err != nil {
        return "", "", nil, fmt.Errorf("unable to decode CA data: %v", err)
    }

    // Use the AWS CLI to get the authentication token
    token, err := getAWSTokenUsingCLI(region, clusterName)
    if err != nil {
        return "", "", nil, fmt.Errorf("unable to get authentication token: %v", err)
    }

    return token, apiServer, caData, nil
}

1. Create an AWS Session:

   sess, err := session.NewSession(&aws.Config{
       Region: aws.String(region),
   })

Initializes a new AWS session configured for a specific region.
This session is used to create clients for AWS services, like EKS, to interact with AWS resources.

2. Create an EKS Client:

eksClient := eks.New(sess)

Creates a client for the EKS service using the AWS session.
The EKS client allows us to make API calls to the EKS service, such as retrieving cluster details.

3. Describe the EKS Cluster:

   clusterDetails, err := eksClient.DescribeCluster(&eks.DescribeClusterInput{
       Name: aws.String(clusterName),
   })

Calls the DescribeCluster API to get details about the specified EKS cluster.
We need the cluster’s API server URL and CA data to connect securely.

4. Extract API Server URL and CA Data:

   apiServer := *clusterDetails.Cluster.Endpoint
   caDataBase64 := *clusterDetails.Cluster.CertificateAuthority.Data

Retrieves the API server URL and the base64-encoded CA data from the cluster details.

5. Decode CA Data:

   caData, err := base64.StdEncoding.DecodeString(caDataBase64)

Decodes the base64-encoded CA data into a byte slice.

6. Get Authentication Token:

token, err := getAWSTokenUsingCLI(region, clusterName)

Calls a helper function to retrieve an authentication token using the AWS CLI.
The token is used to authenticate requests to the EKS API server.

7. Return the Results:

return token, apiServer, caData, nil

Lúc này thì nó sẽ chia ra làm 2 khi mà tool cần get token để access vào eks.

Sử dụng command AWS CLI để get token:

// getAWSTokenUsingCLI runs `aws eks get-token` to retrieve the authentication token for EKS
func getAWSTokenUsingCLI(region, clusterName string) (string, error) {
    // Run the AWS CLI command to get the token
    cmd := exec.Command("aws", "eks", "get-token", "--region", region, "--cluster-name", clusterName)
    output, err := cmd.Output()
    if err != nil {
        return "", fmt.Errorf("failed to run AWS CLI: %v", err)
    }

    // The output will be in JSON format, we need to extract the token from it
    var tokenResp struct {
        Status struct {
            Token string `json:"token"`
        } `json:"status"`
    }

    // Decode the JSON response into the struct
    err = json.Unmarshal(output, &tokenResp)
    if err != nil {
        return "", fmt.Errorf("failed to parse AWS CLI output: %v", err)
    }

    // Return the token
    return tokenResp.Status.Token, nil
}

The getAWSTokenUsingCLI function is designed to retrieve an authentication token for an Amazon EKS (Elastic Kubernetes Service) cluster using the AWS CLI. This token is necessary for authenticating requests to the EKS API server.

Chúng ta sẽ cần tìm hiểu chút về Parse JSON Output:

   var tokenResp struct {
       Status struct {
           Token string `json:"token"`
       } `json:"status"`
   }
   err = json.Unmarshal(output, &tokenResp)

Defines a structure to match the expected JSON output format from the AWS CLI.
The AWS CLI returns the token in JSON format, so we need to parse this JSON to extract the token.

Trong 1 số trường hợp chúng ta không muốn client cài đặt aws cli trên máy:

// getAWSTokenUsingIAMAuthenticator generates the authentication token using the AWS IAM Authenticator
func getAWSTokenUsingIAMAuthenticator(region, clusterName string) (string, error) {
    // Create an AWS session (SDK v1)
    sess, err := session.NewSession(&aws.Config{
        Region: aws.String(region),
    })
    if err != nil {
        return "", fmt.Errorf("unable to create AWS session: %v", err)
    }

    // Create an STS client (SDK v1)
    stsClient := sts.New(sess)

    // Create a token generator
    generator, err := token.NewGenerator(false, false)
    if err != nil {
        return "", fmt.Errorf("failed to create token generator: %v", err)
    }

    // Generate a token using the STS client to authenticate with the EKS cluster
    tk, err := generator.GetWithSTS(clusterName, stsClient)
    if err != nil {
        return "", fmt.Errorf("unable to generate token using IAM Authenticator: %v", err)
    }

    // Return the generated token
    return tk.Token, nil
}

Có một điều mình cần announce hiện tại để get token thì chúng ta cần sử dụng aws-sdk-go (v1) không phải là aws-sdk-go-v2

  1. Create an AWS Session
    sess, err := session.NewSession(&aws.Config{
        Region: aws.String(region),
    })

Initializes a new AWS session configured for a specific region.
This session is used to create clients for AWS services, such as STS (Security Token Service), to interact with AWS resources.

2. Create an STS Client:

stsClient := sts.New(sess)

Creates a client for the AWS STS service using the AWS session.
The STS client is used to interact with AWS STS, which is involved in generating temporary credentials.

3. Create a Token Generator:

generator, err := token.NewGenerator(false, false)

The token generator is responsible for creating the authentication token that will be used to access the EKS cluster.

4. Generate the Token:

tk, err := generator.GetWithSTS(clusterName, stsClient)

Uses the token generator to create a token for the specified EKS cluster, utilizing the STS client.
The generated token is used to authenticate with the EKS API server, allowing secure access to the cluster.

Tới đây chúng ta đã có token, apiServer, CA data
token, apiServer, caData, err := getEksToken(region, clusterName)

Tiếp đến chúng ta cần tạo a Kubernetes clientset

func getK8sClient(token, apiServer string, caData []byte) (*kubernetes.Clientset, error) {
    // Dynamically create a kubeconfig in memory, including the CA data
    kubeconfig := clientcmd.NewDefaultClientConfig(api.Config{
        Clusters: map[string]*api.Cluster{
            "elearning-eks": {
                Server:                   apiServer,
                CertificateAuthorityData: caData,
            },
        },
        Contexts: map[string]*api.Context{
            "elearning-eks": {
                Cluster:  "elearning-eks",
                AuthInfo: "elearning-eks",
            },
        },
        CurrentContext: "elearning-eks",
        AuthInfos: map[string]*api.AuthInfo{
            "elearning-eks": {
                Token: token,
            },
        },
    }, nil)

    // Create the Kubernetes client from the in-memory kubeconfig
    config, err := kubeconfig.ClientConfig()
    if err != nil {
        return nil, fmt.Errorf("unable to create Kubernetes config: %v", err)
    }

    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        return nil, fmt.Errorf("unable to create Kubernetes client: %v", err)
    }
    return clientset, nil
}

1. Create an In-Memory Kubeconfig:

   kubeconfig := clientcmd.NewDefaultClientConfig(api.Config{
       Clusters: map[string]*api.Cluster{
           "elearning-eks": {
               Server:                   apiServer,
               CertificateAuthorityData: caData,
           },
       },
       Contexts: map[string]*api.Context{
           "elearning-eks": {
               Cluster:  "elearning-eks",
               AuthInfo: "elearning-eks",
           },
       },
       CurrentContext: "elearning-eks",
       AuthInfos: map[string]*api.AuthInfo{
           "elearning-eks": {
               Token: token,
           },
       },
   }, nil)

Constructs a kubeconfig in memory with the necessary details to connect to the Kubernetes cluster.

  • Components:Clusters:
    • Defines the cluster with its API server URL and CA data.
    • Contexts: Specifies the context, linking the cluster and authentication information.
    • CurrentContext: Sets the active context to use for operations.
    • AuthInfos: Provides the authentication token for accessing the cluster.

The kubeconfig contains all the information required to authenticate and connect to the Kubernetes API server.

2. Create Kubernetes Client Configuration:

   config, err := kubeconfig.ClientConfig()

Converts the in-memory kubeconfig into a rest.Config object, which is used by the Kubernetes client.
The rest.Config object is necessary for creating a clientset that can interact with the Kubernetes API.

3. Create Kubernetes Clientset:

   clientset, err := kubernetes.NewForConfig(config)

Uses the rest.Config to create a Kubernetes clientset.
The clientset is the main interface for interacting with the Kubernetes API, allowing operations like listing pods, nodes, etc.

Sau khi đã có clientSet chúng ta hoàn toàn có thể interact với K8S API

// Step 3: Use the clientset to interact with Kubernetes
    // Example: List pods
    pods, err := clientset.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{})
    if err != nil {
        log.Fatalf("Error listing pods: %v", err)
    }
    fmt.Println("Pods in cluster:")
    for _, pod := range pods.Items {
        fmt.Println(pod.Name)
    }

    // Example: List nodes
    nodes, err := clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
    if err != nil {
        log.Fatalf("Error listing nodes: %v", err)
    }
    fmt.Println("Nodes in cluster:")
    for _, node := range nodes.Items {
        fmt.Println(node.Name)
    }


AWS - Amazon Web Service, Golang, Kubernetes

Post navigation

Previous Post: How to aws cli authenticate with AWS
Next Post: EKS Crossplane

More Related Articles

[Golang] Using Repository Pattern to integrate the Database (Postgres) Golang
[AWS] Look into Data Transfer on AWS AWS - Amazon Web Service
[GRPC/Golang] Learning GRPC and Golang through the easy and actual lessons. Golang
[Golang] Design config file or environment file with Golang Golang
[Golang] Chuẩn bị 1 project golang. Coding
[Golang] To use regex to filter and give any values you want. Golang

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Tham Gia Group DevOps nhé!
Để Nim có nhiều động lực ra nhiều bài viết.
Để nhận được những thông báo mới nhất.

Recent Posts

  • [Azure] The subscription is not registered to use namespace ‘Microsoft.ContainerService’ May 8, 2025
  • [Azure] Insufficient regional vcpu quota left May 8, 2025
  • [WordPress] How to add a Dynamic watermark on WordPress. May 6, 2025
  • [vnet/Azure] VNet provisioning via Terraform. April 28, 2025
  • [tracetcp] How to perform a tracert command using a specific port. April 3, 2025

Archives

  • May 2025
  • April 2025
  • March 2025
  • February 2025
  • January 2025
  • December 2024
  • November 2024
  • October 2024
  • September 2024
  • August 2024
  • July 2024
  • June 2024
  • May 2024
  • April 2024
  • March 2024
  • February 2024
  • January 2024
  • December 2023
  • November 2023
  • October 2023
  • September 2023
  • August 2023
  • July 2023
  • June 2023
  • May 2023
  • April 2023
  • March 2023
  • February 2023
  • January 2023
  • December 2022
  • November 2022
  • October 2022
  • September 2022
  • August 2022
  • July 2022
  • June 2022
  • May 2022
  • April 2022
  • March 2022
  • February 2022
  • January 2022
  • December 2021
  • November 2021
  • October 2021
  • September 2021
  • August 2021
  • July 2021
  • June 2021

Categories

  • BareMetal
    • NextCloud
  • CI/CD
    • Argo Events
    • ArgoCD
    • ArgoWorkflows
    • Git
      • Bitbucket
    • Harbor
    • Jenkins
    • Spinnaker
    • TeamCity
  • Coding
    • DevSecOps
    • Golang
    • Jquery & JavaScript
    • Laravel
    • NextJS 14 & ReactJS & Type Script
    • Python
    • Selenium
    • Terraform
      • AWS – Amazon Web Service
      • Azure Cloud
      • GCP – Google Cloud
  • Kubernetes & Container
    • Apache Kafka
      • Kafka
      • Kafka Connect
      • Lenses
    • Docker
    • Helm Chart
    • Isito-EnvoyFilter
    • Kong Gateway
    • Kubernetes
      • Ingress
      • Pod
    • Longhorn – Storage
    • MetalLB
    • OAuth2 Proxy
    • Vault
    • VictoriaMetrics
  • Log, Monitor & Tracing
    • DataDog
    • ELK
      • Kibana
      • Logstash
    • Fluent
    • Grafana
    • Prometheus
  • Uncategorized
  • Admin

Copyright © 2025 NimTechnology.