Skip to content
39 changes: 28 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Container Explorer provides the following functionalities:
- Exploring images
- Exploring snapshots
- Exploring contents
- Exploring container drift
- Mounting containers
- Support JSON output

Expand All @@ -28,39 +29,43 @@ The figure below shows the output of the container-explorer --help command.
```text
NAME:
container-explorer - A standalone utility to explore container details

USAGE:
container-explorer [global options] command [command options] [arguments...]
ce [global options] command [command options] [arguments...]

VERSION:
0.0.2
0.2.1 (20240502)

DESCRIPTION:
A standalone utility to explore container details.

Container explorer supports exploring containers managed using containerd and
docker. The utility also supports exploring containers created and managed
using Kubernetes.
docker. The utility also supports exploring containers created and managed using
Kubernetes.


COMMANDS:
list, ls Lists container related information
info show internal information
mount mount a container to a mount point
mount-all, mount_all mount all containers
drift, diff identifies container filesystem changes
help, h Shows a list of commands or help for one command

GLOBAL OPTIONS:
--debug enable debug messages
--containerd-root value, -c value specify containerd root directory
--image-root value, -i value specify mount point for a disk image
--metadata-file value, -m value specify the path to containerd metadata file i.e. meta.db
--snapshot-metadata-file value, -s value specify the path to containerd snapshot metadata file i.e. metadata.db.
--use-layer-cache attempt to use cached layers where layers are symlinks
--layer-cache value cached layer folder within the snapshot root (default: "layers")
--namespace value, -n value specify container namespace (default: "default")
--docker-managed specify docker manages standalone or Kubernetes containers
--docker-root value specify docker root directory. This is only used with flag --docker-managed
--support-container-data value a yaml file containing information about support containers
--output value output format in json, table. Default is table (default: "table")
--output-file value, -o value output file to save the content
--help, -h show help
--version, -v print the version
```
Expand Down Expand Up @@ -146,6 +151,18 @@ forensic VM as `/dev/sdb`.
drwxr-xr-x 1 root root 4096 Feb 5 08:54 f3c910583a81e7441e2cbd209b72afa4740e676ff8d82f2c74fdc5c78e179c10
```

6. See filesystem changes

```shell
sudo ce -i /mnt/case/ --output json --support-container-data supportcontainer.yaml drift
```

In order to see drift of a particular container, supply the container ID with drift/diff

```shell
sudo ce -i /mnt/case/ --output json --support-container-data supportcontainer.yaml drift f3c910583a81e7441e2cbd209b72afa4740e676ff8d82f2c74fdc5c78e179c10
```

6. Use your favorite forensic tool to process mounted containers.

## Mounting Disk Image
Expand Down
116 changes: 116 additions & 0 deletions cmd/commands/drift.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
Copyright 2024 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package commands

import (
"fmt"
"runtime"
"os"
"strings"
"text/tabwriter"

log "github.com/sirupsen/logrus"
"github.com/urfave/cli"
)

var DriftCommand = cli.Command{
Name: "drift",
Aliases: []string{"diff"},
Usage: "identifies container filesystem changes",
Description: "identifies container filesystem changes for all containers",
ArgsUsage: "[containerID]",
Flags: []cli.Flag{
cli.StringFlag{
Name: "filter",
Usage: "comma separated label filter using key=value pair",
},
cli.BoolFlag{
Name: "mount-support-containers",
Usage: "mount Kubernetes supporting containers",
},
},
Action: func(clictx *cli.Context) error {
// Mounting a container is only supported on a Linux operating system.
if runtime.GOOS != "linux" {
return fmt.Errorf("feature is only supported on Linux")
}
output := clictx.GlobalString("output")
outputfile := clictx.GlobalString("output-file")
filter := clictx.String("filter")

// Getting container ID positional arg
var containerID string
if clictx.Args().Present() {
containerID = clictx.Args().First()
}

ctx, exp, cancel, err := explorerEnvironment(clictx)
if err != nil {
return err
}
defer cancel()

drifts, err := exp.ContainerDrift(ctx, filter, !clictx.Bool("mount-support-containers"), containerID)
if err != nil {
log.WithField("message", err).Error("retrieving container drift")
if output == "json" && outputfile != "" {
data := []string{}
writeOutputFile(data, outputfile)
}
return nil
}
// Handle output formats
if strings.ToLower(output) == "json" {
if outputfile != "" {
writeOutputFile(drifts, outputfile)
} else {
printAsJSON(drifts)
}
return nil
}

// Default to table output
tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, '\t', 0)
defer tw.Flush()

if output == "table" {
// Define the header
fmt.Fprintf(tw, "CONTAINER ID\tADDED/MODIFIED\tDELETED\n")
}

for _, drift := range drifts {
switch strings.ToLower(output) {
case "json_line":
printAsJSONLine(drift)
default:
// Prepare the data for display
addedOrModified := strings.Join(drift.AddedOrModified, ", ")
inaccessibleFiles := strings.Join(drift.InaccessibleFiles, ", ")

displayValues := fmt.Sprintf("%s\t%s\t%s",
drift.ContainerID,
addedOrModified,
inaccessibleFiles,
)

fmt.Fprintf(tw, "%v\n", displayValues)
}
}
// default
return nil
},
}
1 change: 1 addition & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ func main() {
cecommands.InfoCommand,
cecommands.MountCommand,
cecommands.MountAllCommand,
cecommands.DriftCommand,
}

app.Before = func(context *cli.Context) error {
Expand Down
6 changes: 6 additions & 0 deletions explorers/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,9 @@ type Container struct {
Running bool
ExposedPorts []string
}

type Drift struct {
ContainerID string
AddedOrModified []string
InaccessibleFiles []string
}
Loading