[Add] Updated conftest to latest version, policies updated, precommit hook also updated
This commit is contained in:
15
terraform/LICENSE
Normal file
15
terraform/LICENSE
Normal file
@@ -0,0 +1,15 @@
|
||||
Conftest - Write tests against your config files
|
||||
|
||||
Copyright (C) 2019 Gareth Rushgrove
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,66 +1,52 @@
|
||||
# Terraform Security as Code
|
||||
# Conftest
|
||||
|
||||
This directory contains Terraform configurations for creating a Kubernetes cluster on Proxmox VMs. Security is implemented as code through policy checks.
|
||||
[](https://goreportcard.com/report/open-policy-agent/conftest) [](https://app.netlify.com/sites/vibrant-villani-65041c/deploys)
|
||||
|
||||
## Security Policies
|
||||
Conftest helps you write tests against structured configuration data. Using Conftest you can
|
||||
write tests for your Kubernetes configuration, Tekton pipeline definitions, Terraform code,
|
||||
Serverless configs or any other config files.
|
||||
|
||||
Security policies are defined as Open Policy Agent (OPA) Rego files in the `policy/` directory:
|
||||
Conftest uses the Rego language from [Open Policy Agent](https://www.openpolicyagent.org/) for writing
|
||||
the assertions. You can read more about Rego in [How do I write policies](https://www.openpolicyagent.org/docs/how-do-i-write-policies.html)
|
||||
in the Open Policy Agent documentation.
|
||||
|
||||
- **main.rego**: Combined security policy file that includes:
|
||||
- VM security (password auth, root login, qemu-agent)
|
||||
- Network security (bridge configuration, IPv6, DNS)
|
||||
- Provider security (TLS verification, version pinning)
|
||||
Here's a quick example. Save the following as `policy/deployment.rego`:
|
||||
|
||||
## Running Security Checks
|
||||
```rego
|
||||
package main
|
||||
|
||||
### Prerequisites
|
||||
deny[msg] {
|
||||
input.kind == "Deployment"
|
||||
not input.spec.template.spec.securityContext.runAsNonRoot
|
||||
|
||||
1. Install OPA CLI and Conftest:
|
||||
```bash
|
||||
# Install OPA
|
||||
curl -L -o opa https://openpolicy.io/downloads/latest/opa_linux_amd64
|
||||
chmod 755 opa
|
||||
sudo mv opa /usr/local/bin
|
||||
|
||||
# Install Conftest
|
||||
wget https://github.com/open-policy-agent/conftest/releases/download/v0.42.1/conftest_0.42.1_Linux_x86_64.tar.gz
|
||||
tar xzf conftest_0.42.1_Linux_x86_64.tar.gz
|
||||
sudo mv conftest /usr/local/bin
|
||||
```
|
||||
msg := "Containers must not run as root"
|
||||
}
|
||||
|
||||
2. Install Trivy:
|
||||
```bash
|
||||
# For Debian/Ubuntu
|
||||
sudo apt-get install trivy
|
||||
deny[msg] {
|
||||
input.kind == "Deployment"
|
||||
not input.spec.selector.matchLabels.app
|
||||
|
||||
# For other systems, see: https://aquasecurity.github.io/trivy/latest/getting-started/installation/
|
||||
```
|
||||
msg := "Containers must provide app label for pod selectors"
|
||||
}
|
||||
```
|
||||
|
||||
3. Install Checkov:
|
||||
```bash
|
||||
pip install checkov
|
||||
```
|
||||
Assuming you have a Kubernetes deployment in `deployment.yaml` you can run Conftest like so:
|
||||
|
||||
### Running Policy Checks
|
||||
```console
|
||||
$ conftest test deployment.yaml
|
||||
FAIL - deployment.yaml - Containers must not run as root
|
||||
FAIL - deployment.yaml - Containers must provide app label for pod selectors
|
||||
|
||||
1. Generate a Terraform plan and convert to JSON:
|
||||
```bash
|
||||
cd terraform
|
||||
terraform init
|
||||
terraform plan -out=tfplan
|
||||
terraform show -json tfplan > tfplan.json
|
||||
```
|
||||
2 tests, 0 passed, 0 warnings, 2 failures, 0 exceptions
|
||||
```
|
||||
|
||||
2. Run Conftest with OPA policies:
|
||||
```bash
|
||||
conftest test tfplan.json -p policy/
|
||||
```
|
||||
Conftest isn't specific to Kubernetes. It will happily let you write tests for any configuration files in a variety of different formats. See the [documentation](https://www.conftest.dev/) for [installation instructions](https://www.conftest.dev/install/) and
|
||||
more details about the features.
|
||||
|
||||
3. Run Trivy IaC security scan:
|
||||
```bash
|
||||
# Skip AWS policies and use variables file
|
||||
trivy config --severity HIGH,CRITICAL --skip-policy "aws.*" --tf-vars="variables.tfvars" .
|
||||
```
|
||||
## Want to contribute to Conftest?
|
||||
|
||||
4. Run Checkov:
|
||||
```
|
||||
* See [DEVELOPMENT.md](DEVELOPMENT.md) to build and test Conftest itself.
|
||||
* See [CONTRIBUTING.md](CONTRIBUTING.md) to get started.
|
||||
|
||||
For discussions and questions join us on the [Open Policy Agent Slack](https://slack.openpolicyagent.org/)
|
||||
in the `#opa-conftest` channel.
|
||||
|
||||
@@ -17,8 +17,8 @@ resource "proxmox_vm_qemu" "proxmox_vm_master" {
|
||||
nameserver = "1.1.1.1 8.8.8.8"
|
||||
ipconfig0 = "ip=${var.master_ips[count.index]}/${var.networkrange},gw=${var.gateway}"
|
||||
skip_ipv6 = true
|
||||
ciuser = "debian"
|
||||
cipassword = ""
|
||||
ciuser = "root"
|
||||
cipassword = "test_passwd"
|
||||
sshkeys = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKXXnm9Hl4fPCt/Xjd/8E5tKY+edtM/BvdMOXpx40oWG iac@proxmox.vadzik-iot.ru"
|
||||
|
||||
# Most cloud-init images require a serial device for their display
|
||||
|
||||
@@ -7,7 +7,7 @@ import input
|
||||
vms := [r | r := input.planned_values.root_module.resources[_]; r.type == "proxmox_vm_qemu"]
|
||||
|
||||
# Helper function to check if a value is empty or undefined
|
||||
is_empty(value) {
|
||||
is_empty(value) if {
|
||||
value == ""
|
||||
} {
|
||||
value == null
|
||||
@@ -19,28 +19,28 @@ is_empty(value) {
|
||||
min_memory = 512
|
||||
|
||||
# Deny if VM allows password authentication
|
||||
deny[msg] {
|
||||
deny contains msg if {
|
||||
some vm in vms
|
||||
not is_empty(vm.values.cipassword)
|
||||
msg := sprintf("VM '%s' uses password authentication. Use SSH keys only.", [vm.name])
|
||||
}
|
||||
|
||||
# Deny if VM allows root login
|
||||
deny[msg] {
|
||||
deny contains msg if {
|
||||
some vm in vms
|
||||
vm.values.ciuser == "root"
|
||||
msg := sprintf("VM '%s' allows root login. Use a non-root user.", [vm.name])
|
||||
}
|
||||
|
||||
# Deny if qemu-agent is not enabled
|
||||
deny[msg] {
|
||||
deny contains msg if {
|
||||
some vm in vms
|
||||
vm.values.agent != 1
|
||||
msg := sprintf("VM '%s' does not have qemu-agent enabled (agent = 1).", [vm.name])
|
||||
}
|
||||
|
||||
# Deny if VM uses insecure network bridge
|
||||
deny[msg] {
|
||||
deny contains msg if {
|
||||
some vm in vms
|
||||
net := vm.values.network[_]
|
||||
net.bridge != "vmbr2"
|
||||
@@ -48,28 +48,28 @@ deny[msg] {
|
||||
}
|
||||
|
||||
# Deny if IPv6 is not disabled
|
||||
deny[msg] {
|
||||
deny contains msg if {
|
||||
some vm in vms
|
||||
not vm.values.skip_ipv6
|
||||
msg := sprintf("VM '%s' does not have IPv6 disabled (skip_ipv6 = true).", [vm.name])
|
||||
}
|
||||
|
||||
# Deny if TLS verification is disabled
|
||||
deny[msg] {
|
||||
deny contains msg if {
|
||||
tls_enabled := input.variables.pm_tls_insecure.value
|
||||
tls_enabled == true
|
||||
msg := "TLS verification must be enabled (pm_tls_insecure = false)"
|
||||
}
|
||||
|
||||
# Deny if provider version is not pinned
|
||||
deny[msg] {
|
||||
deny contains msg if {
|
||||
provider := input.configuration.terraform.required_providers.proxmox
|
||||
not startswith(provider.version_constraint, "=")
|
||||
msg := "Provider version must be pinned with '=' constraint"
|
||||
}
|
||||
|
||||
# Deny if VM memory is below minimum requirement
|
||||
deny[msg] {
|
||||
deny contains msg if {
|
||||
some vm in vms
|
||||
memory := to_number(vm.values.memory)
|
||||
memory < min_memory
|
||||
@@ -77,20 +77,20 @@ deny[msg] {
|
||||
}
|
||||
|
||||
# Deny if VM does not have a description
|
||||
deny[msg] {
|
||||
deny contains msg if {
|
||||
some vm in vms
|
||||
is_empty(vm.values.desc)
|
||||
msg := sprintf("VM '%s' must have a description for documentation purposes.", [vm.name])
|
||||
}
|
||||
|
||||
# Deny if VM uses default SCSI controller
|
||||
deny[msg] {
|
||||
deny contains msg if {
|
||||
some vm in vms
|
||||
vm.values.scsihw == "lsi"
|
||||
msg := sprintf("VM '%s' uses default SCSI controller. Use virtio-scsi-pci for better performance.", [vm.name])
|
||||
}
|
||||
|
||||
# Test rule to verify policy is loaded
|
||||
test_policy_loaded {
|
||||
test_policy_loaded if {
|
||||
true
|
||||
}
|
||||
@@ -109,47 +109,46 @@ mock_input_insecure := {
|
||||
}
|
||||
|
||||
# Test secure configuration passes
|
||||
test_secure_config {
|
||||
input := mock_input_secure
|
||||
count(deny) == 0
|
||||
test_secure_config if {
|
||||
count(deny) == 0 with input as mock_input_secure
|
||||
}
|
||||
|
||||
# Test password authentication
|
||||
test_password_auth {
|
||||
test_password_auth if {
|
||||
deny["VM 'insecure_vm' uses password authentication. Use SSH keys only."] with input as mock_input_insecure
|
||||
}
|
||||
|
||||
# Test qemu agent
|
||||
test_qemu_agent {
|
||||
test_qemu_agent if {
|
||||
deny["VM 'insecure_vm' does not have qemu-agent enabled (agent = 1)."] with input as mock_input_insecure
|
||||
}
|
||||
|
||||
# Test network bridge
|
||||
test_network_bridge {
|
||||
test_network_bridge if {
|
||||
deny["VM 'insecure_vm' uses insecure network bridge 'vmbr0'. Use 'vmbr2'."] with input as mock_input_insecure
|
||||
}
|
||||
|
||||
# Test TLS verification
|
||||
test_tls_verification {
|
||||
test_tls_verification if {
|
||||
deny["TLS verification must be enabled (pm_tls_insecure = false)"] with input as mock_input_insecure
|
||||
}
|
||||
|
||||
# Test provider version pinning
|
||||
test_provider_version {
|
||||
test_provider_version if {
|
||||
deny["Provider version must be pinned with '=' constraint"] with input as mock_input_insecure
|
||||
}
|
||||
|
||||
# Test minimum memory requirement
|
||||
test_minimum_memory {
|
||||
test_minimum_memory if {
|
||||
deny["VM 'insecure_vm' has insufficient memory (256MB). Minimum required: 512MB."] with input as mock_input_insecure
|
||||
}
|
||||
|
||||
# Test VM description requirement
|
||||
test_vm_description {
|
||||
test_vm_description if {
|
||||
deny["VM 'insecure_vm' must have a description for documentation purposes."] with input as mock_input_insecure
|
||||
}
|
||||
|
||||
# Test SCSI controller requirement
|
||||
test_scsi_controller {
|
||||
test_scsi_controller if {
|
||||
deny["VM 'insecure_vm' uses default SCSI controller. Use virtio-scsi-pci for better performance."] with input as mock_input_insecure
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
{
|
||||
"planned_values": {
|
||||
"root_module": {
|
||||
"resources": [
|
||||
{
|
||||
"type": "proxmox_vm_qemu",
|
||||
"name": "insecure_vm",
|
||||
"values": {
|
||||
"cipassword": "password123",
|
||||
"ciuser": "root",
|
||||
"agent": 0,
|
||||
"network": [
|
||||
{
|
||||
"bridge": "vmbr0"
|
||||
}
|
||||
],
|
||||
"skip_ipv6": false,
|
||||
"memory": 256,
|
||||
"desc": "",
|
||||
"scsihw": "lsi",
|
||||
"cpu": "",
|
||||
"backup": false,
|
||||
"tags": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"configuration": {
|
||||
"provider_config": {
|
||||
"proxmox": {
|
||||
"expressions": {
|
||||
"pm_tls_insecure": {
|
||||
"constant_value": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"terraform": {
|
||||
"required_providers": {
|
||||
"proxmox": {
|
||||
"version_constraint": "~2.9.14"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,6 @@
|
||||
# Security Check Script for Terraform
|
||||
# This script runs all security checks on your Terraform configuration
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
@@ -65,7 +63,7 @@ terraform show -json tfplan | jq > tfplan.json
|
||||
|
||||
echo -e "\n${YELLOW}Running OPA policy checks...${NC}"
|
||||
if [ -d "policy" ]; then
|
||||
conftest test tfplan.json -p policy/
|
||||
conftest test -p policy/ tfplan.json
|
||||
CONFTEST_EXIT=$?
|
||||
if [ $CONFTEST_EXIT -eq 0 ]; then
|
||||
echo -e "${GREEN}✅ OPA policy checks passed.${NC}"
|
||||
|
||||
Reference in New Issue
Block a user