Publishing a Flex Gateway Custom Policy Using Rust (Connected Mode)

Co-Author- https://medium.com/@kushanjali838

Rohit Singh
Another Integration Blog
7 min readApr 3, 2023

--

To publish custom policies for Anypoint Flex Gateway using Rust, we need to follow below steps:

  • Create policy definition files.
  • Publish policy definition asset to Exchange.
  • Create implementation files.
  • Add policy implementation to the published policy definition.

Prerequisites

  • Anypoint Platform with Administrator Access
  • Github Access
  • Rust must be Installed on the System (Download from here if not already https://www.rust-lang.org/tools/install)
  • Flex Gateway created on Anypoint Platform

Create Policy Definition Files

Before uploading the policy implementation, it is necessary to create both a JSON and a YAML policy definition file.

These files provide essential information for the API Manager to render the user interface and metadata regarding the policy implementation. T

  • The JSON file outlines the policy’s interface using the JSON schema language.
  • The YAML file contains information about the policy’s category, interface scope, required characteristics, and RAML/OAS snippets.
  • You may create these files locally or copy the custom policy definition examples.

Create the JSON Schema File

The JSON schema file specifies the interface for the policy by identifying which properties are required or supported to configure the policy. The file also includes more annotations to refine the type for each property that enables some fields to perform a special behavior in the Anypoint platform. For example, Dataweave validations or secure handling of secrets.

The JSON file must include the following fields:

  • Top-level @context
    References the vocabulary used for the extra type annotations. The aliases used to namespace the vocabulary are optional. Commonly-used names can be security or config.
    Values for the security and config aliases are:
  • Security: anypoint://vocabulary/policy.yaml#
  • Config: anypoint://vocabulary/policyConfigurationsForUI.yaml#
  • Top-level title
  • $schema with a link to the JSON Schema spec (see example)
  • Root type of object
  • Top-level description
  • Each property must also include:
  • Title
    The title is used by API Manager UI to render the field name.
  • Description
    The description is used by API Manager UI to describe the field.
  • Type
    Only primitive types are supported, for example integer, string, object, boolean, and array.

Each property can include the following:

  • Format
    Options are dataweaveExpression and ipRange.
  • Default
    Allows the user to enter a default value which is rendered in the UI.
  • @context with a @characteristics array
    Further refines the type with more annotations with the following options:
  • config:commaSeparatedValues
    The value of this field results in an array
  • security:sensitive Determines whether the property is masked when entering the property in the API Manager UI.

The following code is a example of a basic authentication JSON schema:

{

“title”: “Custom Auth Header”,

“type”: “object”,

“description”: “Enforces HTTP authentication matching x-custom-auth value to what is configured in the policy.”,

“properties”: {

“secret-value”: {

“title”: “Custom Auth Header Password”,

“type”: “string”,

“@context”: {

“@characteristics”: [

“security:sensitive”

]

}

}

},

“required”: [

“secret-value”

],

“unevaluatedProperties”: false,

“@context”: {

“@vocab”: “anypoint://vocabulary/policy.yaml#”,

“security”: “anypoint://vocabulary/policy.yaml#”

},

“$id”: “custom-auth-header-simple”,

“$schema”: “https://json-schema.org/draft/2019-09/schema"

}

Create the Definition Metadata YAML File

The YAML file provides information about the policy and its requirements. The YAML file is not tied to any specific runtime or binary.

The file must have these fields configured:

  • Header
    Header must be #%Policy Definition 0.1.
  • Name
    User-friendly name used to display the policy name in API Manager UI. Must be a string value.
  • Description
    Must be a string value.
  • Category
    Category to which the policy belongs. Used to group and filter policies in API Manager UI. Any string value is valid. For example, security, quality of service, compliance, troubleshooting, and transformation.
  • Provided Characteristics
    A list used to define the characteristics the policy provides. Must be an array of strings. Use providedCharacteristics: [] to leave empty.

The following code is an example of a basic authentication definition YAML file:

#%Policy Definition 0.1

name: Custom Auth Header

description: Enforces HTTP Basic authentication according to the details configured in the policy.

category: Security

providedCharacteristics:

- Requires authentication

requiredCharacteristics: []

interfaceScope: [“api”, “resource”]

interfaceTransformation: []

encryptionSupported: true

violationCategory: authentication

Create Metadata YAML File (Implementation)

The metadata YAML file provides details about the specific implementation of the policy definition. A single policy definition can have several implementations. Each an independent asset in Exchange or different versions of the same Exchange asset.

The metadata YAML file must include the following fields:

  • Header
    #%Policy Implementation 1.0
  • Technology
    Either mule4 or flexGateway.
  • Name
    Name of the implementation.
  • minRuntimeVersion
    A semantic version representing the first runtime version that the implementation binary is compatible with. For example, a mule binary might only be compatible from 4.3.0 onwards.

The YAML file can also include Release notes.

The following code is an example of a implementation metadata YAML file:

#%Policy Implementation 1.0

minRuntimeVersion: 1.4.0

technology: mule4

name: Simple Auth Mule Implementation

releaseNotes: “<some notes here>”

Create the Implementation Binary Files

The implementation binary file is a JAR file for Mule 4 policies or a WebAssembly WASM file for Anypoint Flex Gateway. These files should support all of the configuration fields and function the way the definition metadata describes.

  • Create the Rust project via the following command: cargo new flex_custom_policy_auth_header — lib
  • This creates a flex_custom_policy_auth_header directory
  • Copy the following into Cargo.toml, located in the flex_custom_policy_auth_header directory:

[package]

name = “flex_custom_policy_auth_header”

version = “0.1.0”

edition = “2021”

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]

