Skip to content

Commit

Permalink
New feature: parameter "--container-engine"
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
wrabcak committed Oct 25, 2019
1 parent 57f661a commit b5fd92d
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 15 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
48 changes: 48 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,24 @@ def test_basic_cri(self):
)
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(
Expand All @@ -114,6 +132,21 @@ def test_default_podman(self):
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(
Expand All @@ -122,6 +155,21 @@ def test_default_docker(self):
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(
Expand Down
15 changes: 13 additions & 2 deletions udica/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down
6 changes: 6 additions & 0 deletions udica/man/man8/udica.8
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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/>

Expand Down
51 changes: 38 additions & 13 deletions udica/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -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":
Expand All @@ -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)

Expand All @@ -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):
Expand Down Expand Up @@ -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)

0 comments on commit b5fd92d

Please sign in to comment.