Cannot make a Policy to rate limit an API

Good afternoon.

I am trying to rate limit a specific API following the steps below:

  1. Create an API.

Api Definition

{
  "name": "Config-Api-Products",
  "api_id": "Config-Api-Products",
  "org_id": "1",
  "auth_configs": {
    "authToken": {
      "auth_header_name": "X-Api-Key"
    }
  },
  "definition": {
    "location": "header",
    "key": "X-Api-Version"
  },
  "version_data": {
    "not_versioned": true,
    "versions": {
      "Default": {
        "name": "Default",
        "use_extended_paths": true
      }
    }
  },
  "proxy": {
    "listen_path": "/product/list",
    "target_url": "https://my-server/products",
    "strip_listen_path": true
  },
  "active": true
}

  1. Create a Key with access rights to this API. In this access token, I don’t set any Rate Limits, since I want to retrieve it from the policy instead:

Sample API Gateway call

curl --location --request POST 'localhost:7070/tyk/keys/create' \
--header 'X-Tyk-Authorization: my_tyk_token' \
--header 'Content-Type: application/json' \
--data-raw '{
  "org_id": "1",
  "access_rights": {
    "Config-Api-Products": {
      "api_id": "Config-Api-Products",
      "api_name": "Config-Api-Products",
      "versions": ["Default"]
    }
  }
}'

Sample API Gateway Response:

{
    "key": "generated_tyk_token_key",
    "status": "ok",
    "action": "added",
    "key_hash": "e042e6ef"
}

  1. Create a policy. For that I am mapping the policies directory on tyk using compose file.

docker-compose.yml

version: '3.3'
services:
  tyk-gateway:
    image: docker.tyk.io/tyk-gateway/tyk-gateway:v3.2.1
    ports:
      - 7070:7070
    networks:
      - tyk
    volumes:
      - $PWD/tyk.standalone.conf:/opt/tyk-gateway/tyk.conf
      - $PWD/apps:/opt/tyk-gateway/apps
      - $PWD/middleware:/opt/tyk-gateway/middleware
      - $PWD/certs:/opt/tyk-gateway/certs
      - $PWD/policies:/opt/tyk-gateway/policies
    depends_on:
      - tyk-redis
  tyk-redis:
    image: redis:latest
    command: redis-server --appendonly yes
    networks:
      - tyk
    ports:
      - 7171:6379
    volumes:
      - $PWD/redis-data:/data

networks:
  tyk:

policies.json

{
  "Config-Api-Products-Policy": {
    "org_id": 1,
    "rate": 1,
    "per": 5,
    "active": true,
    "name": "Config-Api-Products-Policy",
    "quota_max": 30,
    "quota_renewal_rate": 60,
    "state": "active",
    "access_rights": {
      "Config-Api-Products": {
        "api_id": "Config-Api-Products",
        "api_name": "Config-Api-Products",
        "versions": ["Default"]
      }
    }
  }
}

File base policy management enablement

  "policies": {
    "policy_source": "file",
    "policy_record_name": "/opt/tyk-gateway/policies/policies.json"
  }

Call to API that should be rate-limited

curl --location --request GET 'localhost:7070/product/list' \
--header 'X-Api-Key: generated_tyk_token_key' \
--header 'Authorization: Bearer my_bearer_backend_token'

With that configuration, I was expecting that the API would not be able to be called once for every 5 seconds, but I can do multiple API calls and Tyk doesn’t block it. Also, I called the API much more than 30 times in 60 seconds and Tyk is not blocking those calls either.

What am I missing here? Can anyone please help me with that?

Thank you.

I suspect the reason you are seeing this is because your rate limits are too small. See API Management 101: Rate Limiting - Tyk. Tyk uses a “leaky” algorithm.

If you want to change this behaviour, look at Upgrading to v2.3 from v2.2. Set “enable_redis_rolling_limiter”: true in your tyk.conf file.

I will look into it. Thank you!
The only reason I have set the rate limit so small is that I wanted to actually test it manually, but I guess I can increase it and try to test it with a small application. I will post the results here later.

The low limits don’t seem to be the problem, unfortunately.
I’ve created a kotlin application that sent around 2000 request in less than a second and I didn’t get any 429 - Too Many Requests from Tyk.
Here are the logs of my first and last request on the gateway:

2021-08-27 12:30:38.186  INFO 74232 --- [nio-8080-exec-1] c.f.apicaller.service.ApiCallerService   : 0 - Calling the API - http://localhost:7070/api/product/list
2021-08-27 12:30:38.264  INFO 74232 --- [nio-8080-exec-1] c.f.apicaller.service.ApiCallerService   : 1999 - Calling the API - http://localhost:7070/api/product/list

As you can see the 2k request happened in less than 100ms and looking in my logs I saw that all responses were HTTP 200. Tyk never blocked any call respecting the rate limits provided (you can see the policy I created on Tyk below).

I also discovered that if I add the limits on the key generation without any policy attached to the API, they work, even when the limits are very low. The problem here is that the limits are exactly the same to all APIs and I don’t want that. E.g.

