Partitioned policy when field not set in key

For a partitioned policy suppose rate limit is being partitioned and a rate is set in policy but a rate is not set in the key object, then it does not seem to enforce any kind of rate limiting at all.

How to use the rate limiting defined in policy if rate field is not set in the key?

Can someone please shed some light on how to approach this scenario in Tyk?

To achieve or enforce policy rate limiting, you would simply have to set the partitioning section as outlined in our documentation to your specific scenario. I have dropped a sample below

"DemoPartitionedPolicy": {
		"auth_type": "authToken",
		"auth_types": [
				"authToken"
		],
		"state": "active",
		"graphql_enabled": false,
		"id": "59672779fa4387000129507d",
		"name": "Demo Partitioned Policy",
		"org_id": "XXXX",
		"rate": 1000,
		"per": 60,
		"quota_max": -1,
		"quota_renewal_rate": -1,
		"throttle_interval": -1,
		"throttle_retry_limit": -1,
		"max_query_depth": -1,
		"access_rights": {
				"<API ID>": {
						"api_name": "<API NAME>",
						"api_id": "<API ID>",
						"versions": [
								"Default"
						],
						"allowed_urls": [],
						"restricted_types": null,
            "limit": null,
            "field_access_rights": null,
						"allowance_scope": ""
				}
		},
		"hmac_enabled": false,
		"active": true,
		"is_inactive": false,
		"tags": [],
		"key_expires_in": -1,
		"partitions": {
				"quota": false,
				"rate_limit": true,
				"complexity": false,
				"acl": true,
				"per_api": false
		},
		"meta_data": {}
	}

If you only wanted enforce rate limiting, when you could remove the API defined in the access_rights and set the acl to be false. You can learn more about the difference scenarios you could orchestrate by visiting out documentation regarding partitioned policy functionality

Partitioned policy is working fine, my requirement is that provided the rate limiting is partitioned in policy but in key I do not mention any rate limit(That is I have not added the “rate”, “per” fields in the key and used the gateway api to set the key).

When I tried, it was not enforcing any kind of rate limiting(nothing is actually mentioned in key but there is something in policy which is not being used due to the partition). I need to use the rate limit mentioned in policy if nothing is specified in the key. How can I do it in Tyk?

Does this mean that you have 2 different APIs in the policy? One that has it’s own rate limit and another that should depend on the policie’s rate limit?

No, one API with a partitioned policy but if there isn’t any rate limit set at key level it should use rate limit defined in policy.

I am not sure of a use case where you only want to use one partition API for a policy. Unless you are using multiple policies to create a key.

Anyways, there is a conditional check when a key created through a policy. If you don’t specify a rate limit, then the policy’s rate limit would be applied to the API instead. The example below should work for your use case.

"partitions": {
	"quota": false,
	"rate_limit": false,
	"complexity": false, // this depends if you are using GRAPH/UDG
	"acl": false,
	"per_api": true
}
  • quota: If set to true, enforce the quota element of this policy
  • rate_limit: If set to true, enforce the rate limit of this policy
  • acl: If set to true, enforce the access control rules of this policy
  • complexity: If set to true, enforce the GraphQL complexity rules of this policy
  • per_api: if set to true, please set quota, rate_limit, and acl to false

I hope I have been able to help. If not, then kindly share your policy definition and key creation API body.

Sorry to say it didn’t answer it. I doubt if you are not still getting to my point.

Key

{
    "expires": -1,
    "quota_max": 50,
    "quota_renewal_rate": 60,
    "org_id": "basic",
    "access_rights": {
        "test-api-id": {
            "api_name": "Test api",
            "api_id": "test-api-id",
            "versions": ["Default"]
        }
    },
    "meta_data": {},
    "basic_auth_data": {
        "password": "test-password"
    },
    "hmac_enabled": false,
    "hmac_string": "",
    "is_inactive": false,
    "apply_policy_id": "",
    "apply_policies": ["partitioned"],
    "monitor": {
        "trigger_limits": []
    }
}

Policy

"partitioned": {
        "rate": 12,
        "per": 1,
        "quota_max": 24,
        "quota_renewal_rate": 60,
        "access_rights": {
            "test-api-id": {
                "apiname": "Test api",
                "apiid": "test-api-id",
                "versions": ["Default"]
            }
        },
        "org_id": "basic",
        "hmac_enabled": false,
        "partitions": {
            "quota": true,
            "rate_limit": false,
            "acl": true,
            "complexity": true
        }
    }

Here, notice rate limit of policy “partitioned” is being partitioned but there isn’t any “rate” or “per” fields defined in key. In this case I want to use rate of 12 request per second which is defined in the policy “partitioned” to be used instead. When I try it out it does not keep any rate limit and passes as many requests per second without any restrictions.

The issue is in your policy configuration

When I try it out it does not keep any rate limit and passes as many requests per second without any restrictions.

Maybe the word partition in the policy definition might be confusing. But your configuration is literally telling the key not to apply the rate limit in the policy.

If you change this value to true, it would apply the rate limit in the policy. If false, it would ignore the rate limit in the policy.

