Skip to content

Commit

Permalink
fix(checks): check the package manager in AVD-DS-0017
Browse files Browse the repository at this point in the history
  • Loading branch information
nikpivkin authored and simar7 committed Mar 14, 2024
1 parent 27184b6 commit 1e43dca
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 39 deletions.
2 changes: 1 addition & 1 deletion avd_docs/dockerfile/general/AVD-DS-0017/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ The instruction 'RUN <package-manager> update' should always be followed by '<pa
{{ remediationActions }}

### Links
- https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
- https://docs.docker.com/develop/develop-images/instructions/#run


75 changes: 43 additions & 32 deletions checks/docker/update_instruction_alone.rego
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# schemas:
# - input: schema["dockerfile"]
# related_resources:
# - https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
# - https://docs.docker.com/develop/develop-images/instructions/#run
# custom:
# id: DS017
# avd_id: AVD-DS-0017
Expand All @@ -19,46 +19,57 @@ package builtin.dockerfile.DS017

import data.lib.docker

install_cmds = {
"upgrade",
"install",
"source-install",
"reinstall",
"groupinstall",
"localinstall",
"add",
}

update_cmds = {
"update",
"up",
}

package_managers = {
{"apt-get", "apt"},
{"yum"},
{"apk"},
{"dnf"},
{"zypper"},
}

deny[res] {
run := docker.run[_]
run_cmd := concat(" ", run.Value)
cmds := regex.split(`\s*&&\s*`, run_cmd)

command = concat(" ", run.Value)

is_valid_update(command)
not update_followed_by_install(command)
update_res = has_update(cmds)
not update_followed_by_install(cmds, update_res)

msg := "The instruction 'RUN <package-manager> update' should always be followed by '<package-manager> install' in the same RUN statement."
res := result.new(msg, run)
}

is_valid_update(command) {
chained_parts := regex.split(`\s*&&\s*`, command)

array_split := split(chained_parts[_], " ")

len = count(array_split)

update := {"update", "--update"}

array_split[len - 1] == update[_]
has_update(cmds) = {
"package_manager": package_manager,
"cmd_index": index,
} {
index := contains_cmd_with_package_manager(cmds, update_cmds, package_managers[package_manager])
}

update_followed_by_install(command) {
command_list = [
"upgrade",
"install",
"source-install",
"reinstall",
"groupinstall",
"localinstall",
"apk add",
]

update := indexof(command, "update")
update != -1

install := indexof(command, command_list[_])
install != -1
update_followed_by_install(cmds, update_res) {
install_index := contains_cmd_with_package_manager(cmds, install_cmds, update_res.package_manager)
update_res.cmd_index < install_index
}

update < install
contains_cmd_with_package_manager(cmds, cmds_to_check, package_manager) = cmd_index {
cmd_parts := split(cmds[cmd_index], " ")
some i, j
cmd_parts[i] == package_manager[_]
cmd_parts[j] == cmds_to_check[_]
i < j
}
161 changes: 155 additions & 6 deletions checks/docker/update_instruction_alone_test.rego
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ test_denied {
},
{
"Cmd": "run",
"Value": ["apt-get install -y --no-install-recommends mysql-client && rm -rf /var/lib/apt/lists/*"],
"Value": ["apt-get install -y --no-install-recommends mysql-client && rm -rf /var/lib/apt/lists/*"],
},
{
"Cmd": "entrypoint",
Expand All @@ -21,7 +21,6 @@ test_denied {
]}]}

count(r) == 1
trace(sprintf("%s", [r[_]]))
r[_].msg == "The instruction 'RUN <package-manager> update' should always be followed by '<package-manager> install' in the same RUN statement."
}

