Skip to content

Commit

Permalink
Add Regal linting in CI pipeline
Browse files Browse the repository at this point in the history
Simplified now by the new [setup-regal](https://github.com/StyraInc/setup-regal) GitHub Action.
The new-ish `--format github` flag will also annotate PRs with any violation encountered
in the code at the location of the violation, making it really easy to spot.

Also fixed some style violations from more recent Regal rules, and amended the Regal
configuration to ignore some of the new rules that would require more work to enable.

Let me know what you all think, and have a great weekend!

Signed-off-by: Anders Eknert <[email protected]>
  • Loading branch information
anderseknert committed Oct 6, 2023
1 parent 8da97f9 commit 3886fd9
Show file tree
Hide file tree
Showing 37 changed files with 105 additions and 80 deletions.
26 changes: 17 additions & 9 deletions .github/workflows/pr-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
with:
use-verbose-mode: 'yes'

# main job of testing and building the env.
# main job of testing and building the env.
test_pr_checks:
# needs: [markdown-link-check]
permissions:
Expand All @@ -42,10 +42,10 @@ jobs:
# needs: [test_pr_checks]
# uses: kubescape/workflows/.github/workflows/coverage-check.yaml@main
# if: |
# ${{ (always() &&
# (contains(needs.*.result, 'success')) &&
# !(contains(needs.*.result, 'skipped')) &&
# !(contains(needs.*.result, 'failure')) &&
# ${{ (always() &&
# (contains(needs.*.result, 'success')) &&
# !(contains(needs.*.result, 'skipped')) &&
# !(contains(needs.*.result, 'failure')) &&
# !(contains(needs.*.result, 'cancelled'))) }}
# with:
# COVERAGELIMIT: "58"
Expand All @@ -70,7 +70,7 @@ jobs:
name: checkout repo content
with:
token: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}

# Test using Golang OPA hot rule compilation
- name: Set up Go
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568
Expand All @@ -84,12 +84,20 @@ jobs:
apt update && apt install -y cmake
GOPATH=$(go env GOPATH) make
- name: Set up Regal
uses: StyraInc/[email protected]
with:
version: v0.10.1

- name: Lint Rego
run: regal lint --format github rules

- name: setup python
uses: actions/setup-python@v4
with:
python-version: 3.10.6

# validate control-ID duplications
# validate control-ID duplications
- run: python ./scripts/validations.py

# generating subsections ids
Expand Down Expand Up @@ -117,7 +125,7 @@ jobs:
path: ${{ env.REGO_ARTIFACT_PATH }}/
if-no-files-found: error

# test kubescape with regolibrary artifacts
# test kubescape with regolibrary artifacts
ks-and-rego-test:
uses: kubescape/workflows/.github/workflows/kubescape-cli-e2e-tests.yaml@main
if: |
Expand Down Expand Up @@ -145,7 +153,7 @@ jobs:
]'
DOWNLOAD_ARTIFACT_PATH: ${{ needs.build-and-rego-test.outputs.REGO_ARTIFACT_PATH }}
secrets: inherit

clean-up:
name: Remove pre-release folder and clean up
runs-on: ubuntu-latest
Expand Down
12 changes: 12 additions & 0 deletions rules/.regal/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ rules:
# This should be enabled, but the version of OPA used here is
# too old to recognize the object.keys built-in function
level: ignore
no-defined-entrypoint:
level: ignore
use-some-for-output-vars:
level: ignore
imports:
prefer-package-imports:
level: ignore
style:
avoid-get-and-list-prefix:
level: ignore
Expand All @@ -15,6 +22,11 @@ rules:
level: ignore
prefer-snake-case:
level: ignore
prefer-some-in-iteration:
level: ignore
rule-length:
level: error
max-rule-length: 50
todo-comment:
level: ignore
use-assignment-operator:
Expand Down
8 changes: 4 additions & 4 deletions rules/CVE-2021-25742/raw.rego
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ deny[msga] {
is_tag_image(image)

# Extracting version from image tag
tag_version_match := regex.find_all_string_submatch_n("[0-9]+\\.[0-9]+\\.[0-9]+", image, -1)[0][0]
tag_version_match := regex.find_all_string_submatch_n(`[0-9]+\.[0-9]+\.[0-9]+`, image, -1)[0][0]
image_version_str_arr := split(tag_version_match,".")
image_version_arr := [to_number(image_version_str_arr[0]),to_number(image_version_str_arr[1]),to_number(image_version_str_arr[2])]

# Check if vulnerable
# Check if vulnerable
is_vulnerable(image_version_arr, deployment.metadata.namespace)

path := sprintf("spec.template.spec.containers[%v].image", [format_int(i, 10)])
Expand All @@ -25,7 +25,7 @@ deny[msga] {
}
}


