Skip to content

Commit

Permalink
Linkerd tutorial (#273)
Browse files Browse the repository at this point in the history
Co-authored-by: Ori Shoshan <ori@otterize.com>
  • Loading branch information
evyatarmeged and orishoshan authored Jan 26, 2025
1 parent 61aae4a commit 74c141a
Show file tree
Hide file tree
Showing 18 changed files with 531 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ other-client-74cc54f7b5-9rctd 2/2 Running 0 32s

</details>

monitor both client attempts to call the server with additional terminal windows,
Monitor both client attempts to call the server with additional terminal windows,
so we can see the effects of our changes in real time.

2. **Open a new terminal window [client]** and tail the client log:
Expand Down Expand Up @@ -205,7 +205,7 @@ NAME AGE
authorization-policy-to-nginx-from-client.otterize-tutorial-istio 6s
```

If you've attached Otterize OSS to Otterize Cloud, go back to see the [access graph in your browser](https://app.otterize.com):
Go back to see the [access graph in your browser](https://app.otterize.com):

![Access graph](/img/quick-tutorials/k8s-istio-authorization-policies/protected.png)

Expand Down
2 changes: 1 addition & 1 deletion docs/features/istio/tutorials/k8s-istio-watcher.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ For a complete list of the CLI capabilities read the [CLI command reference](/re

### Show the access graph in Otterize Cloud

If you've attached Otterize OSS to Otterize Cloud, you can now also see the [access graph in your browser](https://app.otterize.com):
You can now see the [access graph in your browser](https://app.otterize.com):

![Access graph](/img/quick-tutorials/network-mapper/otterize-tutorial-access-graph-istio.png)

Expand Down
2 changes: 1 addition & 1 deletion docs/features/kafka/tutorials/k8s-kafka-mapping.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ client-2 in namespace otterize-tutorial-kafka-mapping calls:
- Kafka topic: mytopic, operations: [produce describe]
```

If you've attached Otterize OSS to Otterize Cloud, go back to see the [access graph in your browser](https://app.otterize.com).
Go back to see the [access graph in your browser](https://app.otterize.com).
**To only see Kafka information**, make sure to de-select the 'Use in access graph' settings for network policies and Istio policies, and leave Kafka ACLs selected, like so:
![Access graph settings](/img/quick-tutorials/kafka-mapping/settings.png)

Expand Down
8 changes: 8 additions & 0 deletions docs/features/linkerd/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"label": "Linkerd",
"position": 7,
"collapsed": true,
"customProps": {
"image": "/img/icons/linkerd-no-word-mark.svg"
}
}
52 changes: 52 additions & 0 deletions docs/features/linkerd/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
sidebar_position: 1
title: Linkerd | Overview
hide_title: true
---

import DocsLinkCard from "@site/src/components/LinkCard";

export const tutorials = [
{
title: 'Linkerd AuthorizationPolicy automation',
description: 'Generate AuthorizationPolicy docs from existing connections',
url: '/features/linkerd/tutorials/linkerd-authorization-policies'
},
];

# Linkerd
Otterize can enforce access between services using Linkerd Authorization Policies.

### Tutorials

To learn how to use the Intents Operator to enforce access using Linkerd authorization policies. Try the quickstart tutorial below.

<DocsLinkCard items={tutorials} colSize={"sm"}/>


### How does Otterize work with Linkerd?

1. First, the cluster must have [Otterize installed](/overview/installation).
2. To have Otterize generate Linkerd authorization policies, declare and apply ([IBAC](/overview/intent-based-access-control)) ClientIntents for your services.
Once you do so, Otterize will generate a Linkerd authorization policy allowing access from the client service, identified by its service account, to the server, identified by a Linkerd Server resource.
The HTTP Resources section in the ClientIntents is optional: if you do not specify it, all pod-to-pod access is allowed.

```yaml

apiVersion: k8s.otterize.com/v1alpha3
kind: ClientIntents
metadata:
name: client
namespace: otterize-tutorial-linkerd
spec:
service:
name: client
calls:
- name: server-abc
type: http
HTTPResources:
- path: /client-path
methods: [ GET ]

```

5 changes: 5 additions & 0 deletions docs/features/linkerd/tutorials/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"label": "Tutorials",
"position": 2,
"collapsed": false
}
265 changes: 265 additions & 0 deletions docs/features/linkerd/tutorials/linkerd-authorization-policies.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
---
sidebar_position: 3
title: Linkerd AuthorizationPolicy automation
image: /img/quick-tutorials/k8s-linkerd-authorization-policies/social.png
---

import CodeBlock from "@theme/CodeBlock";
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

