Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Make policy loop with io.kubewarden.policy.echo.loop annot #46

Closed
wants to merge 1 commit into from
Closed
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
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ will contain the JSON representation of the the `AdmissionReview`.

These are the annotations being watched:

* `io.kubewarden.policy.echo.create`: rejects creation of objects with this annotations
* `io.kubewarden.policy.echo.updates`: rejects changes to objects with this annotations
* `io.kubewarden.policy.echo.delete`: rejects deletions of objects with this annotations
* `io.kubewarden.policy.echo.connect`: rejects CONNECT operations to objects with this annotations
- `io.kubewarden.policy.echo.create`: rejects creation of objects with this annotations
- `io.kubewarden.policy.echo.updates`: rejects changes to objects with this annotations
- `io.kubewarden.policy.echo.delete`: rejects deletions of objects with this annotations
- `io.kubewarden.policy.echo.connect`: rejects CONNECT operations to objects with this annotations
- `io.kubewarden.policy.echo.loop`: the policy loops. This will result in a
rejection as the policy-server timeout is reached and it fails-closed.

We will cover these in depth inside of the *"examples"* section.
We will cover these in depth inside of the _"examples"_ section.

## Settings

Expand Down Expand Up @@ -95,10 +97,10 @@ spec:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
```

Attempting to create this object will fail because the `echo` policy rejects
Expand Down
16 changes: 16 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ enum Operation {
Update,
Delete,
Connect,
Loop,
}

impl Operation {
Expand All @@ -26,6 +27,8 @@ impl Operation {
.expect("delete jmespath should not fail"),
Operation::Connect => jmespath::compile("request.object.metadata.annotations")
.expect("connect jmespath should not fail"),
Operation::Loop => jmespath::compile("request.object.metadata.annotations")
.expect("connect jmespath should not fail"),
}
}

Expand All @@ -35,6 +38,7 @@ impl Operation {
Operation::Update => "io.kubewarden.policy.echo.update",
Operation::Delete => "io.kubewarden.policy.echo.delete",
Operation::Connect => "io.kubewarden.policy.echo.connect",
Operation::Loop => "io.kubewarden.policy.echo.loop",
}
}
}
Expand All @@ -48,6 +52,7 @@ impl TryFrom<&String> for Operation {
"UPDATE" => Ok(Operation::Update),
"DELETE" => Ok(Operation::Delete),
"CONNECT" => Ok(Operation::Connect),
"LOOP" => Ok(Operation::Loop),
_ => Err(format!("unknown type of operation: {value}")),
}
}
Expand All @@ -74,6 +79,11 @@ fn validate(payload: &[u8]) -> CallResult {
.ok_or_else(|| anyhow!("jmespath didn't return a string"))?,
)?;

if matches!(operation, Operation::Loop) {
#[allow(clippy::empty_loop)]
loop {}
}

// Search the data with the compiled expression
let result = operation.annotation_expr().search(data.clone())?;
if result.is_object() {
Expand Down Expand Up @@ -115,6 +125,12 @@ mod tests {
expected_validation_result: true,
settings: Settings {},
},
Testcase {
name: String::from("loop"),
fixture_file: String::from("test_data/create_loop.json"),
expected_validation_result: true,
settings: Settings {},
},
];

for tc in &test_cases {
Expand Down
166 changes: 166 additions & 0 deletions test_data/create_loop.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
{
"dryRun": false,
"kind": {
"group": "apps",
"kind": "Deployment",
"version": "v1"
},
"name": "nginx",
"namespace": "default",
"object": {
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"annotations": {
"io.kubewarden.policy.echo.loop": "true",
"kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"annotations\":{\"io.kubewarden.policy.echo.create\":\"true\"},\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"replicas\":0,\"selector\":{\"matchLabels\":{\"app\":\"nginx\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"nginx\"}},\"spec\":{\"containers\":[{\"image\":\"nginx:latest\",\"name\":\"nginx\",\"ports\":[{\"containerPort\":80}]}]}}}}\n"
},
"creationTimestamp": "2022-06-22T13:23:21Z",
"generation": 1,
"managedFields": [
{
"apiVersion": "apps/v1",
"fieldsType": "FieldsV1",
"fieldsV1": {
"f:metadata": {
"f:annotations": {
".": {},
"f:io.kubewarden.policy.echo.create": {},
"f:kubectl.kubernetes.io/last-applied-configuration": {}
}
},
"f:spec": {
"f:progressDeadlineSeconds": {},
"f:replicas": {},
"f:revisionHistoryLimit": {},
"f:selector": {},
"f:strategy": {
"f:rollingUpdate": {
".": {},
"f:maxSurge": {},
"f:maxUnavailable": {}
},
"f:type": {}
},
"f:template": {
"f:metadata": {
"f:labels": {
".": {},
"f:app": {}
}
},
"f:spec": {
"f:containers": {
"k:{\"name\":\"nginx\"}": {
".": {},
"f:image": {},
"f:imagePullPolicy": {},
"f:name": {},
"f:ports": {
".": {},
"k:{\"containerPort\":80,\"protocol\":\"TCP\"}": {
".": {},
"f:containerPort": {},
"f:protocol": {}
}
},
"f:resources": {},
"f:terminationMessagePath": {},
"f:terminationMessagePolicy": {}
}
},
"f:dnsPolicy": {},
"f:restartPolicy": {},
"f:schedulerName": {},
"f:securityContext": {},
"f:terminationGracePeriodSeconds": {}
}
}
}
},
"manager": "kubectl-client-side-apply",
"operation": "Update",
"time": "2022-06-22T13:23:21Z"
}
],
"name": "nginx",
"namespace": "default",
"uid": "5be2582c-c8fb-4318-8d47-6df8a24affc7"
},
"spec": {
"progressDeadlineSeconds": 600,
"replicas": 0,
"revisionHistoryLimit": 10,
"selector": {
"matchLabels": {
"app": "nginx"
}
},
"strategy": {
"rollingUpdate": {
"maxSurge": "25%",
"maxUnavailable": "25%"
},
"type": "RollingUpdate"
},
"template": {
"metadata": {
"creationTimestamp": null,
"labels": {
"app": "nginx"
}
},
"spec": {
"containers": [
{
"image": "nginx:latest",
"imagePullPolicy": "Always",
"name": "nginx",
"ports": [
{
"containerPort": 80,
"protocol": "TCP"
}
],
"resources": {},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File"
}
],
"dnsPolicy": "ClusterFirst",
"restartPolicy": "Always",
"schedulerName": "default-scheduler",
"securityContext": {},
"terminationGracePeriodSeconds": 30
}
}
},
"status": {}
},
"operation": "CREATE",
"options": {
"apiVersion": "meta.k8s.io/v1",
"fieldManager": "kubectl-client-side-apply",
"kind": "CreateOptions"
},
"requestKind": {
"group": "apps",
"kind": "Deployment",
"version": "v1"
},
"requestResource": {
"group": "apps",
"resource": "deployments",
"version": "v1"
},
"resource": {
"group": "apps",
"resource": "deployments",
"version": "v1"
},
"uid": "307362f8-ffb1-481a-9ce7-7e6192fbc699",
"userInfo": {
"groups": ["system:masters", "system:authenticated"],
"username": "minikube-user"
}
}
Loading