Skip to content

Commit

Permalink
Merge pull request #1448 from DelusionalOptimist/delusionaloptimist/f…
Browse files Browse the repository at this point in the history
…eat/extended-vm-support

feat(*): extended VM support
  • Loading branch information
daemon1024 authored Jan 22, 2024
2 parents 0b27784 + f642a76 commit 2bac1d1
Show file tree
Hide file tree
Showing 30 changed files with 1,678 additions and 1,182 deletions.
2 changes: 1 addition & 1 deletion KubeArmor/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ run: build
.PHONY: run-container
run-container: build
cd $(CURDIR); sudo rm -f /tmp/kubearmor.log
cd $(CURDIR); sudo -E ./kubearmor -logPath=/tmp/kubearmor.log -enableKubeArmorHostPolicy -enableKubeArmorPolicy -k8s=false
cd $(CURDIR); DEBUG=true sudo -E ./kubearmor -logPath=/tmp/kubearmor.log -enableKubeArmorHostPolicy -enableKubeArmorPolicy -k8s=false -criSocket=unix:///var/run/docker.sock

.PHONY: run-host-only
run-host-only: build
Expand Down
67 changes: 66 additions & 1 deletion KubeArmor/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"io"
"net"
"net/url"
"os"
"os/exec"
"path/filepath"
Expand All @@ -19,6 +20,9 @@ import (

kc "github.com/kubearmor/KubeArmor/KubeArmor/config"
kg "github.com/kubearmor/KubeArmor/KubeArmor/log"
"golang.org/x/sys/unix"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand Down Expand Up @@ -375,6 +379,9 @@ func IsK8sEnv() bool {
return false
}

// ContainerRuntimeSocketKeys contains FIFO ordered keys of container runtimes
var ContainerRuntimeSocketKeys = []string{"docker", "containerd", "cri-o"}

// ContainerRuntimeSocketMap Structure
var ContainerRuntimeSocketMap = map[string][]string{
"docker": {
Expand All @@ -396,7 +403,7 @@ var ContainerRuntimeSocketMap = map[string][]string{

// GetCRISocket Function
func GetCRISocket(ContainerRuntime string) string {
for k := range ContainerRuntimeSocketMap {
for _, k := range ContainerRuntimeSocketKeys {
if ContainerRuntime != "" && k != ContainerRuntime {
continue
}
Expand Down Expand Up @@ -456,3 +463,61 @@ func WriteToFile(val interface{}, destFile string) error {
}
return nil
}

// ParseURL with/without scheme and return host, port or error
func ParseURL(address string) (string, string, error) {
var host string
port := "80"

addr, err := url.Parse(address)
if err != nil || addr.Host == "" {
// URL without scheme
u, repErr := url.ParseRequestURI("http://" + address)
if repErr != nil {
return "", "", fmt.Errorf("Error while parsing URL: %s", err)
}

addr = u
}

host = addr.Hostname()
if addr.Port() != "" {
port = addr.Port()
}

return host, port, nil
}

// handle gRPC errors

Check warning on line 491 in KubeArmor/common/common.go

View workflow job for this annotation

GitHub Actions / go-lint

comment on exported function HandleGRPCErrors should be of the form "HandleGRPCErrors ..."
func HandleGRPCErrors(err error) error {
if err == nil {
return nil
}

if status, ok := status.FromError(err); ok {
switch status.Code() {
case codes.OK:
// noop
return nil
//case codes.Unavailable, codes.Canceled, codes.DeadlineExceeded:
// return status.Err()
default:
return status.Err()
}
}

return nil
}

// get boot time

Check warning on line 512 in KubeArmor/common/common.go

View workflow job for this annotation

GitHub Actions / go-lint

comment on exported function GetBootTime should be of the form "GetBootTime ..."
// credits: https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/util/boottime_util_linux.go
func GetBootTime() string {
currentTime := time.Now()

var info unix.Sysinfo_t
if err := unix.Sysinfo(&info); err != nil {
return ""
}

return currentTime.Add(-time.Duration(info.Uptime) * time.Second).Truncate(time.Second).UTC().String()
}
11 changes: 11 additions & 0 deletions KubeArmor/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type KubearmorConfig struct {
EnforcerAlerts bool // policy enforcer
DefaultPostureLogs bool // Enable/Disable Default Posture logs for AppArmor LSM

StateAgent bool // enable KubeArmor state agent
}

// GlobalCfg Global configuration for Kubearmor
Expand Down Expand Up @@ -84,6 +85,7 @@ const (
BPFFsPath string = "bpfFsPath"
EnforcerAlerts string = "enforcerAlerts"
ConfigDefaultPostureLogs string = "defaultPostureLogs"
ConfigStateAgent string = "enableKubeArmorStateAgent"
)

func readCmdLineParams() {
Expand Down Expand Up @@ -125,6 +127,8 @@ func readCmdLineParams() {

defaultPostureLogs := flag.Bool(ConfigDefaultPostureLogs, true, "Default Posture Alerts (for Apparmor only)")

stateAgent := flag.Bool(ConfigStateAgent, false, "enabling KubeArmor State Agent client")

flags := []string{}
flag.VisitAll(func(f *flag.Flag) {
kv := fmt.Sprintf("%s:%v", f.Name, f.Value)
Expand Down Expand Up @@ -171,6 +175,8 @@ func readCmdLineParams() {
viper.SetDefault(EnforcerAlerts, *enforcerAlerts)

viper.SetDefault(ConfigDefaultPostureLogs, *defaultPostureLogs)

viper.SetDefault(ConfigStateAgent, *stateAgent)
}

// LoadConfig Load configuration
Expand Down Expand Up @@ -198,6 +204,9 @@ func LoadConfig() error {

GlobalCfg.Cluster = viper.GetString(ConfigCluster)
GlobalCfg.Host = viper.GetString(ConfigHost)
if hostname, err := os.Hostname(); GlobalCfg.Host == "" && err == nil {
GlobalCfg.Host = strings.Split(hostname, ".")[0]
}

GlobalCfg.GRPC = viper.GetString(ConfigGRPC)
GlobalCfg.LogPath = viper.GetString(ConfigLogPath)
Expand Down Expand Up @@ -256,6 +265,8 @@ func LoadConfig() error {

GlobalCfg.DefaultPostureLogs = viper.GetBool(ConfigDefaultPostureLogs)

GlobalCfg.StateAgent = viper.GetBool(ConfigStateAgent)

kg.Printf("Final Configuration [%+v]", GlobalCfg)

return nil
Expand Down
33 changes: 33 additions & 0 deletions KubeArmor/core/containerdHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import (
"fmt"
"os"
"strconv"
"strings"
"time"

kl "github.com/kubearmor/KubeArmor/KubeArmor/common"
cfg "github.com/kubearmor/KubeArmor/KubeArmor/config"
kg "github.com/kubearmor/KubeArmor/KubeArmor/log"
"github.com/kubearmor/KubeArmor/KubeArmor/state"
tp "github.com/kubearmor/KubeArmor/KubeArmor/types"

pb "github.com/containerd/containerd/api/services/containers/v1"
Expand Down Expand Up @@ -132,6 +134,10 @@ func (ch *ContainerdHandler) GetContainerInfo(ctx context.Context, containerID s
if val, ok := containerLabels["io.kubernetes.pod.name"]; ok {
container.EndPointName = val
}
} else if val, ok := containerLabels["kubearmor.io/namespace"]; ok {
container.NamespaceName = val
} else {
container.NamespaceName = "container_namespace"
}

iface, err := typeurl.UnmarshalAny(res.Container.Spec)
Expand Down Expand Up @@ -169,6 +175,23 @@ func (ch *ContainerdHandler) GetContainerInfo(ctx context.Context, containerID s

// == //

if cfg.GlobalCfg.StateAgent && !cfg.GlobalCfg.K8sEnv {
container.ContainerImage = res.Container.Image //+ kl.GetSHA256ofImage(inspect.Image)

container.NodeName = cfg.GlobalCfg.Host

labels := []string{}
for k, v := range res.Container.Labels {
labels = append(labels, k+"="+v)
}
for k, v := range spec.Annotations {
labels = append(labels, k+"="+v)
}
container.Labels = strings.Join(labels, ",")
}

// == //

return container, nil
}

Expand Down Expand Up @@ -305,6 +328,11 @@ func (dm *KubeArmorDaemon) UpdateContainerdContainer(ctx context.Context, contai
dm.ContainersLock.Unlock()
}

if cfg.GlobalCfg.StateAgent {
container.Status = "running"
go dm.StateAgent.PushContainerEvent(container, state.EventAdded)
}

dm.Logger.Printf("Detected a container (added/%.12s/pidns=%d/mntns=%d)", containerID, container.PidNS, container.MntNS)

} else if action == "destroy" {
Expand Down Expand Up @@ -345,6 +373,11 @@ func (dm *KubeArmorDaemon) UpdateContainerdContainer(ctx context.Context, contai
dm.RuntimeEnforcer.UnregisterContainer(containerID)
}

if cfg.GlobalCfg.StateAgent {
container.Status = "terminated"
go dm.StateAgent.PushContainerEvent(container, state.EventDeleted)
}

dm.Logger.Printf("Detected a container (removed/%.12s/pidns=%d/mntns=%d)", containerID, container.PidNS, container.MntNS)
}

Expand Down
79 changes: 79 additions & 0 deletions KubeArmor/core/dockerHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"os"
"strconv"
"strings"
"time"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/events"
Expand All @@ -18,6 +19,7 @@ import (
kl "github.com/kubearmor/KubeArmor/KubeArmor/common"
cfg "github.com/kubearmor/KubeArmor/KubeArmor/config"
kg "github.com/kubearmor/KubeArmor/KubeArmor/log"
"github.com/kubearmor/KubeArmor/KubeArmor/state"
tp "github.com/kubearmor/KubeArmor/KubeArmor/types"
)

Expand All @@ -37,6 +39,9 @@ type DockerVersion struct {
type DockerHandler struct {
DockerClient *client.Client
Version DockerVersion

// needed for container info
NodeIP string
}

// NewDockerHandler Function
Expand Down Expand Up @@ -65,6 +70,8 @@ func NewDockerHandler() (*DockerHandler, error) {

docker.DockerClient = DockerClient

docker.NodeIP = kl.GetExternalIPAddr()

kg.Printf("Initialized Docker Handler (version: %s)", clientVersion)

return docker, nil
Expand Down Expand Up @@ -112,6 +119,10 @@ func (dh *DockerHandler) GetContainerInfo(containerID string) (tp.Container, err
if val, ok := containerLabels["io.kubernetes.pod.name"]; ok {
container.EndPointName = val
}
} else if val, ok := containerLabels["kubearmor.io/namespace"]; ok {
container.NamespaceName = val
} else {
container.NamespaceName = "container_namespace"
}

container.AppArmorProfile = inspect.AppArmorProfile
Expand All @@ -134,6 +145,48 @@ func (dh *DockerHandler) GetContainerInfo(containerID string) (tp.Container, err

// == //

if cfg.GlobalCfg.StateAgent && !cfg.GlobalCfg.K8sEnv {
container.ContainerImage = inspect.Config.Image //+ kl.GetSHA256ofImage(inspect.Image)

container.NodeName = cfg.GlobalCfg.Host

labels := []string{}
for k, v := range inspect.Config.Labels {
labels = append(labels, k+"="+v)
}

if _, ok := containerLabels["kubearmor.io/container.name"]; !ok {
labels = append(labels, "kubearmor.io/container.name="+container.ContainerName)
}

container.Labels = strings.Join(labels, ",")

var podIP string
if inspect.HostConfig.NetworkMode.IsNone() || inspect.HostConfig.NetworkMode.IsContainer() {
podIP = ""
} else if inspect.HostConfig.NetworkMode.IsHost() {
podIP = dh.NodeIP
} else if inspect.HostConfig.NetworkMode.IsDefault() {
podIP = inspect.NetworkSettings.Networks["bridge"].IPAddress
} else {
networkName := inspect.HostConfig.NetworkMode.NetworkName()
podIP = inspect.NetworkSettings.Networks[networkName].IPAddress
}
container.ContainerIP = podIP

// time format used by docker engine is RFC3339Nano
lastUpdatedAt, err := time.Parse(time.RFC3339Nano, inspect.State.StartedAt)
if err == nil {
container.LastUpdatedAt = lastUpdatedAt.UTC().String()
}
// finished at is IsZero until a container exits
timeFinished, err := time.Parse(time.RFC3339Nano, inspect.State.FinishedAt)
if err == nil && !timeFinished.IsZero() && timeFinished.After(lastUpdatedAt) {
lastUpdatedAt = timeFinished
}

}

return container, nil
}

Expand Down Expand Up @@ -258,6 +311,10 @@ func (dm *KubeArmorDaemon) GetAlreadyDeployedDockerContainers() {
dm.ContainersLock.Unlock()
}

if cfg.GlobalCfg.StateAgent {
go dm.StateAgent.PushContainerEvent(container, state.EventAdded)
}

if dm.SystemMonitor != nil && cfg.GlobalCfg.Policy {
// update NsMap
dm.SystemMonitor.AddContainerIDToNsMap(container.ContainerID, container.NamespaceName, container.PidNS, container.MntNS)
Expand Down Expand Up @@ -358,6 +415,11 @@ func (dm *KubeArmorDaemon) UpdateDockerContainer(containerID, action string) {
dm.ContainersLock.Unlock()
}

if cfg.GlobalCfg.StateAgent {
container.Status = "running"
go dm.StateAgent.PushContainerEvent(container, state.EventAdded)
}

dm.Logger.Printf("Detected a container (added/%.12s)", containerID)

} else if action == "stop" || action == "destroy" {
Expand Down Expand Up @@ -399,13 +461,30 @@ func (dm *KubeArmorDaemon) UpdateDockerContainer(containerID, action string) {
}
dm.EndPointsLock.Unlock()

if cfg.GlobalCfg.StateAgent {
container.Status = "terminated"
go dm.StateAgent.PushContainerEvent(container, state.EventDeleted)
}

if dm.SystemMonitor != nil && cfg.GlobalCfg.Policy {
// update NsMap
dm.SystemMonitor.DeleteContainerIDFromNsMap(containerID, container.NamespaceName, container.PidNS, container.MntNS)
dm.RuntimeEnforcer.UnregisterContainer(containerID)
}

dm.Logger.Printf("Detected a container (removed/%.12s)", containerID)
} else if action == "die" && cfg.GlobalCfg.StateAgent {
// handle die - keep map but update state
dm.ContainersLock.Lock()
container, ok := dm.Containers[containerID]
if !ok {
dm.ContainersLock.Unlock()
return
}
dm.ContainersLock.Unlock()

container.Status = "waiting"
go dm.StateAgent.PushContainerEvent(container, state.EventUpdated)
}
}

Expand Down
Loading

0 comments on commit 2bac1d1

Please sign in to comment.