Skip to content

Commit

Permalink
feat: add examples of custom checks
Browse files Browse the repository at this point in the history
Signed-off-by: Nikita Pivkin <[email protected]>
  • Loading branch information
nikpivkin committed Nov 26, 2024
1 parent 08abf3c commit b8d736b
Show file tree
Hide file tree
Showing 15 changed files with 753 additions and 2 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ rego: fmt-rego test-rego

.PHONY: fmt-rego
fmt-rego:
opa fmt -w lib/ checks/
opa fmt -w lib/ checks/ examples/

.PHONY: test-rego
test-rego:
go run ./cmd/opa test --explain=fails lib/ checks/ --ignore '*.yaml'
go run ./cmd/opa test --explain=fails lib/ checks/ examples/ --ignore '*.yaml'

.PHONY: bundle
bundle: create-bundle verify-bundle
Expand Down
9 changes: 9 additions & 0 deletions examples/docker-compose/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version: '3.8'

services:
web:
build: .
ports:
- "8000:5000"
redis:
image: "redis:latest"
32 changes: 32 additions & 0 deletions examples/docker-compose/latest_tag.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## METADATA
# title: Avoid using 'latest' tag in container images
# description: |
# The 'latest' tag in container images does not guarantee consistency across deployments.
# Using explicit version tags ensures that the exact image version is used,
# reducing the risk of unexpected changes or vulnerabilities in your environment.
#
# Avoid using 'latest' in your `docker-compose.yaml` files to maintain predictable deployments.
# scope: package
# schemas:
# - input: schema["container"]
# related_resources:
# - https://docs.docker.com/reference/compose-file/services/#image
# custom:
# id: AVD-COMPOSE-0001
# avd_id: AVD-COMPOSE-0001
# provider: generic
# severity: MEDIUM
# short_code: avoid-latest-tag
# recommended_action: Use specific image tags instead of 'latest' for reliable deployments.
# input:
# selector:
# - type: yaml
package user.compose.latest_tag

import rego.v1

deny contains res if {
some name, service in input.services
endswith(service.image, ":latest")
res := result.new(sprintf("Avoid using 'latest' tag in container image for %q", [name]), {})
}
31 changes: 31 additions & 0 deletions examples/docker-compose/latest_tag_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package user.compose.latest_tag_test

import rego.v1

import data.user.compose.latest_tag as check

test_deny_latest_tag if {
inp := {"services": {
"web": {
"build": ".",
"ports": ["8000:5000"],
},
"redis": {"image": "redis:latest"},
}}

res := check.deny with input as inp
count(res) == 1
}

test_allow_specific_tag if {
inp := {"services": {
"web": {
"build": ".",
"ports": ["8000:5000"],
},
"redis": {"image": "redis:7.4"},
}}

res := check.deny with input as inp
res == set()
}
19 changes: 19 additions & 0 deletions examples/kubernetes/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-deployment
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-app-container
image: web-app:1.0
ports:
- containerPort: 80
31 changes: 31 additions & 0 deletions examples/kubernetes/no_deployment_allowed.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## METADATA
# title: Deployment not allowed
# description: |
# This check ensures that Kubernetes Deployments are not used in your environment.
# Deployments may be restricted for various reasons, such as the need to use other controllers (e.g., StatefulSets, DaemonSets) or the avoidance of certain deployment strategies.
#
# Avoid using the 'Deployment' kind to ensure compliance with your organization's deployment strategy.
# scope: package
# schemas:
# - input: schema["kubernetes"]
# related_resources:
# - https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
# custom:
# id: AVD-KUBE-0001
# severity: HIGH
# short_code: no-deployment-allowed
# recommended_action: Avoid using Kubernetes Deployments. Consider alternative resources like StatefulSets or DaemonSets.
# input:
# selector:
# - type: kubernetes
package user.kubernetes.no_deployment_allowed

import rego.v1

deny contains res if {
input.kind == "Deployment"
res := result.new(
sprintf("Found deployment '%s' but deployments are not allowed", [input.metadata.name]),
{},
)
}
52 changes: 52 additions & 0 deletions examples/kubernetes/no_deployment_allowed_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package user.kubernetes.no_deployment_allowed_test

import rego.v1

import data.user.kubernetes.no_deployment_allowed as check

test_deny_deployment if {
inp := {
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {"name": "web-app-deployment"},
"spec": {
"replicas": 3,
"selector": {"matchLabels": {"app": "web-app"}},
"template": {
"metadata": {"labels": {"app": "web-app"}},
"spec": {"containers": [{
"name": "web-app-container",
"image": "web-app:1.0",
"ports": [{"containerPort": 80}],
}]},
},
},
}

res := check.deny with input as inp
count(res) == 1
}

