Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/scripts/samples-linters/ignore-list/k8s
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
assets/queries/k8s/hpa_targets_invalid_object/test/positive.yaml
assets/queries/k8s/network_policy_ingress_not_restricted/test/positive.yaml
assets/queries/k8s/network_policy_ingress_not_restricted/test/negative.yaml
assets/queries/k8s/ingress_whitelist_open_to_all/test/positive.yaml
assets/queries/k8s/ingress_whitelist_open_to_all/test/negative.yaml
2 changes: 1 addition & 1 deletion .github/workflows/validate-k8s-samples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ jobs:
run: |
python3 -u .github/scripts/samples-linters/validate-syntax.py \
"assets/queries/k8s/**/test/*.yaml" \
--extra ' --skip-kinds CustomResourceDefinition,KubeletConfiguration,Policy,EncryptionConfiguration,KubeSchedulerConfiguration,SecretProviderClass,Service,Configuration,ContainerSource,Revision' \
--extra ' --skip-kinds CustomResourceDefinition,KubeletConfiguration,Policy,EncryptionConfiguration,KubeSchedulerConfiguration,SecretProviderClass,Service,Configuration,ContainerSource,Revision --ignore-missing-schemas' \
--linter .bin/kubeval \
--skip '.github/scripts/samples-linters/ignore-list/k8s' -v
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
COPY . .

# Build the Go app
USER root
RUN mkdir -p bin
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build \
-ldflags "-s -w -X github.com/Checkmarx/kics/v2/internal/constants.Version=${VERSION} -X github.com/Checkmarx/kics/v2/internal/constants.SCMCommit=${COMMIT} -X github.com/Checkmarx/kics/v2/internal/constants.SentryDSN=${SENTRY_DSN} -X github.com/Checkmarx/kics/v2/internal/constants.BaseURL=${DESCRIPTIONS_URL}" \
-a -installsuffix cgo \
Expand All @@ -31,7 +33,7 @@
# kics-scan ignore-line
FROM checkmarx/git:2.53.0-r0@sha256:6f398e9772fc0271cbdd77b065a09c9244004fbda17c1c58ba01b412a4292bde

ENV TERM xterm-256color

Check warning on line 36 in Dockerfile

View workflow job for this annotation

GitHub Actions / Trivy docker image scan (Dockerfile)

Legacy key/value format with whitespace separator should not be used

LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format More info: https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/

Check warning on line 36 in Dockerfile

View workflow job for this annotation

GitHub Actions / Grype docker image scan (Dockerfile)

Legacy key/value format with whitespace separator should not be used

LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format More info: https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/

Check warning on line 36 in Dockerfile

View workflow job for this annotation

GitHub Actions / integration-tests

Legacy key/value format with whitespace separator should not be used

LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format More info: https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/

Check warning on line 36 in Dockerfile

View workflow job for this annotation

GitHub Actions / e2e-tests (1.25.x, ubuntu-latest, Dockerfile)

Legacy key/value format with whitespace separator should not be used

LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format More info: https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/

# Copy built binary to the runtime container
# Vulnerability fixed in latest version of KICS remove when gh actions version is updated
Expand All @@ -47,7 +49,7 @@
USER root

# Healthcheck the container
ENV PATH $PATH:/app/bin

Check warning on line 52 in Dockerfile

View workflow job for this annotation

GitHub Actions / Trivy docker image scan (Dockerfile)

Legacy key/value format with whitespace separator should not be used

LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format More info: https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/

Check warning on line 52 in Dockerfile

View workflow job for this annotation

GitHub Actions / Grype docker image scan (Dockerfile)

Legacy key/value format with whitespace separator should not be used

LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format More info: https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/

Check warning on line 52 in Dockerfile

View workflow job for this annotation

GitHub Actions / integration-tests

Legacy key/value format with whitespace separator should not be used

LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format More info: https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/

Check warning on line 52 in Dockerfile

View workflow job for this annotation

GitHub Actions / e2e-tests (1.25.x, ubuntu-latest, Dockerfile)

Legacy key/value format with whitespace separator should not be used

LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format More info: https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/

# Command to run the executable
ENTRYPOINT ["/app/bin/kics"]
13 changes: 13 additions & 0 deletions assets/queries/k8s/ingress_whitelist_open_to_all/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"id": "3a7d4239-f768-438f-a30b-23a26f885966",
"queryName": "Ingress Whitelist Open To All IPs",
"severity": "HIGH",
"category": "Networking and Firewall",
"descriptionText": "Kubernetes Ingress resources should not set the 'nginx.ingress.kubernetes.io/whitelist-source-range' annotation to '0.0.0.0/0' or '::/0'. These values allow traffic from all IPv4 or IPv6 addresses, effectively disabling the source IP restriction and exposing the service to the entire internet.",
"descriptionUrl": "https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#whitelist-source-range",
"platform": "Kubernetes",
"descriptionID": "3a7d4239",
"cloudProvider": "common",
"cwe": "668",
"riskScore": "7.5"
}
29 changes: 29 additions & 0 deletions assets/queries/k8s/ingress_whitelist_open_to_all/query.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package Cx

