Initial commit - 611 cybersecurity skills across all subdomains

This commit is contained in:
mukul975
2026-02-25 10:47:44 +01:00
commit 22a7ab1462
1765 changed files with 280648 additions and 0 deletions
@@ -0,0 +1,307 @@
---
name: implementing-policy-as-code-with-open-policy-agent
description: >
This skill covers implementing Open Policy Agent (OPA) and Gatekeeper for policy-as-code
enforcement in Kubernetes and CI/CD pipelines. It addresses writing Rego policies, deploying
OPA Gatekeeper as a Kubernetes admission controller, testing policies in development, and
integrating policy evaluation into deployment pipelines.
domain: cybersecurity
subdomain: devsecops
tags: [devsecops, cicd, opa, gatekeeper, policy-as-code, kubernetes, secure-sdlc]
version: 1.0.0
author: mahipal
license: MIT
---
# Implementing Policy as Code with Open Policy Agent
## When to Use
- When enforcing organizational security policies across Kubernetes clusters programmatically
- When requiring admission control that blocks non-compliant resources from being created
- When implementing policy governance that can be version-controlled, tested, and audited
- When standardizing security rules across multiple clusters and environments
- When needing a flexible policy engine that extends beyond Kubernetes to APIs and CI/CD
**Do not use** for vulnerability scanning (use Trivy/Checkov), for runtime threat detection (use Falco), or for network policy enforcement (use Kubernetes NetworkPolicy or Calico).
## Prerequisites
- Kubernetes cluster with admin access for Gatekeeper installation
- Helm for Gatekeeper deployment
- OPA CLI or conftest for local policy testing
- Rego knowledge for policy authoring
## Workflow
### Step 1: Install OPA Gatekeeper
```bash
# Install Gatekeeper via Helm
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm install gatekeeper gatekeeper/gatekeeper \
--namespace gatekeeper-system --create-namespace \
--set replicas=3 \
--set audit.replicas=1 \
--set audit.writeToRAMDisk=true
```
### Step 2: Create Constraint Templates
```yaml
# templates/k8s-required-labels.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema:
type: object
properties:
labels:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
violation[{"msg": msg}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_]}
missing := required - provided
count(missing) > 0
msg := sprintf("Missing required labels: %v", [missing])
}
---
# templates/k8s-container-limits.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8scontainerlimits
spec:
crd:
spec:
names:
kind: K8sContainerLimits
validation:
openAPIV3Schema:
type: object
properties:
cpu:
type: string
memory:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8scontainerlimits
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.resources.limits.cpu
msg := sprintf("Container %v has no CPU limit", [container.name])
}
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.resources.limits.memory
msg := sprintf("Container %v has no memory limit", [container.name])
}
---
# templates/k8s-block-privileged.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sblockprivileged
spec:
crd:
spec:
names:
kind: K8sBlockPrivileged
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sblockprivileged
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
container.securityContext.privileged == true
msg := sprintf("Privileged container not allowed: %v", [container.name])
}
violation[{"msg": msg}] {
container := input.review.object.spec.initContainers[_]
container.securityContext.privileged == true
msg := sprintf("Privileged init container not allowed: %v", [container.name])
}
```
### Step 3: Apply Constraints
```yaml
# constraints/require-labels.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: require-team-labels
spec:
enforcementAction: deny
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
- apiGroups: ["apps"]
kinds: ["Deployment", "StatefulSet"]
excludedNamespaces:
- kube-system
- gatekeeper-system
parameters:
labels:
- "team"
- "environment"
- "cost-center"
---
# constraints/block-privileged.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sBlockPrivileged
metadata:
name: block-privileged-containers
spec:
enforcementAction: deny
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
- apiGroups: ["apps"]
kinds: ["Deployment", "DaemonSet", "StatefulSet"]
excludedNamespaces:
- kube-system
```
### Step 4: Test Policies with conftest
```bash
# Install conftest
brew install conftest
# Test Kubernetes manifests against OPA policies locally
conftest test deployment.yaml --policy policies/ --output json
# Test Terraform against OPA policies
conftest test terraform/main.tf --policy policies/terraform/ --parser hcl2
# Test Dockerfiles
conftest test Dockerfile --policy policies/docker/
```
```rego
# policies/kubernetes/deny_latest_tag.rego
package kubernetes
deny[msg] {
input.kind == "Deployment"
container := input.spec.template.spec.containers[_]
endswith(container.image, ":latest")
msg := sprintf("Container %v uses :latest tag. Pin to specific version.", [container.name])
}
deny[msg] {
input.kind == "Deployment"
container := input.spec.template.spec.containers[_]
not contains(container.image, ":")
msg := sprintf("Container %v has no tag. Pin to specific version.", [container.name])
}
```
### Step 5: Integrate Policy Testing in CI/CD
```yaml
# .github/workflows/policy-test.yml
name: Policy Validation
on:
pull_request:
paths: ['k8s/**', 'terraform/**', 'policies/**']
jobs:
conftest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install conftest
run: |
wget -q https://github.com/open-policy-agent/conftest/releases/download/v0.50.0/conftest_0.50.0_Linux_x86_64.tar.gz
tar xzf conftest_0.50.0_Linux_x86_64.tar.gz
sudo mv conftest /usr/local/bin/
- name: Test K8s manifests
run: conftest test k8s/**/*.yaml --policy policies/kubernetes/ --output json
- name: Test Terraform
run: conftest test terraform/*.tf --policy policies/terraform/ --parser hcl2
```
## Key Concepts
| Term | Definition |
|------|------------|
| OPA | Open Policy Agent — general-purpose policy engine using Rego language for policy decisions |
| Rego | OPA's declarative query language for writing policy rules |
| Gatekeeper | Kubernetes-native OPA integration implementing admission control via ConstraintTemplates |
| ConstraintTemplate | CRD defining the Rego policy logic and parameters schema for a class of constraints |
| Constraint | Instance of a ConstraintTemplate with specific parameters and scope (which resources to check) |
| Admission Controller | Kubernetes component that intercepts API requests before persistence and can allow or deny them |
| conftest | CLI tool for testing structured data (YAML, JSON, HCL) against OPA policies |
## Tools & Systems
- **Open Policy Agent (OPA)**: General-purpose policy engine for unified policy enforcement
- **Gatekeeper**: Kubernetes admission controller built on OPA with CRD-based configuration
- **conftest**: Testing framework for OPA policies against configuration files
- **Kyverno**: Alternative Kubernetes policy engine using YAML-based policies (no Rego required)
- **Styra DAS**: Commercial OPA management platform with policy authoring, testing, and distribution
## Common Scenarios
### Scenario: Enforcing Container Security Standards Across Clusters
**Context**: Multiple development teams deploy to shared Kubernetes clusters. Some teams run privileged containers and images without resource limits, causing security and stability issues.
**Approach**:
1. Deploy Gatekeeper on all clusters via GitOps (Helm chart in a FluxCD repository)
2. Create ConstraintTemplates for: no privileged containers, required resource limits, required labels, no latest tag
3. Start with `enforcementAction: warn` to identify violations without blocking deployments
4. Notify teams of violations and provide a 2-week remediation window
5. Switch to `enforcementAction: deny` after the remediation period
6. Add `excludedNamespaces` for kube-system and monitoring namespaces
**Pitfalls**: Deploying Gatekeeper with deny mode immediately can break existing workloads. Always start with warn mode. Overly restrictive policies without exemptions for system namespaces can prevent cluster components from functioning.
## Output Format
```
OPA Policy Evaluation Report
==============================
Cluster: production-east
Date: 2026-02-23
Gatekeeper Version: 3.16.0
CONSTRAINT SUMMARY:
K8sRequiredLabels: 12 violations (warn)
K8sBlockPrivileged: 0 violations (deny)
K8sContainerLimits: 8 violations (deny)
K8sBlockLatestTag: 3 violations (deny)
BLOCKED DEPLOYMENTS (deny):
[K8sContainerLimits] deployment/api-server in ns/payments
- Container 'api' has no memory limit
[K8sBlockLatestTag] deployment/frontend in ns/web
- Container 'nginx' uses :latest tag
AUDIT VIOLATIONS (warn):
[K8sRequiredLabels] namespace/staging
- Missing labels: {cost-center}
```
@@ -0,0 +1,75 @@
# OPA Policy as Code Templates
## Gatekeeper ConstraintTemplate Library
```yaml
# Block containers running as root
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sblockrootuser
spec:
crd:
spec:
names:
kind: K8sBlockRootUser
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sblockrootuser
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
container.securityContext.runAsUser == 0
msg := sprintf("Container %v runs as root (UID 0)", [container.name])
}
violation[{"msg": msg}] {
input.review.object.spec.securityContext.runAsUser == 0
msg := "Pod runs as root (UID 0)"
}
```
## conftest Policy for CI/CD
```rego
# policies/kubernetes/security.rego
package kubernetes
deny[msg] {
input.kind == "Deployment"
container := input.spec.template.spec.containers[_]
container.securityContext.privileged == true
msg := sprintf("Privileged container '%v' not allowed", [container.name])
}
deny[msg] {
input.kind == "Deployment"
container := input.spec.template.spec.containers[_]
not container.resources.limits
msg := sprintf("Container '%v' missing resource limits", [container.name])
}
deny[msg] {
input.kind == "Deployment"
container := input.spec.template.spec.containers[_]
endswith(container.image, ":latest")
msg := sprintf("Container '%v' uses :latest tag", [container.name])
}
```
## GitHub Actions Integration
```yaml
name: Policy Check
on:
pull_request:
paths: ['k8s/**']
jobs:
conftest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: open-policy-agent/conftest-action@v1
with:
files: k8s/
policy: policies/kubernetes/
```
@@ -0,0 +1,26 @@
# Standards Reference: Policy as Code with OPA
## NIST SP 800-53 - Security and Privacy Controls
| Control | OPA Policy | Description |
|---------|-----------|-------------|
| AC-3 | Block unauthorized access | Enforce RBAC and namespace isolation |
| AC-6 | Least privilege | Block privileged containers and host access |
| CM-2 | Baseline configuration | Require resource limits and labels |
| CM-6 | Configuration settings | Enforce approved image registries |
| SI-7 | Software integrity | Require image signatures and digests |
## CIS Kubernetes Benchmark Mapping
- 5.1.1: Ensure RBAC is enabled → OPA can enforce RBAC policies
- 5.2.1: Minimize privileged containers → K8sBlockPrivileged constraint
- 5.2.2: Minimize host namespace sharing → Block hostNetwork/hostPID
- 5.2.5: Ensure allowPrivilegeEscalation is false → OPA constraint
- 5.7.1: Create administrative boundaries between resources → Namespace policies
## OWASP Kubernetes Security Cheat Sheet
- Enforce Pod Security Standards via admission control
- Restrict container capabilities using OPA policies
- Enforce network policies and resource quotas
- Validate image provenance and signatures
@@ -0,0 +1,55 @@
# Workflow Reference: Policy as Code with OPA
## Policy Lifecycle
```
Author Rego Policy
┌──────────────────┐
│ Unit Test with │
│ OPA test │
└──────┬───────────┘
┌──────────────────┐
│ Integration Test │
│ with conftest │
└──────┬───────────┘
┌──────────────────┐
│ Deploy to Cluster│
│ (warn mode) │
└──────┬───────────┘
┌──────────────────┐
│ Monitor + Triage │
│ Violations │
└──────┬───────────┘
┌──────────────────┐
│ Switch to deny │
│ mode │
└──────────────────┘
```
## OPA/Gatekeeper Architecture
```
API Request → Kubernetes API Server → Gatekeeper Webhook
┌──────┴──────┐
│ OPA Engine │
│ (Rego eval) │
└──────┬──────┘
┌──────┴──────┐
│ Constraint │
│ Templates │
└──────┬──────┘
Allow / Deny
```
@@ -0,0 +1,167 @@
#!/usr/bin/env python3
"""
OPA Policy Evaluation Pipeline Script
Runs conftest against Kubernetes manifests and Terraform files,
evaluates policy compliance, and generates reports.
Usage:
python process.py --manifests-dir ./k8s --policies-dir ./policies
python process.py --manifests-dir ./terraform --policies-dir ./policies --parser hcl2
"""
import argparse
import json
import os
import subprocess
import sys
from dataclasses import dataclass, field
from datetime import datetime, timezone
from pathlib import Path
@dataclass
class PolicyViolation:
file: str
rule: str
message: str
severity: str = "HIGH"
def run_conftest(manifests_dir: str, policies_dir: str,
parser: str = "yaml") -> dict:
"""Run conftest and return JSON results."""
files = []
extensions = {"yaml": [".yaml", ".yml"], "hcl2": [".tf"], "dockerfile": ["Dockerfile"]}
for ext in extensions.get(parser, [".yaml", ".yml"]):
files.extend(str(p) for p in Path(manifests_dir).rglob(f"*{ext}"))
if not files:
return {"results": [], "error": f"No {parser} files found in {manifests_dir}"}
cmd = [
"conftest", "test",
"--policy", policies_dir,
"--output", "json",
"--parser", parser
] + files
try:
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
if proc.stdout:
return {"results": json.loads(proc.stdout), "error": ""}
return {"results": [], "error": proc.stderr[:300]}
except subprocess.TimeoutExpired:
return {"results": [], "error": "conftest timed out"}
except FileNotFoundError:
return {"results": [], "error": "conftest not found"}
except json.JSONDecodeError:
return {"results": [], "error": "Failed to parse conftest output"}
def parse_conftest_results(results: list) -> list:
"""Parse conftest JSON results into violations."""
violations = []
for result in results:
filename = result.get("filename", "unknown")
for failure in result.get("failures", []):
violations.append(PolicyViolation(
file=filename,
rule=failure.get("metadata", {}).get("rule", "unknown"),
message=failure.get("msg", ""),
severity="HIGH"
))
for warning in result.get("warnings", []):
violations.append(PolicyViolation(
file=filename,
rule=warning.get("metadata", {}).get("rule", "unknown"),
message=warning.get("msg", ""),
severity="MEDIUM"
))
return violations
def check_gatekeeper_violations(namespace: str = "") -> list:
"""Query Gatekeeper audit violations from the cluster."""
cmd = ["kubectl", "get", "constraints", "-o", "json"]
if namespace:
cmd.extend(["-n", namespace])
try:
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if proc.returncode != 0:
return []
data = json.loads(proc.stdout)
violations = []
for item in data.get("items", []):
status = item.get("status", {})
for v in status.get("violations", []):
violations.append(PolicyViolation(
file=f"{v.get('kind', '')}/{v.get('name', '')}",
rule=item.get("kind", ""),
message=v.get("message", ""),
severity="HIGH" if item.get("spec", {}).get("enforcementAction") == "deny" else "MEDIUM"
))
return violations
except (subprocess.TimeoutExpired, FileNotFoundError, json.JSONDecodeError):
return []
def main():
parser = argparse.ArgumentParser(description="OPA Policy Evaluation Pipeline")
parser.add_argument("--manifests-dir", required=True)
parser.add_argument("--policies-dir", required=True)
parser.add_argument("--parser", default="yaml", choices=["yaml", "hcl2", "dockerfile"])
parser.add_argument("--output", default="policy-report.json")
parser.add_argument("--fail-on-violations", action="store_true")
parser.add_argument("--check-cluster", action="store_true",
help="Also check Gatekeeper violations in cluster")
args = parser.parse_args()
violations = []
print(f"[*] Evaluating policies from {args.policies_dir} against {args.manifests_dir}")
result = run_conftest(os.path.abspath(args.manifests_dir),
os.path.abspath(args.policies_dir), args.parser)
if result.get("error"):
print(f"[WARN] {result['error']}")
else:
violations.extend(parse_conftest_results(result["results"]))
print(f" conftest: {len(violations)} violations")
if args.check_cluster:
cluster_violations = check_gatekeeper_violations()
violations.extend(cluster_violations)
print(f" cluster: {len(cluster_violations)} audit violations")
report = {
"metadata": {"date": datetime.now(timezone.utc).isoformat()},
"summary": {
"total_violations": len(violations),
"high": sum(1 for v in violations if v.severity == "HIGH"),
"medium": sum(1 for v in violations if v.severity == "MEDIUM")
},
"violations": [
{"file": v.file, "rule": v.rule, "message": v.message, "severity": v.severity}
for v in violations
]
}
output_path = os.path.abspath(args.output)
with open(output_path, "w") as f:
json.dump(report, f, indent=2)
print(f"[*] Report: {output_path}")
passed = len(violations) == 0
print(f"\n[{'PASS' if passed else 'FAIL'}] {len(violations)} policy violations found")
for v in violations[:10]:
print(f" [{v.severity}] {v.file}: {v.message[:100]}")
if args.fail_on_violations and not passed:
sys.exit(1)
if __name__ == "__main__":
main()