diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index a10ebc1..074f235 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -69,7 +69,7 @@ jobs: cache-to: type=gha,mode=max - name: Scan image with Trivy - uses: aquasecurity/trivy-action@0.33.1 + uses: aquasecurity/trivy-action@0.34.1 with: image-ref: "${{ env.GHCR_REPO }}:${{ github.sha }}-${{ matrix.tag }}" format: "table" diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 38d0bd5..2115cf9 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -33,7 +33,7 @@ jobs: submodules: recursive - name: Create SBOM with Trivy - uses: aquasecurity/trivy-action@0.33.1 + uses: aquasecurity/trivy-action@0.34.1 with: scan-type: 'fs' format: 'spdx-json' @@ -43,7 +43,7 @@ jobs: scanners: "vuln" - name: Create docker image SBOM with Trivy - uses: aquasecurity/trivy-action@0.33.1 + uses: aquasecurity/trivy-action@0.34.1 with: image-ref: "ghcr.io/defguard/defguard-proxy:${{ steps.vars.outputs.VERSION }}" scan-type: 'image' @@ -53,7 +53,7 @@ jobs: scanners: "vuln" - name: Create security advisory file with Trivy - uses: aquasecurity/trivy-action@0.33.1 + uses: aquasecurity/trivy-action@0.34.1 with: scan-type: 'fs' format: 'json' @@ -63,7 +63,7 @@ jobs: scanners: "vuln" - name: Create docker image security advisory file with Trivy - uses: aquasecurity/trivy-action@0.33.1 + uses: aquasecurity/trivy-action@0.34.1 with: image-ref: "ghcr.io/defguard/defguard-proxy:${{ steps.vars.outputs.VERSION }}" scan-type: 'image' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ad533e6..3eb5f32 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,7 +35,7 @@ jobs: with: submodules: recursive - name: Scan code with Trivy - uses: aquasecurity/trivy-action@0.33.1 + uses: aquasecurity/trivy-action@0.34.1 with: scan-type: 'fs' scan-ref: '.' diff --git a/Cargo.lock b/Cargo.lock index f4674b6..c1c5225 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -397,6 +397,7 @@ dependencies = [ "iana-time-zone", "js-sys", "num-traits", + "serde", "wasm-bindgen", "windows-link", ] @@ -692,20 +693,22 @@ dependencies = [ [[package]] name = "defguard_certs" version = "0.0.0" -source = "git+https://github.com/DefGuard/defguard.git?rev=3304a76f1262eb381a44a0d6906595215cb740b8#3304a76f1262eb381a44a0d6906595215cb740b8" +source = "git+https://github.com/DefGuard/defguard.git?rev=9c6cbd5108470f9c8dc9b4ee740a9a08f071468c#9c6cbd5108470f9c8dc9b4ee740a9a08f071468c" dependencies = [ "base64", + "chrono", "rcgen", "rustls-pki-types", - "serde", "sqlx", "thiserror 2.0.18", + "time", + "x509-parser", ] [[package]] name = "defguard_version" version = "0.0.0" -source = "git+https://github.com/DefGuard/defguard.git?rev=8649a9ba225d7bd2066a09c9e1347705c34bd158#8649a9ba225d7bd2066a09c9e1347705c34bd158" +source = "git+https://github.com/DefGuard/defguard.git?rev=9c6cbd5108470f9c8dc9b4ee740a9a08f071468c#9c6cbd5108470f9c8dc9b4ee740a9a08f071468c" dependencies = [ "axum", "http", @@ -798,9 +801,9 @@ dependencies = [ [[package]] name = "dispatch2" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ "bitflags", "objc2", @@ -1983,9 +1986,9 @@ dependencies = [ [[package]] name = "objc2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" dependencies = [ "objc2-encode", ] diff --git a/Cargo.toml b/Cargo.toml index 68055d2..9ef7b8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,8 +7,8 @@ homepage = "https://github.com/DefGuard/proxy" repository = "https://github.com/DefGuard/proxy" [dependencies] -defguard_version = { git = "https://github.com/DefGuard/defguard.git", rev = "8649a9ba225d7bd2066a09c9e1347705c34bd158" } -defguard_certs = { git = "https://github.com/DefGuard/defguard.git", rev = "3304a76f1262eb381a44a0d6906595215cb740b8" } +defguard_certs = { git = "https://github.com/DefGuard/defguard.git", rev = "9c6cbd5108470f9c8dc9b4ee740a9a08f071468c" } +defguard_version = { git = "https://github.com/DefGuard/defguard.git", rev = "9c6cbd5108470f9c8dc9b4ee740a9a08f071468c" } # base `axum` deps axum = { version = "0.8", features = ["ws"] } axum-client-ip = "0.7" @@ -20,7 +20,7 @@ axum-extra = { version = "0.10", features = [ # match axum-extra -> cookies time = { version = "0.3", default-features = false } tokio = { version = "1", features = ["macros", "rt-multi-thread"] } -tokio-stream = { version = "0.1" } +tokio-stream = "0.1" tower-http = { version = "0.6", features = ["fs", "trace"] } # logging/tracing tracing = "0.1" @@ -52,9 +52,9 @@ mime_guess = "2.0" base64 = "0.22" tower = "0.5" futures-util = "0.3" -ammonia = "4.1.1" +ammonia = "4.1" +bytes = "1.11" chrono = "0.4" -bytes = { version = "1.11" } [build-dependencies] tonic-prost-build = "0.14" diff --git a/src/http.rs b/src/http.rs index 39e4b29..bd3b6fb 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,3 +1,5 @@ +#[cfg(unix)] +use std::{fs::Permissions, os::unix::fs::PermissionsExt}; use std::{ io::ErrorKind, net::{IpAddr, Ipv4Addr, SocketAddr}, @@ -20,7 +22,7 @@ use axum_extra::extract::cookie::Key; use clap::crate_version; use defguard_version::{server::DefguardVersionLayer, Version}; use serde::Serialize; -use tokio::{net::TcpListener, task::JoinSet}; +use tokio::{fs::OpenOptions, io::AsyncWriteExt, net::TcpListener, task::JoinSet}; use tower_governor::{ governor::GovernorConfigBuilder, key_extractor::SmartIpKeyExtractor, GovernorLayer, }; @@ -127,11 +129,8 @@ async fn core_version_middleware( } let core_connected = app_state.grpc_server.connected.load(Ordering::Relaxed); - let core_connected_header = if core_connected { - HeaderValue::from_static("true") - } else { - HeaderValue::from_static("false") - }; + let core_connected_header = + HeaderValue::from_static(if core_connected { "true" } else { "false" }); response .headers_mut() @@ -164,6 +163,8 @@ pub async fn run_setup( err.into() } })?; + #[cfg(unix)] + tokio::fs::set_permissions(cert_dir, Permissions::from_mode(0o700)).await?; } // Only attempt setup if not already configured @@ -189,9 +190,19 @@ pub async fn run_setup( let cert_path = cert_dir.join(GRPC_CERT_NAME); let key_path = cert_dir.join(GRPC_KEY_NAME); - tokio::fs::write(&cert_path, grpc_cert_pem) - .await - .map_err(|err| { + // Certificate and its key will be accessed only to this process's user. + let mut options = OpenOptions::new(); + options.write(true).create(true).truncate(true); + #[cfg(unix)] + options.mode(0o600); // rw------- + + // Write certificate to a file. + options + .clone() + .open(&cert_path) + .await? + .write_all(grpc_cert_pem.as_bytes()) + .await.map_err(|err| { if err.kind() == ErrorKind::PermissionDenied { anyhow::anyhow!( "Cannot write certificate file {}. Permission denied for certificate directory {}.", @@ -202,7 +213,11 @@ pub async fn run_setup( err.into() } })?; - tokio::fs::write(&key_path, grpc_key_pem) + // Write key to a file. + options + .open(&key_path) + .await? + .write_all(grpc_key_pem.as_bytes()) .await .map_err(|err| { if err.kind() == ErrorKind::PermissionDenied { @@ -334,8 +349,8 @@ pub async fn run_server( // build application debug!("Setting up API server"); let shared_state = AppState { - cookie_key, grpc_server, + cookie_key, }; // Setup tower_governor rate-limiter