Functions for Firewall
Look up the event, the methods, and the request metadata a function running on a firewall can use to allow, deny, drop, or answer a request.
A function on a firewall is JavaScript code that the firewall runs on a request when one of its rules calls it. The code receives the request as a firewall event. The methods of that event decide the request: they add headers and let it continue, deny it, drop it, or answer it. To follow a request from the rule to the function and back, refer to How Firewall works.
A function on a firewall runs before the application, so its code decides whether a request reaches the application at all. Code that takes part in serving a request the firewall allowed runs on an application instead, from a function whose execution environment is application. For the instance that puts such a function on an application, refer to Function instances.
Execution environment
Every function carries an execution environment, and a firewall runs only a function whose environment is firewall. You set the environment when you create the function in Functions:
| Interface | Setting | Value for a firewall function |
|---|---|---|
| API | execution_environment, a field of the function | firewall |
| Azion CLI | --execution-environment, a flag of azion create function | firewall |
The API field takes application or firewall, and it defaults to application. A function created without the field is an application function, and the API refuses an instance of it on a firewall. The CLI help reads Either 'edge_application' or 'edge_firewall' for the flag. Neither value is in the API enum, and the API refuses both. azion describe function --function-id <function-id> --format json prints the field of an existing function, such as "execution_environment": "application".
In Azion Console, the Function field of a function instance lists only the functions whose environment is firewall.
A function with the firewall environment still runs on no request until two more objects point at it. A function instance puts the function on one firewall, and a rule whose Run Function behavior names that instance calls it. To write that rule, refer to Run Function.
The firewall must also have Functions enabled. Until it does, Azion Console hides the firewall’s Functions Instances tab and lists the behavior as Run Function - required Functions, which you cannot select. The Functions switch sits in the Modules section of the firewall’s Main Settings tab. A firewall created through the API, the CLI, or the Console create page starts with Functions enabled. The Console create drawer starts with it off.
The firewall event
A function on a firewall registers a listener for the firewall event with addEventListener. The listener receives the event, which carries the request in event.request and the methods that decide it.
To read a header the request already carries, call event.request.headers.get(<name>). The Functions on a firewall example reads several request headers this way to choose what its handler does.
Every function on a firewall must end with a finishing outcome, such as event.continue(), event.deny(), or event.drop(). To write conditionals that always reach one outcome, refer to Firewall best practices.
Event methods
The table lists the methods a function on a firewall calls on the firewall event, in alphabetical order.
| Method | Arguments | What it does |
|---|---|---|
event.addRequestHeader() | A header name and its value | Adds the header to the request that goes on to the origin |
event.addResponseHeader() | A header name and its value | Adds the header to the response the user receives |
event.args() | The name of an argument, such as 'arg_name' | Reads that argument from the Arguments of the function instance |
event.continue() | None | Ends the function with a finishing outcome. The firewall resumes processing from the Run Function behavior that called the function |
event.deny() | None | Finishes the request with HTTP 403 Forbidden. The status, the body, and the reason are fixed |
event.drop() | None | Finishes the request without an answer to the client |
event.respondWith() | A Response object | Intercepts the request and answers it with a custom response, whose status, headers, and content the object sets |
event.waitUntil() | A promise, such as the one an async handler returns | Runs an async handler from the synchronous listener. Without it, the promise can end in unexpected exceptions |
event.addRequestHeader
event.addRequestHeader() adds a header to the request that goes on to the origin. It takes two arguments, the header name and its value. This listener adds two headers and lets the request continue:
event.addResponseHeader
event.addResponseHeader() adds a header to the response the user receives. It takes the same two arguments, the header name and its value. This listener adds two response headers and lets the request continue:
event.deny
event.deny() finishes the request with HTTP 403 Forbidden. It takes no arguments, so the function cannot change the status, the body, or the reason of that response. For a response the function controls, event.respondWith() is the method to call. This listener denies every request it receives:
event.drop
event.drop() finishes the request without an answer to the client, and takes no arguments. This listener drops every request it receives:
event.respondWith
event.respondWith() intercepts the request and answers it with a custom response. It takes a Response object, which sets the status, the headers, and the content of the answer. The call in this section runs inside a firewall listener and answers with a JSON body, the status 599, and a content-type of application/json:
Metadata
A function on a firewall reads request metadata to filter access to the application and to apply different logic by scenario. Four groups of that metadata describe where a request comes from and how it arrives. The Metadata API reference lists the fields of each group.
| Group | What it holds | Fields |
|---|---|---|
| GeoIP | Where the request comes from. Use it to deny access to the application from certain places | GeoIP metadata |
| Remote | The IP address and the TCP port the client uses | Remote metadata |
| Server | The protocol the request uses | Server metadata |
| TLS | Details available when the request arrives over a secure TLS connection | TLS metadata |
Limits
A function on a firewall runs within two sets of bounds. The limits of the function itself, such as its code size, memory, CPU time, and sub-requests, are on Functions limits. The bounds of the firewall and of its function instances are on Firewall limits.
The arguments of a function instance, which the function reads with event.args(), hold at most 100,000 bytes. A larger payload is refused with Value size (in bytes) is too big. Maximum size allowed is 100000 bytes.
Errors
Two refusals come from the execution environment of a function. Azion CLI prints each message inside brackets, after Error: Failed to create function: or Error: failed to create the Firewall Function Instance:. azion create function closes its message with Check your settings and try again. If the error persists, contact Azion support.
| Message | Command | What causes it | What to do |
|---|---|---|---|
"edge_firewall" is not a valid choice. | azion create function | --execution-environment edge_firewall, a value the CLI help lists and the API does not accept | Use --execution-environment firewall |
Invalid edge function runtime. You should use a function designed for Edge Firewall. | azion create firewall-instance | The function’s execution environment is application | Instantiate a function whose execution environment is firewall |