AScript Fine-Grained Traffic Management Practices

Updated at:
Copy as MD

AScript is a flexible and powerful scripting language for Alibaba Cloud Application Load Balancer (ALB). It lets you use custom scripts to implement fine-grained traffic management policies on ALB instances, overcoming the limitations of traditional load balancers. This topic introduces AScript through three common scenarios: identifying abnormal requests, implementing custom authentication, and controlling request and response headers.

AScript overview

AScript executes custom rules triggered at different phases of the request and response lifecycle for custom traffic management. These rules use custom scripts to flexibly manage request and response flows, providing fine-grained control over your business logic.

Key features

  • Business logic isolation: AScript rules isolate different business functions and requirements into separate scripts. This prevents rules from interfering with each other.

  • Execution flow control: You can define the priority and trigger conditions for each rule to match your specific business scenarios.

  • Execution phases: You can configure a rule to run at a specific execution phase.

    • Before rule execution in the request flow: This phase is ideal for pre-processing request paths. Use cases include automatically rewriting URIs, adding URI prefixes, and converting file extensions to lowercase.

    • After a request direction rule is executed: This applies to scenarios where requests are further processed after they are handled by standard forwarding rules, such as rewriting filenames and types.

    • Before rule execution in the response flow: This phase is suitable for final processing before a response is sent to the client. Use cases include modifying the HTTP header or the response body.

  • Listener-level scope: AScript rules operate at the listener level, ensuring each rule is closely aligned with the traffic patterns of its associated listener.

Limitations

  • Only standard and WAF-enabled ALB instances support AScript. Basic instances do not.

  • AScript includes a free quota of 25 script lines. You are charged for any lines that exceed this quota. For detailed billing rules, see ALB billing rules.

Prerequisites

  • You have created a standard or WAF-enabled Internet-facing ALB instance and a server group. For more information, see Create and manage ALB instances and Create and manage a server group.

  • You have configured an HTTP listener and associated the listener with the server group. For more information, see Add an HTTP listener.

  • You have added two ECS instances, ECS01 and ECS02, to the server group and deployed an application on each instance.

    To deploy the test application on ECS01

    yum install -y nginx
    systemctl start nginx.service
    cd /usr/share/nginx/html/
    echo "Hello World ! This is ECS01." > index.html

    To deploy the test application on ECS02

    yum install -y nginx
    systemctl start nginx.service
    cd /usr/share/nginx/html/
    echo "Hello World ! This is ECS02." > index.html
  • You have registered a domain name and completed an ICP filing. For more information, see Register a domain name on Alibaba Cloud and ICP filing process.

Use cases

The following sections describe three use cases that demonstrate the capabilities of AScript programmable script rules.

Use case 1: Abnormal request identification

A company uses Application Load Balancer (ALB) to host its services in an Alibaba Cloud region and frequently encounters abnormal requests. Large volumes of malicious requests and traffic from unknown sources put a heavy load on the backend servers, slowing down normal services and impacting the user experience.

To resolve this issue, the company decides to use ALB to block abnormal requests. Although standard ALB forwarding rules can route requests based on domain names and paths, they have limited capabilities for deeper user behavior analysis, such as inspecting the User-Agent header. Therefore, the company chooses to use AScript to extend the capabilities of ALB.

With AScript, ALB can match and analyze the User-Agent field in HTTP request headers. By writing AScript rules, you can implement custom logic to identify abnormal or malicious behaviors, such as requests from bots or automated scripts. If a request is identified as abnormal, AScript can return a custom response, blocking potential security threats and ensuring service stability and data security.

In this example, a company uses an AScript programmable script rule to check the following conditions when a request is sent to its ALB instance:

  • The hostname is example.com.

  • The URI path starts with /order/create.

  • The User-Agent in the HTTP request header does not contain the string trusted.

If all the preceding conditions are met, AScript sets the status code to 403 and returns the custom response message The order data is abnormal. Otherwise, ALB forwards the request to the backend service as normal.

Corresponding AScript rule

if and(eq($host,'example.com'),eq(get(split($request_uri, '?'),1),'/order/create')){
    if not(match_re($http_user_agent,'.*trusted.*')){
        exit(403,'{"code":10063,"msg":"The order data is abnormal","data":{}}')
    }
}
image

