Skip to content

Commit

Permalink
Merge pull request #492 from kubescape/fix-docker.io
Browse files Browse the repository at this point in the history
use func image.parse_normalized_name to identify docker images
  • Loading branch information
YiscahLevySilas1 authored Aug 15, 2023
2 parents 3a321c9 + 0c72268 commit 8b372db
Show file tree
Hide file tree
Showing 8 changed files with 239 additions and 4 deletions.
3 changes: 2 additions & 1 deletion controls/C-0001-forbiddencontainerregistries.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"description": "In cases where the Kubernetes cluster is provided by a CSP (e.g., AKS in Azure, GKE in GCP, or EKS in AWS), compromised cloud credential can lead to the cluster takeover. Attackers may abuse cloud account credentials or IAM mechanism to the cluster\u2019s management layer.",
"remediation": "Limit the registries from which you pull container images from",
"rulesNames": [
"rule-identify-blocklisted-image-registries"
"rule-identify-blocklisted-image-registries",
"rule-identify-blocklisted-image-registries-v1"
],
"long_description": "Running a compromised image in a cluster can compromise the cluster. Attackers who get access to a private registry can plant their own compromised images in the registry. The latter can then be pulled by a user. In addition, users often use untrusted images from public registries (such as Docker Hub) that may be malicious. Building images based on untrusted base images can also lead to similar results.",
"test": "Checking image from pod spec, if the registry of the image is from the list of blocked registries we raise an alert.",
Expand Down
3 changes: 2 additions & 1 deletion controls/C-0078-imagesfromallowedregistry.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"description": "This control is intended to ensure that all the used container images are taken from the authorized repositories. It allows user to list all the approved repositories and will fail all the images taken from any repository outside of this list.",
"remediation": "You should enable all trusted repositories in the parameters of this control.",
"rulesNames": [
"container-image-repository"
"container-image-repository",
"container-image-repository-v1"
],
"long_description": "If attackers get access to the cluster, they can re-point kubernetes to a compromized container repository. This control is intended to ensure that all the container images are taken from the authorized repositories only. User should list all the approved repositories in the parameters of this control so that any potential dangerous image can be identified.",
"test": "Checks if image is from allowed listed registry.",
Expand Down
47 changes: 47 additions & 0 deletions rules/container-image-repository-v1/raw.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package armo_builtins

untrustedImageRepo[msga] {
wl := input[_]
containers_path := get_containers_path(wl)
containers := object.get(wl, containers_path, [])
container := containers[i]
name := image.parse_normalized_name(container.image)
not image_in_allowed_list(name)
path := sprintf("%s[%d].image", [concat(".", containers_path), i])

msga := {
"alertMessage": sprintf("image '%v' in container '%s' comes from untrusted registry", [name, container.name]),
"packagename": "armo_builtins",
"alertScore": 2,
"fixPaths": [],
"failedPaths": [path],
"alertObject": {"k8sApiObjects": [wl]},
}
}

# image_in_allowed_list - rule to check if an image complies with imageRepositoryAllowList.
image_in_allowed_list(image){
# see default-config-inputs.json for list values
allowedlist := data.postureControlInputs.imageRepositoryAllowList
registry := allowedlist[_]
startswith(image, registry)
}

# get_containers_path - get resource containers paths for {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"}
get_containers_path(resource) := result {
resource_kinds := {"Deployment", "ReplicaSet", "DaemonSet", "StatefulSet", "Job"}
resource_kinds[resource.kind]
result = ["spec", "template", "spec", "containers"]
}

# get_containers_path - get resource containers paths for "Pod"
get_containers_path(resource) := result {
resource.kind == "Pod"
result = ["spec", "containers"]
}

