Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions _topic_maps/_topic_map.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ Topics:
File: coredns
- Name: Using X.509 cryptographic identity verification
File: rhcl-using-x509-crypt-id-verify
- Name: Configuring and deploying PlanPolicy
File: rhcl-planpolicy
---
Name: Registering MCP servers and creating policies
Dir: mcp_gateway_config
Expand Down
38 changes: 38 additions & 0 deletions deployment/rhcl-planpolicy.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
:_mod-docs-content-type: ASSEMBLY
include::_attributes/attributes.adoc[]
[id="rhcl-planpolicy"]
= Configuring and deploying the PlanPolicy extension
:context: rhcl-planpolicy

toc::[]

[role="_abstract"]
With a `PlanPolicy` extension, you can define different service tiers, or plans, with their associated rate limits and automatically categorize authenticated users into these plans.

include::modules/con-rhcl-planpolicy-overview.adoc[leveloffset=+1]

include::modules/proc-rhcl-configuring-authentication-planpolicy.adoc[leveloffset=+2]

include::modules/proc-rhcl-authpolicy-verify.adoc[leveloffset=+2]

include::modules/proc-rhcl-create-secrets.adoc[leveloffset=+2]

include::modules/proc-rhcl-deploying-planpolicy-rate-limiting.adoc[leveloffset=+2]

include::modules/proc-rhcl-planpolicy-ratelimiting-verify.adoc[leveloffset=+2]

include::modules/ref-rhcl-planpolicy-custom-resources-params.adoc[leveloffset=+1]

include::modules/ref-rhcl-planpolicy-targeting-routes.adoc[leveloffset=+2]

include::modules/ref-rhcl-planpolicy-target-gateway.adoc[leveloffset=+2]

include::modules/ref-rhcl-planpolicy-plan-predicates.adoc[leveloffset=+2]

include::modules/ref-rhcl-planpolicy-plan-limits.adoc[leveloffset=+2]

include::modules/ref-rhcl-planpolicy-known-limitations.adoc[leveloffset=+2]

== Additional resources

* link:rhcl-ocp-web-console[Using the {product-title} web console]
21 changes: 21 additions & 0 deletions modules/con-rhcl-planpolicy-overview.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Module included in the following assemblies:
//
// *deployment/rhcl-planpolicy.adoc

:_mod-docs-content-type: CONCEPT
[id="con-rhcl-planpolicy-overview_{context}"]
= PlanPolicy

[role="_abstract"]
You can use a `PlanPolicy` object to implement tiered service offerings where different users receive different rate limits based on their subscription plan or other attributes.

[NOTE]
====
The `PlanPolicy` object uses the `spec.plans.limits` parameter to enforce rate limits at the plan tier level instead of the individual subscriber level.
====

A `PlanPolicy` works in conjunction with `AuthPolicy` and `RateLimitPolicy` custom resources (CRs) in the following sequence:

. An `AuthPolicy` CR authenticates a user request with stored identity metadata, including their plan information.
. The `PlanPolicy` object evaluates CEL predicate expressions against the authenticated identity to determine the user's plan tier.
. {prodname} then enforces the rate limits defined for the user-matched plan tier.
12 changes: 12 additions & 0 deletions modules/proc-ref-rhcl-planpolicy-known-limitations.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Module included in the following assemblies:
//
// *deployment/rhcl-planpolicy.adoc

:_mod-docs-content-type: REFERENCE
[id="ref-rhcl-planpolicy-known-limitations_{context}"]
= Known limitations

[role="_abstract"]
* A `PlanPolicy` object can only target HTTPRoutes, GRPCRoutes, and Gateways defined in the same namespace as the `PlanPolicy` object.
* Plan predicates are evaluated in order. More specific predicates must appear before more general ones to ensure correct plan assignment.
* Plan identification requires authentication to be configured through an AuthPolicy. Without an AuthPolicy, predicates that check `auth.identity` will not match.
82 changes: 82 additions & 0 deletions modules/proc-rhcl-authpolicy-verify.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Module included in the following assemblies:
//
// *deployment/rhcl-planpolicy.adoc

:_mod-docs-content-type: PROCEDURE
[id="proc-rhcl-authpolicy-verify_{context}"]
= Verifying the acceptance of the 'AuthPolicy' CR

[role="_abstract"]
You can confirm the acceptance of the `AuthPolicy` custom resource (CR) by running a few commands.

.Procedure