Expand Down Expand Up @@ -57,7 +56,7 @@ test_chained_denied {
},
{
"Cmd": "run",
"Value": ["apt-get install -y --no-install-recommends mysql-client && rm -rf /var/lib/apt/lists/*"],
"Value": ["apt-get install -y --no-install-recommends mysql-client && rm -rf /var/lib/apt/lists/*"],
},
{
"Cmd": "entrypoint",
Expand All @@ -77,16 +76,24 @@ test_allowed {
},
{
"Cmd": "run",
"Value": ["apt-get update && apt-get install -y --no-install-recommends mysql-client && rm -rf /var/lib/apt/lists/*"],
"Value": ["apt-get update && apt-get install -y --no-install-recommends mysql-client && rm -rf /var/lib/apt/lists/*"],
},
{
"Cmd": "run",
"Value": ["apk update && apk add --no-cache git ca-certificates"],
"Value": ["apk update && apk add --no-cache git ca-certificates"],
},
{
"Cmd": "run",
"Value": ["apk --update add easy-rsa"],
},
{
"Cmd": "run",
"Value": ["/bin/sh /scripts/someScript.sh update"],
},
{
"Cmd": "run",
"Value": ["apt-get install -y nginx"],
},
{
"Cmd": "entrypoint",
"Value": ["mysql"],
Expand All @@ -104,9 +111,151 @@ test_allow_upgrade {
},
{
"Cmd": "run",
"Value": ["apt-get update && apt upgrade --yes"],
"Value": ["test && apt-get update && apt upgrade --yes"],
},
]}]}

count(r) == 0
}

test_without_install_cmd_allowed {
r := deny with input as {"Stages": [{"Name": "alpine:latest", "Commands": [
{
"Cmd": "from",
"Value": ["alpine:latest"],
},
{
"Cmd": "run",
"Value": ["echo \"Test\""],
},
]}]}

count(r) == 0
}

test_non_package_manager_update_allowed {
r := deny with input as {"Stages": [{"Name": "maven:alpine", "Commands": [
{
"Cmd": "from",
"Value": ["FROM maven:alpine"],
},
{
"Cmd": "copy",
"Value": ["build.sbt version.sbt ./"],
},
{
"Cmd": "run",
"Value": ["sbt update "],
},
]}]}

count(r) == 0
}

test_dnf_update_denied {
r := deny with input as {"Stages": [{
"Name": "centos:8",
"Commands": [
{
"Cmd": "from",
"Value": ["centos:8"],
},
{
"Cmd": "run",
"Value": ["dnf update -y"],
},
],
}]}

count(r) == 1
}

test_dnf_update_allowed {
r := deny with input as {"Stages": [{
"Name": "centos:8",
"Commands": [
{
"Cmd": "from",
"Value": ["centos:8"],
},
{
"Cmd": "run",
"Value": ["dnf update && dnf install -y dnf-plugins-core"],
},
],
}]}

count(r) == 0
}

test_zypper_update_denied {
r := deny with input as {"Stages": [{
"Name": "opensuse/tumbleweed",
"Commands": [
{
"Cmd": "from",
"Value": ["opensuse/tumbleweed"],
},
{
"Cmd": "run",
"Value": ["zypper up -y"],
},
],
}]}

count(r) == 1
}

test_zypper_update_allowed {
r := deny with input as {"Stages": [{
"Name": "opensuse/tumbleweed",
"Commands": [
{
"Cmd": "from",
"Value": ["opensuse/tumbleweed"],
},
{
"Cmd": "run",
"Value": ["zypper up -y && zypper install -y curl wget zip unzip tar git"],
},
],
}]}

count(r) == 0
}

test_yum_update_denied {
r := deny with input as {"Stages": [{
"Name": "centos:latest",
"Commands": [
{
"Cmd": "from",
"Value": ["centos:latest"],
},
{
"Cmd": "run",
"Value": ["yum update -y"],
},
],
}]}

count(r) == 1
}

test_yum_update_allowed {
r := deny with input as {"Stages": [{
"Name": "centos:latest",
"Commands": [
{
"Cmd": "from",
"Value": ["centos:latest"],
},
{
"Cmd": "run",
"Value": ["yum update -y && yum -y install java-11-openjdk"],
},
],
}]}

count(r) == 0
}

0 comments on commit 1e43dca

Please sign in to comment.