Skip to content

Commit

Permalink
Merge pull request #62 from jasonmadigan/82-dev-spaces-oas
Browse files Browse the repository at this point in the history
OAS generation and Dev Spaces
  • Loading branch information
david-martin authored Mar 14, 2024
2 parents 5069fe3 + fd620bc commit 7296e1b
Showing 1 changed file with 351 additions and 0 deletions.
351 changes: 351 additions & 0 deletions doc/openapi-openshift-dev-spaces.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,351 @@
# Integrating Kuadrant OAS Extensions with Red Hat OpenShift Dev Spaces

[OpenAPI Extensions](https://swagger.io/docs/specification/openapi-extensions/) enhance the standard OpenAPI specification by adding custom functionality. Kuadrant OpenAPI extensions, identified by the prefix `x-kuadrant`, allow the integration of Kuadrant policies directly within your API specs.

[Red Hat OpenShift Dev Spaces](https://developers.redhat.com/developer-sandbox/ide) offers a browser-based, cloud-native IDE that supports rapid and decentralized development within container-based environments. This tutorial demonstrates how to use OpenShift Dev Spaces to modify an OpenAPI specification by incorporating Kuadrant policies and then employ `kuadrantctl` to create Kubernetes resources for both Gateway API and Kuadrant.


To follow along, you'll need access to a Dev Spaces instance. This can be either:

- A self-hosted instance.
- An instance provided through the [Red Hat Developer Sandbox](https://developers.redhat.com/developer-sandbox/ide).

## Setting up your Workspace

First, create a Workspace in Dev Spaces for your project:

1. Fork the following repository: [https://github.com/Kuadrant/blank-petstore](https://github.com/Kuadrant/blank-petstore).
2. In Dev Spaces, select `Create Workspace`, enter the URL of your forked repository (e.g., `https://github.com/<your-username>/blank-petstore.git`), and then click `Create & Open`.

## Configuring VSCode in Dev Spaces

For this tutorial, we'll:

- Install `kuadrantctl` within your workspace to demonstrate Kubernetes resource generation from your modified OpenAPI spec.
- (Optionally) Configure `git` with your username and email to enable pushing changes back to your repository.


### `kuadrantctl` installation

To install `kuadrantctl` in your Dev Spaces workspace, execute the following command:

```bash
curl -sL "https://github.com/kuadrant/kuadrantctl/releases/download/v0.2.0/kuadrantctl-v0.2.0-linux-amd64.tar.gz" | tar xz -C /home/user/.local/bin
```

This will place `kuadrantctl` in `/home/user/.local/bin`, which is included in the container's `$PATH` by default.

### Configuring Git (Optional)

If you plan to push changes back to your repository, configure your git username and email:

```bash
git config --global user.email "[email protected]"
git config --global user.name "Foo Example"
```

## Editing Your OpenAPI Spec

Upon creating your workspace, Dev Spaces will launch VSCode loaded with your forked repository. Navigate to the `openapi.yaml` file within the sample app to begin modifications.

### Kuadrant Policies Introduction

We'll enhance our API spec by applying Kuadrant policies to the following endpoints:

`/pet/findByStatus`
`/user/login`
`/store/inventory`

In this tutorial, we're going to introduce some Kuadrant policies via this OAS. We will:

- Generate a `HTTPRoute` to expose these three routes for an existing Gateway API `Gateway`
- Add API key authentication for the `/user/login` route, using Kuadrant's `AuthPolicy` API and OAS' `securitySchemes`
- Add a Kuadrant `RateLimitPolicy` to the `/store/inventory` endpoint, to limit the amount of requests this endpoint can receive

### Defining a Gateway

Utilize the `x-kuadrant` extension in the `info` block to specify a `Gateway`. This information will be used to generate `HTTPRoute`s at the path level:

For example:

```yaml
info:
x-kuadrant:
route: ## HTTPRoute metadata
name: "petstore"
namespace: "petstore"
labels: ## map[string]string
deployment: petstore
hostnames: ## []gateway.networking.k8s.io/v1beta1.Hostname
- example.com
parentRefs: ## []gateway.networking.k8s.io/v1beta1.ParentReference
- name: apiGateway
namespace: gateways
```
Add this extension to the `info` section.


### Specifing `HTTPRoute`'s for each Path

For each path, add an `x-kuadrant` extension with `backendRefs` to link our routes to our paths:


```yaml
/pet/findByStatus:
x-kuadrant:
backendRefs:
- name: petstore
namespace: petstore
port: 8080
get:
# ...
```

```yaml
/user/login:
x-kuadrant:
backendRefs:
- name: petstore
namespace: petstore
port: 8080
get:
# ...
```

```yaml
/store/inventory:
x-kuadrant:
backendRefs:
- name: petstore
namespace: petstore
port: 8080
get:
# ...
```

**Note:** The `x-kuadrant` extension at the path level applies to all HTTP methods defined within. For method-specific policies, move the extension inside the relevant HTTP method block (e.g., `get`, `post`).


### Implementing `AuthPolicy` and Security Schemes

To secure the `/user/login` endpoint with API key authentication, use the following configuration:

```yaml
/user/login:
# ...
get:
security:
- api_key: []
```


```yaml
components:
schemas:
# ...
securitySchemes:
api_key:
type: apiKey
name: api_key
in: header
```

This configuration generates an `AuthPolicy` that references an API key stored in a labeled `Secret`:

```yaml
apiVersion: v1
kind: Secret
metadata:
name: petstore-api-key
namespace: petstore
labels:
authorino.kuadrant.io/managed-by: authorino
kuadrant.io/apikeys-by: api_key
stringData:
api_key: secret
type: Opaque
```

We don't recommend using a simple, static API key for your app, but will do so for this tutorial for the sake of simplicity.


### Applying a `RateLimitPolicy` to an Endpoint


To enforce rate limiting on the `/store/inventory` endpoint, add the following `x-kuadrant` extension:

```yaml
/store/inventory:
get:
# ...
x-kuadrant:
backendRefs:
# ...
rate_limit:
rates:
- limit: 10
duration: 10
unit: second
```

This limits requests to 10 every 10 seconds for the `/store/inventory` endpoint.

## `kuadrantctl` and Kubernetes resource generation

With our extensions in place, let's use `kuadrantctl` to generate some Kubernetes resources, including:

- An `HTTPRoute` for our petstore app for each of our endpoints
- An `AuthPolicy` with a simple, static API key from a secret for the `/user/login` endpoint
- A `RateLimitPolicy` with a rate limit of 10 requests every 10 seconds for the `/store/inventory` endpoint

Open a new terminal in Dev Spaces, and run the following.

```bash
kuadrantctl generate gatewayapi httproute --oas openapi.yaml | yq -y
```

Outputs:

```yaml
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
name: petstore
namespace: petstore
creationTimestamp: null
labels:
deployment: petstore
spec:
parentRefs:
- namespace: gateways
name: apiGateway
hostnames:
- example.com
rules:
- matches:
- path:
type: Exact
value: /api/v3/pet/findByStatus
method: GET
backendRefs:
- name: petstore
namespace: petstore
port: 8080
- matches:
- path:
type: Exact
value: /api/v3/store/inventory
method: GET
backendRefs:
- name: petstore
namespace: petstore
port: 8080
- matches:
- path:
type: Exact
value: /api/v3/user/login
method: GET
backendRefs:
- name: petstore
namespace: petstore
port: 8080
status:
parents: null
```


```bash
kuadrantctl generate kuadrant authpolicy --oas openapi.yaml | yq -y
```

Outputs:

```yaml
apiVersion: kuadrant.io/v1beta2
metadata:
name: petstore
namespace: petstore
creationTimestamp: null
labels:
deployment: petstore
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: petstore
namespace: petstore
routeSelectors:
- matches:
- path:
type: Exact
value: /api/v3/user/login
method: GET
rules:
authentication:
GETuserlogin_api_key:
credentials:
customHeader:
name: api_key
apiKey:
selector:
matchLabels:
kuadrant.io/apikeys-by: api_key
routeSelectors:
- matches:
- path:
type: Exact
value: /api/v3/user/login
method: GET
status: {}
```


```bash
kuadrantctl generate kuadrant ratelimitpolicy --oas openapi.yaml | yq -y
```

Outputs:

```yaml
apiVersion: kuadrant.io/v1beta2
metadata:
name: petstore
namespace: petstore
creationTimestamp: null
labels:
deployment: petstore
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: petstore
namespace: petstore
limits:
GETstoreinventory:
routeSelectors:
- matches:
- path:
type: Exact
value: /api/v3/store/inventory
method: GET
rates:
- limit: 10
duration: 10
unit: second
status: {}
```

You can now apply these policies to a running app via `kubectl` or `oc`.

If you've completed the optional `git` configuration step above, you can now `git commit` the changes above and push these to your fork.

# Next

Here are some extra documentation on using `x-kuadrant` OAS extensions with `kuadrantctl`:

- [Guide to `kuadrantctl` and OAS extensions](./openapi-kuadrant-extensions.md)
- [Generating Gateway API HTTPRoutes with `kuadrantctl`](./generate-gateway-api-httproute.md)
- [Generating Kuadrant AuthPolicy with `kuadrantctl`](./generate-kuadrant-auth-policy.md)
- [Generate Kuadrant RateLimitPolicy with `kuadrantctl`](./generate-kuadrant-rate-limit-policy.md)

0 comments on commit 7296e1b

Please sign in to comment.