Skip to content
Merged
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
31 changes: 31 additions & 0 deletions integration/envoy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,37 @@ static_resources:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- address:
socket_address:
address: 0.0.0.0
port_value: 1063
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
route_config:
virtual_hosts:
- name: local_route
domains:
- "*"
routes:
- match:
prefix: "/"
route:
cluster: httpbin
http_filters:
- name: dynamic_modules/passthrough
typed_config:
# https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/dynamic_modules/v3/dynamic_modules.proto#envoy-v3-api-msg-extensions-dynamic-modules-v3-dynamicmoduleconfig
"@type": type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter
dynamic_module_config:
name: rust_module
filter_name: random_auth
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: httpbin
connect_timeout: 5000s
Expand Down
71 changes: 50 additions & 21 deletions integration/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,28 +65,28 @@ func TestIntegration(t *testing.T) {
// to pull the image.
time.Sleep(5 * time.Second)

t.Run("health checking", func(t *testing.T) {
require.Eventually(t, func() bool {
req, err := http.NewRequest("GET", "http://localhost:1062/uuid", nil)
require.NoError(t, err)

resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Logf("Envoy not ready yet: %v", err)
return false
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
t.Logf("Envoy not ready yet: %v", err)
return false
}
t.Logf("response: status=%d body=%s", resp.StatusCode, string(body))
return resp.StatusCode == 200
}, 30*time.Second, 1*time.Second)
})
t.Run("http_access_logger", func(t *testing.T) {
t.Run("health checking", func(t *testing.T) {
require.Eventually(t, func() bool {
req, err := http.NewRequest("GET", "http://localhost:1062/uuid", nil)
require.NoError(t, err)

resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Logf("Envoy not ready yet: %v", err)
return false
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
t.Logf("Envoy not ready yet: %v", err)
return false
}
t.Logf("response: status=%d body=%s", resp.StatusCode, string(body))
return resp.StatusCode == 200
}, 30*time.Second, 1*time.Second)
})

t.Run("check access log", func(t *testing.T) {
require.Eventually(t, func() bool {
// List files in the access log directory
files, err := os.ReadDir(tmpdir)
Expand Down Expand Up @@ -131,4 +131,33 @@ func TestIntegration(t *testing.T) {
return found
}, 30*time.Second, 1*time.Second)
})

t.Run("http_random_auth", func(t *testing.T) {
got200 := false
got403 := false
require.Eventually(t, func() bool {
req, err := http.NewRequest("GET", "http://localhost:1063/uuid", nil)
require.NoError(t, err)

resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Logf("Envoy not ready yet: %v", err)
return false
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
t.Logf("Envoy not ready yet: %v", err)
return false
}
t.Logf("response: status=%d body=%s", resp.StatusCode, string(body))
if resp.StatusCode == 200 {
got200 = true
}
if resp.StatusCode == 403 {
got403 = true
}
return got200 && got403
}, 30*time.Second, 200*time.Millisecond)
})
}
88 changes: 88 additions & 0 deletions rust/Cargo.lock

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

1 change: 1 addition & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ repository = "https://github.com/envoyproxy/dynamic-modules-example"
envoy-proxy-dynamic-modules-rust-sdk = { git = "https://github.com/envoyproxy/envoy", rev = "4a113b5118003682833ba612202eb68628861ac6" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
rand = "0.9.0"

[dev-dependencies]
tempfile = "3.16.0"
Expand Down
47 changes: 47 additions & 0 deletions rust/src/http_random_auth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use envoy_proxy_dynamic_modules_rust_sdk::*;
use rand::prelude::*;

/// This implements the [`envoy_proxy_dynamic_modules_rust_sdk::HttpFilterConfig`] trait.
///
/// The trait corresponds to a Envoy filter chain configuration.
pub struct FilterConfig {}

impl FilterConfig {
/// This is the constructor for the [`FilterConfig`].
///
/// filter_config is the filter config from the Envoy config here:
/// https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/dynamic_modules/v3/dynamic_modules.proto#envoy-v3-api-msg-extensions-dynamic-modules-v3-dynamicmoduleconfig
pub fn new(_filter_config: &str) -> Self {
Self {}
}
}

impl<EC: EnvoyHttpFilterConfig, EHF: EnvoyHttpFilter> HttpFilterConfig<EC, EHF> for FilterConfig {
/// This is called for each new HTTP filter.
fn new_http_filter(&mut self, _envoy: &mut EC) -> Box<dyn HttpFilter<EHF>> {
Box::new(Filter {})
}
}

/// This implements the [`envoy_proxy_dynamic_modules_rust_sdk::HttpFilter`] trait.
///
/// This is a passthrough filter that does nothing.
pub struct Filter {}

/// This implements the [`envoy_proxy_dynamic_modules_rust_sdk::HttpFilter`] trait.
///
/// Default implementation of all methods is to return `Continue`.
impl<EHF: EnvoyHttpFilter> HttpFilter<EHF> for Filter {
fn on_request_headers(
&mut self,
envoy_filter: &mut EHF,
_end_of_stream: bool,
) -> abi::envoy_dynamic_module_type_on_http_filter_request_headers_status {
let reject = rand::rng().random::<bool>();
if reject {
envoy_filter.send_response(403, vec![], Some(b"Access forbidden"));
return abi::envoy_dynamic_module_type_on_http_filter_request_headers_status::StopIteration;
}
abi::envoy_dynamic_module_type_on_http_filter_request_headers_status::Continue
}
}
2 changes: 2 additions & 0 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use envoy_proxy_dynamic_modules_rust_sdk::*;

mod http_access_logger;
mod http_passthrough;
mod http_random_auth;

declare_init_functions!(init, new_http_filter_config_fn);

Expand Down Expand Up @@ -34,6 +35,7 @@ fn new_http_filter_config_fn<EC: EnvoyHttpFilterConfig, EHF: EnvoyHttpFilter>(
"passthrough" => Some(Box::new(http_passthrough::FilterConfig::new(filter_config))),
"access_logger" => http_access_logger::FilterConfig::new(filter_config)
.map(|config| Box::new(config) as Box<dyn HttpFilterConfig<EC, EHF>>),
"random_auth" => Some(Box::new(http_random_auth::FilterConfig::new(filter_config))),
_ => panic!("Unknown filter name: {}", filter_name),
}
}
Loading