Skip to content

A Proxy-Wasm module allowing communication to Authorino and Limitador.

License

Notifications You must be signed in to change notification settings

Kuadrant/wasm-shim

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Folders and files

NameName
Last commit message
Last commit date

Latest commit

f5e9e17 · Oct 22, 2024
Oct 17, 2024
Oct 17, 2024
Oct 22, 2024
Oct 17, 2024
Oct 18, 2024
Oct 22, 2024
Mar 2, 2022
Oct 3, 2024
Sep 9, 2022
Oct 2, 2024
Oct 2, 2024
Jul 26, 2024
Aug 21, 2024
Oct 4, 2024
Oct 22, 2024
Jun 6, 2024

Repository files navigation

Wasm-shim

Rust FOSSA Status

A Proxy-Wasm module written in Rust, acting as a shim between Envoy and Limitador.

Sample configuration

Following is a sample configuration used by the shim.

extensions:
  auth-ext:
    type: auth
    endpoint: auth-cluster
    failureMode: deny
    timeout: 10ms
  ratelimit-ext:
    type: ratelimit
    endpoint: ratelimit-cluster
    failureMode: deny
policies:
  - name: rlp-ns-A/rlp-name-A
    hostnames: [ "*.toystore.com" ]
    rules:
    - conditions:
      - allOf:
        - selector: request.url_path
          operator: startswith
          value: /get
        - selector: request.host
          operator: eq
          value: test.toystore.com
        - selector: request.method
          operator: eq
          value: GET
      actions:
      - extension: ratelimit-ext
        scope: rlp-ns-A/rlp-name-A
        data:
          - selector:
              selector: request.headers.My-Custom-Header
          - static:
              key: admin
              value: "1"

Features

Condition operators implemented

#[derive(Deserialize, PartialEq, Debug, Clone)]
pub enum WhenConditionOperator {
    #[serde(rename = "eq")]
    EqualOperator,
    #[serde(rename = "neq")]
    NotEqualOperator,
    #[serde(rename = "startswith")]
    StartsWithOperator,
    #[serde(rename = "endswith")]
    EndsWithOperator,
    #[serde(rename = "matches")]
    MatchesOperator,
}

The matches operator is a a simple globbing pattern implementation based on regular expressions. The only characters taken into account are:

  • ?: 0 or 1 characters
  • *: 0 or more characters
  • +: 1 or more characters

Selectors

Selector of an attribute from the contextual properties provided by kuadrant. See Well Known Attributes for more info about available attributes.

The struct is

#[derive(Deserialize, Debug, Clone)]
pub struct SelectorItem {
    // Selector of an attribute from the contextual properties provided by kuadrant
    // during request and connection processing
    pub selector: String,

    // If not set it defaults to `selector` field value as the descriptor key.
    #[serde(default)]
    pub key: Option<String>,

    // An optional value to use if the selector is not found in the context.
    // If not set and the selector is not found in the context, then no data is generated.
    #[serde(default)]
    pub default: Option<String>,
}

Selectors are tokenized at each non-escaped occurrence of a separator character .. Example:

Input: this.is.a.exam\.ple -> Retuns: ["this", "is", "a", "exam.ple"].

Some path segments include dot . char in them. For instance envoy filter names: envoy.filters.http.header_to_metadata. In that particular cases, the dot chat (separator), needs to be escaped.

Well Known Attributes

Attribute Description
Envoy Attributes Contextual properties provided by Envoy during request and connection processing
source.remote_address This attribute evaluates to the trusted client address (IP address without port) as it is being defined by Envoy Doc

Building

Prerequisites:

  • Install wasm32-unknown-unknown build target
rustup target add wasm32-unknown-unknown

Build the WASM module

make build

Build the WASM module in release mode

make build BUILD=release

Testing

cargo test

Running local development environment (kind)

docker is required.

Run local development environment

make local-setup

This deploys a local kubernetes cluster using kind, with the local build of wasm-shim mapped to the envoy container. An echo API as well as limitador, authorino, and some test policies are configured.

To expose the envoy endpoint run the following:

kubectl port-forward --namespace kuadrant-system deployment/envoy 8000:8000

There is then a single auth policy defined for e2e testing:

  • auth-a which defines auth is required for requests to /get for the AuthConfig with effective-route-1
curl -H "Host: test.a.auth.com" http://127.0.0.1:8000/get -i
# HTTP/1.1 401 Unauthorized
curl -H "Host: test.a.auth.com" -H "Authorization: APIKEY IAMALICE" http://127.0.0.1:8000/get -i
# HTTP/1.1 200 OK

And some rate limit policies defined for e2e testing:

  • rlp-a: Only one data item. Data selector should not generate return any value. Thus, descriptor should be empty and rate limiting service should not be called.
curl -H "Host: test.a.rlp.com" http://127.0.0.1:8000/get -i
  • rlp-b: Conditions do not match. Hence, rate limiting service should not be called.
curl -H "Host: test.b.rlp.com" http://127.0.0.1:8000/get -i
  • rlp-c: Descriptor entries from multiple data items should be generated. Hence, rate limiting service should be called.
curl -H "Host: test.c.rlp.com" -H "x-forwarded-for: 50.0.0.1" -H "My-Custom-Header-01: my-custom-header-value-01" -H "x-dyn-user-id: bob" http://127.0.0.1:8000/get -i

The expected descriptor entries:

Entry { key: "limit_to_be_activated", value: "1" }
Entry { key: "source.address", value: "50.0.0.1:0" }
Entry { key: "request.headers.My-Custom-Header-01", value: "my-custom-header-value-01" }
Entry { key: "user_id", value: "bob" }
  • multi-a which defines two actions for authenticated ratelimiting.
curl -H "Host: test.a.multi.com" http://127.0.0.1:8000/get -i
# HTTP/1.1 401 Unauthorized

Alice has 5 requests per 10 seconds:

while :; do curl --write-out '%{http_code}\n' --silent --output /dev/null -H "Authorization: APIKEY IAMALICE" -H "Host: test.a.multi.com" http://127.0.0.1:8000/get | grep -E --color "\b(429)\b|$"; sleep 1; done

Bob has 2 requests per 10 seconds:

while :; do curl --write-out '%{http_code}\n' --silent --output /dev/null -H "Authorization: APIKEY IAMBOB" -H "Host: test.a.multi.com" http://127.0.0.1:8000/get | grep -E --color "\b(429)\b|$"; sleep 1; done

To rebuild and deploy to the cluster:

make build local-rollout

Stop and clean up resources:

make local-cleanup

License

Apache 2.0 License

FOSSA Status