is_nginx_image(image) {
contains(image, "nginx-controller")
}
Expand Down Expand Up @@ -57,7 +57,7 @@ is_vulnerable(image_version, namespace) {
image_version[2] == 0
is_allow_snippet_annotation_on(namespace)
}

is_vulnerable(image_version, namespace) {
image_version[0] == 1
image_version[1] == 0
Expand Down
8 changes: 4 additions & 4 deletions rules/CVE-2022-0185/raw.rego
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ package armo_builtins
deny[msga] {
node := input[_]
node.kind == "Node"
kernel_version_match := regex.find_all_string_submatch_n("[0-9]+\\.[0-9]+\\.[0-9]+", node.status.nodeInfo.kernelVersion, -1)
kernel_version_match := regex.find_all_string_submatch_n(`[0-9]+\.[0-9]+\.[0-9]+`, node.status.nodeInfo.kernelVersion, -1)
kernelVersion := kernel_version_match[0][0]

kernel_version_arr := split(kernelVersion, ".")
to_number(kernel_version_arr[0]) == 5
to_number(kernel_version_arr[1]) >= 1
to_number(kernel_version_arr[1]) <= 16
to_number(kernel_version_arr[2]) < 2
to_number(kernel_version_arr[2]) < 2

node.status.nodeInfo.operatingSystem == "linux"
path := "status.nodeInfo.kernelVersion"

Expand Down
2 changes: 1 addition & 1 deletion rules/K8s common labels usage/raw.rego
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ deny[msga] {
}
}

#handles cronjob
# handles cronjob
deny[msga] {
wl := input[_]
wl.kind == "CronJob"
Expand Down
4 changes: 2 additions & 2 deletions rules/alert-any-hostpath/raw.rego
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ deny[msga] {
}
}

#handles majority of workload resources
# handles majority of workload resources
deny[msga] {
wl := input[_]
spec_template_spec_patterns := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"}
Expand All @@ -48,7 +48,7 @@ deny[msga] {
}
}

#handles CronJobs
# handles CronJobs
deny[msga] {
wl := input[_]
wl.kind == "CronJob"
Expand Down
10 changes: 5 additions & 5 deletions rules/alert-rw-hostpath/raw.rego
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ deny[msga] {
}
}

#handles majority of workload resources
# handles majority of workload resources
deny[msga] {
wl := input[_]
spec_template_spec_patterns := {"Deployment","ReplicaSet","DaemonSet","StatefulSet","Job"}
Expand All @@ -57,11 +57,11 @@ deny[msga] {
"alertObject": {
"k8sApiObjects": [wl]
}

}
}

#handles CronJobs
# handles CronJobs
deny[msga] {
wl := input[_]
wl.kind == "CronJob"
Expand All @@ -73,7 +73,7 @@ deny[msga] {
volume_mount := container.volumeMounts[k]
volume_mount.name == volume.name
beggining_of_path := "spec.jobTemplate.spec.template.spec."
result := is_rw_mount(volume_mount, beggining_of_path, i, k)
result := is_rw_mount(volume_mount, beggining_of_path, i, k)
failed_path := get_failed_path(result)
fixed_path := get_fixed_path(result)

Expand Down Expand Up @@ -112,4 +112,4 @@ is_rw_mount(mount, beggining_of_path, i, k) = [failed_path, fix_path] {
mount.readOnly == false
failed_path = sprintf("%vcontainers[%v].volumeMounts[%v].readOnly", [beggining_of_path, format_int(i, 10), format_int(k, 10)])
fix_path = ""
}
}
2 changes: 1 addition & 1 deletion rules/anonymous-requests-to-kubelet-updated/raw.rego
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package armo_builtins

#CIS 4.2.1 https://workbench.cisecurity.org/sections/1126668/recommendations/1838638
# CIS 4.2.1 https://workbench.cisecurity.org/sections/1126668/recommendations/1838638

deny[msga] {
obj := input[_]
Expand Down
10 changes: 5 additions & 5 deletions rules/audit-policy-content/raw.rego
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ deny[msga] {
}

# Sample rules object
#rules:
# - level: RequestResponse
# resources:
# - group: ""
# resources: ["pods"]
# rules:
# - level: RequestResponse
# resources:
# - group: ""
# resources: ["pods"]
are_audit_file_rules_valid(rules) if {
seeked_resources_with_audit_level := {
"secrets": {
Expand Down
1 change: 1 addition & 0 deletions rules/cluster-admin-role/raw.rego
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package armo_builtins
import future.keywords.in

# returns subjects with cluster admin role
# regal ignore:rule-length
deny[msga] {
subjectVector := input[_]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package armo_builtins

#CIS 4.2.3 https://workbench.cisecurity.org/sections/1126668/recommendations/1838643
# CIS 4.2.3 https://workbench.cisecurity.org/sections/1126668/recommendations/1838643

deny[msga] {
obj := input[_]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ deny[msga] {
policies.kind == "PolicyVersion"
policies.metadata.provider == "eks"

#node_instance_role_policies := ["arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"]
# node_instance_role_policies := ["arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"]
some policy in node_instance_role_policies
some stat, _ in policies.data.policiesDocuments[policy].Statement
not isPolicyCompliant(policies, policy, stat)
Expand Down
4 changes: 2 additions & 2 deletions rules/etcd-unique-ca/raw.rego
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package armo_builtins

import future.keywords.in

#CIS 2.7 https://workbench.cisecurity.org/sections/1126654/recommendations/1838578
# CIS 2.7 https://workbench.cisecurity.org/sections/1126654/recommendations/1838578

deny[msga] {
etcdPod := [pod | pod := input[_]; filter_input(pod, "etcd")]
Expand Down Expand Up @@ -39,7 +39,7 @@ filter_input(obj, res) {
}

get_argument_value(command, argument) = value {
args := regex.split("=", command)
args := split(command, "=")
some i, sprintf("%v", [argument]) in args
value := args[i + 1]
}
Expand Down
7 changes: 4 additions & 3 deletions rules/exposed-critical-pods/filter.rego
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package armo_builtins

# regal ignore:rule-length
deny[msga] {
services := [ x | x = input[_]; x.kind == "Service" ]
pods := [ x | x = input[_]; x.kind == "Pod" ]
Expand All @@ -9,8 +10,8 @@ deny[msga] {
service := services[_]
vuln := vulns[_]

# vuln data is relevant
count(vuln.data) > 0
# vuln data is relevant
count(vuln.data) > 0

# service is external-facing
filter_external_access(service)
Expand All @@ -33,7 +34,7 @@ deny[msga] {
"namespace": pod.metadata.namespace
}

external_objects = {
external_objects = {
"apiVersion": "result.vulnscan.com/v1",
"kind": pod.kind,
"metadata": metadata,
Expand Down
9 changes: 5 additions & 4 deletions rules/exposed-critical-pods/raw.rego
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package armo_builtins

# regal ignore:rule-length
deny[msga] {
services := [ x | x = input[_]; x.kind == "Service" ]
pods := [ x | x = input[_]; x.kind == "Pod" ]
Expand All @@ -9,8 +10,8 @@ deny[msga] {
service := services[_]
vuln := vulns[_]

# vuln data is relevant
count(vuln.data) > 0
# vuln data is relevant
count(vuln.data) > 0

# service is external-facing
filter_external_access(service)
Expand All @@ -22,7 +23,7 @@ deny[msga] {
container := pod.spec.containers[i]

# image has vulnerabilities

container.image == vuln.metadata.name

# At least one critical vulnerabilities
Expand All @@ -37,7 +38,7 @@ deny[msga] {
"namespace": pod.metadata.namespace
}

external_objects = {
external_objects = {
"apiVersion": "result.vulnscan.com/v1",
"kind": pod.kind,
"metadata": metadata,
Expand Down
9 changes: 5 additions & 4 deletions rules/exposed-rce-pods/filter.rego
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package armo_builtins


# regal ignore:rule-length
deny[msga] {
services := [ x | x = input[_]; x.kind == "Service" ; x.apiVersion == "v1"]
pods := [ x | x = input[_]; x.kind == "Pod" ; x.apiVersion == "v1"]
Expand All @@ -9,8 +10,8 @@ deny[msga] {
service := services[_]
vuln := vulns[_]

# vuln data is relevant
count(vuln.data) > 0
# vuln data is relevant
count(vuln.data) > 0

# service is external-facing
filter_external_access(service)
Expand All @@ -33,7 +34,7 @@ deny[msga] {
"namespace": pod.metadata.namespace
}

external_objects = {
external_objects = {
"apiVersion": "result.vulnscan.com/v1",
"kind": pod.kind,
"metadata": metadata,
Expand Down
Loading

0 comments on commit 3886fd9

Please sign in to comment.