Skip to content

Commit

Permalink
Edits of the Istio visual tutorial.
Browse files Browse the repository at this point in the history
  • Loading branch information
usarid committed Jun 25, 2023
1 parent c4ac0bd commit 113f8e0
Showing 1 changed file with 70 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import TabItem from '@theme/TabItem';
Istio authorization policies are a powerful and flexible tool, but using them to achieve a zero-trust architecture with fine-grained pod-to-pod access control can be difficult to implement and maintain.

In this tutorial, we will show you how to roll out Istio authorization policies with intent-based access control (IBAC).
With IBAC, you won't need to manually keep track of pod labels or service accounts. You won't need to manage Istio authorization policies at all — they'll be generated and managed automatically! We'll even show you how to generate policies for all discovered traffic in the cluster with just one command.
With IBAC, you won't need to manually keep track of pod labels or service accounts. You won't need to manage Istio authorization policies at all — they'll be generated and managed automatically. We'll even show you how to generate policies for all discovered traffic in the cluster with just one command.

By the end of this tutorial, each server in the cluster will only allow the incoming calls declared by client services in their client intents files, and block any undeclared (unintentional) calls. Call declarations, and the authorization policies they'll generate, will specify not just the server but also the HTTP path and method.
By the end of this tutorial, each server in the cluster will only allow the incoming calls declared by client services in their client intents files, and block any undeclared (unintended) calls. Call declarations, and the authorization policies they'll generate, will be specific not just down to the server but also to the HTTP path and method.

All the capabilities of IBAC for Istio are within Otterize OSS, while the access graph in Otterize Cloud will guide us
visually in these steps and support us in the process of zero trust adoption in our cluster without breaking anything.
Expand Down Expand Up @@ -63,12 +63,15 @@ Before you start, you'll need a Kubernetes cluster. Having a cluster with a [CNI

</details>

<details>
<summary>Enhance Istio Exported Metrics with HTTP Methods and Request Paths</summary>
:::tip
HTTP request paths and methods aren't exported in Envoy's connection metrics by default, but we do want to capture those
details when creating the network map. That way we not only have better visibility of the calling patterns,
e.g. in the access graph, but we can also use that information to automatically capture fine-grained intents and
use them to generate Istio authorization policies.
:::

After successfully installing Istio, we can enrich Otterize Network Mapper with Envoy metrics information to
include HTTP resource access details in the network map. However, HTTP requests data isn't logged by default, so we
need to enable it ourselves.
<details>
<summary>Enhance Istio exported metrics with HTTP methods and request paths</summary>

Apply this configuration in the `istio-system` namespace, propagating it to all namespaces covered by the mesh.

Expand All @@ -82,13 +85,6 @@ kubectl apply -f https://docs.otterize.com/code-examples/network-mapper/istio-te

</details>

:::tip
HTTP request paths and methods aren't exported in Envoy's connection metrics by default, but we do want to capture those
details when creating the network map. That way we not only have better visibility of the calling patterns,
e.g. in the access graph, but we can also use that information to automatically capture fine-grained intents and
use them to generate Istio authorization policies.
:::

## Deploy demo to simulate traffic
<details>
<summary>Create a namespace for our demo application and label it for Istio injection</summary>
Expand All @@ -109,8 +105,8 @@ kubectl apply -n otterize-visual-tutorial-istio -f https://docs.otterize.com/cod

## Seeing the access graph

