Skip to content

Commit

Permalink
Update doc/user-guides/secure-protect-connect.md (#374)
Browse files Browse the repository at this point in the history
* Update doc/user-guides/secure-protect-connect.md

Co-authored-by: Jason Madigan <[email protected]>

number and fix link

remove uneeded resolve

remove unneeded var

* enhancements to the secure-protect-connect user guide

---------

Co-authored-by: Guilherme Cassolato <[email protected]>
  • Loading branch information
maleck13 and guicassolato authored Dec 12, 2023
1 parent 0e08054 commit 0c65df1
Showing 1 changed file with 75 additions and 81 deletions.
156 changes: 75 additions & 81 deletions doc/user-guides/secure-protect-connect.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,39 @@
# Kuadrant Quick Start
# Secure, Protect and Connect services with Kuadrant

## Pre-requisites

- Completed the [single cluster quick start](https://docs.kuadrant.io/getting-started-single/)
- Completed the [Single-cluster Quick Start](https://docs.kuadrant.io/getting-started-single-cluster/)

## Overview
## Overview

In this guide, we will cover the different policies from Kuadrant and how you can use them to secure, protect and connect an istio controlled gateway in a single cluster and how you can set more refined protection on the HTTPRoutes exposed by that gateway.
In this guide, we will cover the different policies from Kuadrant and how you can use them to secure, protect and connect an Istio-controlled gateway in a single cluster, and how you can set more refined protection on the HTTPRoutes exposed by that gateway.

Here are the steps we will go through:

- [Deploy a sample application](#deploy-the-example-app-we-will-serve-via-our-gateway)
- [Define a new Gateway](#define-a-new-istio-managed-gateway)
- [Ensure TLS based secure connectivity to the gateway with `TLSPolicy`](#define-tlspolicy)
- [Define a default `RateLimitPolicy` to set some infrastructure limits on your gateway](#define-infrastructure-rate-limiting)
- [Define a default `AuthPolicy` to `Deny ALL` access to the gateway](#define-a-gateway-authpolicy)
- [Define `DNSPolicy` to bring traffic to the gateway](#define-dnspolicy)
- [Override the Gateway's Deny ALL `AuthPolicy`](#override-the-gateways-deny-all-authpolicy)
- [Override the Gateway `RateLimits`](#override-the-gateways-ratelimits)
1) [Deploy a sample application](#-deploy-the-example-app-we-will-serve-via-our-gateway)
2) [Define a new Gateway](#-define-a-new-istio-managed-gateway)
3) [Ensure TLS-based secure connectivity to the gateway with a TLSPolicy](#-define-the-tlspolicy)
4) [Define a default RateLimitPolicy to set some infrastructure limits on your gateway](#-define-infrastructure-rate-limiting)
5) [Define a default AuthPolicy to deny all access to the gateway](#-define-the-gateway-authpolicy)
6) [Define a DNSPolicy to bring traffic to the gateway](#-define-the-dnspolicy)
7) [Override the Gateway's deny-all AuthPolicy with an endpoint-specific policy](#-override-the-gateways-deny-all-authpolicy)
8) [Override the Gateway rate limits with an endpoint-specific policy](#-override-the-gateways-ratelimitpolicy)

To help with this walk through, you should set a `KUADRANT_ZONE_ROOT_DOMAIN` environment variable to a domain you want to use. If it you want to try DNSPolicy, this should also be a domain you have access to the DNS for in AWS Route53 or GCP. E.g.:

To help with this walk through, you should set a `KUADRANT_ZONE_ROOT_DOMAIN` environmental variable to a domain you want to use. If it you want to try `DNSPolicy` this should also be a domain you have access to the DNS for in `route53 or GCP`. Example:
```export KUADRANT_ZONE_ROOT_DOMAIN=my.domain.iown```
```sh
export KUADRANT_ZONE_ROOT_DOMAIN=my.domain.iown
```

### Deploy the example app we will serve via our gateway
### Deploy the example app we will serve via our gateway

`kubectl apply -f https://raw.githubusercontent.com/Kuadrant/kuadrant-operator/main/examples/toystore/toystore.yaml`
```sh
kubectl apply -f https://raw.githubusercontent.com/Kuadrant/kuadrant-operator/main/examples/toystore/toystore.yaml
```

### Define a new Istio managed gateway
### Define a new Istio-managed gateway

```
```sh
kubectl --context kind-kuadrant-local apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
Expand All @@ -54,15 +58,19 @@ spec:
EOF
```

If you take a look at the gateway status, you will see a TLS status error similar to the following:

If you take a look at the gateway status you will see a tls status error something like:
` message: invalid certificate reference /Secret/apps-hcpapps-tls. secret kuadrant-system/apps-hcpapps-tls not found`. This is because there is currently not TLS secret in place. Lets fix that with a `TLSPolicy`
```
message: invalid certificate reference /Secret/apps-hcpapps-tls. secret kuadrant-system/apps-hcpapps-tls not found
```

### Define TLSPolicy
This is because currently there is not a TLS secret in place. Let's fix that by creating a TLSPolicy.

Note: For convenience in the setup, we have setup a self signed CA as a cluster issuer on the kind cluster.
### ❸ Define the TLSPolicy

```
Note: For convenience, in the setup, we have created a self-signed CA as a cluster issuer in the Kubernetes cluster.

```sh
kubectl --context kind-kuadrant-local apply -f - <<EOF
apiVersion: kuadrant.io/v1alpha1
kind: TLSPolicy
Expand All @@ -81,24 +89,15 @@ spec:
EOF

kubectl wait tlspolicy api-gateway-tls -n kuadrant-system --for=condition=ready
```

Now if you look at the status of the gateway you will see the error is gone and the status of the policy you will see the listener is now secured with a tls certificate and the gateway is marked as affected by the tls policy. Our communication with our gateway is now secured via TLS. Note any new listeners will also be handled by the `TLSPolicy`
Now, if you look at the status of the gateway, you will see the error is gone, and the status of the policy will report the listener as now secured with a TLS certificate and the gateway as affected by the TLS policy.

Our communication with our gateway is now secured via TLS. Note that any new listeners will also be handled by the TLSPolicy.

Lets define a HTTPRoute and test our policy. We will re-use this with some of the other policies.



```
export INGRESS_PORT=$(kubectl get gtw api-gateway -o jsonpath='{.spec.listeners[?(@.name=="api")].port}' -n kuadrant-system)
export INGRESS_HOST=$(kubectl get gtw api-gateway -o jsonpath='{.status.addresses[0].value}' -n kuadrant-system)
export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
Let's define a HTTPRoute and test our policy. We will re-use this later on with some of the other policies as well.

```sh
kubectl --context kind-kuadrant-local apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
Expand Down Expand Up @@ -131,23 +130,21 @@ spec:
- name: toystore
port: 80
EOF
```

With this HTTPRoute in place the service we deployed later is exposed via the gateway. We should be able to access our endpoint via HTTPS:
With this HTTPRoute in place, the service we deployed is exposed via the gateway. We should be able to access our endpoint via HTTPS:

```
curl -k --resolve api.${KUADRANT_ZONE_ROOT_DOMAIN}:443:${INGRESS_HOST} "https://api.$KUADRANT_ZONE_ROOT_DOMAIN/cars"
```sh
export INGRESS_HOST=$(kubectl get gtw api-gateway -o jsonpath='{.status.addresses[0].value}' -n kuadrant-system)

curl -k --resolve api.${KUADRANT_ZONE_ROOT_DOMAIN}:443:${INGRESS_HOST} "https://api.$KUADRANT_ZONE_ROOT_DOMAIN/cars"
```

### Define Infrastructure Rate Limiting
### Define Infrastructure Rate Limiting

So we have a secure communications in place. But there is nothing limiting users from overloading our infrastructure and service components that will sit behind this gateway. Lets and a rate limiting layer to protect our services and infrastructure.
We have a secure communication in place. However, there is nothing limiting users from overloading our infrastructure and service components that will sit behind this gateway. Let's add a rate limiting layer to protect our services and infrastructure.

```
```sh
kubectl --context kind-kuadrant-local apply -f - <<EOF
apiVersion: kuadrant.io/v1beta2
kind: RateLimitPolicy
Expand All @@ -167,24 +164,22 @@ spec:
unit: second
EOF

kubectl wait ratelimitpolicy infra-ratelimit -n kuadrant-system --for=condition=available
```

The limit here is artificially low in order for us to show it working easily. Lets test it with our endpoint:
The limit here is artificially low in order for us to show it working easily. Let's test it with our endpoint:

```
```sh
for i in {1..10}; do curl -k --resolve api.${KUADRANT_ZONE_ROOT_DOMAIN}:443:${INGRESS_HOST} "https://api.$KUADRANT_ZONE_ROOT_DOMAIN/cars" && sleep 1; done
```

Here we should see `409s` start returning after the 5th request.
We should see `409`s start returning after the 5th request.

### Define a Gateway `AuthPolicy`
### Define the Gateway AuthPolicy

So communication is secured and we have some protection for our infrastructure, but we do not trust any client to access our endpoints. By default we want to allow only authenticated access. To protect our gateway we will add a `DENY ALL` `AuthPolicy`. Later we will override this with a specific `AuthPolicy` for the API.
Communication is secured and we have some protection for our infrastructure, but we do not trust any client to access our endpoints. By default, we want to allow only authenticated access. To protect our gateway, we will add a _deny-all_ AuthPolicy. Later, we will override this with a more specific AuthPolicy for the API.

```
```sh
kubectl --context kind-kuadrant-local apply -f - <<EOF
apiVersion: kuadrant.io/v1beta2
kind: AuthPolicy
Expand Down Expand Up @@ -215,19 +210,19 @@ spec:
EOF
```

Lets test again. This time we expect a `403`
Let's test it again. This time we expect a `403`.

```
```sh
curl -k --resolve api.${KUADRANT_ZONE_ROOT_DOMAIN}:443:${INGRESS_HOST} "https://api.$KUADRANT_ZONE_ROOT_DOMAIN/cars"
```

### Define DNSPolicy
(skip of you did not setup a DNS provider during the setup)
### ❻ Define the DNSPolicy

Now we have our gateway protected and communications secured, we are ready to configure DNS so it is easy for clients to connect and access the APIs we intend to expose via this gateway. Note during the setup of this walk through, we setup a `DNS Provider` secret and a `ManagedZone`.
(Skip this step if you did not configure a DNS provider during the setup.)

```
Now, we have our gateway protected and communications secured. We are ready to configure DNS, so it is easy for clients to connect and access the APIs we intend to expose via this gateway. Note that during the setup of this walk through, we created a DNS Provider secret and a ManagedZone resource.

```sh
kubectl --context kind-kuadrant-local apply -f - <<EOF
apiVersion: kuadrant.io/v1alpha1
kind: DNSPolicy
Expand All @@ -245,29 +240,27 @@ EOF
kubectl wait dnspolicy simple-dnspolicy -n kuadrant-system --for=condition=ready
```

If you want to see the DNSRecord created by the this policy, execute
If you want to see the DNSRecord created by the this policy, execute the following command:

```
```sh
kubectl get dnsrecord api-gateway-api -n kuadrant-system -o=yaml
```

So now we have a wildcard DNS record to bring traffic to our gateway.
So now we have a wildcard DNS record to bring traffic to our gateway.

Lets test again. This time we expect a `403` still as the DENY_ALL is still in effect. Notice we no longer need to set the Host header directly.


```
curl -k --resolve api.${KUADRANT_ZONE_ROOT_DOMAIN}:443:${INGRESS_HOST} "https://api.$KUADRANT_ZONE_ROOT_DOMAIN/cars" -i
Let's test it again. This time we expect a `403` still as the _deny-all_ policy is still in effect. Notice we no longer need to set the Host header directly.

```sh
curl -k "https://api.$KUADRANT_ZONE_ROOT_DOMAIN/cars" -i
```

### Override the Gateway's Deny ALL `AuthPolicy`
### Override the Gateway's deny-all AuthPolicy

Next we are going to allow authenticated access to our toystore API. To do this we will define an `AuthPolicy` that targets the `HTTPRoute`. Note that any new `HTTPRoutes` will still be effected by the gateway level policy but as we want users to now access this API we need to override the gateway policy. For simplicity we will use an API Key to allow access, but many other options are available.
Next, we are going to allow authenticated access to our Toystore API. To do this, we will define an AuthPolicy that targets the HTTPRoute. Note that any new HTTPRoutes will still be affected by the gateway-level policy, but as we want users to now access this API, we need to override that policy. For simplicity, we will use API keys to authenticate the requests, though many other options are available.

Lets define an API Key for user `bob` and `alice`
Let's define an API Key for users **bob** and **alice**.

```
```sh
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
Expand All @@ -281,7 +274,6 @@ metadata:
stringData:
api_key: IAMBOB
type: Opaque
---
apiVersion: v1
kind: Secret
Expand All @@ -296,11 +288,11 @@ stringData:
api_key: IAMALICE
type: Opaque
EOF
```
```

Now we will override the `AuthPolicy` to use API Keys:
Now, we will override the AuthPolicy to start accepting the API keys:

```
```sh
kubectl apply -f - <<EOF
apiVersion: kuadrant.io/v1beta2
kind: AuthPolicy
Expand All @@ -324,10 +316,9 @@ spec:
EOF
```

### Override the Gateway's RateLimits

So the gateway limits are good general set of limits. But as the developers of this API we know that we only want to allow a certain number of requests to specific users and a general limit for all other users
### ❽ Override the Gateway's RateLimitPolicy

The gateway limits are a good set of limits for the general case, but as the developers of this API we know that we only want to allow a certain number of requests to specific users, and a general limit for all other users.

```sh
kubectl apply -f - <<EOF
Expand Down Expand Up @@ -358,14 +349,17 @@ spec:
EOF
```

So here again just an example, we have given `bob` twice as many requests to use as everyone else.
As just another example, we have given **bob** twice as many requests to use compared to everyone else.

Let's test this new setup.

Lets test this new setup:
By sending requests as **alice**:

```sh
while :; do curl -k --resolve api.${KUADRANT_ZONE_ROOT_DOMAIN}:443:${INGRESS_HOST} --write-out '%{http_code}\n' --silent --output /dev/null -H 'Authorization: APIKEY IAMALICE' "https://api.$KUADRANT_ZONE_ROOT_DOMAIN/cars" | grep -E --color "\b(429)\b|$"; sleep 1; done
```

By sending requests as **bob**:

```sh
while :; do curl -k --resolve api.${KUADRANT_ZONE_ROOT_DOMAIN}:443:${INGRESS_HOST} --write-out '%{http_code}\n' --silent --output /dev/null -H 'Authorization: APIKEY IAMBOB' "https://api.$KUADRANT_ZONE_ROOT_DOMAIN/cars" | grep -E --color "\b(429)\b|$"; sleep 1; done
Expand Down

0 comments on commit 0c65df1

Please sign in to comment.