curl --location --request POST 'localhost:7070/tyk/keys/create' \
--header 'X-Tyk-Authorization: my_tyk_token' \
--header 'Content-Type: application/json' \
--data-raw '{
  "org_id": "1",
  "rate": 2,
  "per": 5,
  "quota_max": 150,
  "quota_renewal_rate": 120,
  "access_rights": {
    "Config-Api-Products": {
      "api_id": "Config-Api-Products",
      "api_name": "Config-Api-Products",
      "versions": ["Default"]
    },
    "Config-Api-Vendors": {
      "api_id": "Config-Api-Vendors",
      "api_name": "Config-Api-Vendors",
      "versions": ["Default"]
    },
    "Config-Api-Clients-By-Id": {
      "api_id": "Config-Api-Clients-By-Id",
      "api_name": "Config-Api-Clients-By-Id",
      "versions": ["Default"]
    }
  }
}'

But If I send no rate limits on the key and add rate limit through a policy on a specif API, I cannot make them work as I expected. E.g:
Key Generation

curl --location --request POST 'localhost:7070/tyk/keys/create' \
--header 'X-Tyk-Authorization: my_tyk_token' \
--header 'Content-Type: application/json' \
--data-raw '{
  "org_id": "1",
  "access_rights": {
    "Config-Api-Products": {
      "api_id": "Config-Api-Products",
      "api_name": "Config-Api-Products",
      "versions": ["Default"]
    },
    "Config-Api-Vendors": {
      "api_id": "Config-Api-Vendors",
      "api_name": "Config-Api-Vendors",
      "versions": ["Default"]
    },
    "Config-Api-Clients-By-Id": {
      "api_id": "Config-Api-Clients-By-Id",
      "api_name": "Config-Api-Clients-By-Id",
      "versions": ["Default"]
    }
  }
}'

Policy for One API with increased limits

{
  "Config-Api-Products-Policy": {
    "org_id": 1,
    "rate": 500,
    "per": 1,
    "quota_max": 150,
    "quota_renewal_rate": 120,
    "active": true,
    "name": "Config-Api-Products-Policy",
    "state": "active",
    "access_rights": {
      "Config-Api-Products": {
        "api_id": "Config-Api-Products",
        "api_name": "Config-Api-Products",
        "versions": ["Default"]
      }
    }
  }
}

Screenshot showing Tyk working when I add the rate limits on the key creation. No policy was added in this context
Working Rate Limiting Config-Api-Products API

Any ideas here?
Thank you!!

So what you want to achieve is policy-A has access to API-1, API-2, API-3, and there are rate limits applied to API-1, API-2, API-3? So for example

a) policy-A: API-1 5calls/minute, API-2 100calls/second, API-3 5calls/hour
b) policy-B: API-1 100calls/second, API-2 500calls/hour, API-3 1call/24 hours

?

1 Like

Hello @Jesum_Yip

We just wanted to send you a public thanks for your contributions on Tyk Community Forum. It’s so good to see Tyk users helping one another! :muscle:

Here is a virtual medal. Please let us know if you or your wider team would like any Tyk swag

medalgiphy

I want that a generated key to have access to all APIs and have different rate limit applied to different APIs.

So Key-A has access to API-1, API-2, …, API-N and each of these N APIs have different rate limits applied to them.

Thank you for your reply!

Some tyk swag would be most welcome! We’re not picky. :slight_smile:

Let me test this out tomorrow in my installation. For what it’s worth, I have enabled the redis rolling limiter in my environment. However this setting is not recommended in high traffic environments.

I also tried with Redis rolling limiter just to check if it would do any difference and it didn’t :frowning:
Thank you for the help so far!

Hello @rdasilva_fispan

I don’t see you applying the policy to the key you are creating. That could be the problem.

You need to add apply_policy_id field or apply_policies array to the API Key creation request.

Example:

{
  "allowance": 1000,
  "rate": 1000,
  "per": 60,
  "expires": -1,
  "quota_max": -1,
  "quota_renews": 1406121006,
  "quota_remaining": 0,
  "quota_renewal_rate": 60,
  "access_rights": {
    "3": {
      "api_name": "Tyk Test API",
      "api_id": "3"
    }
  },
  "org_id": "53ac07777cbb8c2d53000002",
  "basic_auth_data": {
    "password": "",
    "hash_type": ""
  },
  "hmac_enabled": false,
  "hmac_string": "",
  "is_inactive": false,
  "apply_policy_id": "",
  "apply_policies": [
    "59672779fa4387000129507d",
    "53222349fa4387004324324e",
    "543534s9fa4387004324324d"
    ],
  "monitor": {
    "trigger_limits": []
  }
}

Regards,
Zaid

Thanks for the reply, @zaid. Let me try that.

That actually worked. Thank you for pointing that out.
I will double check, but I don’t remember seeing that on the docs.

Once again, thank you!

No problem @rdasilva_fispan glad I could help!