Procedure

Step 1: Add an AScript rule

  1. Log on to the Application Load Balancer (ALB) console.

  2. On the Instances page, click the ID of the target instance.

  3. Click the Listener tab, and then click the ID of the target listener.

  4. Click the Forwarding Rules tab. On the Inbound Forwarding Rules tab, click Add Script Before Forwarding Rule Is Applied.

    Note

    If you select the Outbound Forwarding Rules tab, you can only select Add Script Before Forwarding Rule Is Applied.

  5. On the Add Script page, configure the rule and click OK.

    Parameter

    Description

    Name

    Enter a custom name for the rule.

    Script Code

    Enter the rule code. This example uses the following code.

    if and(eq($host,'example.com'),eq(get(split($request_uri, '?'),1),'/order/create')){
        if not(match_re($http_user_agent,'.*trusted.*')){
            exit(403,'{"code":10063,"msg":"The order data is abnormal","data":{}}')
        }
    }

    Run Script At

    The rule's execution position. This parameter cannot be changed. In this example, the value is Not Executed.

    Status

    The status of the rule. The default setting (enabled) is used in this example.

    Advanced Settings

    This example uses the default setting, which is unselected.

Step 2: Configure DNS settings

Copy the DNS name of your ALB instance. Then, add a CNAME record to point your domain name to the instance's DNS name.

  1. Log on to the Alibaba Cloud DNS console.

  2. On the Public Zone page, click Add Zone.

  3. In the Add Zone dialog box, enter your host's domain name, and then click OK.

    Important

    Your domain must be verified with a TXT record.

  4. Find the target domain name and click Settings in the Actions column.

  5. On the Settings page, click Add Record.

  6. In the Add Record panel, configure the following parameters to add a CNAME record, and then click OK.

    Parameter

    Description

    Record Type

    Select CNAME from the drop-down list.

    Hostname

    The prefix for your domain name.

    DNS Query Source

    Use the default setting.

    Record Value

    Enter the DNS name of the ALB instance that you copied earlier.

    TTL

    Time to Live (TTL) is the duration for which a DNS record is cached on a DNS server. This example uses the default value.

