From db3c73606c836c99c58df6c67537217bf4fdd338 Mon Sep 17 00:00:00 2001 From: Dustin Rouillard Date: Thu, 7 Nov 2024 00:20:45 -0700 Subject: [PATCH] Convert boosted api received hook to signature validation --- .github/workflows/build.yml | 26 ----------------------- .github/workflows/deploy.yml | 40 +++++++++++++++++++++++++++++++++++ Cargo.lock | 3 +++ Cargo.toml | 3 +++ src/services/hooks/boosted.rs | 28 +++++++++++++++++++++--- 5 files changed, 71 insertions(+), 29 deletions(-) delete mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/deploy.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index b1c3fb0..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,26 +0,0 @@ -on: - push: - branches: - - main - -jobs: - build: - name: Build, and push - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Log in to the Container registry - uses: docker/login-action@v1 - with: - registry: ghcr.io - username: dustinrouillard - password: ${{ secrets.GHCR_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: ./ - push: true - tags: ghcr.io/${{ github.repository }}:${{ github.sha }} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..f0755da --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,40 @@ +on: + push: + branches: + - main + +env: + RESOURCE_NAME: deployment/dstn-api + +jobs: + build: + name: Build, and push + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Log in to the Container registry + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: ./ + push: true + cache-from: type=gha + cache-to: type=gha,mode=max + tags: ghcr.io/${{ github.repository }}:${{ github.sha }},ghcr.io/${{ github.repository }}:latest + + - name: Set deployment image + uses: danielr1996/kubectl-action@1.0.0 + with: + kubeconfig: ${{ secrets.KUBECONFIG }} + args: set image ${{ env.RESOURCE_NAME }} api=ghcr.io/${{ github.repository }}:${{ github.sha }} diff --git a/Cargo.lock b/Cargo.lock index 05b74e4..c4f58a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -446,6 +446,7 @@ dependencies = [ "actix-multipart", "actix-web", "actix-web-lab", + "base64 0.22.1", "bytes", "chrono", "envconfig", @@ -453,6 +454,7 @@ dependencies = [ "futures-util", "gql_client", "hex", + "hmac", "infer", "influxdb2", "influxdb2-structmap", @@ -474,6 +476,7 @@ dependencies = [ "serde_urlencoded", "serde_with", "sha1", + "sha2 0.10.8", "tokio", "tracing", "tracing-actix-web", diff --git a/Cargo.toml b/Cargo.toml index cfd2e64..b23a2c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,9 @@ prometheus-http-query = "0.8.3" influxdb2 = "0.5.1" influxdb2-structmap = "0.2.0" serde_repr = "0.1.19" +hmac = "0.12.1" +sha2 = "0.10.8" +base64 = "0.22.1" [profile.release] lto = true diff --git a/src/services/hooks/boosted.rs b/src/services/hooks/boosted.rs index 8624624..94ae424 100644 --- a/src/services/hooks/boosted.rs +++ b/src/services/hooks/boosted.rs @@ -1,6 +1,10 @@ use actix_web::{http::Error, post, web, HttpRequest, HttpResponse}; +use base64::engine::general_purpose::STANDARD; +use base64::Engine; use envconfig::Envconfig as _; +use hmac::{Hmac, Mac}; use redis::aio::ConnectionManager; +use sha2::Sha256; use crate::{ config::Config, @@ -17,14 +21,32 @@ async fn execute( ) -> Result { let config = Config::init_from_env().unwrap(); - let auth_header = req.headers().get("authorization"); + let auth_header = req.headers().get("x-hook-signature"); if auth_header.is_none() { return Ok(HttpResponse::BadRequest().finish()); } - let auth_header = auth_header.unwrap().to_str().unwrap(); + let received_signature = auth_header.unwrap().to_str().unwrap(); + let received_signature_bytes = match STANDARD.decode(received_signature) + { + Ok(bytes) => bytes, + Err(_) => { + return Ok( + HttpResponse::BadRequest().body("Invalid signature encoding"), + ) + } + }; + + let mut mac = + Hmac::::new_from_slice(config.boosted_hook_token.as_bytes()) + .expect("HMAC can take key of any size"); + let payload_string = + serde_json::to_string::(&payload) + .unwrap_or("".into()); + mac.update(payload_string.as_bytes()); - if auth_header != config.boosted_hook_token { + let expected_signature = mac.finalize().into_bytes().to_vec(); + if expected_signature != received_signature_bytes { return Ok(HttpResponse::BadRequest().finish()); }