Can you try setting "rate_limit": true and test the outcome?

I am using partition to take rate from key. If set to true it will take it from policy, then what is the use of partitioning? I have set it to false to set the rate in key.

What I am asking is suppose there was no rate set in a specific key I need to use rate from policy rather than no rate limit as it happens now.

I see where the issue is. You’re missing the field setting in your policy to enable per API policy limits. You just need to specify the per_api field in the partitions section.

"partitions": {
    "per_api": true
}

As mentioned earlier, you can decide not to enforce policy limits by enabling the field and APIs without a rate limit or quota would inherit from the policy if not is set by the key. Please note that you have to set acl, quota and rate_limit to false. Or you can just remove it as shown above, since it’s false by default.

Kindly re-test your rate limiting afterwards and confirm if the result is as expected?

When “per_api” is set to true it is only accepting the rate limit from “limit” field inside “access_rights” of policy. If “limit” field is not defined then rate limit in that policy set using “rate” and “per” fields is used.

It is not taking the rate limit in key anyhow.

If rate is set in key or rate is not set in key as well, it is always taking from policy based on if “limit” field is present or not.

I just want to add one related observation I found.

"partitions": {
            "quota": false,
            "rate_limit": false,
            "acl": false,
            "complexity": false,
            "per_api": true
        }
  • When “acl” field inside “partition” is set to false rate limiting is always taken from policy.

  • On the other hand if “acl” is set to true, suppose rate_limiting is set to true then it is taken from policy else taken from key.(Which is obviously correct as per documentation)

I am a bit unclear about this? Is this with the per_api enabled (as shown below)? Also, does this mean that you have gotten the expected outcome?

If it’s still not working, can you insert the access_rights into the policy definition instead and try again. I have dropped an example below

Policy Definition

{
	"access_rights": {
		"<API-01-ID>": {
			"allowed_urls": [],
			"api_id": "<API-01-ID>",
			"api_name": "<API-01-NAME>",
			"versions": [
				"Default"
			]
		},
		"<API-02-ID>": {
			"allowance_scope": "",
			"allowed_urls": [],
			"api_id": "<API-02-ID>",
			"api_name": "<API-02-NAME>",
			"field_access_rights": null,
			"limit": {
				"per": -1,
				"rate": -1
			},
			"restricted_types": null,
			"versions": [
				"Default"
			]
		}
	},
	"active": true,
	"auth_type": "authToken",
	"auth_types": [
		"authToken"
	],
	"id": "<POLICY-ID>",
	"is_inactive": false,
	"key_expires_in": 86400,
	"name": "<POLICY-NAME>",
	"org_id": "<ORG-ID>",
	"partitions": {
		"per_api": true
	},
	"per": 5,
	"quota_max": 24,
	"quota_renewal_rate": 60,
	"rate": 30,
	"state": "active",
	"tags": null,
	"throttle_interval": -1,
	"throttle_retry_limit": -1
}

Key Creation API Body

{
	"access_rights": {},
	"alias": "<KEY-NAME>",
	"apply_policies": [
		"<POLICY-ID>"
	],
	"apply_policy_id": "",
	"expires": 86400,
	"is_inactive": false,
	"org_id": "<ORG-ID>"
}

You should see a value for the allowed_scope in the key. That tells the key what restrictions are applied to it (whether it is a per_api restriction or one inherited from the policy).

{
    "last_check": 0,
    "allowance": 0,
    "rate": 0,
    "per": 0,
    "throttle_interval": 0,
    "throttle_retry_limit": 0,
    "max_query_depth": 0,
    "date_created": "2022-04-20T11:39:25.9511266Z",
    "expires": 0,
    "quota_max": 0,
    "quota_renews": 1650454765,
    "quota_remaining": 0,
    "quota_renewal_rate": 0,
    "access_rights": {
        "free": {
            "api_name": "Free API",
            "api_id": "free",
            "versions": [
                "Default"
            ],
            "allowed_urls": [],
            "restricted_types": null,
            "limit": {
                "rate": 30,
                "per": 5,
                "throttle_interval": -1,
                "throttle_retry_limit": -1,
                "max_query_depth": -1,
                "quota_max": 24,
                "quota_renews": 0,
                "quota_remaining": 24,
                "quota_renewal_rate": 60
            },
            "field_access_rights": null,
            "allowance_scope": "partitioned-05"
        },
        "subscriber": {
            "api_name": "Subscriber API",
            "api_id": "subscriber",
            "versions": [
                "Default"
            ],
            "allowed_urls": [],
            "restricted_types": null,
            "limit": {
                "rate": -1,
                "per": -1,
                "throttle_interval": 0,
                "throttle_retry_limit": 0,
                "max_query_depth": 0,
                "quota_max": 0,
                "quota_renews": 0,
                "quota_remaining": 0,
                "quota_renewal_rate": 0
            },
            "field_access_rights": null,
            "allowance_scope": "subscriber"
        }
    },
    "org_id": "adi",
    "oauth_client_id": "",
    "oauth_keys": null,
    "certificate": "",
    "basic_auth_data": {
        "password": "",
        "hash_type": ""
    },
    "jwt_data": {
        "secret": ""
    },
    "hmac_enabled": false,
    "enable_http_signature_validation": false,
    "hmac_string": "",
    "rsa_certificate_id": "",
    "is_inactive": false,
    "apply_policy_id": "",
    "apply_policies": [
        "partitioned-05"
    ],
    "data_expires": 0,
    "monitor": {
        "trigger_limits": null
    },
    "enable_detail_recording": false,
    "enable_detailed_recording": false,
    "meta_data": {},
    "tags": [],
    "alias": "Sailor Partition Key 14",
    "last_updated": "1650454765",
    "id_extractor_deadline": 0,
    "session_lifetime": 0,
    "key_id": "adi40db3a9e51e24ae0bcdca4bf1562eda2"
}