Step 3: Verify the results

  1. Test normal requests.

    Use any client with internet access.

    1. You can access the backend service by visiting http://<access_address> in a browser. If you refresh the browser multiple times, the returned content alternates between ECS01 and ECS02.

    2. Open a command-line interface on the client and run the following command multiple times. The response message switches between ECS01 and ECS02.

      curl http://<your_access_address>
      C:\Users\xxx>curl http://xxx
      Hello World ! This is ECS01.
      C:\Users\xxx>curl http://xxx
      Hello World ! This is ECS02.
  2. Test abnormal requests.

    Run the command. A response of {"code":10063,"msg":"The order data is abnormal","data":{}} indicates that the forwarding rule defined by the AScript programmable script has taken effect.

    curl -v  -H "Host:example.com" -H "User-Agent:suspicious test" http://<your_access_address>/order/create
    C:\Users\xxx>curl -v  -H "Host:example.com" -H "User-Agent:suspicious test" http://xxx/order/create
    *   Trying xxx:80...
    * Connected to xxx (xxx) port 80
    > GET /order/create HTTP/1.1
    > Host:example.com
    > Accept: */*
    > User-Agent:suspicious test
    >
    < HTTP/1.1 403 Forbidden
    < Date: Wed, 10 Jul 2024 08:08:42 GMT
    < Content-Type: application/octet-stream
    < Transfer-Encoding: chunked
    < Connection: keep-alive
    <
    {"code":10063,"msg":"The order data is abnormal","data":0}
    * Connection #0 to host xxx left intact

Use case 2: Custom authentication

A company uses ALB to host its services in an Alibaba Cloud region. The backend server group includes multiple servers that run different applications. The company faces a challenge: users must log on multiple times to access different applications, which degrades the user experience and increases management overhead. The company wants to implement Single Sign-On (SSO) so that users can use a unified authentication credential to access all applications.

To achieve this, the company decides to use AScript to implement custom logic. By writing custom AScript rules, the company can perform detailed checks and operations on request headers such as Authorization and Cookie. This allows an SSO token from a cookie to be converted into a unified authentication credential. AScript can also inject detailed log information into response headers to facilitate debugging and tracing of the authentication process. This programmable logging capability surpasses traditional load balancers and enhances ALB's ability to maintain system security.

In this example, a company uses AScript to check whether the request header contains an Authorization field:

  • If the header exists, the rule logs the length of the Authorization value and related information.

  • If the header does not exist, the rule checks whether the Cookie header contains an SSO_token.

    • If the SSO_token exists, the rule logs its length, injects it as a Bearer Token into the Authorization request header, and logs this action.

    • If the SSO_token is also missing, the rule logs that both are missing.

Corresponding AScript rule

# Checks if a given value is missing.
def is_missing(val){
    if val{
        return or(null(val),le(len(val),1))
    }else{
        return true
    }
}
# Adds a log entry to the HTTP response header. 
# The key is specified by the key parameter, and the message is provided by the msg parameter.
def log_on_rsp_header(key, msg) {
    add_rsp_header(concat('ascript-log_', key), msg) 
}
# Main logic
# Check if the Authorization header exists in the request. If it does, log its length.
if $http_authorization {
    log_on_rsp_header('authorization', concat('len=', len($http_authorization)))
}
# Check if an SSO_token exists in the request cookie. If it does, log its length.
if $cookie_sso_token {
    log_on_rsp_header('sso_token', concat('len=', len($cookie_sso_token)))  
}
if is_missing($http_authorization) {
    if not(is_missing($cookie_sso_token)) {
       # If the Authorization header is missing but the SSO_token exists in the cookie,
       # inject the SSO_token as a Bearer Token into the Authorization request header and log the action.
       add_req_header('authorization', concat('Bearer ',$cookie_sso_token))      
       add_rsp_header('ascript-log', 'use sso_token as authorization in request header') 
    } else {
       # If both the Authorization header and the SSO_token in the cookie are missing, log this scenario.
       add_rsp_header('ascript-log', 'authorization is missing and cookie sso_token is missing too')         
    }  
} else {
    # If the Authorization header exists, log this scenario.
    log_on_rsp_header('miss-authorization', 'val = false')
}
image

Procedure

Step 1: Add an AScript rule

  1. Log on to the Application Load Balancer (ALB) console.

  2. On the Instances page, click the ID of the target instance.

  3. Click the Listener tab, and then click the ID of the target listener.

  4. Click the Forwarding Rules tab. On the Inbound Forwarding Rules tab, click Add Script Before Forwarding Rule Is Applied.

    Note

    If you select the Outbound Forwarding Rules tab, you can only select Add Script Before Forwarding Rule Is Applied.

  5. On the Add Script page, configure the rule and click OK.

    Parameter

    Description

    Name

    Enter a custom name for the rule.

    Script Code

    Enter the rule code. This example uses the following code.

    def is_missing(val){
        if val{
            return or(null(val),le(len(val),1))
        }else{
            return true
        }
    }
    def log_on_rsp_header(key, msg) {
        add_rsp_header(concat('ascript-log_', key), msg) 
    }
    
    if $http_authorization {
        log_on_rsp_header('authorization', concat('len=', len($http_authorization)))
    }
    if $cookie_sso_token {
        log_on_rsp_header('sso_token', concat('len=', len($cookie_sso_token)))  
    }
    
    if is_missing($http_authorization) {
        if not(is_missing($cookie_sso_token)) {
           add_req_header('authorization', concat('Bearer ',$cookie_sso_token))      
           add_rsp_header('ascript-log', 'use sso_token as authorization in request header') 
        } else {
           add_rsp_header('ascript-log', 'authorization is missing and cookie sso_token is missing too')         
        }  
    } else {
        log_on_rsp_header('miss-authorization', 'val = false')
    }

    Run Script At

    The rule's execution position. This parameter cannot be changed. In this example, the value is Not Executed.

    Status

    The status of the rule. The default setting (enabled) is used in this example.

    Advanced Settings

    This example uses the default setting, which is unselected.

Step 2: Configure DNS settings

Copy the DNS name of your ALB instance. Then, add a CNAME record to point your domain name to the instance's DNS name.

  1. Log on to the Alibaba Cloud DNS console.

  2. On the Public Zone page, click Add Zone.

  3. In the Add Zone dialog box, enter your host's domain name, and then click OK.

    Important

    Your domain must be verified with a TXT record.

  4. Find the target domain name and click Settings in the Actions column.

  5. On the Settings page, click Add Record.

  6. In the Add Record panel, configure the following parameters to add a CNAME record, and then click OK.

    Parameter

    Description

    Record Type

    Select CNAME from the drop-down list.

    Hostname

    The prefix for your domain name.

    DNS Query Source

    Use the default setting.

    Record Value

    Enter the DNS name of the ALB instance that you copied earlier.

    TTL

    Time to Live (TTL) is the duration for which a DNS record is cached on a DNS server. This example uses the default value.

Step 3: Verify the results

  1. Test a request with no authentication credentials.

    This example uses a client that can access the public network. Open the cmd window on the client and run the following command. Because the request header does not contain Authorization and the cookie does not contain SSO_token, the response header returns the log message authorization is missing and cookie sso_token is missing too.

    curl -v http://<your_access_address>
    C:\Users\xxx>curl -v  http://xxx
    *   Trying xxx:80...
    * Connected to xxx (xxx) port 80
    > GET / HTTP/1.1
    > Host: xxx
    > User-Agent: curl/8.4.0
    > Accept: */*
    >
    < HTTP/1.1 200 OK
    < Date: Wed, 10 Jul 2024 08:33:17 GMT
    < Content-Type: text/html
    < Content-Length: 29
    < Connection: keep-alive
    < Last-Modified: Wed, 10 Jul 2024 07:19:48 GMT
    < ETag: "668e3614-1d"
    < Accept-Ranges: bytes
    < ascript-log: authorization is missing and cookie sso_token is missing too
    <
    Hello World ! This is ECS01.
    * Connection #0 to host xxx left intact
  2. Test sending a request with the SSO_token in the cookie.

    Run the following command to add SSO_token to the Cookie request header. You can see that the log output in the response header is ascript-log_sso_token: len=13 and use sso_token as authorization in request header.

    curl -v -b "sso_token=ah$sgdj#sgava" http://<your_access_address>
    C:\Users\xxx>curl -v -b "sso_token=ah$sgdj#sgava" http://xxx
    *   Trying xxx:80...
    * Connected to xxx (xxx) port 80
    > GET / HTTP/1.1
    > Host: xxx
    > User-Agent: curl/8.4.0
    > Accept: */*
    > Cookie: sso_token=ah$sgdj#sgava
    >
    < HTTP/1.1 200 OK
    < Date: Wed, 10 Jul 2024 08:36:08 GMT
    < Content-Type: text/html
    < Content-Length: 29
    < Connection: keep-alive
    < Last-Modified: Wed, 10 Jul 2024 07:21:29 GMT
    < ETag: "668e3679-1d"
    < Accept-Ranges: bytes
    < ascript-log_sso_token: len=13
    < ascript-log: use sso_token as authorization in request header
    <
    Hello World ! This is ECS02.
    * Connection #0 to host xxx left intact
  3. To test, send a request with the Authorization request header.

    Run the following command to add Authorization to the request header. You can see the log output ascript-log_authorization: len=20 and ascript-log_miss-authorization: val = false in the response header.

    curl -v -H "authorization: Bearer ah$sgdj#sgava" http://<your_access_address>
    C:\Users\xxx>curl -v -H "authorization: Bearer ah$sgdj#sgava" http://xxx
    *   Trying xxx:80...
    * Connected to xxx (xxx) port 80
    > GET / HTTP/1.1
    > Host: xxx
    > User-Agent: curl/8.4.0
    > Accept: */*
    > authorization: Bearer ah$sgdj#sgava
    >
    < HTTP/1.1 200 OK
    < Date: Wed, 10 Jul 2024 08:38:12 GMT
    < Content-Type: text/html
    < Content-Length: 29
    < Connection: keep-alive
    < Last-Modified: Wed, 10 Jul 2024 07:19:48 GMT
    < ETag: "668e3614-1d"
    < Accept-Ranges: bytes
    < ascript-log_authorization: len=20
    < ascript-log_miss-authorization: val = false
    <
    Hello World ! This is ECS01.
    * Connection #0 to host xxx left intact

