Act

Act, a core component of GatewayD, is a policy engine that supports signals, policies and actions. It enables a range of functionalities by automating the execution of business rules. The business rules are currently written as expressions in the Expr language, with support for external policy engines to come. The expressions are evaluated against the signals received from the plugins (and possibly other sources). If the policy expressions evaluate to true (boolean) or any other type recognized by the corresponding action, then the action will be executed. Alternatively, Act can publish the result of policy evaluation to a Redis Pub/Sub queue in the Output format. This enables plugins and external systems to subscribe to the events published on that channel and run any arbitrary actions necessary based on the given parameters.

Previously, there were only a single signal, policy and action, called the terminatePolicy, which were hard-coded into the GatewayD codebase. This made it difficult to extend and customize the behavior of GatewayD. With the new Act, based on this proposal, the signals, policies and actions are pluggable and can be extended to support custom requirements. This opens up a wide range of possibilities for customizing the behavior of GatewayD to suit the needs of different use cases. For example, a policy can be written to check if the request is coming from a specific IP address, and if so, the action can be to terminate the request.

For more information about configuring policies, see the plugins’ general configuration.

The Act component is currently under active development and the core functionality is available in the GatewayD and the SDK codebases. The information provided here is based on the proposal and the current state of the development. The documentation will be updated as the development progresses.

Signals

A signal is a message that is sent to the policy engine to trigger the evaluation of the policies. The signals are generated by the plugins and are sent to the policy engine for evaluation. The signals can be of different types, such as terminate, log, etc., and can contain different types of data, such as the log message and log level, and whether the signal is enabled or not. A signal consists of two fields:

  1. name: The name of the signal, such as terminate, log, etc.
  2. metadata: The metadata associated with the signal, such as the log message and log level. This can be used to pass additional information to the policy engine for evaluation.

For example, the terminate signal can be sent with the following metadata:

name: terminate
metadata:
  terminate: true

Policies

A policy is a set of rules that are evaluated against the signals to determine whether the actions should be executed. The policies are written as expressions in the Expr language, with support for external policy engines to come. The expressions are evaluated against the signals received from the plugins and the corresponding actions are executed if the policy expressions evaluate to a type recognized by the action. Policies have the following fields:

  1. name: The name of the policy, such as terminate, log, etc.
  2. policy: The policy expression written in the Expr language.
  3. metadata: The metadata associated with the policy, such as the log message and log level. This can be used to pass additional information to the policy engine for evaluation.

For example, the policy that matches the terminate signal can be written as:

name: terminate
policy: "Signal.terminate == true && Policy.terminate == 'stop'"
metadata:
  terminate: "stop" # Change this to "continue" to continue the execution

Certain fields are made available to the policy expressions for evaluation. These fields are:

  1. Name: The name of the signal.
  2. Signal: The metadata of the signal that is sent to the policy engine for evaluation.
  3. Policy: The policy that is evaluated against the signal. This includes the policy name and metadata.
  4. Hook: The plugin hook that is run to generate the signal. This includes the hook name, priority, input parameters and output result.

The Hook field is a map that contains the following fields:

Field Description Type Example
Hook.Name The name of the hook. string HOOK_NAME_ON_TRAFFIC_FROM_CLIENT
Hook.Priority The priority of the hook. string 1000
Hook.Params The input parameters. map {"server": {"remote": "127.0.0.1:5432", "local": "127.0.0.1:53684"}, "client": {"remote": "127.0.0.1:15432", "local": "127.0.0.1:37502"}, ...}
  1. Hook.Name (string)
  2. Hook.Priority (string)
  3. Hook.Params (map)
    1. Hook.Params.server.remote (string)
    2. Hook.Params.server.local (string)
    3. Hook.Params.client.remote (string)
    4. Hook.Params.client.local (string)
    5. Hook.Params.request (bytes) (currently not usable in Expr language, but will be available in the future via helper functions)
  4. Hook.Result (map) (usually a superset of Hook.Params)
    1. Hook.Result.server.remote (string)
    2. Hook.Result.server.local (string)
    3. Hook.Result.client.remote (string)
    4. Hook.Result.client.local (string)
    5. Hook.Result.request (bytes) (currently not usable in Expr language, but will be available in the future via helper functions)
    6. Hook.Result.response (bytes) (currently not usable in Expr language, but will be available in the future via helper functions)
    7. Fields parsed by the postgres.HandleClientMessage and postgres.HandleServerMessage functions, see wire.go.

Actions

The action can be run in sync or async mode, and it can return a result or an error. Async actions can be configured to be published to a Redis channel instead of running in a background goroutine. To configure Act to publish async actions to a Redis channel, use actionRedis value of general configuration The actions are executed, or published, if the policy expressions evaluate to true (boolean) or any other type recognized by the action. The actions have the following fields:

  1. name: The name of the action, such as terminate, log, etc.
  2. metadata: The metadata associated with the action, such as the log message and log level.
  3. sync: Whether the action should be run in sync or async mode.
  4. terminal: Whether the action is terminal or not.
  5. run: The function that is executed when the action is triggered. This is currently written in Go, with support for writing actions in other languages to come.
  6. timeout: Optional value to indicate the timeout for the action in seconds. If not given, the actionTimeout value of general configuration will be used to determine the timeout. If both of these values have a zero value, the action will run without a timeout.

For example, the action that matches the terminate policy can be written as:

name: terminate
metadata:
  terminate: "stop"
sync: true
terminal: true

The terminate function is available here.

Signals, policies and actions must have the same name to be matched and executed. For example, the terminate signal will be matched with the terminate policy and the terminate action will be executed if the policy expression evaluates to true.