. Confirm that the `AuthPolicy` CR was accepted by checking its status by running the following command:
+
[source,terminal,subs="+quotes"]
----
$ oc get authpolicy _<sample_app.yaml>_ -n ${KUADRANT_GATEWAY_NS} -o jsonpath='{.status.conditions[?(@.type=="Accepted")].status}'
----
* Replace `_<sample_app.yaml>_` with the name of your application.
* Replace ${KUADRANT_GATEWAY_NS} with the namespace you used for this Connectivity Link deployment.
+
.Expected output
[source,terminal,subs="+quotes"]
----
True
----
. Check that your `AuthPolicy` has `Accepted` and `Enforced` status by running the following command:
+
[source,terminal,subs="+quotes"]
----
$ oc get authpolicy ${KUADRANT_GATEWAY_NAME}-auth -n ${KUADRANT_GATEWAY_NS} -o=jsonpath='{.status.conditions[?(@.type=="Accepted")].message}{"\n"}{.status.conditions[?(@.type=="Enforced")].message}'
----
* Replace 'KUADRANT_GATEWAY_NAME' with the name for your gateway in {product-title}.
* Replace 'KUADRANT_GATEWAY_NS' with the namespace for your gateway in {product-title}.
+
----
AuthPolicy has been accepted
AuthPolicy has been successfully enforced
----
+
. Confirm that all three API key secrets are present in the gateway namespace by running the following command:
+
[source,terminal,subs="+quotes"]
----
$ oc get secrets -n ${KUADRANT_GATEWAY_NS} -l app=_<sample_app.yaml>_
bronze-key Opaque 1 2 mins
gold-key Opaque 1 2 mins
----
* Replace 'KUADRANT_GATEWAY_NS' with the namespace for your gateway in {product-title}.
* Replace `_<sample_app.yaml>_` with the name of your application.
+Replace <your-api-hostname> with the host name for your API.
+
[source,terminal,subs="+quotes"]
----
$ $ curl -H 'Authorization: APIKEY _<gold_api_key_value>_' http://_<your_api_hostname>_/toy -i
----
* Replace _<gold_api_key_value>_ with with the actual API key string.
* Replace _<your-api-hostname>_ with the host name for your API.
+
.Expected output
[source,terminal,subs="+quotes"]
----
HTTP/1.1 401 Unauthorized
----
+
. Send a request with a valid API key and confirm that it succeeds by running the following command:
+
[source,terminal,subs="+quotes"]
----
$ curl -H 'Host: _<your-api-hostname>_' \
-H 'Authorization: APIKEY _<gold-api-key-value>_' \
http://_<gateway-hostname>_/toy -i
----
* Replace _<gold_api_key_value>_ with with the actual API key string.
* Replace _<gateway-hostname>_ with the host name for your API.
+
.Expected output
[source,terminal,subs="+quotes"]
----
HTTP/1.1 200 OK
----
52 changes: 52 additions & 0 deletions modules/proc-rhcl-configuring-authentication-planpolicy.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Module included in the following assemblies:
//
// *deployment/rhcl-planpolicy.adoc

:_mod-docs-content-type: PROCEDURE
[id="proc-rhcl-configuring-authentication-planpolicy_{context}"]
= Creating an AuthPolicy with API key authentication

[role="_abstract"]
You can configure API key authentication on a Gateway by deploying an AuthPolicy and creating per-plan API key secrets, so that {prodname} can identify which rate-limiting plan applies to each request.

.Prerequisites

* You installed {prodname}.
* You installed {oc-first}.
* You are logged in to your cluster.
* You created the `Gateway` and `HTTPRoute` objects for your deployment.

.Procedure

. Deploy an AuthPolicy that targets the Gateway and enables API key authentication by using the following example:
+
.Example API key AuthPolicy CR
[source,yaml,subs="+quotes"]
----
kind: AuthPolicy
metadata:
name: _<sample_app>_
namespace: ${KUADRANT_GATEWAY_NS}
spec:
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: ${KUADRANT_GATEWAY_NAME}
rules:
authentication:
"api-key-plan":
apiKey:
selector:
matchLabels:
app: _<sample_app>_
allNamespaces: true
credentials:
authorizationHeader:
prefix: APIKEY
----
* Replace `_<sample_app>_ ` with the name of your application.
* Replace 'KUADRANT_GATEWAY_NS' with the namespace for your gateway in {product-title}.
* Replace `KUADRANT_GATEWAY_NAME` with the name of your gateway in {product-title}.
+
* The `spec.rules.rules.authentication."api-key-plan".apiKey.selector.matchLabels` field value points to the API key `Secrets` objects that carry the `app: _<sample_app.yaml>_ label.
* Setting `spec.rules.rules.authentication."api-key-plan".apiKey.selector.allNamespaces: true` allows secrets from any namespace to be matched.
67 changes: 67 additions & 0 deletions modules/proc-rhcl-create-secrets.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Module included in the following assemblies:
//
// *deployment/rhcl-planpolicy.adoc

:_mod-docs-content-type: PROCEDURE
[id="proc-rhcl-create-secrets_{context}"]
= Creating API key `Secret` objects

[role="_abstract"]
You can create API key 'Secret` objects for each plan tier.

[IMPORTANT]
====
The following example creates API key `Secret` objects for each plan tier that you want to use. The following example uses API keys to authenticate the requests. Other options, such as OpenID Connect, might be more appropriate for production use. Use the "least-access" approach that is best for your use case.
====

