1
1
mirror of https://github.com/containers/udica synced 2024-09-28 11:00:10 +02:00

New feature: parameter "--container-engine"

Following commit adds new parameter for to specify which container
engine is used for inspecting container.

Example:
        # udica --container-engine podman -j my_container.json my_container
        ...

        # udica -e docker -j my_container.json my_container
        ...

In some situations udica fails to identify which engine is used,
therefore this parameter has to be used.

Commit includes also test for the feature.
This commit is contained in:
Lukas Vrabec 2019-10-25 19:21:01 +02:00
parent 57f661a4c6
commit b5fd92d03f
No known key found for this signature in database
GPG Key ID: 47201AC42F29CE06
5 changed files with 106 additions and 15 deletions

@ -215,3 +215,4 @@ Real example is demonstrated in following demo.
* It's not possible to detect capabilities used by container in docker engine, therefore you *have to* use '-c' to specify capabilities for docker container manually.
* It's not possible to generate custom local policy using "audit2allow -M" tool from AVCs where source context was generated by udica. For this purpose please use '--append-rules' option.
* In some situations udica fails to identify which container engine is used, therefore "--container-engine" parameter has to be used to inform udica how JSON inspection file should be parsed.

@ -106,6 +106,24 @@ class TestBase(unittest.TestCase):
)
self.assert_policy(test_file("test_basic.cri.cil"))
def test_basic_specified_engine_cri(self):
"""Start CRI-O mounting /var/spool with read/write perms and /home with readonly perms"""
output = self.run_udica(
[
"udica",
"--container-engine",
"CRI-O",
"-j",
"tests/test_basic.cri.json",
"--full-network-access",
"my_container",
]
)
self.assert_templates(
output, ["base_container", "net_container", "home_container"]
)
self.assert_policy(test_file("test_basic.cri.cil"))
def test_default_podman(self):
"""podman run fedora"""
output = self.run_udica(
@ -114,6 +132,21 @@ class TestBase(unittest.TestCase):
self.assert_templates(output, ["base_container"])
self.assert_policy(test_file("test_default.podman.cil"))
def test_default_specified_engine_podman(self):
"""podman run fedora"""
output = self.run_udica(
[
"udica",
"-e",
"podman",
"-j",
"tests/test_default.podman.json",
"my_container",
]
)
self.assert_templates(output, ["base_container"])
self.assert_policy(test_file("test_default.podman.cil"))
def test_default_docker(self):
"""docker run fedora"""
output = self.run_udica(
@ -122,6 +155,21 @@ class TestBase(unittest.TestCase):
self.assert_templates(output, ["base_container"])
self.assert_policy(test_file("test_default.docker.cil"))
def test_default_specified_engine_docker(self):
"""docker run fedora"""
output = self.run_udica(
[
"udica",
"-e",
"docker",
"-j",
"tests/test_default.docker.json",
"my_container",
]
)
self.assert_templates(output, ["base_container"])
self.assert_policy(test_file("test_default.docker.cil"))
def test_default_oci(self):
"""podman run ubi8"""
output = self.run_udica(

@ -113,6 +113,15 @@ def get_args():
required=False,
default=None,
)
parser.add_argument(
"-e",
"--container-engine",
type=str,
help="Specify which container engine is used for the inspected container (supports: CRI-O, docker, podman)",
dest="ContainerEngine",
required=False,
default="-",
)
args = parser.parse_args()
return vars(args)
@ -169,11 +178,13 @@ def main():
exit(3)
try:
inspect_format = parse.get_inspect_format(container_inspect_raw)
inspect_format = parse.get_inspect_format(
container_inspect_raw, opts["ContainerEngine"]
)
except Exception as e:
print("Couldn't parse inspect data:", e)
exit(3)
container_inspect = parse_inspect(container_inspect_raw)
container_inspect = parse_inspect(container_inspect_raw, opts["ContainerEngine"])
container_mounts = parse.get_mounts(container_inspect, inspect_format)
container_ports = parse.get_ports(container_inspect, inspect_format)

@ -61,6 +61,10 @@ Append more SELinux allow rules generated from SELinux denials in audit daemon.
.I \-s, \-\-stream-connect DOMAIN
Allow container to stream connect with given SELinux domain.
.TP
.I \-e, \-\-container-engine ENGINE
Specify which container engine is used for the inspected container (supports: CRI-O, docker, podman)
.TP
.I \-\-full\-network\-access
Allow a container full network access
@ -110,6 +114,8 @@ you have to use '-c' to specify capabilities for docker container manually.
It is not possible to generate a custom local policy using the "audit2allow -M" command from AVCs where source context was generated by udica. For this purpose please use '--append-rules' option.
In some situations udica fails to identify which container engine is used, therefore "--container-engine" parameter has to be used to inform udica how JSON inspection file should be parsed.
.SH REPORTING BUGS
Report bugs to <https://github.com/containers/udica/issues/>

@ -35,6 +35,12 @@ def json_is_podman_format(json_rep):
def adjust_json_from_docker(json_rep):
"""If the json comes from a docker call, we need to adjust it to make use
of it. """
if not isinstance(json_rep[0]["NetworkSettings"]["Ports"], dict):
raise Exception(
"Error parsing docker engine inspection JSON structure, try to specify container engine using '--container-engine' parameter"
)
for item in json_rep[0]["Mounts"]:
item["source"] = item["Source"]
if item["Mode"] == "rw":
@ -55,28 +61,37 @@ def adjust_json_from_docker(json_rep):
json_rep[0]["NetworkSettings"]["Ports"] = temp_ports
def parse_inspect(data):
def parse_inspect(data, ContainerEngine):
json_rep = json.loads(data)
if json_is_podman_or_docker_format(json_rep):
if not json_is_podman_format(json_rep):
adjust_json_from_docker(json_rep)
engine = validate_container_engine(ContainerEngine)
if engine == "-":
if json_is_podman_or_docker_format(json_rep):
if not json_is_podman_format(json_rep):
adjust_json_from_docker(json_rep)
if engine == "docker":
adjust_json_from_docker(json_rep)
return json_rep
def get_inspect_format(data):
json_rep = json.loads(data)
if json_is_podman_or_docker_format(json_rep):
if json_is_podman_format(json_rep):
return "podman"
return "docker"
return "CRI-O"
def get_inspect_format(data, ContainerEngine):
engine = validate_container_engine(ContainerEngine)
if engine == "-":
json_rep = json.loads(data)
if json_is_podman_or_docker_format(json_rep):
if json_is_podman_format(json_rep):
return "podman"
return "docker"
return "CRI-O"
else:
return engine
def get_mounts(data, inspect_format):
if inspect_format in ["podman", "docker"]:
return data[0]["Mounts"]
if inspect_format == "CRI-O":
if inspect_format == "CRI-O" and not json_is_podman_or_docker_format(data):
return data["status"]["mounts"]
raise Exception("Error getting mounts from unknown format %s" % inspect_format)
@ -88,7 +103,7 @@ def get_ports(data, inspect_format):
# Not applicable in the CRI-O case, since this is handled by the
# kube-proxy/CNI.
return []
raise Exception("Error getting mounts from unknown format %s" % inspect_format)
raise Exception("Error getting ports from unknown format %s" % inspect_format)
def get_caps(data, opts, inspect_format):
@ -149,3 +164,13 @@ def parse_avc_file(data):
append_rules.append(new_rule)
return append_rules
def validate_container_engine(ContainerEngine):
supported_engines = ["docker", "podman", "CRI-O", "CRIO", "-"]
if ContainerEngine in supported_engines:
if ContainerEngine == "CRIO":
return "CRI-O"
return ContainerEngine
else:
raise Exception("Container Engine %s is not supported." % ContainerEngine)