Skip to content

Commit

Permalink
feat: refactor server code
Browse files Browse the repository at this point in the history
Signed-off-by: James Petersen <[email protected]>
  • Loading branch information
found-it committed Dec 10, 2024
1 parent 5cdd068 commit 03f824e
Show file tree
Hide file tree
Showing 12 changed files with 251 additions and 140 deletions.
33 changes: 17 additions & 16 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
[package]
name = "webhook"
name = "protect-webhook"
version = "0.1.0"
edition = "2021"

[dependencies]
anyhow = "1.0.94"
base64 = "0.22.1"
bytes = "1.9.0"
env_logger = "0.11.5"
log = "0.4.22"
serde = { version = "1.0.215", features = ["derive"] }
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ ENV TARGET_LIBC=musl TARGET_VENDOR=unknown

WORKDIR /usr/src/app
COPY . .
RUN cargo build --release --bin webhook
RUN mv ./target/release/webhook /usr/sbin/protect-webhook
RUN cargo build --release --bin protect-webhook
RUN mv ./target/release/protect-webhook /usr/sbin/protect-webhook

FROM scratch
ENTRYPOINT ["/usr/sbin/protect-webhook"]
Expand Down
4 changes: 2 additions & 2 deletions charts/protect-webhook/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
apiVersion: v2
name: protect-webhook
description: A Helm chart for Kubernetes
description: A Helm chart for the Edera Protect Mutating Webhook

# A chart can be either an 'application' or a 'library' chart.
#
Expand All @@ -21,4 +21,4 @@ version: 0.1.0
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.16.0"
appVersion: "0.1.0"
2 changes: 1 addition & 1 deletion charts/protect-webhook/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ spec:
protocol: TCP
env:
- name: RUST_LOG
value: debug
value: {{ .Values.logLevel | default "info" }}
livenessProbe:
{{- toYaml .Values.livenessProbe | nindent 12 }}
readinessProbe:
Expand Down
1 change: 1 addition & 0 deletions charts/protect-webhook/templates/webhook.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ webhooks:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
failurePolicy: {{ .Values.webhook.failurePolicy | default "Ignore" }}
{{- end }}
rules:
- operations: ["CREATE"]
Expand Down
20 changes: 5 additions & 15 deletions charts/protect-webhook/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,19 @@
replicaCount: 1

image:
repository: ttl.sh/beet/protect-webhook
repository: ghcr.io/edera-dev/protect-webhook
# This sets the pull policy for images.
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: "latest@sha256:c7c690744c66213d0792c4c6bcea99eb4c49da31f81ba18c9b774f7c0987a85e"
tag: "latest"

# This is for the secretes for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
imagePullSecrets: []
# This is to override the chart name.
nameOverride: ""
fullnameOverride: ""

podAnnotations:
cert-manager.io/inject-ca-from: edera-system/webhook-ca
podAnnotations: {}

podLabels: {}

Expand All @@ -42,16 +41,10 @@ readinessProbe:
port: 8443

# Additional volumes on the output Deployment definition.
volumes:
- name: webhook-tls
secret:
secretName: webhook-server-tls
volumes: []

# Additional volumeMounts on the output Deployment definition.
volumeMounts:
- name: webhook-tls
mountPath: /certs
readOnly: true
volumeMounts: []

nodeSelector: {}

Expand All @@ -61,6 +54,3 @@ affinity: {}

webhook:
serviceNamespace: edera-system
objectSelector:
matchLabels:
actions-ephemeral-runner: "true"
106 changes: 3 additions & 103 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,109 +1,9 @@
use anyhow::Result;
use base64::prelude::*;
use log::{debug, info};
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::env;
use warp::Filter;

const RUNTIME_CLASS: &str = "edera";

#[derive(Deserialize, Debug, Clone)]
struct AdmissionReview {
request: Option<AdmissionRequest>,
}

#[derive(Deserialize, Debug, Clone)]
struct AdmissionRequest {
uid: String,
}

#[derive(Serialize, Debug)]
#[serde(rename_all = "camelCase")]
struct AdmissionReviewResponse {
api_version: String,
kind: String,
response: Option<Response>,
}