The test results demonstrate that AScript allows you to manage the content and format of authentication credentials, including how they are replaced or enhanced. You can write custom authentication rules to meet your specific business requirements.

Use case 3: Custom request and response headers

A company uses ALB to host its services in an Alibaba Cloud region. The backend server group includes multiple servers that run applications. As the business grows, the company needs to implement Cross-Origin Resource Sharing (CORS). Specifically, frontend applications from different domains need to access resources and services hosted on these servers. Due to the browser's same-origin policy, cross-origin requests are blocked by default, which prevents resources from loading and disrupts the user experience and business workflows. The company also needs flexible cross-origin policies based on different request headers to meet various access requirements.

Standard ALB forwarding rules lack the flexibility for complex CORS policies. You cannot use a single forwarding rule to implement effective cross-origin policies for different request headers. To resolve this, the company uses the customization capabilities of AScript.

With AScript, the company can achieve the following:

  • Determine if a request has a valid cross-origin header.

  • Identify the request origin (from the Origin or Referer header) to determine whether the request is from an allowed domain.

  • Dynamically add Access-Control-Allow-Origin and other relevant CORS response headers to allow cross-origin requests from specific domains.

  • Provide more granular control, such as restricting available HTTP methods, headers, and frame options.

In this example, an AScript rule checks if the request origin is from an allowed domain (such as example.com, example.org, or test.com). If a match is found, ALB dynamically adds the required CORS response headers to enable valid cross-origin interactions.

