From 87379b4d7a87cbeba9839926b7c91d355a797353 Mon Sep 17 00:00:00 2001 From: Daniel Areste Hernandez Date: Wed, 26 Nov 2025 13:04:43 +0100 Subject: [PATCH 1/2] feat: collect JWT payload --- pkg/jobs/nic_job_list.go | 107 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/pkg/jobs/nic_job_list.go b/pkg/jobs/nic_job_list.go index 4fd5687..78fc7fe 100644 --- a/pkg/jobs/nic_job_list.go +++ b/pkg/jobs/nic_job_list.go @@ -21,6 +21,7 @@ package jobs import ( "bytes" "context" + "encoding/base64" "encoding/json" "fmt" "path/filepath" @@ -30,6 +31,7 @@ import ( "github.com/nginxinc/nginx-k8s-supportpkg/pkg/crds" "github.com/nginxinc/nginx-k8s-supportpkg/pkg/data_collector" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -54,8 +56,113 @@ func ParseNginxIngressProductInfo(res []byte) data_collector.ProductInfo { return productInfo } +// Returns the first found pod with the 'ingress' substring in its name +func getNginxIngressPod(dc *data_collector.DataCollector, ctx context.Context) (v1.Pod, error) { + for _, namespace := range dc.Namespaces { + pods, err := dc.K8sCoreClientSet.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{}) + if err != nil { + dc.Logger.Printf("\tCould not retrieve pod list for namespace %s: %v\n", namespace, err) + } else { + for _, pod := range pods.Items { + if strings.Contains(pod.Name, "ingress") { + return pod, nil + } + } + } + } + return v1.Pod{}, fmt.Errorf("no nginx-ingress pod found in the provided namespaces") +} + func NICJobList() []Job { jobList := []Job{ + { + Name: "parse-entitlement", + Timeout: time.Second * 10, + Execute: func(dc *data_collector.DataCollector, ctx context.Context, ch chan JobResult) { + jobResult := JobResult{Files: make(map[string][]byte), Error: nil} + + ingressPod, err := getNginxIngressPod(dc, ctx) + if err != nil { + dc.Logger.Printf("\tCould not find nginx-ingress pod: %v\n", err) + jobResult.Error = err + ch <- jobResult + return + } + + for _, container := range ingressPod.Spec.Containers { + if container.Name == "nginx-ingress" { + for _, arg := range container.Args { + if strings.Contains(arg, "mgmt-configmap") { + configMapString := strings.SplitN(arg, "=", 2) + if len(configMapString) != 2 { + dc.Logger.Printf("\tCould not parse mgmt-configmap argument: %s\n", arg) + jobResult.Error = fmt.Errorf("could not parse mgmt-configmap argument: %s", arg) + ch <- jobResult + return + } + configMapName := strings.Split(configMapString[1], "/")[1] + configMapNamespace := strings.Replace(strings.Split(configMapString[1], "/")[0], "$(POD_NAMESPACE)", ingressPod.Namespace, 1) + + configMap, err := dc.K8sCoreClientSet.CoreV1().ConfigMaps(configMapNamespace).Get(ctx, configMapName, metav1.GetOptions{}) + if err != nil { + dc.Logger.Printf("\tCould not retrieve ConfigMap %s in namespace %s: %v\n", configMapName, configMapNamespace, err) + jobResult.Error = err + ch <- jobResult + return + } + + licenseTokenSecretName, exists := configMap.Data["license-token-secret-name"] + if !exists { + dc.Logger.Printf("\tConfigMap %s in namespace %s does not contain 'license-token-secret-name' key\n", configMapName, configMapNamespace) + jobResult.Error = fmt.Errorf("configmap %s in namespace %s does not contain 'license-token-secret-name' key", configMapName, configMapNamespace) + ch <- jobResult + return + } + + licenseTokenSecret, err := dc.K8sCoreClientSet.CoreV1().Secrets(configMapNamespace).Get(ctx, licenseTokenSecretName, metav1.GetOptions{}) + if err != nil { + dc.Logger.Printf("\tCould not retrieve Secret %s in namespace %s: %v\n", licenseTokenSecretName, configMapNamespace, err) + jobResult.Error = err + ch <- jobResult + return + } + + licenseToken, exists := licenseTokenSecret.Data["license.jwt"] + if !exists { + dc.Logger.Printf("\tSecret %s in namespace %s does not contain 'license.jwt' key\n", licenseTokenSecretName, configMapNamespace) + jobResult.Error = fmt.Errorf("secret %s in namespace %s does not contain 'license.jwt' key", licenseTokenSecretName, configMapNamespace) + ch <- jobResult + return + } + + claim := strings.Split(string(licenseToken), ".")[1] + decodedClaim, err := base64.RawStdEncoding.DecodeString(claim) + if err != nil { + dc.Logger.Printf("\tCould not decode license token claim from Secret %s in namespace %s: %v\n", licenseTokenSecretName, configMapNamespace, err) + jobResult.Error = err + ch <- jobResult + return + } + + var prettyJSON bytes.Buffer + err = json.Indent(&prettyJSON, decodedClaim, "", " ") + if err != nil { + dc.Logger.Printf("\tCould not format license token claim JSON from Secret %s in namespace %s: %v\n", licenseTokenSecretName, configMapNamespace, err) + jobResult.Error = err + ch <- jobResult + return + } + + fileName := fmt.Sprintf("%s_payload.json", licenseTokenSecretName) + jobResult.Files[filepath.Join(dc.BaseDir, "entitlement", ingressPod.Namespace, fileName)] = prettyJSON.Bytes() + break + } + } + } + } + ch <- jobResult + }, + }, { Name: "exec-nginx-ingress-version", Timeout: time.Second * 10, From e4898af369f0b000181e5fd2e8eea71957eb4862 Mon Sep 17 00:00:00 2001 From: Daniel Areste Hernandez Date: Wed, 26 Nov 2025 13:37:00 +0100 Subject: [PATCH 2/2] fix: reorder nic jobs --- pkg/jobs/nic_job_list.go | 176 +++++++++++++++++++-------------------- 1 file changed, 88 insertions(+), 88 deletions(-) diff --git a/pkg/jobs/nic_job_list.go b/pkg/jobs/nic_job_list.go index 78fc7fe..1338c50 100644 --- a/pkg/jobs/nic_job_list.go +++ b/pkg/jobs/nic_job_list.go @@ -75,94 +75,6 @@ func getNginxIngressPod(dc *data_collector.DataCollector, ctx context.Context) ( func NICJobList() []Job { jobList := []Job{ - { - Name: "parse-entitlement", - Timeout: time.Second * 10, - Execute: func(dc *data_collector.DataCollector, ctx context.Context, ch chan JobResult) { - jobResult := JobResult{Files: make(map[string][]byte), Error: nil} - - ingressPod, err := getNginxIngressPod(dc, ctx) - if err != nil { - dc.Logger.Printf("\tCould not find nginx-ingress pod: %v\n", err) - jobResult.Error = err - ch <- jobResult - return - } - - for _, container := range ingressPod.Spec.Containers { - if container.Name == "nginx-ingress" { - for _, arg := range container.Args { - if strings.Contains(arg, "mgmt-configmap") { - configMapString := strings.SplitN(arg, "=", 2) - if len(configMapString) != 2 { - dc.Logger.Printf("\tCould not parse mgmt-configmap argument: %s\n", arg) - jobResult.Error = fmt.Errorf("could not parse mgmt-configmap argument: %s", arg) - ch <- jobResult - return - } - configMapName := strings.Split(configMapString[1], "/")[1] - configMapNamespace := strings.Replace(strings.Split(configMapString[1], "/")[0], "$(POD_NAMESPACE)", ingressPod.Namespace, 1) - - configMap, err := dc.K8sCoreClientSet.CoreV1().ConfigMaps(configMapNamespace).Get(ctx, configMapName, metav1.GetOptions{}) - if err != nil { - dc.Logger.Printf("\tCould not retrieve ConfigMap %s in namespace %s: %v\n", configMapName, configMapNamespace, err) - jobResult.Error = err - ch <- jobResult - return - } - - licenseTokenSecretName, exists := configMap.Data["license-token-secret-name"] - if !exists { - dc.Logger.Printf("\tConfigMap %s in namespace %s does not contain 'license-token-secret-name' key\n", configMapName, configMapNamespace) - jobResult.Error = fmt.Errorf("configmap %s in namespace %s does not contain 'license-token-secret-name' key", configMapName, configMapNamespace) - ch <- jobResult - return - } - - licenseTokenSecret, err := dc.K8sCoreClientSet.CoreV1().Secrets(configMapNamespace).Get(ctx, licenseTokenSecretName, metav1.GetOptions{}) - if err != nil { - dc.Logger.Printf("\tCould not retrieve Secret %s in namespace %s: %v\n", licenseTokenSecretName, configMapNamespace, err) - jobResult.Error = err - ch <- jobResult - return - } - - licenseToken, exists := licenseTokenSecret.Data["license.jwt"] - if !exists { - dc.Logger.Printf("\tSecret %s in namespace %s does not contain 'license.jwt' key\n", licenseTokenSecretName, configMapNamespace) - jobResult.Error = fmt.Errorf("secret %s in namespace %s does not contain 'license.jwt' key", licenseTokenSecretName, configMapNamespace) - ch <- jobResult - return - } - - claim := strings.Split(string(licenseToken), ".")[1] - decodedClaim, err := base64.RawStdEncoding.DecodeString(claim) - if err != nil { - dc.Logger.Printf("\tCould not decode license token claim from Secret %s in namespace %s: %v\n", licenseTokenSecretName, configMapNamespace, err) - jobResult.Error = err - ch <- jobResult - return - } - - var prettyJSON bytes.Buffer - err = json.Indent(&prettyJSON, decodedClaim, "", " ") - if err != nil { - dc.Logger.Printf("\tCould not format license token claim JSON from Secret %s in namespace %s: %v\n", licenseTokenSecretName, configMapNamespace, err) - jobResult.Error = err - ch <- jobResult - return - } - - fileName := fmt.Sprintf("%s_payload.json", licenseTokenSecretName) - jobResult.Files[filepath.Join(dc.BaseDir, "entitlement", ingressPod.Namespace, fileName)] = prettyJSON.Bytes() - break - } - } - } - } - ch <- jobResult - }, - }, { Name: "exec-nginx-ingress-version", Timeout: time.Second * 10, @@ -349,6 +261,94 @@ func NICJobList() []Job { ch <- jobResult }, }, + { + Name: "parse-entitlement", + Timeout: time.Second * 10, + Execute: func(dc *data_collector.DataCollector, ctx context.Context, ch chan JobResult) { + jobResult := JobResult{Files: make(map[string][]byte), Error: nil} + + ingressPod, err := getNginxIngressPod(dc, ctx) + if err != nil { + dc.Logger.Printf("\tCould not find nginx-ingress pod: %v\n", err) + jobResult.Error = err + ch <- jobResult + return + } + + for _, container := range ingressPod.Spec.Containers { + if container.Name == "nginx-ingress" { + for _, arg := range container.Args { + if strings.Contains(arg, "mgmt-configmap") { + configMapString := strings.SplitN(arg, "=", 2) + if len(configMapString) != 2 { + dc.Logger.Printf("\tCould not parse mgmt-configmap argument: %s\n", arg) + jobResult.Error = fmt.Errorf("could not parse mgmt-configmap argument: %s", arg) + ch <- jobResult + return + } + configMapName := strings.Split(configMapString[1], "/")[1] + configMapNamespace := strings.Replace(strings.Split(configMapString[1], "/")[0], "$(POD_NAMESPACE)", ingressPod.Namespace, 1) + + configMap, err := dc.K8sCoreClientSet.CoreV1().ConfigMaps(configMapNamespace).Get(ctx, configMapName, metav1.GetOptions{}) + if err != nil { + dc.Logger.Printf("\tCould not retrieve ConfigMap %s in namespace %s: %v\n", configMapName, configMapNamespace, err) + jobResult.Error = err + ch <- jobResult + return + } + + licenseTokenSecretName, exists := configMap.Data["license-token-secret-name"] + if !exists { + dc.Logger.Printf("\tConfigMap %s in namespace %s does not contain 'license-token-secret-name' key\n", configMapName, configMapNamespace) + jobResult.Error = fmt.Errorf("configmap %s in namespace %s does not contain 'license-token-secret-name' key", configMapName, configMapNamespace) + ch <- jobResult + return + } + + licenseTokenSecret, err := dc.K8sCoreClientSet.CoreV1().Secrets(configMapNamespace).Get(ctx, licenseTokenSecretName, metav1.GetOptions{}) + if err != nil { + dc.Logger.Printf("\tCould not retrieve Secret %s in namespace %s: %v\n", licenseTokenSecretName, configMapNamespace, err) + jobResult.Error = err + ch <- jobResult + return + } + + licenseToken, exists := licenseTokenSecret.Data["license.jwt"] + if !exists { + dc.Logger.Printf("\tSecret %s in namespace %s does not contain 'license.jwt' key\n", licenseTokenSecretName, configMapNamespace) + jobResult.Error = fmt.Errorf("secret %s in namespace %s does not contain 'license.jwt' key", licenseTokenSecretName, configMapNamespace) + ch <- jobResult + return + } + + claim := strings.Split(string(licenseToken), ".")[1] + decodedClaim, err := base64.RawStdEncoding.DecodeString(claim) + if err != nil { + dc.Logger.Printf("\tCould not decode license token claim from Secret %s in namespace %s: %v\n", licenseTokenSecretName, configMapNamespace, err) + jobResult.Error = err + ch <- jobResult + return + } + + var prettyJSON bytes.Buffer + err = json.Indent(&prettyJSON, decodedClaim, "", " ") + if err != nil { + dc.Logger.Printf("\tCould not format license token claim JSON from Secret %s in namespace %s: %v\n", licenseTokenSecretName, configMapNamespace, err) + jobResult.Error = err + ch <- jobResult + return + } + + fileName := fmt.Sprintf("%s_payload.json", licenseTokenSecretName) + jobResult.Files[filepath.Join(dc.BaseDir, "entitlement", ingressPod.Namespace, fileName)] = prettyJSON.Bytes() + break + } + } + } + } + ch <- jobResult + }, + }, } return jobList }