Otterize automates mTLS-based, HTTP-level pod-to-pod access control with Linkerd authorization (authZ) policies, within your Kubernetes cluster.

Implementing this kind of access control with Linkerd can be challenging.
For example, each target server needs a matching `Server` resource, `MeshTLSAuthentication` resources need to be created & matched with identities
in order to use mTLS based authorization policies, etc. Using Otterize `ClientIntents`, this is all managed for you.

To help you avoid manually managing complicated authorization policies per server, Otterize implements **intent-based access control** (IBAC).
You just declare what calls the client pods intend to make,
and everything is automatically wired together so only intended calls are allowed.

In this tutorial, we will:

- Deploy a Linkerd demo application with two client pods and one server pod.
- Declare that the first client intends to call the server with a specific HTTP path and method.
- See that a Linkerd `Server` resource was created for our target, a `MeshTLSAuthentication` resource was created for our client, and an `AuthorizationPolicy` was autogenerated to allow that traffic, and to block the (undeclared) calls from the other client.

## Prerequisites

### 1. Install Linkerd
Install Linkerd by following the [Installing Linkerd](https://linkerd.io/2-edge/tasks/install/) tutorial.

### 2. Deploy Otterize
If you do not have a cluster, we will need to prepare one with [network policy support](/overview/installation#create-a-cluster-with-support-for-network-policies)

To deploy Otterize, head over to [Otterize Cloud](https://app.otterize.com) and associate a Kubernetes cluster on the [Integrations page](https://app.otterize.com/integrations), and follow the instructions. If you already have a Kubernetes cluster connected, skip this step.

Otterize should be deployed with enforcement on.

## Tutorial

### Deploy the two clients and the server

Deploy a simple example consisting of `client` and `other-client` calling `nginx` over HTTP:

```shell
curl ${ABSOLUTE_URL}/code-examples/linkerd-authorization-policies/all.yaml | linkerd inject - | kubectl apply -f -
```

Notice we use `linkerd inject` from Linkerd's CLI beforce we apply our resources to Kubernetes, to include them as part of the mesh.

### Apply intents

We will now declare that the **client** intends to call the **server** at a particular HTTP path using a specific HTTP method.

When the intents YAML is applied, creating a custom resource of type `ClientIntents`,
Otterize will start creating Linkerd resources to enable the intended access and to block non-declared access:
1. A `Server` resource is created for the target in the `ClientIntents` (if required). A `Server` resource represents a service in the mesh that listens for incoming requests. It's configured to define the service's protocol, port, and other relevant settings.
2. A `MeshTLSAuthentication` resource that is used to represent mesh identities, which will be created for our client.
3. An `HTTPRoute` that will represent a single path, allowing for more fine-grained enforcement. This will be attached to the `Server` resource.
4. Finally, an `AuthorizationPolicy` to bind it all together - enabling the intended traffic from
(**client** &rarr; **server** with the declared path and method) and block all unintended calls (e.g., **client-other** &rarr; **server**).

:::tip

You can click on the services or the lines connecting them to see which ClientIntents you need to apply to make the connection go green!

:::

1. Here is the `intents.yaml` declaration of the client, which we will apply below:

```yaml
{@include: ../../../../static/code-examples/linkerd-authorization-policies/intents.yaml}
```

To apply it, use:
```shell
kubectl apply -n otterize-tutorial-linkerd -f ${ABSOLUTE_URL}/code-examples/linkerd-authorization-policies/intents.yaml
```
### See it in action

<details>
<summary>Optional: check deployment status</summary>
Check that the client and server pods were deployed

```bash
kubectl get pods -n otterize-tutorial-linkerd
```

You should see

```
NAME READY STATUS RESTARTS AGE
client-68b775f766-749r4 2/2 Running 0 32s
nginx-c646898-2lq7l 2/2 Running 0 32s
other-client-74cc54f7b5-9rctd 2/2 Running 0 32s
```

</details>

Monitor both client attempts to call the server with additional terminal windows,
so we can see the effects of our changes in real time.

2. **Open a new terminal window [client]** and tail the client log:

```bash
kubectl logs -f --tail 1 -n otterize-tutorial-linkerd deploy/client
```

<details>
<summary>Expected output</summary>

At this point the client should be able to communicate with the server:

```
Calling server...
HTTP/1.1 200 OK
...
hello from /client-path
```

</details>

3. **Open another terminal window [client-other]** and tail the other-client log:

```bash
kubectl logs -f --tail 1 -n otterize-tutorial-linkerd deploy/other-client
```

<details>
<summary>Expected output</summary>

At this point the client should be able to communicate with the server:

```
Calling server...
HTTP/1.1 200 OK
...
hello from /other-client-path
```

</details>

Keep an eye on the logs being tailed in the **[other-client]** terminal window,
and apply this `intents.yaml` file in your **main terminal window** using:

```shell
kubectl apply -f ${ABSOLUTE_URL}/code-examples/linkerd-authorization-policies/intents.yaml
```

:::tip
Client intents are the cornerstone of [intent-based access control (IBAC)](/overview/intent-based-access-control).
::: 2. You should quickly see in the **[other-client]** terminal that it times out when calling the server,
as expected since it didn't declare its intents:

```bash
Calling server...
HTTP/1.1 200 OK
...
hello from /other-client-path # <- before applying the intents file
# highlight-start
Calling server... # <- after applying the intents file
curl timed out
Terminated
# highlight-end
```

3. And in the **[client]** terminal you should see that calls go through, as expected since they were declared:

```bash
Calling server...
HTTP/1.1 200 OK
...
hello from /client-path
```


### View it in the cloud
Go back to see the [access graph in your browser](https://app.otterize.com):

![Access graph](/img/quick-tutorials/linkerd/linkerd.png)

And upon clicking the green arrow:
![Access graph](/img/quick-tutorials/linkerd/linkerd_viz.png)

It's now clear what happened:

1. The server is now protected, and is also blocking some of its clients.
2. Calls from **[client]** &rarr; **[nginx]** are declared and therefore allowed (green arrow).
3. Calls from **[client-other]** &rarr; **[nginx]** are not declared and therefore blocked (red arrow). Click on the arrow to see what to do about it.

:::tip Done!
Otterize did its job of both protecting the server _and_ allowing intended access.
:::

### What did we accomplish?

Controlling access through Linkerd authorization policies no longer means having to write AuthorizationPolicies, Server, MeshTLSAuth or HTTPRoute resources.

Otterize generated a specific Linkerd authorization policy on the ingress of the pod of the server, allowing the server to
be accessed by the pod of the client, based on that client's declared intent. Otterize automated the creation of a `Server` resource
and its pairing with the target server through labels, the creation of a `MeshTLSAuthentication` resource and its pairing with the client's service account,
and binding it all to an `AuthorizationPolicy` to protect the server and allow only intended access.

Otterize saved us from doing all this work: by simply declaring the client's intents in `intents.yaml`,
all the appropriate configuration was managed automatically behind the scenes.

Have a look at the Linkerd resources that Otterize automatically generated:

<Tabs>

<TabItem value="server.yaml" label="Server" default>

This represents a server in the mesh that listens for incoming requests. It's configured to define the service's protocol, port, and other relevant settings.
Matched with the target pod using label selectors, autogenerated by Otterize.

```yaml
{@include: ../../../../static/code-examples/linkerd-authorization-policies/resources/server.yaml}
```

</TabItem>

<TabItem value="meshtlsauth.yaml" label="MeshTLSAuthentication" default>

Otterize pairs `MeshTLSAuthentication` with the client workload's service account.

```yaml
{@include: ../../../../static/code-examples/linkerd-authorization-policies/resources/meshtlsauth.yaml}
```

</TabItem>
<TabItem value="httproute.yaml" label="HTTPRoute" default>

An HTTPRoute defines a set of rules which match HTTP requests to that resource. It is attached to a "parent" resource - in this case, the previously created `Server` resource.

```yaml
{@include: ../../../../static/code-examples/linkerd-authorization-policies/resources/httproute.yaml}
```

</TabItem>
<TabItem value="authpolicy.yaml" label="AuthorizationPolicy" default>

Which binds it all together and mentions the `HTTPRoute` or `Server` (The thing to be authorized) and the `MeshTLSAuthentication` (the clients that have autorization).

```yaml
{@include: ../../../../static/code-examples/linkerd-authorization-policies/resources/authpolicy.yaml}
```

</TabItem>

</Tabs>



:::tip Bonus tutorial
Try to create an intents file yourself for **client-other**, and apply it to allow this other client to call the server.
:::

## Teardown

To remove Linkerd and the deployed examples run:

```bash
kubectl delete namespace otterize-tutorial-linkerd
linkerd uninstall | kubectl delete -f -
```
5 changes: 5 additions & 0 deletions docs/getting-started/README.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ export const features = [
icon: '/img/icons/istio-no-word-mark.svg',
url: '/features/istio/'
},
{
title: 'Linkerd',
icon: '/img/icons/linkerd-no-word-mark.svg',
url: '/features/linkerd'
},
{
title: 'GitHub',
icon: '/img/icons/github-logo.svg',
Expand Down
Loading

0 comments on commit 74c141a

Please sign in to comment.