Not solved.

It is taking value from policy but it is not taking value from key even if it is set in the key.

What I want is if there is a rate limit (“rate” and “per” fields) value in key use it otherwise if the rate is not set use the values from policy associated with that key.

Is this with the per_api enabled (as shown below)? Yes it is the same.

There is already an “access_rights” field in policy definition.
Please check this policy snippet:

There isn’t any allowed_scope but there is a field called “allowance_scope” and it is set with value as the api-id.

I think I now understand what it is you want to achieve. And unfortunately the Policy, Key and API relationship are not designed that way.

You can create keys in 2 ways:

  • From a policy - which is being used as a template
  • Directly on a range of API(s) - as set in the access_rights section in the definition

You cannot combine both of them to try and achieve something complex. It’s either the APIs are defined in the policy (where they can be managed) or they are defined in the key. Adding the same API in the access_rights when it’s already present in the policy does not override the values already set in policy.

If you’ve specified the access_rights in the policy, then there is no need to set it again in the key. Tyk first checks if there is a policy assigned to the key. If there is a policy template, then it would use that. If not then it would use the APIs as defined in the key. A policy can only managed the access_rights of the APIs that are set within it. The policy cannot manage or modify the properties set in a key, unless enforcement is enabled in the policy.

I hope this makes it clear.

I don’t think this is answering my query.

  • First of all please let me know the actual usage of “per_api” field. From what I understood from observations and the word meaning(“per api”) it is for setting different rate, quota etc separately for different APIs which are accessible in a given policy(those APIs listed in the “access_rights” section of policy).
    For example, if policy P has two APIs A, B inside “access_rights” section, we can set rate limiting individually for APIs rather than the global rate limit for policy P

    So I didn’t understand how it will satisfy my requirement.

    On setting “per_api” to true and setting the “limits” section for API inside “access_rights” for rate limits it takes rate defined in “limits” section of policy.

  • As I have already mentioned before, I want to use partitioned policy to set the rate limits in key. And suppose there wasn’t any rate set in the key(which was supposed to be there in the key) then I have to use the rate limits defined in the policy instead of no rate limit at all. With “per_api” and “limits” set it always takes from policy and not from key at all.

  • From my observations I see when “acl”, “rate” fields inside “partitions” section is set to false(I tried it with and without “per_api” set to true) it always took rate from policy. And for “per_api” to be set true we need to set “acl”, “rate”, “quota” inside “partitions” section to be set as false as you mentioned earlier.(The point to note is “acl” and “rate” is false so it could have took rates from policy)

  • Adding or removing the “access_rights” section from key or policy (with or without “per_api”: true) do not make any difference.

  • FYI I don’t want to combine global rate limits in policy and rate limits for individual APIs(set using “limit” section inside “access_rights”) to do anything complex. I mentioned it since you told about setting “per_api” to true. So I added rate limits inside the “limit” section of “access_rights”. Otherwise I don’t need to deal with it. I just want the global rate limits set in policy and key as in:

{
    "last_check": n,
    "allowance": n,
    "rate": n,
    "per": m,
    "throttle_interval": n,
    "throttle_retry_limit": n,
    .....
}

I believe my requirement is clear to you?

  • So are you saying my requirement cannot be achieved?

I am iterating my requirement again:

Policy must be paritioned to take value from key.

If there is a rate set in key → use it.

If the fields to set rate(“rate”, “per” fields) are not present in key → Use the rate from policy associated with the key(In policy I have set a rate limit I just want it to be used. It should not allow as many requests to pass through as it happens now)

I have already told an example here.

I believe my requirement is clear to you?

  • So are you saying my requirement cannot be achieved?

Yes your requirement is very clear to me. And, no it cannot be achieved.

Policy must be paritioned to take value from key.

If there is a rate set in key → use it.

If the fields to set rate(“rate”, “per” fields) are not present in key → Use the rate from policy associated with the key(In policy I have set a rate limit I just want it to be used. It should not allow as many requests to pass through as it happens now)

When partitioned, you need to define it in the key. It’s either you enforce it to use what is defined in the policy or set it yourself in the key. You cannot set it to be both in the key and policy. A simple rule of thumb to follow:

  • If it is defined in the policy, then there is no need to define in the key. The policy is the template for the key
  • If it is not defined or enforced in the policy, then you need to specify it in the key