Skip to content

Commit 61b68ea

Browse files
authored
Create README.md
1 parent 2cd96ad commit 61b68ea

1 file changed

Lines changed: 165 additions & 0 deletions

File tree

PaS/README.md

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
2+
### Policy-as-Code (PaC)
3+
4+
Policy-as-Code (PaC) is a core practice in modern DevSecOps. It involves defining security, compliance, and operational rules in a machine-readable format. This code is then automatically enforced within the CI/CD pipeline, preventing insecure infrastructure from being provisioned and enabling a "Shift-Left" security approach.
5+
6+
Here are three practical examples of PaC tasks:
7+
8+
---
9+
10+
### Example 1: Cloud Infrastructure Security Scanning (AWS S3)
11+
12+
**Task:** Prevent the creation of publicly accessible AWS S3 buckets to avoid data leaks.
13+
14+
**Tool:** `Checkov`, `Terrascan`, or `Tfsec` (for scanning Terraform code).
15+
16+
**Policy Logic (as Code):**
17+
Tools like Checkov come with hundreds of built-in policies written as code. The relevant policy here is `CKV_AWS_18`: "Ensure the S3 bucket has access logging enabled" and `CKV_AWS_54`: "Ensure S3 bucket has block public policy enabled".
18+
19+
**How it works in the pipeline:**
20+
1. A developer writes Terraform code to create an S3 bucket.
21+
2. The CI/CD pipeline runs `terraform plan`.
22+
3. The next step runs `checkov` to scan the Terraform code against its policies.
23+
4. If a violation is found, the pipeline fails, blocking the unsafe resource from being created.
24+
25+
**Terraform code that would be blocked:** (`bad_bucket.tf`)
26+
```hcl
27+
resource "aws_s3_bucket" "my_public_bucket" {
28+
bucket = "my-unsafe-data-bucket"
29+
30+
# Missing 'block_public_acls' and other security settings - VIOLATION!
31+
# tags = { ... }
32+
}
33+
```
34+
35+
**Pipeline Log Output:**
36+
```
37+
Check: CKV_AWS_54: "Ensure S3 bucket has block public policy enabled"
38+
FAILED for resource: aws_s3_bucket.my_public_bucket
39+
File: /bad_bucket.tf:1-5
40+
41+
Check: CKV_AWS_18: "Ensure the S3 bucket has access logging enabled"
42+
FAILED for resource: aws_s3_bucket.my_public_bucket
43+
File: /bad_bucket.tf:1-5
44+
```
45+
46+
---
47+
48+
### Example 2: Kubernetes Manifest Security Validation
49+
50+
**Task:** Enforce that all Pods in a production namespace run as a non-root user and must have CPU/Memory limits defined.
51+
52+
**Tool:** `Conftest` (which uses the Open Policy Agent (OPA) Rego language) or `Kube-score`.
53+
54+
**Policy Code (Written in Rego for OPA/Conftest):** (`policy/k8s_security.rego`)
55+
```rego
56+
package main
57+
58+
deny[msg] {
59+
input.kind == "Pod"
60+
not input.spec.securityContext.runAsNonRoot
61+
msg = "Pods must not run as root user. Set runAsNonRoot to true."
62+
}
63+
64+
deny[msg] {
65+
input.kind == "Pod"
66+
not input.spec.containers[_].resources.limits
67+
msg = "All containers must have CPU/Memory limits set."
68+
}
69+
70+
deny[msg] {
71+
input.kind == "Pod"
72+
input.spec.containers[_].securityContext.privileged
73+
msg = "Running privileged containers is not allowed."
74+
}
75+
```
76+
77+
**How it works in the pipeline:**
78+
1. A developer commits a Kubernetes YAML manifest for deployment.
79+
2. The pipeline runs a step like `conftest test deployment.yaml -p policy/k8s_security.rego`.
80+
3. Conftest evaluates the manifest against the defined Rego policies.
81+
4. Any policy denial causes the pipeline to fail, preventing the insecure deployment.
82+
83+
**Manifest that would be blocked:** (`deployment.yaml`)
84+
```yaml
85+
apiVersion: v1
86+
kind: Pod
87+
metadata:
88+
name: insecure-pod
89+
spec:
90+
containers:
91+
- name: nginx
92+
image: nginx:latest
93+
securityContext:
94+
privileged: true # VIOLATION! Blocked by policy.
95+
# resources: {} # VIOLATION! Limits are not defined.
96+
```
97+
98+
---
99+
100+
### Example 3: Dockerfile Security Linting
101+
102+
**Task:** Prohibit the use of the `latest` tag (which is mutable and unpredictable) and require specifying a non-root user.
103+
104+
**Tool:** `Conftest` (with OPA/Rego) or `Hadolint` (a specialized Dockerfile linter).
105+
106+
**Policy Code (Written in Rego for Conftest):** (`policy/dockerfile.rego`)
107+
```rego
108+
package main
109+
110+
deny[msg] {
111+
input[i].Cmd == "from"
112+
val := input[i].Value
113+
contains(val[_], "latest")
114+
msg = "Do not use the 'latest' tag. Use a specific versioned tag."
115+
}
116+
117+
deny[msg] {
118+
not user_exists
119+
msg = "Dockerfile must specify a non-root user with the USER instruction."
120+
}
121+
122+
user_exists {
123+
input[i].Cmd == "user"
124+
}
125+
```
126+
127+
**How it works in the pipeline:**
128+
1. A developer creates or modifies a `Dockerfile`.
129+
2. The pipeline uses a tool to parse the Dockerfile into a JSON structure.
130+
3. `Conftest` tests this JSON representation against the Rego policies.
131+
4. Violations fail the pipeline, stopping the image build process.
132+
133+
**Dockerfile that would be blocked:**
134+
```dockerfile
135+
FROM nginx:latest # VIOLATION! Uses the 'latest' tag.
136+
137+
COPY . /usr/share/nginx/html
138+
139+
# VIOLATION! No USER instruction defined to switch from root.
140+
CMD ["nginx", "-g", "daemon off;"]
141+
```
142+
143+
### Integration into a CI/CD Pipeline
144+
145+
These PaC checks are a form of **Static Application Security Testing (SAST) for Infrastructure as Code (IaC)**. They are executed early in the CI/CD process, often in a dedicated stage.
146+
147+
**A typical pipeline stage looks like this:**
148+
149+
```yaml
150+
stages:
151+
- test
152+
- security-sast # <- PaC checks run here
153+
- build
154+
- deploy
155+
156+
security_checks:
157+
stage: security-sast
158+
image: openpolicyagent/conftest:latest
159+
script:
160+
- conftest test Dockerfile --policy policy/dockerfile.rego
161+
- conftest test deployment.yaml --policy policy/k8s_security.rego
162+
- checkov -d terraform/
163+
allow_failure: false # If any check fails, the pipeline fails.
164+
```
165+

0 commit comments

Comments
 (0)