In the Clusters table at Otterize Cloud UI, your [cluster](https://app.otterize.com/clusters) should be displaying all three Otterize OSS
operators &mdash; the intents operator, network mapper, and credentials operator. They should all be in connected state, indicated by a green dot.
In the Otterize Cloud web app, within the [Clusters tab](https://app.otterize.com/clusters), your cluster should be displaying all three Otterize OSS
operators &mdash; the intents operator, network mapper, and credentials operator &mdash; in the green connected state.

![Access graph](/img/quick-tutorials/istio-visual-tutorial/cluster-connected.png)

Expand All @@ -121,61 +117,62 @@ You should see the map for the demo running in your cluster:

Each service is shown as a node in the access graph, while the dashed lines (edges) connecting the services show access between them, as detected by the network mapper.

The lines are dashed because the client services are missing intent declarations: we've discovered their intents to call the servers, but they haven't declared those intents.
The lines are dashed because the client services are missing intent declarations: we've *discovered* their intents to call the servers, but they haven't *declared* those intents.

Otterize can manage few enforcement mechanisms, but not every cluster will have all of them. Each view take into account
its relevant implementation details and weather communication is enabled by default or not.
In this case, we are using Istio authorization policies, so we need to adjust the access graph view to take into account
Istio authorization policies, so turn on the Istio policies "Use in access graph" toggle and turn off the network
policies and Kafka ACLs toggle buttons.
Otterize can manage several, and the access graph can take into account their state. For this demo, we're only using Istio authorization policies, so let's adjust the access graph view to only take them into account: in the Istio policies section at the top, toggle on "Use in access graph"; and in the sections for network
policies and Kafka ACLs, toggle off "Use in access graph".

![Access graph](/img/quick-tutorials/istio-visual-tutorial/access-graph-panel.png)

:::danger
Presumably there was something that should be shown once you adjust the toggles as above? I suggest you indicate what that is, and show it here.
:::

## Try out IBAC with shadow mode

Our mission in this tutorial is to achieve zero trust in our cluster, but we don't want to break anything in the process.
One of the biggest challenges in doing so is that Istio authorization policies, like network policies and Kafka ACLs, doesn't
have the ability to let us know what would be blocked *before* we actually block it.
One of the biggest challenges in doing so is that Istio authorization policies, like network policies and Kafka ACLs, can't let us know what would be blocked *before* we actually block it.

Otterize solves this problem by providing a Shadow mode enforcement. In shadow mode, Otterize doesn't actually generate
access controls (in this case, Istio authorization policies) from client intents declarations. Nothing is actually blocked
and the access graph will help us understand what would happen if we were to enable enforcement.
Otterize solves this problem by providing a "shadow mode" enforcement. In shadow mode, Otterize doesn't actually generate
Istio authorization policies from client intents declarations, so nothing is actually blocked.
But Otterize still sees any intent declarations that *would* generate policies, so the access graph can preview what access would be blocked or enabled if we were to generate policies (actual enforcement).

## Choose a first service to protect

There are many services in the demo, but we will pick one and manually protect it before we will automate the process
for the whole cluster. We will start with the `recommendationservice` service, so first find it in the graph, you can
type its name in the search box and select it, the graph will zoom in on it:
Let's pick one service and manually protect it before automating the process for the whole cluster. We will start with the `recommendationservice`. Find it in the access graph, e.g. by typing its name in the search box and selecting it, and the graph will zoom in on it:

![Access graph](/img/quick-tutorials/istio-visual-tutorial/recommendation-graph-phase-0.png)

Now, click on the `recommendationservice` service to see the details panel:
Click on the `recommendationservice` service to see more details:

![Access graph](/img/quick-tutorials/istio-visual-tutorial/recommendation-service-phase-0.png)

On the left panel the state of this service as a server is presented. You can see that this service is unprotected, but
since there are no intents declared for it, it won't block any access even if we enable enforcement - as long as there is
no default `allow nothing` authorization policy in the cluster. On the right panel, the state of this service as a client
is presented, it's not expected to be blocked by any authorization policy either.
At the bottom of this panel, you can see this service as a server (on the left) receiving requests, and as a client (on the right) sending requests.

At the bottom part of panel we can see that this service is called by the `frontend`
service and uses the `GET` method to access the `/recommendations` resource. Let's click the dashed line from `frontend`
As a server, you can see that this service is currently unprotected: Why?
- There is no default `allow nothing` authorization policy configured for the cluster, as we informed the graph in the "Istio policies" section at the top right. That's appropriate for our situation: we want to roll out protection one service at a time, without breaking access to the others.
- The first authorization policy would protect this server, but no policies would be created for it if enforcement were turned on, since no clients have declared their intents to call it. We'll do that in the next step.

At the very bottom of the server section, we can see that this service is called by the `frontend`
service, which uses the `GET` method to access the `/recommendations` resource. Let's click the dashed line from `frontend`
to `recommendationservice` to see the details of the access:

![Access graph](/img/quick-tutorials/istio-visual-tutorial/frontend-recommendation-phase-0.png)

On the left there is a discovered intent for those two services, but it is not declared.
We see that the network mapper *discovered* the intent by the `frontend` to `GET` `/recommendations` on the `recommendationservice`, but the `frontend` did not *declare* it.

(Note also that, as a client, we see the `recommendationservice` not being blocked by any authorization policy either.)

## Make it intentional!
## Declare your intentions!

Now we will take the intent we just discovered and make intentional by declaring that the `frontend` service intends to
call the `recommendationservice` by sending `GET` requests to the HTTP resource at `/recommendations`:
As suggested by the access graph, we will now take the intent we just *discovered* and *declare* that the `frontend` service intends to
call the `recommendationservice` via `GET` requests to the HTTP resource at `/recommendations`:

```yaml
{@include: ../../static/code-examples/ibac-for-istio/phase-1.yaml}
```

We expect this will provide secure access, allowing the intended access from the `frontend` while protecting the `recommendationservice` from unintended access.
We expect this will eventually provide secure access: **allowing** the intended access from the `frontend`, while **protecting** the `recommendationservice` from unintended access (since it will now have an authorization policy on it). Why eventually? Because we'll still need to go from shadow mode to actual enforcement, after getting the reassurance we need.

Apply the above client intents file with:
```bash
Expand All @@ -186,24 +183,33 @@ Look at the access graph again:

![Access graph](/img/quick-tutorials/istio-visual-tutorial/phase-1.png)

The green line from `frontend` to `recommendationservice`, representing the discovered intent from the network mapper, is no longer dashed, but rather **solid**: the access we discovered was needed has now been declared.
The green line from `frontend` to `recommendationservice` is no longer dashed, but rather **solid**: the desired access we discovered has now been declared.

Click on that `frontend` &rarr; `recommendationservice` line:
Click on that solid `frontend` &rarr; `recommendationservice` line:
<img src="/img/quick-tutorials/istio-visual-tutorial/frontend-recommendation-applied.png" alt="Discovered intents" width="600"/>

- We can see the `frontend` calls the `recommendationservice`, and has declared that intent, so it will be guaranteed access even once enforcement is turned on.
We can see the discovered intent to access is also declared, so it will be guaranteed access even after enforcement is turned on.

Click on the `recommendationservice` itself:
<img src="/img/quick-tutorials/istio-visual-tutorial/recommendation-access-state.png" alt="Discovered intents" width="600"/>

Few more notes:
The access graph shows us:

- We can see this service is not currently protected: after all, we're in shadow mode, and there are no authorization policies blocking unintended access.
- Small lock icon with the tag "Istio policies" indicates that this service is protected by Istio authorization policies, once we'll enable enforcement, of course.
- We can also see it would not block any clients once protection is enabled.
- And there is no warning about it remaining unprotected once enforcement is turned on. We have **a green light**, at least as far as this service goes, **for turning on enforcement** and protecting this service from any unintended calls.
- This service is still not currently protected: after all, we're in shadow mode, without enforcement, so there are no authorization policies blocking unintended access.
- The "Istio policies" tag indicates that the protection would be supplied by Istio authorization policies.
- There is no longer a warning about the `recommendationservice` remaining unprotected once enforcement is turned on.
- The arrow leading into the `recommendationservice` (from the `frontend`) is green, meaning it will not be blocked.

We now have **a green light**, at least as far as this service goes, **for turning on enforcement** and protecting this service from any unintended calls without breaking its intended clients.

:::info Ready to enforce?
We could turn on enforcement now.

But instead, let's first protect another service, to show how the access graph would warn us if we're not ready to turn on enforcement.
:::

### Declare more intents

We can see in the access graph that the `recommendationservice` in turn calls the `productcatalogservice`, sending `GET` requests to the resource at `/similar-products`, so let's declare that intent:

```yaml
Expand All @@ -218,25 +224,28 @@ Look at the access graph again:

![Access graph](/img/quick-tutorials/istio-visual-tutorial/phase-2.png)

As before, the line from `recommendationservice` &rarr; `productcatalogservice` is now solid green line, with no warnings. That's what we expected when we properly declare a discovered intent.
As before, the line from `recommendationservice` &rarr; `productcatalogservice` is now solid green line, with no warnings. That's what we expect when we properly declare a discovered intent.

But two other lines, `frontend` &rarr; `productcatalogservice` and `checkoutservice` &rarr; `productcatalogservice`, have turned orange. And a red warning has shown up on the `productcatalogservice`. Why?

Click on one of those orange lines:
<img src="/img/quick-tutorials/istio-visual-tutorial/frontend-productactalogservice-missing-intent.png" alt="Discovered intents" width="600"/>

- There is no declaration of the discovered `GET` calls from the `frontend` to the `productcatalogservice` at `/products`.
- There is no declaration of the discovered `GET /products` calls from the `frontend` to the `productcatalogservice`.
- This undeclared access is not blocked *now* &mdash; because we're still in shadow mode (otherwise the line would have been red).
- But access *would* be blocked once enforcement is turned on. To prevent that, we're told to declare the intent for this call.

Click on the `productcatalogservice`:
Click on the `productcatalogservice` to read its warning:
<img src="/img/quick-tutorials/istio-visual-tutorial/productcatalog-would-block.png" alt="Discovered intents" width="600"/>

:::danger
Update the above screenshot, please, to show Istio policies, and not network policies, for the enforcement.
:::

- We can see it's not protected now, again because we're in shadow mode.
- But we can also see it *would* block any clients once protection is enabled.
- But we can also see it *would* block some clients once protection is enabled.
- And there is an explicit warning to apply the missing intents from all its clients before turning on enforcement.


Let's declare those intents from the `frontend` and `checkoutservice` clients.

<Tabs>
Expand All @@ -263,23 +272,24 @@ Let's go back to the access graph:

![Access graph](/img/quick-tutorials/istio-visual-tutorial/phase-3.png)

Note that all arrows are now green again; specifically, the ones to the `productcatalogservice` are also solid, indicating all access has been declared.

Click on the `productcatalogservice`:

![Access graph](/img/quick-tutorials/istio-visual-tutorial/productcatalog-service-all-green.png)

All is well again: the `productcatalogservice` will be protected, and its 3 declared clients will have access, after enforcement is turned on.
Each client's access is limited to the HTTP resource and method declared in its intents file.
All is well again: the `productcatalogservice` will be protected, and its 3 declared clients will have access, once enforcement is turned on.
Each client's access will be limited to the HTTP resource and method declared in its intents file.

:::tip We can now see how to roll out IBAC gradually:
1. Pick a service to protect.
2. Make sure all its clients declare their intents to call it.
3. When you're ready, and the access graph shows green solid arrows without warnings, turn on enforcement.

The access graph and shadow mode allow us to gain confidence by showing what would happen, highlighting any problems, and pointi ng to their fixes.
The access graph and shadow mode allow us to gain confidence by showing what would happen, highlighting any problems, and pointing to their fixes.
:::


### Protect everything easily
### Optional: protect everything easily
Since Otterize already knows the problems and their fixes, could we somehow automatically bootstrap this for the whole cluster and protect all services, without breaking any intended calls? Yes!

The network mapper keeps track of all attempted calls, after all: those are the discovered intents. If you are confident that all intended call patterns have been exercised while the network mapper was running (so it could capture them), and all the calls it saw are intended and appropriate, you can use that information to automatically generate intent declarations and apply them.
Expand Down

0 comments on commit 113f8e0

Please sign in to comment.