crate-type = [“cdylib”]

name=”flex_custom_policy_auth_header”

path=”src/lib.rs”

[dependencies]

proxy-wasm = { git = “https://github.com/proxy-wasm/proxy-wasm-rust-sdk.git", tag = “v0.2.0” }

serde = { version = “1.0”, features = [“derive”] }

serde_json = “1.0”

log = “0.4”

  • Add the following policy bootstrapping code to a new Rust source file:

use proxy_wasm::traits::*;

use proxy_wasm::types::*;

use log::info;

use serde::{Deserialize, Serialize};

proxy_wasm::main! {{

proxy_wasm::set_log_level(LogLevel::Trace);

proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> {

Box::new(HttpConfigHeaderRoot {

secret: String::new()

})

});

}}

struct HttpConfigHeader {

secret: String

}

impl Context for HttpConfigHeader {}

impl HttpContext for HttpConfigHeader {

fn on_http_request_headers(&mut self, _num_headers: usize, _end_of_stream: bool) -> Action {

info!(“on_http_request_headers”);

if let Some(value) = self.get_http_request_header(“x-custom-auth”) {

if self.secret == value {

info!(“on_http_request_headers allowing”);

return Action::Continue;

}

}

info!(“on_http_request_headers blocking”);

self.send_http_response(401, Vec::new(), None);

Action::Pause

}

fn on_http_request_body(&mut self, _body_size: usize, _end_of_stream: bool) -> Action {

info!(“on_http_request_body”);

Action::Continue

}

fn on_http_response_headers(&mut self, _num_headers: usize, _end_of_stream: bool) -> Action {

info!(“on_http_response_headers”);

Action::Continue

}

fn on_http_response_body(&mut self, _body_size: usize, _end_of_stream: bool) -> Action {

info!(“on_http_response_body”);

Action::Continue

}

}

#[derive(Serialize, Deserialize)]

struct PolicyConfig {

#[serde(alias = “secret-value”)]

secret_value: String

}

struct HttpConfigHeaderRoot {

secret: String

}

impl Context for HttpConfigHeaderRoot {}

impl RootContext for HttpConfigHeaderRoot {

fn on_configure(&mut self, _: usize) -> bool {

if let Some(config_bytes) = self.get_plugin_configuration() {

let config:PolicyConfig = serde_json::from_slice(config_bytes.as_slice()).unwrap();

self.secret = config.secret_value;

info!(“secret header is {}”,self.secret);

}

true

}

fn create_http_context(&self, _: u32) -> Option<Box<dyn HttpContext>> {

Some(Box::new(HttpConfigHeader {

secret: self.secret.clone(),

}))

}

fn get_type(&self) -> Option<ContextType> {

Some(ContextType::HttpContext)

}

}

  • Enable compilation by adding wasm32 as a target:

rustup target add wasm32-unknown-unknown

  • Compile your custom policy via the following command:

cargo build — target wasm32-unknown-unknown — release

  • To enable optimization, install wasm-gc via the following command:

cargo install wasm-gc

  • Perform the optimization by executing wasm-gc against your binary:

wasm-gc target/wasm32-unknown-unknown/release/flex_custom_policy_auth_header.wasm -o target/flex_custom_policy_auth_header-final.wasm

Publish Policy Definition Asset to Exchange

After creating the required policy definition files (JSON and YAML), publish the policy definition asset to Exchange.

  • Open MuleSoft Exchange and click on Publish new asset
  • Enter the name Custom Auth Header
  • Select Policy as Asset Type
  • Upload the file schema.json
  • Upload the file definition.yaml
  • Click on Publish.

Note: Name of asset should be the same that we have given in the Yaml definition file which we have uploaded as definition.yaml.

Add Policy Implementation Files to Published Policy Definition

The policy implementation files that are required to make the policy available in a runtime are a metadata file and a binary file. The metadata file describes what technology the binary file applies to and from which runtime version. The metadata file must be a YAML file. The binary file contains the policy logic and manages the runtime execution. The file can be a WebAssembly (WASM) for Anypoint Flex Gateway or a JAR file for Mule 4 runtime.

  • Click on Implementations and Add Implementation
  • Enter the name Custom Auth Header Impl
  • Upload the file flex_custom_policy_auth_header.wasm you obtained in previous steps after compiling the sources using Rust and Cargo
  • Upload the file implementation.yaml
  • Click on Add Implementation

Apply the Policy to an API from Anypoint API Manager

Once that policy is published in Exchange, it will be ready to be applied to APIs. Follow these steps:

  • Publish an API Spec in Exchange
  • Define in API Manager a new API in the previously created API Flex Gateway
  • Make sure to add the Implementation URI of some existing deployed Api for which you want to make requests through Flex Gateway.
  • Apply in that API instance the policy — defining any text as value — and wait some minutes until it is applied
  • Make a call to the API using postman. It should produce a 401 error
  • Repeat the call, but pass a new header named x-custom-auth with the value you have defined in the policy. The API should produce an HTTP 200 status.

--

--