diff --git a/orbit/changes/48006-queryable-socket-path b/orbit/changes/48006-queryable-socket-path new file mode 100644 index 0000000000..358cc01b72 --- /dev/null +++ b/orbit/changes/48006-queryable-socket-path @@ -0,0 +1,2 @@ +* Adds an optional, queryable socket_path column to both containerd_containers and containerd_mounts. +* Defaults to /run/containerd/containerd.sock when no value is specified, maintaining backwards compatibility. \ No newline at end of file diff --git a/orbit/pkg/table/containerd/containerd_linux.go b/orbit/pkg/table/containerd/containerd_linux.go new file mode 100644 index 0000000000..d80911209f --- /dev/null +++ b/orbit/pkg/table/containerd/containerd_linux.go @@ -0,0 +1,30 @@ +//go:build linux + +package containerd + +import ( + "github.com/containerd/containerd" + "github.com/fleetdm/fleet/v4/orbit/pkg/table/tablehelpers" + "github.com/osquery/osquery-go/plugin/table" +) + +const ( + defaultSocketPath = "/run/containerd/containerd.sock" + socketPathCol = "socket_path" +) + +// resolveSocketPath fetches socket path from the query context. +func resolveSocketPath(queryContext table.QueryContext) string { + paths := tablehelpers.GetConstraints(queryContext, socketPathCol, tablehelpers.WithDefaults(defaultSocketPath)) + if len(paths) == 0 { + return defaultSocketPath + } + return paths[0] +} + +// newClient wraps the creation of containerd.Client to handle the socket path. +func newClient(queryContext table.QueryContext) (*containerd.Client, string, error) { + sp := resolveSocketPath(queryContext) + client, err := containerd.New(sp) + return client, sp, err +} diff --git a/orbit/pkg/table/containerd/containerd_linux_test.go b/orbit/pkg/table/containerd/containerd_linux_test.go new file mode 100644 index 0000000000..255365a873 --- /dev/null +++ b/orbit/pkg/table/containerd/containerd_linux_test.go @@ -0,0 +1,38 @@ +//go:build linux + +package containerd + +import ( + "testing" + + "github.com/fleetdm/fleet/v4/orbit/pkg/table/tablehelpers" + "github.com/stretchr/testify/require" +) + +func TestSocketPath(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + constraints map[string][]string + expected string + }{ + { + name: "return legacy default", + constraints: nil, + expected: defaultSocketPath, + }, + { + name: "return explicit socket", + constraints: map[string][]string{socketPathCol: {"/run/k3s/containerd/containerd.sock"}}, + expected: "/run/k3s/containerd/containerd.sock", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + require.Equal(t, tt.expected, resolveSocketPath(tablehelpers.MockQueryContext(tt.constraints))) + }) + } +} diff --git a/orbit/pkg/table/containerd/containers_linux.go b/orbit/pkg/table/containerd/containers_linux.go index 91fd862e25..9c9f9fab3d 100644 --- a/orbit/pkg/table/containerd/containers_linux.go +++ b/orbit/pkg/table/containerd/containers_linux.go @@ -7,7 +7,6 @@ import ( "fmt" "strings" - "github.com/containerd/containerd" "github.com/containerd/containerd/cio" "github.com/containerd/containerd/namespaces" "github.com/osquery/osquery-go/plugin/table" @@ -26,13 +25,14 @@ func ContainersColumns() []table.ColumnDefinition { table.TextColumn("runtime"), table.TextColumn("command"), table.BigIntColumn("pid"), + table.TextColumn("socket_path"), } } // GenerateContainers is called to return the results for the containerd_containers table at query time. // Constraints for generating can be retrieved from the queryContext. func GenerateContainers(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) { - client, err := containerd.New("/run/containerd/containerd.sock") + client, socketPath, err := newClient(queryContext) if err != nil { return nil, fmt.Errorf("Failed to connect to containerd: %v", err) } @@ -100,6 +100,7 @@ func GenerateContainers(ctx context.Context, queryContext table.QueryContext) ([ "runtime": info.Runtime.Name, "pid": pid, "command": command, + "socket_path": socketPath, } rows = append(rows, row) } diff --git a/orbit/pkg/table/containerd/mounts_linux.go b/orbit/pkg/table/containerd/mounts_linux.go index cc432c6988..5932dfcece 100644 --- a/orbit/pkg/table/containerd/mounts_linux.go +++ b/orbit/pkg/table/containerd/mounts_linux.go @@ -7,7 +7,6 @@ import ( "fmt" "strings" - "github.com/containerd/containerd" "github.com/containerd/containerd/namespaces" "github.com/osquery/osquery-go/plugin/table" "github.com/rs/zerolog/log" @@ -22,13 +21,14 @@ func MountsColumns() []table.ColumnDefinition { table.TextColumn("source"), table.TextColumn("destination"), table.TextColumn("options"), + table.TextColumn("socket_path"), } } // GenerateMounts is called to return the results for the containerd_mounts table at query time. // Constraints for generating can be retrieved from the queryContext. func GenerateMounts(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) { - client, err := containerd.New("/run/containerd/containerd.sock") + client, socketPath, err := newClient(queryContext) if err != nil { return nil, fmt.Errorf("Failed to connect to containerd: %w", err) } @@ -67,6 +67,7 @@ func GenerateMounts(ctx context.Context, queryContext table.QueryContext) ([]map "source": mount.Source, "destination": mount.Destination, "options": strings.Join(mount.Options, ","), + "socket_path": socketPath, } rows = append(rows, row) } diff --git a/schema/osquery_fleet_schema.json b/schema/osquery_fleet_schema.json index a97fe8ed2e..a9ab4fee7f 100644 --- a/schema/osquery_fleet_schema.json +++ b/schema/osquery_fleet_schema.json @@ -4776,9 +4776,15 @@ "type": "integer", "required": false, "description": "PID of the container process." + }, + { + "name": "socket_path", + "type": "text", + "required": false, + "description": "Path to the containerd socket to query (default: /run/containerd/containerd.sock)." } ], - "examples": "Get all containers from all namespaces:\n\n```\nSELECT * FROM containerd_containers;\n```\n\nGet only running containers in the `default` namespace:\n\n```\nSELECT * FROM containerd_containers WHERE namespace='default' AND state='running';\n```", + "examples": "Get all containers from all namespaces:\n\n```\nSELECT * FROM containerd_containers;\n```\n\nGet only running containers in the `default` namespace:\n\n```\nSELECT * FROM containerd_containers WHERE namespace='default' AND state='running';\n```\n\nQuery containers from a k3s containerd socket:\n\n```\nSELECT * FROM containerd_containers WHERE socket_path = '/run/k3s/containerd/containerd.sock';\n```", "notes": "This table is not a core osquery table. It is included as part of Fleet's agent\n([fleetd](https://fleetdm.com/docs/get-started/anatomy#fleetd)).\n\nThe `containerd` table is available on Linux systems with containerd installed. It provides\ninformation about the containers managed by containerd, including their state, image, and runtime.\n\nThis table is useful for systems using containerd as a container runtime, such as those running\nKubernetes. See the `docker_containers` table for information about containers managed by Docker.", "url": "https://fleetdm.com/tables/containerd_containers", "fleetRepoUrl": "https://github.com/fleetdm/fleet/blob/main/schema/tables/containerd_containers.yml" @@ -4826,9 +4832,15 @@ "type": "text", "required": false, "description": "Mount options (comma-separated)." + }, + { + "name": "socket_path", + "type": "text", + "required": false, + "description": "Path to the containerd socket to query (default: /run/containerd/containerd.sock)." } ], - "examples": "Get all mounts for all containers:\n\n```\nSELECT * FROM containerd_mounts;\n```\n\nGet mounts for a specific container:\n\n```\nSELECT * FROM containerd_mounts WHERE container_id='abc123';\n```\n\nGet all bind mounts:\n\n```\nSELECT * FROM containerd_mounts WHERE type='bind';\n```", + "examples": "Get all mounts for all containers:\n\n```\nSELECT * FROM containerd_mounts;\n```\n\nGet mounts for a specific container:\n\n```\nSELECT * FROM containerd_mounts WHERE container_id='abc123';\n```\n\nGet all bind mounts:\n\n```\nSELECT * FROM containerd_mounts WHERE type='bind';\n```\n\nQuery mounts from a k3s containerd socket:\n\n```\nSELECT * FROM containerd_mounts WHERE socket_path = '/run/k3s/containerd/containerd.sock';\n```", "notes": "This table is not a core osquery table. It is included as part of Fleet's agent\n([fleetd](https://fleetdm.com/docs/get-started/anatomy#fleetd)).\n\nThe `containerd_mounts` table is available on Linux systems with containerd installed. It provides\ninformation about the mounts configured for containers managed by containerd.\n\nThis table is useful for systems using containerd as a container runtime, such as those running\nKubernetes. See the `docker_container_mounts` table for information about mounts in Docker containers.", "url": "https://fleetdm.com/tables/containerd_mounts", "fleetRepoUrl": "https://github.com/fleetdm/fleet/blob/main/schema/tables/containerd_mounts.yml" diff --git a/schema/tables/containerd_containers.yml b/schema/tables/containerd_containers.yml index 6024cef529..09f89e7ec1 100644 --- a/schema/tables/containerd_containers.yml +++ b/schema/tables/containerd_containers.yml @@ -49,6 +49,11 @@ columns: required: false description: |- PID of the container process. + - name: socket_path + type: text + required: false + description: |- + Path to the containerd socket to query (default: /run/containerd/containerd.sock). examples: |- Get all containers from all namespaces: @@ -61,6 +66,12 @@ examples: |- ``` SELECT * FROM containerd_containers WHERE namespace='default' AND state='running'; ``` + + Query containers from a k3s containerd socket: + + ``` + SELECT * FROM containerd_containers WHERE socket_path = '/run/k3s/containerd/containerd.sock'; + ``` notes: |- This table is not a core osquery table. It is included as part of Fleet's agent diff --git a/schema/tables/containerd_mounts.yml b/schema/tables/containerd_mounts.yml index a3f0048a0b..d3f83ff881 100644 --- a/schema/tables/containerd_mounts.yml +++ b/schema/tables/containerd_mounts.yml @@ -34,6 +34,11 @@ columns: required: false description: |- Mount options (comma-separated). + - name: socket_path + type: text + required: false + description: |- + Path to the containerd socket to query (default: /run/containerd/containerd.sock). examples: |- Get all mounts for all containers: @@ -53,6 +58,12 @@ examples: |- SELECT * FROM containerd_mounts WHERE type='bind'; ``` + Query mounts from a k3s containerd socket: + + ``` + SELECT * FROM containerd_mounts WHERE socket_path = '/run/k3s/containerd/containerd.sock'; + ``` + notes: |- This table is not a core osquery table. It is included as part of Fleet's agent ([fleetd](https://fleetdm.com/docs/get-started/anatomy#fleetd)).