From 696cea1e87494a7ce19a48c2093853bc09715fee Mon Sep 17 00:00:00 2001
From: alegrey91 <ale_grey_91@hotmail.it>
Date: Fri, 10 Dec 2021 17:51:12 +0100
Subject: [PATCH] feat: add ports and mounts support for containerd engine
Signed-off-by: Alessio Greggi <ale_grey_91@hotmail.it>
---
udica/__main__.py | 2 +-
udica/parse.py | 37 ++++++++++++++-
udica/policy.py | 118 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 155 insertions(+), 2 deletions(-)
diff --git a/udica/__main__.py b/udica/__main__.py
index d72a4b4..18ff5cd 100644
--- a/udica/__main__.py
+++ b/udica/__main__.py
@@ -18,7 +18,7 @@ import argparse
# import udica
from udica.parse import parse_avc_file
-from udica.parse import ENGINE_ALL, ENGINE_PODMAN, ENGINE_DOCKER
+from udica.parse import ENGINE_ALL, ENGINE_PODMAN, ENGINE_DOCKER, ENGINE_CONTAINERD
from udica.version import version
from udica import parse
from udica.policy import create_policy, load_policy, generate_playbook
diff --git a/udica/parse.py b/udica/parse.py
index 59b3dc5..7b355f3 100644
--- a/udica/parse.py
+++ b/udica/parse.py
@@ -25,8 +25,11 @@ ENGINE_CRIO = "CRI-O"
#: Constant for the docker engine
ENGINE_DOCKER = "docker"
+#: Constant for the containerd engine
+ENGINE_CONTAINERD = "containerd"
+
#: All supported engines
-ENGINE_ALL = [ENGINE_PODMAN, ENGINE_CRIO, ENGINE_DOCKER]
+ENGINE_ALL = [ENGINE_PODMAN, ENGINE_CRIO, ENGINE_DOCKER, ENGINE_CONTAINERD]
# Decorator for verifying that getting value from "data" won't
@@ -79,6 +82,8 @@ def get_engine_helper(data, ContainerEngine):
return PodmanHelper()
elif engine == ENGINE_CRIO:
return CrioHelper()
+ elif engine == ENGINE_CONTAINERD:
+ return ContainerdHelper()
raise RuntimeError("Unkown engine")
@@ -204,6 +209,35 @@ class CrioHelper(EngineHelper):
return []
+class ContainerdHelper(EngineHelper):
+ def __init__(self):
+ super().__init__(ENGINE_CONTAINERD)
+
+ @getter_decorator
+ def get_devices(self, data):
+ return []
+
+ @getter_decorator
+ def get_mounts(self, data):
+ return data[0]["Spec"]["mounts"]
+
+ @getter_decorator
+ def get_ports(self, data):
+ json_data = json.loads(data[0]["Labels"]["nerdctl/ports"])
+ ports = []
+ for port in json_data:
+ new_ports = {
+ "portNumber": port["HostPort"],
+ "protocol": port["Protocol"]
+ }
+ ports.append(new_ports)
+ return ports
+
+ @getter_decorator
+ def get_caps(self, data, opts):
+ return []
+
+
def parse_cap(data):
return data.decode().split("\n")[1].split(",")
@@ -254,6 +288,7 @@ def parse_avc_file(data):
def validate_container_engine(ContainerEngine):
+ print(ContainerEngine)
if ContainerEngine in ENGINE_ALL + ["CRIO", "-"]:
# Fix CRIO reference to use ENGINE_CRIO
if ContainerEngine == "CRIO":
diff --git a/udica/policy.py b/udica/policy.py
index 1d53e2a..a0d449a 100644
--- a/udica/policy.py
+++ b/udica/policy.py
@@ -178,6 +178,8 @@ def create_policy(
# mounts
if inspect_format == "CRI-O":
write_policy_for_crio_mounts(mounts, policy)
+ elif inspect_format == "containerd":
+ write_policy_for_containerd_mounts(mounts, policy)
else:
write_policy_for_podman_mounts(mounts, policy)
@@ -429,6 +431,122 @@ def write_policy_for_podman_mounts(mounts, policy):
+ " ))) \n"
)
+def write_policy_for_containerd_mounts(mounts, policy):
+ # mount JSON example:
+ # {
+ # "destination": "/sys/fs/cgroup",
+ # "type": "cgroup",
+ # "source": "cgroup",
+ # "options": [
+ # "ro",
+ # "nosuid",
+ # "noexec",
+ # "nodev"
+ # ]
+ # }
+ for item in sorted(mounts, key=lambda x: str(x["source"])):
+ if not item["source"].find("/"):
+ if item["source"] == LOG_CONTAINER and "ro" in item["options"]:
+ policy.write(" (blockinherit log_container)\n")
+ add_template("log_container")
+ continue
+
+ if item["source"] == LOG_CONTAINER and "ro" not in item["options"]:
+ policy.write(" (blockinherit log_rw_container)\n")
+ add_template("log_container")
+ continue
+
+ if item["source"] == HOME_CONTAINER and "ro" in item["options"]:
+ policy.write(" (blockinherit home_container)\n")
+ add_template("home_container")
+ continue
+
+ if item["source"] == HOME_CONTAINER and "ro" not in item["options"]:
+ policy.write(" (blockinherit home_rw_container)\n")
+ add_template("home_container")
+ continue
+
+ if item["source"] == TMP_CONTAINER and "ro" in item["options"]:
+ policy.write(" (blockinherit tmp_container)\n")
+ add_template("tmp_container")
+ continue
+
+ if item["source"] == TMP_CONTAINER and "ro" not in item["options"]:
+ policy.write(" (blockinherit tmp_rw_container)\n")
+ add_template("tmp_container")
+ continue
+
+ if item["source"] == CONFIG_CONTAINER and "ro" in item["options"]:
+ policy.write(" (blockinherit config_container)\n")
+ add_template("config_container")
+ continue
+
+ if item["source"] == CONFIG_CONTAINER and "ro" not in item["options"]:
+ policy.write(" (blockinherit config_rw_container)\n")
+ add_template("config_container")
+ continue
+
+ contexts = list_contexts(item["source"])
+ for context in contexts:
+ if "ro" not in item["options"]:
+ policy.write(
+ " (allow process "
+ + context
+ + " ( dir ( "
+ + perms.perm["dir_rw"]
+ + " ))) \n"
+ )
+ policy.write(
+ " (allow process "
+ + context
+ + " ( file ( "
+ + perms.perm["file_rw"]
+ + " ))) \n"
+ )
+ policy.write(
+ " (allow process "
+ + context
+ + " ( fifo_file ( "
+ + perms.perm["fifo_rw"]
+ + " ))) \n"
+ )
+ policy.write(
+ " (allow process "
+ + context
+ + " ( sock_file ( "
+ + perms.perm["socket_rw"]
+ + " ))) \n"
+ )
+ if "ro" in item["options"]:
+ policy.write(
+ " (allow process "
+ + context
+ + " ( dir ( "
+ + perms.perm["dir_ro"]
+ + " ))) \n"
+ )
+ policy.write(
+ " (allow process "
+ + context
+ + " ( file ( "
+ + perms.perm["file_ro"]
+ + " ))) \n"
+ )
+ policy.write(
+ " (allow process "
+ + context
+ + " ( fifo_file ( "
+ + perms.perm["fifo_ro"]
+ + " ))) \n"
+ )
+ policy.write(
+ " (allow process "
+ + context
+ + " ( sock_file ( "
+ + perms.perm["socket_ro"]
+ + " ))) \n"
+ )
+
def load_policy(opts):
PWD = getcwd()
--
2.35.3