Corresponding AScript rule

h = $http_origin
if not(h) {
    h = $http_referer
}
pcs = capture_re(h, '^(.*?)(\.example\.com|\.example\.org|\.test\.com)(:\d+)?')
sec1 = get(pcs, 1)
sec2 = get(pcs, 2)
sec3 = get(pcs, 3)
if (sec2) {
    add_rsp_header('cross-origin-resource-policy', 'cross-origin')
    add_rsp_header('access-control-allow-methods', 'GET,PUT,POST,DELETE,UPDATE,OPTIONS')
    add_rsp_header('access-control-allow-credentials', 'true')
    add_rsp_header('access-control-allow-headers', 'Cookie,Set-Cookie,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,Host,Origin,csrf-token-fe1a2a3s12,xhrFields')
    if not(sec3) {
        add_rsp_header('access-control-allow-origin', concat(sec1, sec2))
        add_rsp_header('x-frame-options', concat('ALLOW-FROM ', sec1, sec2))
    } else {
        add_rsp_header('access-control-allow-origin', concat(sec1, sec2, sec3))
    }
}
image

Procedure

Step 1: Add an AScript rule

  1. Log on to the Application Load Balancer (ALB) console.

  2. On the Instances page, click the ID of the target instance.

  3. Click the Listener tab, and then click the ID of the target listener.

  4. Click the Forwarding Rules tab. On the Inbound Forwarding Rules tab, click Add Script Before Forwarding Rule Is Applied.

    Note

    If you select the Outbound Forwarding Rules tab, you can only select Add Script Before Forwarding Rule Is Applied.

  5. On the Add Script page, configure the rule and click OK.

    Parameter

    Description

    Name

    Enter a custom name for the rule.

    Script Code

    Enter the rule code. This example uses the following code.

    h = $http_origin
    if not(h) {
        h = $http_referer
    }
    
    pcs = capture_re(h, '^(.*?)(\.example\.com|\.example\.org|\.test\.com)(:\d+)?')
    sec1 = get(pcs, 1)
    sec2 = get(pcs, 2)
    sec3 = get(pcs, 3)
    
    if (sec2) {
        add_rsp_header('cross-origin-resource-policy', 'cross-origin')
        add_rsp_header('access-control-allow-methods', 'GET,PUT,POST,DELETE,UPDATE,OPTIONS')
        add_rsp_header('access-control-allow-credentials', 'true')
        add_rsp_header('access-control-allow-headers', 'Cookie,Set-Cookie,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,Host,Origin,csrf-token-fe1a2a3s12,xhrFields')
        if not(sec3) {
            add_rsp_header('access-control-allow-origin', concat(sec1, sec2))
            add_rsp_header('x-frame-options', concat('ALLOW-FROM ', sec1, sec2))
        } else {
            add_rsp_header('access-control-allow-origin', concat(sec1, sec2, sec3))
        }
    }

    Run Script At

    The rule's execution position. This parameter cannot be changed. In this example, the value is Not Executed.

    Status

    The status of the rule. The default setting (enabled) is used in this example.

    Advanced Settings

    This example uses the default setting, which is unselected.