# Ingress whitelist-source-range annotation set to 0.0.0.0/0 or ::/0 allows all IPs.
CxPolicy[result] {
document := input.document[i]
document.kind == "Ingress"
metadata := document.metadata

whitelist := metadata.annotations["nginx.ingress.kubernetes.io/whitelist-source-range"]
open_cidr_in_whitelist(whitelist)

result := {
"documentId": input.document[i].id,
"resourceType": document.kind,
"resourceName": metadata.name,
"searchKey": sprintf("metadata.name={{%s}}.annotations", [metadata.name]),
"issueType": "IncorrectValue",
"keyExpectedValue": sprintf("Ingress '%s' whitelist-source-range should restrict access to specific IP ranges", [metadata.name]),
"keyActualValue": sprintf("Ingress '%s' whitelist-source-range is set to '%s', allowing access from all IP addresses", [metadata.name, whitelist]),
}
}

open_cidr_in_whitelist(whitelist) {
contains(whitelist, "0.0.0.0/0")
}

open_cidr_in_whitelist(whitelist) {
contains(whitelist, "::/0")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: restricted-whitelist
annotations:
nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/16,192.168.0.0/24"
spec:
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myservice
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: single-ip-whitelist
annotations:
nginx.ingress.kubernetes.io/whitelist-source-range: "203.0.113.42/32"
spec:
rules:
- host: internal.example.com
http:
paths:
- path: /admin
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 8080
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: open-whitelist-ipv4
annotations:
nginx.ingress.kubernetes.io/whitelist-source-range: "0.0.0.0/0"
spec:
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myservice
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: open-whitelist-ipv6
annotations:
nginx.ingress.kubernetes.io/whitelist-source-range: "::/0"
spec:
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myservice
port:
number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: open-whitelist-combined
annotations:
nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/16,0.0.0.0/0"
spec:
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myservice
port:
number: 443
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[
{
"queryName": "Ingress Whitelist Open To All IPs",
"severity": "HIGH",
"line": 5
},
{
"queryName": "Ingress Whitelist Open To All IPs",
"severity": "HIGH",
"line": 24
},
{
"queryName": "Ingress Whitelist Open To All IPs",
"severity": "HIGH",
"line": 43
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"id": "d44bdf72-1b6c-44a7-bd67-4933211fe36c",
"queryName": "Network Policy Ingress Not Restricted",
"severity": "HIGH",
"category": "Networking and Firewall",
"descriptionText": "Kubernetes NetworkPolicy ingress rules should define a 'from' block to restrict which sources can send traffic to the selected pods. An ingress rule without a 'from' block allows traffic from all sources, including any IP address on the internet.",
"descriptionUrl": "https://kubernetes.io/docs/concepts/services-networking/network-policies/#behavior-of-to-and-from-selectors",
"platform": "Kubernetes",
"descriptionID": "d44bdf72",
"cloudProvider": "common",
"cwe": "668",
"riskScore": "7.5"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package Cx

import data.generic.common as common_lib

# An ingress rule without a 'from' block allows traffic from ALL sources (any IP).
CxPolicy[result] {
document := input.document[i]
document.kind == "NetworkPolicy"
metadata := document.metadata
spec := document.spec

ingress_in_scope(spec)

ingress_rule := spec.ingress[j]
not common_lib.valid_key(ingress_rule, "from")

result := {
"documentId": input.document[i].id,
"resourceType": document.kind,
"resourceName": metadata.name,
"searchKey": sprintf("metadata.name={{%s}}.spec.ingress", [metadata.name]),
"issueType": "MissingAttribute",
"keyExpectedValue": sprintf("NetworkPolicy '%s' ingress rule [%d] should define a 'from' block to restrict source IPs", [metadata.name, j]),
"keyActualValue": sprintf("NetworkPolicy '%s' ingress rule [%d] has no 'from' block, allowing traffic from all sources", [metadata.name, j]),
}
}

# policyTypes explicitly includes Ingress
ingress_in_scope(spec) {
lower(spec.policyTypes[_]) == "ingress"
}

# policyTypes is absent — K8s defaults to controlling Ingress when ingress rules are present
ingress_in_scope(spec) {
not common_lib.valid_key(spec, "policyTypes")
common_lib.valid_key(spec, "ingress")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: restricted-ingress
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Ingress
ingress:
- from:
- ipBlock:
cidr: 10.0.0.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 8080
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
spec:
podSelector:
matchLabels:
app: isolated
policyTypes:
- Ingress
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-ingress-empty-rule
spec:
podSelector:
matchLabels:
app: myapp
policyTypes:
- Ingress
ingress:
- {}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-any-source-with-ports
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- ports:
- protocol: TCP
port: 80
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"queryName": "Network Policy Ingress Not Restricted",
"severity": "HIGH",
"line": 11
},
{
"queryName": "Network Policy Ingress Not Restricted",
"severity": "HIGH",
"line": 22
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"id": "9b848928-9211-4bbe-9a7f-6bb651447593",
"queryName": "Security Group Ingress With Wide CIDR Range",
"severity": "HIGH",
"category": "Networking and Firewall",
"descriptionText": "AWS Security Group ingress rules should not use overly broad CIDR blocks. A CIDR prefix length of /8 or shorter (e.g., 10.0.0.0/1, 0.0.0.0/8) allows millions to billions of IP addresses to reach your resources. Use the most specific CIDR range required.",
"descriptionUrl": "https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group",
"platform": "Terraform",
"descriptionID": "9b848928",
"cloudProvider": "aws",
"cwe": "668",
"riskScore": "7.2"
}
Loading
Loading