#[derive(Serialize, Debug)]
#[serde(rename_all = "camelCase")]
struct Response {
uid: String,
allowed: bool,
patch_type: Option<String>,
patch: Option<String>,
}
mod server;

#[tokio::main]
async fn main() -> Result<()> {
env_logger::init();

let certs_dir = env::var("WEBHOOK_CERTS_DIR").unwrap_or("/certs".to_string());
let crt_file = env::var("WEBHOOK_CRT_FILE").unwrap_or("tls.crt".to_string());
let key_file = env::var("WEBHOOK_KEY_FILE").unwrap_or("tls.key".to_string());
info!("configured certs directory to: {}", certs_dir);

// TODO: Make healthz and livez listen on http rather than https if they need to do more
let routes = routes();

info!("listening on 8443");
warp::serve(routes)
.tls()
.cert_path(format!("{}/{}", certs_dir, crt_file))
.key_path(format!("{}/{}", certs_dir, key_file))
.run(([0, 0, 0, 0], 8443))
.await;

Ok(())
}

fn routes() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
mutate().or(livez()).or(healthz())
}

fn healthz() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
warp::get().and(warp::path("healthz")).map(|| {
debug!("GET /healthz");
warp::reply()
})
}

fn livez() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
warp::get().and(warp::path("livez")).map(|| {
debug!("GET /livez");
warp::reply()
})
}

fn mutate() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
warp::post()
.and(warp::path("mutate"))
.and(warp::body::json())
.map(|admission_review: AdmissionReview| {
let response = mutate_internal(admission_review).unwrap();
info!("mutating {:?}", response);
warp::reply::json(&response)
})
}

fn mutate_internal(review: AdmissionReview) -> Result<AdmissionReviewResponse> {
let request = review.request.clone().unwrap();
let patch = json!([{
"op": "add",
"path": "/spec/runtimeClassName",
"value": RUNTIME_CLASS
}]);
let patch_base64 = BASE64_STANDARD.encode(serde_json::to_string(&patch).unwrap());

Ok(AdmissionReviewResponse {
api_version: "admission.k8s.io/v1".to_string(),
kind: "AdmissionReview".to_string(),
response: Some(Response {
uid: request.uid,
allowed: true,
patch_type: Some("JSONPatch".to_string()),
patch: Some(patch_base64),
}),
})
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
server::start().await
}
9 changes: 9 additions & 0 deletions src/server/healthz.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use log::debug;
use warp::Filter;

pub fn handler() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
warp::get().and(warp::path("healthz")).map(|| {
debug!("GET /healthz");
warp::reply()
})
}
9 changes: 9 additions & 0 deletions src/server/livez.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use log::debug;
use warp::Filter;

pub fn handler() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
warp::get().and(warp::path("livez")).map(|| {
debug!("GET /livez");
warp::reply()
})
}
34 changes: 34 additions & 0 deletions src/server/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use anyhow::Result;
use log::info;
use std::env;
use warp::Filter;

mod healthz;
mod livez;
mod mutate;

fn routes() -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
mutate::handler()
.or(livez::handler())
.or(healthz::handler())
}

pub async fn start() -> Result<()> {
let certs_dir = env::var("WEBHOOK_CERTS_DIR").unwrap_or("/certs".to_string());
let crt_file = env::var("WEBHOOK_CRT_FILE").unwrap_or("tls.crt".to_string());
let key_file = env::var("WEBHOOK_KEY_FILE").unwrap_or("tls.key".to_string());
info!("configured certs directory to: {}", certs_dir);

// TODO: Make healthz and livez listen on http rather than https if they need to do more
let routes = routes();

info!("listening on 8443");
warp::serve(routes)
.tls()
.cert_path(format!("{}/{}", certs_dir, crt_file))
.key_path(format!("{}/{}", certs_dir, key_file))
.run(([0, 0, 0, 0], 8443))
.await;

Ok(())
}
Loading

0 comments on commit 03f824e

Please sign in to comment.