haproxyhaproxy-ingress

HAProxy: Check stick-table contains required key


I want to set limit of new users' connections if amount of active users exceeded the required threshold. Users connect to the load balancer via http. I use stick-table to limit the amount of users (by unique header):

frontend echo
    bind *:8881
    mode http

    # user is active if seds any request every 30s or often
    stick-table type string size 100k expire 30s store gpc0_rate(10s) 
    # track keys if table size less than limit
    http-request track-sc0 req.hdr(Client-ID) if { table_cnt lt 100 } 
    # limit of new not active users
    http-request deny deny_status 429 if { table_cnt ge 100 } { <❓check that "Client-ID" keys's value exists in the table> }

    use_backend echo

The main idea is deny requests from all new user if Client-ID header's value is not present in the table. It's possible?


Solution

  • You are close to solution. You need in_table converter:

    Uses the string representation of the input sample to perform a look up in the specified table. If the key is not found in the table, a boolean false is returned. Otherwise a boolean true is returned. This can be used to verify the presence of a certain key in a table tracking some elements (e.g. whether or not a source IP address or an Authorization header was already seen).

    In your case it would be one more acl: acl clientid_in_table req.hdr(client-id),in_table and your config becomes (i prefer naming my ACLs for clarity):

    frontend echo
        bind *:8881
        mode http
    
        # user is active if seds any request every 30s or often
        stick-table type string size 100k expire 30s store gpc0_rate(10s) 
        # ACL to check if client-id is in table
        acl clientid_in_table req.hdr(client-id),in_table
        # track keys if table size less than limit
        http-request track-sc0 req.hdr(Client-ID) if { table_cnt lt 100 } 
        # limit of new not active users
        http-request deny deny_status 429 if { table_cnt ge 100 } !clientid_in_table
    
        use_backend echo
    

    No idea what it does if header is missing in request, but you can deny it on that basis as well if needed.