Skip to content

Commit 8cc6300

Browse files
committed
read SocketPath from node config, unset RuntimeProtocol
Signed-off-by: Matthias Bertschy <[email protected]>
1 parent 4fb52bf commit 8cc6300

File tree

2 files changed

+73
-65
lines changed

2 files changed

+73
-65
lines changed

pkg/containerwatcher/v1/container_watcher_private.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ func (ch *IGContainerWatcher) containerCallback(notif containercollection.PubSub
3636

3737
switch notif.Type {
3838
case containercollection.EventTypeAddContainer:
39-
logger.L().Info("start monitor on container", helpers.String("container ID", notif.Container.Runtime.ContainerID), helpers.String("k8s workload", k8sContainerID))
39+
logger.L().Info("start monitor on container",
40+
helpers.String("container ID", notif.Container.Runtime.ContainerID),
41+
helpers.String("k8s workload", k8sContainerID),
42+
helpers.String("ContainerImageDigest", notif.Container.Runtime.ContainerImageDigest),
43+
helpers.String("ContainerImageName", notif.Container.Runtime.ContainerImageName))
4044
if ch.running {
4145
ch.timeBasedContainers.Add(notif.Container.Runtime.ContainerID)
4246
} else {

pkg/utils/utils.go

Lines changed: 68 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"crypto/sha1"
77
"crypto/sha256"
88
"encoding/hex"
9+
"encoding/json"
910
"errors"
1011
"fmt"
1112
"hash"
@@ -17,15 +18,17 @@ import (
1718
"slices"
1819
"strconv"
1920
"strings"
20-
"syscall"
2121
"time"
2222

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"
2724
"github.com/armosec/utils-k8s-go/wlid"
25+
mapset "github.com/deckarep/golang-set/v2"
2826
"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"
2932
"github.com/kubescape/go-logger"
3033
"github.com/kubescape/go-logger/helpers"
3134
"github.com/kubescape/k8s-interface/instanceidhandler"
@@ -34,18 +37,11 @@ import (
3437
"github.com/kubescape/k8s-interface/k8sinterface"
3538
"github.com/kubescape/k8s-interface/workloadinterface"
3639
"github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1"
40+
"github.com/prometheus/procfs"
3741
v1 "k8s.io/api/core/v1"
42+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3843
"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"
4945
)
5046

5147
var (
@@ -475,9 +471,9 @@ func GetFileSize(path string) (int64, error) {
475471
}
476472

477473
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)
481477
return hex.EncodeToString(hashInBytes)
482478
}
483479

@@ -683,49 +679,6 @@ func ChunkBy[T any](items []T, chunkSize int) [][]T {
683679
}
684680

685681
// 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-
}
729682

730683
func DetectContainerRuntimeViaK8sAPI(ctx context.Context, k8sClient *k8sinterface.KubernetesApi, nodeName string) (*containerutilsTypes.RuntimeConfig, error) {
731684
// Get the current node
@@ -735,17 +688,23 @@ func DetectContainerRuntimeViaK8sAPI(ctx context.Context, k8sClient *k8sinterfac
735688
if err != nil {
736689
return nil, fmt.Errorf("failed to list nodes: %v", err)
737690
}
738-
739691
if len(nodes.Items) == 0 {
740692
return nil, fmt.Errorf("no node found with name: %s", nodeName)
741693
}
742-
743694
node := nodes.Items[0]
695+
// parse the runtime info
744696
runtimeConfig := parseRuntimeInfo(node.Status.NodeInfo.ContainerRuntimeVersion)
745697
if runtimeConfig.Name == igtypes.RuntimeNameUnknown {
746698
return nil, fmt.Errorf("unknown container runtime: %s", node.Status.NodeInfo.ContainerRuntimeVersion)
747699
}
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 = ""
749708
return runtimeConfig, nil
750709
}
751710

@@ -783,3 +742,48 @@ func parseRuntimeInfo(version string) *containerutilsTypes.RuntimeConfig {
783742
}
784743
}
785744
}
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

Comments
 (0)