.Procedure
. Create API key `Secret` objects for each plan tier that you want to use. Each `Secret` must carry the `authorino.kuadrant.io/managed-by: authorino` label and a `secret.kuadrant.io/plan-id` annotation that identifies the plan tier as shown in the following example:
+
.Example `Secret` object for plan tiers
[source,yaml,subs="+quotes"]
----
apiVersion: v1
kind: Secret
metadata:
name: gold-key
namespace: ${KUADRANT_DEVELOPER_NS}
labels:
authorino.kuadrant.io/managed-by: authorino
app: _<sample_app.yaml>_
annotations:
secret.kuadrant.io/plan-id: gold
stringData:
api_key: _<gold_api_key_value>_
type: Opaque
---
apiVersion: v1
kind: Secret
metadata:curl
name: silver-key
namespace: ${KUADRANT_GATEWAY_NS}
labels:
authorino.kuadrant.io/managed-by: authorino
app: _<sample_app.yaml>_
annotations:
secret.kuadrant.io/plan-id: silver
stringData:
api_key: _<silver_api_key_value>_
type: Opaque
---
apiVersion: v1
kind: Secret
metadata:
name: bronze-key
namespace: ${KUADRANT_GATEWAY_NS}
labels:
authorino.kuadrant.io/managed-by: authorino
app: _<sample_app.yaml>_
annotations:
secret.kuadrant.io/plan-id: bronze
stringData:
api_key: _<bronze_api_key_value>_
type: Opaque
----
* Replace 'KUADRANT_GATEWAY_NS' with the namespace for the object.
* Replace `_<sample_app.yaml>_ ` with the name of your application.
* Replace `_<gold_api_key_value>_`, `_<silver_api_key_value>_`, and `_<bronze_api_key_value>_` with the actual API key strings you want to assign to each tier.
99 changes: 99 additions & 0 deletions modules/proc-rhcl-deploying-planpolicy-rate-limiting.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Module included in the following assemblies:
//
// *deployment/rhcl-planpolicy.adoc

:_mod-docs-content-type: PROCEDURE
[id="proc-rhcl-deploying-planpolicy-rate-limiting_{context}"]
= Deploying plan-based rate limiting with a PlanPolicy

[role="_abstract"]
After you create your `AuthPolicy` and secrets, you can create a `PlanPolicy` object to enforce tiered rate limits on specific authenticated users.

[NOTE]
====
You can create a `PlanPolicy` object by using the {prodname} {ocp} web console plugin.
====

.Prerequisites

* You installed {prodname}
* You installed {oc-first}.
* You are logged in to your cluster.
* You created the `Gateway` and the `HTTPRoute` objects for your deployment.
* You configured API key-based authentication.

[NOTE]
====
A `PlanPolicy` can target and HTTPRoute, Gateway, or GRPCRoute.
====

.Procedure

. Apply your `PlanPolicy` object by running the following command:
+
[source,yaml,subs="+quotes"]
----
$ oc apply -f _<planpolicy.yaml>_
----
Replace _<planpolicy.yaml>_ with the name of the `PlanPolicy` object.

. Create a `PlanPolicy` object to enforce plan-based rate limits on the route by using the following example.
+
.Example PlanPolicy object
[source,yaml,subs="+quotes"]
----
apiVersion: extensions.kuadrant.io/v1alpha1
kind: PlanPolicy
metadata:
name: <sample_app_planpolicy.yaml>
namespace: ${KUADRANT_DEVELOPER_NS}
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: _<sample_app.yaml>_
plans:
- tier: gold
predicate: |
has(auth.identity) && auth.identity.metadata.annotations["secret.kuadrant.io/plan-id"] == "gold"
limits:
daily: 5
- tier: silver
predicate: |
has(auth.identity) && auth.identity.metadata.annotations["secret.kuadrant.io/plan-id"] == "silver"
limits:
daily: 2
- tier: bronze
predicate: |
has(auth.identity) && auth.identity.metadata.annotations["secret.kuadrant.io/plan-id"] == "bronze"
limits:
daily: 1
----
+
[NOTE]
====
The `PlanPolicy` object uses the `spec.plans.limits` parameter to enforce rate limits at the plan tier level instead of the individual subscriber level.
====
+
* Replace `_<sample_app.yaml>_` with the name of your application.
* Replace `_<sample_app_planpolicy.yaml>_ with the `PlanPolicy` object for your application.
* Replace 'KUADRANT_DEVELOPER_NS' with the namespace for your developer in {prodname}.
* Each `predicate` is a CEL expression. The predicates are evaluated in order, and the first matching plan is applied to the authenticated user.
+
[NOTE]
====
The CEL expressions can be anything that applies to your use case. You can use an expression different from the `secret.kuadrant.io/plan-id` expression.
====
+
* The `limits` field supports the following windows: `daily`, `weekly`, `monthly`, `yearly`, and `custom`. Custom limits take a `limit` value and a `window` duration string, for example:
+
[source,yaml]
----
limits:
daily: 100
weekly: 500
monthly: 2000
custom:
- limit: 10
window: "1m"
----
Loading