# get_containers_path - get resource containers paths for "CronJob"
get_containers_path(resource) := result {
resource.kind == "CronJob"
result = ["spec", "jobTemplate", "spec", "template", "spec", "containers"]
}
62 changes: 62 additions & 0 deletions rules/container-image-repository-v1/rule.metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"name": "container-image-repository-v1",
"attributes": {
"m$K8sThreatMatrix": "Collection::Images from private registry",
"armoBuiltin": true,
"useFromKubescapeVersion": "v2.9.0"
},
"ruleLanguage": "Rego",
"match": [
{
"apiGroups": [
""
],
"apiVersions": [
"v1"
],
"resources": [
"Pod"
]
},
{
"apiGroups": [
"apps"
],
"apiVersions": [
"v1"
],
"resources": [
"Deployment",
"ReplicaSet",
"DaemonSet",
"StatefulSet"
]
},
{
"apiGroups": [
"batch"
],
"apiVersions": [
"*"
],
"resources": [
"Job",
"CronJob"
]
}
],
"ruleDependencies": [],
"configInputs": [
"settings.postureControlInputs.imageRepositoryAllowList"
],
"controlConfigInputs": [
{
"path": "settings.postureControlInputs.imageRepositoryAllowList",
"name": "Allowed image repositories",
"description": "Kubescape checks that all the containers are using images from the allowed repositories provided in the following list."
}
],
"description": "Fails if image is not from allowed repository",
"remediation": "",
"ruleQuery": ""
}
3 changes: 2 additions & 1 deletion rules/container-image-repository/rule.metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"name": "container-image-repository",
"attributes": {
"m$K8sThreatMatrix": "Collection::Images from private registry",
"armoBuiltin": true
"armoBuiltin": true,
"useUntilKubescapeVersion": "v2.3.8"
},
"ruleLanguage": "Rego",
"match": [
Expand Down
54 changes: 54 additions & 0 deletions rules/rule-identify-blocklisted-image-registries-v1/raw.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package armo_builtins

untrustedImageRepo[msga] {
wl := input[_]
containers_path := get_containers_path(wl)
containers := object.get(wl, containers_path, [])
container := containers[i]
name := image.parse_normalized_name(container.image)
untrusted_or_public_registries(name)
path := sprintf("%s[%d].image", [concat(".", containers_path), i])

msga := {
"alertMessage": sprintf("image '%v' in container '%s' comes from untrusted registry", [name, container.name]),
"packagename": "armo_builtins",
"alertScore": 2,
"fixPaths": [],
"failedPaths": [path],
"alertObject": {"k8sApiObjects": [wl]},
}
}

untrusted_or_public_registries(image){
# see default-config-inputs.json for list values
untrusted_registries := data.postureControlInputs.untrustedRegistries
registry := untrusted_registries[_]
startswith(image, registry)

}

untrusted_or_public_registries(image){
# see default-config-inputs.json for list values
public_registries := data.postureControlInputs.publicRegistries
registry := public_registries[_]
startswith(image, registry)
}

# get_containers_path - get resource containers paths for {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"}
get_containers_path(resource) := result {
resource_kinds := {"Deployment", "ReplicaSet", "DaemonSet", "StatefulSet", "Job"}
resource_kinds[resource.kind]
result = ["spec", "template", "spec", "containers"]
}

# get_containers_path - get resource containers paths for "Pod"
get_containers_path(resource) := result {
resource.kind == "Pod"
result = ["spec", "containers"]
}

# get_containers_path - get resource containers paths for "CronJob"
get_containers_path(resource) := result {
resource.kind == "CronJob"
result = ["spec", "jobTemplate", "spec", "template", "spec", "containers"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"name": "rule-identify-blocklisted-image-registries-v1",
"attributes": {
"m$K8sThreatMatrix": "Initial Access::Compromised images in registry",
"armoBuiltin": true,
"useFromKubescapeVersion": "v2.9.0"
},
"ruleLanguage": "Rego",
"match": [
{
"apiGroups": [
""
],
"apiVersions": [
"v1"
],
"resources": [
"Pod"
]
},
{
"apiGroups": [
"apps"
],
"apiVersions": [
"v1"
],
"resources": [
"Deployment",
"ReplicaSet",
"DaemonSet",
"StatefulSet"
]
},
{
"apiGroups": [
"batch"
],
"apiVersions": [
"*"
],
"resources": [
"Job",
"CronJob"
]
}
],
"ruleDependencies": [],
"configInputs": [
"settings.postureControlInputs.publicRegistries",
"settings.postureControlInputs.untrustedRegistries"
],
"controlConfigInputs": [
{
"path": "settings.postureControlInputs.publicRegistries",
"name": "Public registries",
"description": "Kubescape checks none of these public registries are in use."
},
{
"path": "settings.postureControlInputs.untrustedRegistries",
"name": "Registries block list",
"description": "Kubescape checks none of the following registries are in use."
}
],
"description": "Identifying if pod container images are from unallowed registries",
"remediation": "Use images from safe registry",
"ruleQuery": ""
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"name": "rule-identify-blocklisted-image-registries",
"attributes": {
"m$K8sThreatMatrix": "Initial Access::Compromised images in registry",
"armoBuiltin": true
"armoBuiltin": true,
"useUntilKubescapeVersion": "v2.3.8"
},
"ruleLanguage": "Rego",
"match": [
Expand Down

0 comments on commit 8b372db

Please sign in to comment.