6
6
"crypto/sha1"
7
7
"crypto/sha256"
8
8
"encoding/hex"
9
+ "encoding/json"
9
10
"errors"
10
11
"fmt"
11
12
"hash"
@@ -17,15 +18,17 @@ import (
17
18
"slices"
18
19
"strconv"
19
20
"strings"
20
- "syscall"
21
21
"time"
22
22
23
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24
-
25
- mapset "github.com/deckarep/golang-set/v2"
26
-
23
+ apitypes "github.com/armosec/armoapi-go/armotypes"
27
24
"github.com/armosec/utils-k8s-go/wlid"
25
+ mapset "github.com/deckarep/golang-set/v2"
28
26
"github.com/goradd/maps"
27
+ runtimeclient "github.com/inspektor-gadget/inspektor-gadget/pkg/container-utils/runtime-client"
28
+ containerutilsTypes "github.com/inspektor-gadget/inspektor-gadget/pkg/container-utils/types"
29
+ tracerexectype "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/exec/types"
30
+ traceropentype "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/open/types"
31
+ igtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types"
29
32
"github.com/kubescape/go-logger"
30
33
"github.com/kubescape/go-logger/helpers"
31
34
"github.com/kubescape/k8s-interface/instanceidhandler"
@@ -34,18 +37,11 @@ import (
34
37
"github.com/kubescape/k8s-interface/k8sinterface"
35
38
"github.com/kubescape/k8s-interface/workloadinterface"
36
39
"github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1"
40
+ "github.com/prometheus/procfs"
37
41
v1 "k8s.io/api/core/v1"
42
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
38
43
"k8s.io/apimachinery/pkg/util/validation"
39
-
40
- "github.com/prometheus/procfs"
41
-
42
- runtimeclient "github.com/inspektor-gadget/inspektor-gadget/pkg/container-utils/runtime-client"
43
- containerutilsTypes "github.com/inspektor-gadget/inspektor-gadget/pkg/container-utils/types"
44
- tracerexectype "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/exec/types"
45
- traceropentype "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/open/types"
46
- igtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types"
47
-
48
- apitypes "github.com/armosec/armoapi-go/armotypes"
44
+ kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1"
49
45
)
50
46
51
47
var (
@@ -475,9 +471,9 @@ func GetFileSize(path string) (int64, error) {
475
471
}
476
472
477
473
func CalculateSHA256FileExecHash (path string , args []string ) string {
478
- hash := sha256 .New ()
479
- hash .Write ([]byte (fmt .Sprintf ("%s;%v" , path , args )))
480
- hashInBytes := hash .Sum (nil )
474
+ hsh := sha256 .New ()
475
+ hsh .Write ([]byte (fmt .Sprintf ("%s;%v" , path , args )))
476
+ hashInBytes := hsh .Sum (nil )
481
477
return hex .EncodeToString (hashInBytes )
482
478
}
483
479
@@ -683,49 +679,6 @@ func ChunkBy[T any](items []T, chunkSize int) [][]T {
683
679
}
684
680
685
681
// isUnixSocket checks if the given path is a Unix socket.
686
- func isUnixSocket (path string ) (bool , error ) {
687
- fileInfo , err := os .Stat (path )
688
- if err != nil {
689
- return false , err // Could not obtain the file stats
690
- }
691
-
692
- stat , ok := fileInfo .Sys ().(* syscall.Stat_t )
693
- if ! ok {
694
- return false , fmt .Errorf ("not a unix file" )
695
- }
696
-
697
- // Check if the file is a socket
698
- return (stat .Mode & syscall .S_IFMT ) == syscall .S_IFSOCK , nil
699
- }
700
-
701
- func DetectContainerRuntimes (hostMount string ) ([]* containerutilsTypes.RuntimeConfig , error ) {
702
- runtimes := map [igtypes.RuntimeName ]string {
703
- igtypes .RuntimeNameDocker : runtimeclient .DockerDefaultSocketPath ,
704
- igtypes .RuntimeNameCrio : runtimeclient .CrioDefaultSocketPath ,
705
- igtypes .RuntimeNameContainerd : runtimeclient .ContainerdDefaultSocketPath ,
706
- igtypes .RuntimeNamePodman : runtimeclient .PodmanDefaultSocketPath ,
707
- }
708
-
709
- detectedRuntimes := make ([]* containerutilsTypes.RuntimeConfig , 0 )
710
-
711
- for runtimeName , socketPath := range runtimes {
712
- // Check if the socket is available on the host mount
713
- socketPath = hostMount + socketPath
714
- if isSocket , err := isUnixSocket (socketPath ); err == nil && isSocket {
715
- logger .L ().Info ("Detected container runtime" , helpers .String ("runtime" , runtimeName .String ()), helpers .String ("socketPath" , socketPath ))
716
- detectedRuntimes = append (detectedRuntimes , & containerutilsTypes.RuntimeConfig {
717
- Name : runtimeName ,
718
- SocketPath : socketPath ,
719
- })
720
- }
721
- }
722
-
723
- if len (detectedRuntimes ) == 0 {
724
- return nil , fmt .Errorf ("no container runtimes detected at the following paths: %v" , runtimes )
725
- }
726
-
727
- return detectedRuntimes , nil
728
- }
729
682
730
683
func DetectContainerRuntimeViaK8sAPI (ctx context.Context , k8sClient * k8sinterface.KubernetesApi , nodeName string ) (* containerutilsTypes.RuntimeConfig , error ) {
731
684
// Get the current node
@@ -735,17 +688,23 @@ func DetectContainerRuntimeViaK8sAPI(ctx context.Context, k8sClient *k8sinterfac
735
688
if err != nil {
736
689
return nil , fmt .Errorf ("failed to list nodes: %v" , err )
737
690
}
738
-
739
691
if len (nodes .Items ) == 0 {
740
692
return nil , fmt .Errorf ("no node found with name: %s" , nodeName )
741
693
}
742
-
743
694
node := nodes .Items [0 ]
695
+ // parse the runtime info
744
696
runtimeConfig := parseRuntimeInfo (node .Status .NodeInfo .ContainerRuntimeVersion )
745
697
if runtimeConfig .Name == igtypes .RuntimeNameUnknown {
746
698
return nil , fmt .Errorf ("unknown container runtime: %s" , node .Status .NodeInfo .ContainerRuntimeVersion )
747
699
}
748
-
700
+ // override the socket path
701
+ realSocketPath , err := getContainerRuntimeSocketPath (k8sClient , nodeName )
702
+ if err != nil {
703
+ return nil , fmt .Errorf ("failed to get container runtime socket path from Kubelet configz: %v" , err )
704
+ }
705
+ runtimeConfig .SocketPath = realSocketPath
706
+ // unset the runtime protocol
707
+ runtimeConfig .RuntimeProtocol = ""
749
708
return runtimeConfig , nil
750
709
}
751
710
@@ -783,3 +742,48 @@ func parseRuntimeInfo(version string) *containerutilsTypes.RuntimeConfig {
783
742
}
784
743
}
785
744
}
745
+
746
+ func getContainerRuntimeSocketPath (clientset * k8sinterface.KubernetesApi , nodeName string ) (string , error ) {
747
+ kubeletConfig , err := getCurrentKubeletConfig (clientset , nodeName )
748
+ if err != nil {
749
+ return "" , fmt .Errorf ("getting /configz: %w" , err )
750
+ }
751
+ socketPath , found := strings .CutPrefix (kubeletConfig .ContainerRuntimeEndpoint , "unix://" )
752
+ if ! found {
753
+ return "" , fmt .Errorf ("socket path does not start with unix://" )
754
+ }
755
+ logger .L ().Info ("using the detected container runtime socket path from Kubelet's config" , helpers .String ("socketPath" , socketPath ))
756
+ return socketPath , nil
757
+ }
758
+
759
+ // The /configz endpoint isn't officially documented. It was introduced in Kubernetes 1.26 and been around for a long time
760
+ // as stated in https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/component-base/configz/OWNERS
761
+ func getCurrentKubeletConfig (clientset * k8sinterface.KubernetesApi , nodeName string ) (* kubeletconfigv1beta1.KubeletConfiguration , error ) {
762
+ resp , err := clientset .GetKubernetesClient ().CoreV1 ().RESTClient ().Get ().Resource ("nodes" ).
763
+ Name (nodeName ).Suffix ("proxy" , "configz" ).DoRaw (context .TODO ())
764
+ if err != nil {
765
+ return nil , fmt .Errorf ("fetching /configz from %q: %w" , nodeName , err )
766
+ }
767
+ kubeCfg , err := decodeConfigz (resp )
768
+ if err != nil {
769
+ return nil , err
770
+ }
771
+ return kubeCfg , nil
772
+ }
773
+
774
+ // Decodes the http response from /configz and returns the kubelet configuration
775
+ func decodeConfigz (respBody []byte ) (* kubeletconfigv1beta1.KubeletConfiguration , error ) {
776
+ // This hack because /configz reports the following structure:
777
+ // {"kubeletconfig": {the JSON representation of kubeletconfigv1beta1.KubeletConfiguration}}
778
+ type configzWrapper struct {
779
+ ComponentConfig kubeletconfigv1beta1.KubeletConfiguration `json:"kubeletconfig"`
780
+ }
781
+
782
+ configz := configzWrapper {}
783
+ err := json .Unmarshal (respBody , & configz )
784
+ if err != nil {
785
+ return nil , err
786
+ }
787
+
788
+ return & configz .ComponentConfig , nil
789
+ }
0 commit comments