Step 2: Configure DNS settings

Copy the DNS name of your ALB instance. Then, add a CNAME record to point your domain name to the instance's DNS name.

  1. Log on to the Alibaba Cloud DNS console.

  2. On the Public Zone page, click Add Zone.

  3. In the Add Zone dialog box, enter your host's domain name, and then click OK.

    Important

    Your domain must be verified with a TXT record.

  4. Find the target domain name and click Settings in the Actions column.

  5. On the Settings page, click Add Record.

  6. In the Add Record panel, configure the following parameters to add a CNAME record, and then click OK.

    Parameter

    Description

    Record Type

    Select CNAME from the drop-down list.

    Hostname

    The prefix for your domain name.

    DNS Query Source

    Use the default setting.

    Record Value

    Enter the DNS name of the ALB instance that you copied earlier.

    TTL

    Time to Live (TTL) is the duration for which a DNS record is cached on a DNS server. This example uses the default value.

Step 3: Verify the results

  1. Test a request from a disallowed origin.

    For this example, use any client that can access the public internet. Open the cmd window on the client and run the following command to set the request origin to http://www.example.cn. You can see that the response header does not contain Access-Control-Allow-Origin or other related CORS response headers.

    curl -H "Origin: http://www.example.cn" -v http://<your_access_address>
    C:\Users\xxx>curl -H "Origin: http://www.example.cn" -v http://xxx
    * Trying xxx:80...
    * Connected to xxx (xxx) port 80
    > GET / HTTP/1.1
    > Host: xxx
    > User-Agent: curl/8.4.0
    > Accept: */*
    > Origin: http://www.example.cn
    >
    < HTTP/1.1 200 OK
    < Date: Wed, 10 Jul 2024 08:44:08 GMT
    < Content-Type: text/html
    < Content-Length: 29
    < Connection: keep-alive
    < Last-Modified: Wed, 10 Jul 2024 07:19:48 GMT
    < ETag: "668e3614-1d"
    < Accept-Ranges: bytes
    <
    Hello World ! This is ECS01.
    * Connection #0 to host xxx left intact
  2. Test a request from an allowed origin.

    Run the following command to set the request origin to http://www.example.com. You can see that the response header now includes the relevant cross-origin headers.

    curl -H "Origin: http://example.com" -v http://<your_access_address>
    C:\Users\xxx>curl -H "Origin: http://example.com" -v http://xxx
    *   Trying xxx:80...
    * Connected to xxx (xxx) port 80
    > GET / HTTP/1.1
    > Host: xxx
    > User-Agent: curl/8.4.0
    > Accept: */*
    > Origin: http://example.com
    >
    < HTTP/1.1 200 OK
    < Date: Wed, 10 Jul 2024 08:46:23 GMT
    < Content-Type: text/html
    < Content-Length: 29
    < Connection: keep-alive
    < Last-Modified: Wed, 10 Jul 2024 07:19:48 GMT
    < ETag: "668e3614-1d"
    < Accept-Ranges: bytes
    <
    < cross-origin-resource-policy: cross-origin
    < access-control-allow-methods: GET, PUT, POST, DELETE, UPDATE, OPTIONS
    < access-control-allow-credentials: true
    < access-control-allow-headers: Cookie, Set-Cookie, DNT, X-Mx-ReqToken, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Authorization, Host, Origin, csrf-token-fela2a3s12, xhrFields
    < access-control-allow-origin: http://example.com
    < x-frame-options: ALLOW-FROM http://example.com
    <
    Hello World ! This is ECS01.
    * Connection #0 to host xxx left intact

Related documents