4 stable releases
1.1.5 | Sep 26, 2024 |
---|---|
1.1.4 | Sep 4, 2024 |
1.1.3 | Aug 27, 2024 |
1.1.1 | May 14, 2024 |
#223 in Network programming
331 downloads per month
90KB
2K
SLoC
PerimeterX Fastly Compute@Edge Rust Enforcer
Table of Contents
- Project layout
- Prerequisites
- Configuration
- PX Backend
- Module installation
- Module integration
- Enforcer API
- Logging
- Sample code
Project layout
src
folder contains Fastly Compute@Edge Rust Moduleexample
folder contains a sample Fastly Compute@Edge Rust applicationcontrib/pxconfig.sh
script to create Fastly Config store and populate with default valuescontrib/pxbackend.sh
script to create and configure PX Backend host
Prerequisites
In order to compile and deploy Fastly Compute@Edge Package, Fastly CLI must be installed and configured: Compute@Edge services
Configuration
Module configuration is done using Compute@Edge Config store. Please refer PerimeterX documentation for individual configuration option description.
This is the list of Config store (PXConfig) items and datatypes:
configuration name | type | default | |
---|---|---|---|
px_app_id | string | required | - |
px_cookie_secret | string | required | - |
px_auth_token | string | required | - |
px_module_enabled | bool | optional | false |
px_module_mode | "active_blocking", "monitor" | optional | "monitor" |
px_debug | bool | optional | false |
px_blocking_score | number | optional | 100 |
px_sensitive_headers | list | optional | [] |
px_sensitive_routes | list | optional | [] |
px_filter_by_route | list | optional | [] |
px_filter_by_user_agent | list | optional | [] |
px_filter_by_ip | list | optional | [] |
px_filter_by_http_method | list | optional | [] |
px_custom_cookie_header | string | optional | "" |
px_enforced_routes | list | optional | [] |
px_monitored_routes | list | optional | [] |
px_bypass_monitor_header | string | optional | "" |
px_first_party_enabled | bool | optional | true |
px_custom_logo | string | optional | "" |
px_js_ref | string | optional | "" |
px_css_ref | string | optional | "" |
px_ip_headers | list | optional | [] |
log_endpoint | string | optional | "" |
px_graphql_enabled | bool | optional | false |
px_graphql_routes | list | optional | ["^/graphql$"] |
px_sensitive_graphql_operation_names | list | optional | [] |
px_sensitive_graphql_operation_types | list | optional | [] |
pxconfig.sh
script could be used to populate Config store with the required values. Usage:
Required options:
-s, --service-id=SERVICE_ID specify a service to deploy the Config store
-v, --version=VER specify a service version
-a, --appid=APPID specify an appid
-c, --cookie_secret=SECRET specify a cookie_secret
-t, --auth_token=TOKEN specify an auth_token
PerimeterX Backend
In order for PerimeterX Enforcer to communicate with PerimeterX Collector server, a special "backend" server must be added and configured in Fastly UI (or using contrib/pxbackend.sh script).
Backend parameters (replace ${APP_ID}
with your PerimeterX Application ID):
- Name:
PX_BACKEND_${APP_ID}
- Hostname:
sapi-${APP_ID}.perimeterx.net
- Override host: (empty value)
- Use SSL/TLS: Yes
Installation
Include perimeterx-fastly-enforcer
dependency to Cargo.toml
:
cargo add perimeterx-fastly-enforcer
Module integration
To integrate PerimeterX Rust module into existing Rust code, the following base snippet could be used (for a more advanced example see the project in "example" folder):
let mut px: PXEnforcer = PXEnforcer::new(perimeterx_fastly_enforcer::DEFAULT_CONFIGSTORE_NAME);
let px_result = px.enforce(&mut req)?;
if let Some(r) = px_result {
return Ok(r);
};
//... communicate with Origin server / process request and response
px.post_enforce(&response);
Enforcer API
Initialize PXEnforcer structure, it takes a name of Fastly "ConfigStore" (it's possible to use the default name: perimeterx_fastly_enforcer::DEFAULT_CONFIGSTORE_NAME
)
pub fn new(config_store_name: &str) -> Self
This function takes Request and returns a Result which optionally contains "Response" (for "blocked" or "first party" requests):
pub fn enforce(&mut self, req: &mut Request) -> Result<Option<Response>, Error>
At the end of request processing, the following function must be called to finalize PerimeterX enforcer code:
pub fn post_enforce(&self, res: &Response)
It is possible to access PXContext structure with various Enforcer variables via px.ctx
member:
// send "score" value to the Origin
req.set_header("x-px-score", px.ctx.score.to_string());
To set "custom_parameters" variables, the following callback function could be used:
pub type PXEnrichCustomParamsFn = fn (req: &Request, conf: &PXConfig, params: &mut PXCustomParams);
where:
req
: fastly::Request
conf
: PXConfig
params
: modifiable structure with custom_param1 .. custom_param10 fields
To set custom parameters callback function, use the following setter:
pub fn set_enrich_custom_params_fn(&mut self, f: PXEnrichCustomParamsFn)
Logging
PerimeterX Rust Enforcer logs the most messages (both "info" and "debug") using Level::Info
level.
In order to enable Enforcer to produce "debug" messages, set px_debug
configuration value to true
.
Sample code
This is the simplest example how to use PerimeterX Rust module:
use fastly::{Error, Request, Response};
use perimeterx_fastly_enforcer::pxenforce::PXEnforcer;
const ORIGIN_BACKEND: &str = "origin_backend";
// send a request to the Origin server
fn send_to_origin(req: Request) -> Result<Response, Error> {
match req.send(ORIGIN_BACKEND) {
Ok(r) => return Ok(r),
Err(e) => return Err(e.into()),
}
}
#[fastly::main]
fn main(mut req: Request) -> Result<Response, Error> {
// initialize PX Enforcer
let mut px: PXEnforcer = PXEnforcer::new(perimeterx_fastly_enforcer::DEFAULT_CONFIGSTORE_NAME);
// execute PX Enforcer for Request
let px_result = px.enforce(&mut req)?;
// return, if it's a "blocked" or "first party" response
if let Some(r) = px_result {
return Ok(r);
};
// ... process Client request ...
// we can access "PXContext" structure.
// as an example: send "score" value to the Origin
req.set_header("x-px-score", px.ctx.score.to_string());
// a client function to communicate with the Origin
let response = send_to_origin(req)?;
// ... process Origin response ...
// must be called at the end
px.post_enforce(&response);
// we are ok to send response back to client
return Ok(response);
}
For a complete example: example
folder contains a sample project.
Dependencies
~12–22MB
~334K SLoC