test_allow_stateful_set if {
inp := {
"apiVersion": "apps/v1",
"kind": "StatefulSet",
"metadata": {"name": "web-app-statefulset"},
"spec": {
"serviceName": "web-app",
"replicas": 3,
"selector": {"matchLabels": {"app": "web-app"}},
"template": {
"metadata": {"labels": {"app": "web-app"}},
"spec": {"containers": [{
"name": "web-app-container",
"image": "web-app:1.0",
"ports": [{"containerPort": 80}],
}]},
},
},
}

res := check.deny with input as inp
res == set()
}
35 changes: 35 additions & 0 deletions examples/serverless/python2.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## METADATA
# title: Avoid using Python 2 as provider runtime
# description: |
# Python 2 is deprecated and no longer receives security updates.
# Using any version of Python 2 as the runtime for your provider poses significant risks,
# including exposure to vulnerabilities and lack of support for modern libraries.
#
# Ensure that you use a supported runtime version, such as Python 3.x,
# to maintain the security and reliability of your serverless application.
# scope: package
# schemas:
# - input: schema["yaml"]
# related_resources:
# - https://www.python.org/doc/sunset-python-2/
# custom:
# id: AVD-SERVERLESS-0001
# avd_id: AVD-SERVERLESS-0001
# provider: generic
# severity: HIGH
# short_code: avoid-python2
# recommended_action: Update your provider runtime to a supported Python 3.x version.
# input:
# selector:
# - type: yaml
package user.serverless.avoid_python2

import rego.v1

deny contains res if {
startswith(input.provider.runtime, "python2")
res := result.new(
sprintf("Python 2 (%s) should not be the default provider runtime.", [input.provider.runtime]),
{},
)
}
38 changes: 38 additions & 0 deletions examples/serverless/python2_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package user.serverless.avoid_python2_test

import rego.v1

import data.user.serverless.avoid_python2 as check

test_deny_python2_runtime if {
inp := {
"service": "aws-python-alexa-skill",
"frameworkVersion": ">=1.4.0 <2.0.0",
"provider": {
"name": "aws",
"runtime": "python2.7",
},
"functions": {"luckyNumber": {
"handler": "handler.lucky_number",
"events": ["alexaSkill"],
}},
}

res := check.deny with input as inp
count(res) == 1
}

test_allow_python3_runtime if {
inp := {
"service": "aws-python",
"frameworkVersion": "4",
"provider": {
"name": "aws",
"runtime": "python3.12",
},
"functions": {"hello": {"handler": "handler.hello"}},
}

res := check.deny with input as inp
res == set()
}
13 changes: 13 additions & 0 deletions examples/serverless/serverless.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
service: aws-python-alexa-skill

frameworkVersion: ">=1.4.0 <2.0.0"

provider:
name: aws
runtime: python2.7

functions:
luckyNumber:
handler: handler.lucky_number
events:
- alexaSkill
24 changes: 24 additions & 0 deletions examples/terraform-plan/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions examples/terraform-plan/asg_capacity.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## METADATA
# title: ASG desires too much capacity
# description: |
# This check ensures that an AWS Auto Scaling Group (ASG) does not request an excessively large desired capacity.
# A high desired capacity may lead to unnecessary costs and potential scaling issues.
#
# Ensure that the desired capacity for Auto Scaling Groups is set to a reasonable value, typically within limits defined by your organization.
# scope: package
# schemas:
# - input: schema["json"]
# related_resources:
# - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/autoscaling_group
# custom:
# id: AVD-TFPLAN-0001
# avdid: AVD-TFPLAN-0001
# severity: MEDIUM
# short_code: asg-too-much-capacity
# recommended_action: Reduce the desired capacity of the Auto Scaling Group to an appropriate value.
# input:
# selector:
# - type: json
package user.terraform.asg_capacity_check

import rego.v1

deny contains res if {
some resource in input.planned_values.root_module.resources
resource.type == "aws_autoscaling_group"
resource.values.desired_capacity > 10

res := result.new(
sprintf("ASG $q desires too much capacity: %d.", [resource.name, resource.values.desired_capacity]),
{},
)
}
41 changes: 41 additions & 0 deletions examples/terraform-plan/asg_capacity_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package user.terraform.asg_capacity_check_test

import rego.v1

import data.user.terraform.asg_capacity_check as check

test_deny_asg_too_much_capacity if {
res := check.deny with input as {
"format_version": "0.1",
"terraform_version": "0.12.6",
"planned_values": {"root_module": {"resources": [{
"address": "aws_autoscaling_group.this",
"mode": "managed",
"type": "aws_autoscaling_group",
"name": "this",
"provider_name": "aws",
"schema_version": 0,
"values": {"desired_capacity": 20},
}]}},
}

count(res) == 1
}

test_allow_asg_ok_capacity if {
res := check.deny with input as {
"format_version": "0.1",
"terraform_version": "0.12.6",
"planned_values": {"root_module": {"resources": [{
"address": "aws_autoscaling_group.this",
"mode": "managed",
"type": "aws_autoscaling_group",
"name": "this",
"provider_name": "aws",
"schema_version": 0,
"values": {"desired_capacity": 5},
}]}},
}

res == set()
}
Loading

0 comments on commit b8d736b

Please sign in to comment.