diff --git a/docs/features/istio/tutorials/k8s-istio-authorization-policies.mdx b/docs/features/istio/tutorials/k8s-istio-authorization-policies.mdx index 40204a66a..fd5f2c974 100644 --- a/docs/features/istio/tutorials/k8s-istio-authorization-policies.mdx +++ b/docs/features/istio/tutorials/k8s-istio-authorization-policies.mdx @@ -116,7 +116,7 @@ other-client-74cc54f7b5-9rctd 2/2 Running 0 32s -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: @@ -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) diff --git a/docs/features/istio/tutorials/k8s-istio-watcher.mdx b/docs/features/istio/tutorials/k8s-istio-watcher.mdx index 8767dafcd..b1bdc072b 100644 --- a/docs/features/istio/tutorials/k8s-istio-watcher.mdx +++ b/docs/features/istio/tutorials/k8s-istio-watcher.mdx @@ -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) diff --git a/docs/features/kafka/tutorials/k8s-kafka-mapping.mdx b/docs/features/kafka/tutorials/k8s-kafka-mapping.mdx index b39775e60..be038d5bc 100644 --- a/docs/features/kafka/tutorials/k8s-kafka-mapping.mdx +++ b/docs/features/kafka/tutorials/k8s-kafka-mapping.mdx @@ -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) diff --git a/docs/features/linkerd/_category_.json b/docs/features/linkerd/_category_.json new file mode 100644 index 000000000..085f1f032 --- /dev/null +++ b/docs/features/linkerd/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Linkerd", + "position": 7, + "collapsed": true, + "customProps": { + "image": "/img/icons/linkerd-no-word-mark.svg" + } +} diff --git a/docs/features/linkerd/index.mdx b/docs/features/linkerd/index.mdx new file mode 100644 index 000000000..979727640 --- /dev/null +++ b/docs/features/linkerd/index.mdx @@ -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. + + + + +### 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 ] + +``` + diff --git a/docs/features/linkerd/tutorials/_category_.json b/docs/features/linkerd/tutorials/_category_.json new file mode 100644 index 000000000..bdfe77bf2 --- /dev/null +++ b/docs/features/linkerd/tutorials/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Tutorials", + "position": 2, + "collapsed": false +} diff --git a/docs/features/linkerd/tutorials/linkerd-authorization-policies.mdx b/docs/features/linkerd/tutorials/linkerd-authorization-policies.mdx new file mode 100644 index 000000000..add5483ac --- /dev/null +++ b/docs/features/linkerd/tutorials/linkerd-authorization-policies.mdx @@ -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** → **server** with the declared path and method) and block all unintended calls (e.g., **client-other** → **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 + +
+ Optional: check deployment status + 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 + ``` + +
+ +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 +``` + +
+ Expected output + + At this point the client should be able to communicate with the server: + + ``` + Calling server... + HTTP/1.1 200 OK + ... + hello from /client-path + ``` + +
+ +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 +``` + +
+ Expected output + + 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 + ``` + +
+ +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]** → **[nginx]** are declared and therefore allowed (green arrow). +3. Calls from **[client-other]** → **[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: + + + + + +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} +``` + + + + + +Otterize pairs `MeshTLSAuthentication` with the client workload's service account. + +```yaml +{@include: ../../../../static/code-examples/linkerd-authorization-policies/resources/meshtlsauth.yaml} +``` + + + + +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} +``` + + + + +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} +``` + + + + + + + +:::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 - +``` diff --git a/docs/getting-started/README.mdx b/docs/getting-started/README.mdx index 270a0d986..7f5b622bc 100644 --- a/docs/getting-started/README.mdx +++ b/docs/getting-started/README.mdx @@ -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', diff --git a/static/code-examples/linkerd-authorization-policies/all.yaml b/static/code-examples/linkerd-authorization-policies/all.yaml new file mode 100644 index 000000000..68a14df3b --- /dev/null +++ b/static/code-examples/linkerd-authorization-policies/all.yaml @@ -0,0 +1,111 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: otterize-tutorial-linkerd +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: client + namespace: otterize-tutorial-linkerd +spec: + selector: + matchLabels: + app: client + template: + metadata: + labels: + app: client + spec: + serviceAccountName: client-service-account + containers: + - name: client + image: alpine/curl + command: [ "/bin/sh", "-c", "--" ] + args: [ "while true; do echo \"Calling server...\"; if ! timeout 2 curl -si nginx-service:8080/client-path; then echo \"curl timed out\"; fi; sleep 2; done" ] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: client-service-account + namespace: otterize-tutorial-linkerd + labels: + app: client +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: other-client + namespace: otterize-tutorial-linkerd +spec: + selector: + matchLabels: + app: other-client + template: + metadata: + labels: + app: other-client + spec: + serviceAccountName: other-client-service-account + containers: + - name: other-client + image: alpine/curl + command: [ "/bin/sh", "-c", "--" ] + args: [ "while true; do echo \"Calling server...\"; if ! timeout 2 curl -si nginx-service:8080/other-client-path; then echo \"curl timed out\"; fi; sleep 2; done" ] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: other-client-service-account + namespace: otterize-tutorial-linkerd + labels: + app: other-client +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx + namespace: otterize-tutorial-linkerd +spec: + selector: + matchLabels: + app: nginx + replicas: 1 + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.14.2 + command: ["/bin/sh", "-c"] + args: + - | + echo 'events {}' > /etc/nginx/nginx.conf; + echo 'http {' >> /etc/nginx/nginx.conf; + echo ' include /etc/nginx/mime.types;' >> /etc/nginx/nginx.conf; + echo ' server {' >> /etc/nginx/nginx.conf; + echo ' listen 80;' >> /etc/nginx/nginx.conf; + echo ' server_name localhost;' >> /etc/nginx/nginx.conf; + echo ' location /client-path { return 200 "hello from /client-path\n"; }' >> /etc/nginx/nginx.conf; + echo ' location /other-client-path { return 200 "hello from /other-client-path\n"; }' >> /etc/nginx/nginx.conf; + echo ' }' >> /etc/nginx/nginx.conf; + echo '}' >> /etc/nginx/nginx.conf; + nginx -g "daemon off;" + ports: + - containerPort: 80 +--- +apiVersion: v1 +kind: Service +metadata: + name: nginx-service + namespace: otterize-tutorial-linkerd +spec: + selector: + app: nginx + ports: + - protocol: TCP + port: 8080 + targetPort: 80 +--- diff --git a/static/code-examples/linkerd-authorization-policies/intents.yaml b/static/code-examples/linkerd-authorization-policies/intents.yaml new file mode 100644 index 000000000..36e8b0e41 --- /dev/null +++ b/static/code-examples/linkerd-authorization-policies/intents.yaml @@ -0,0 +1,15 @@ +apiVersion: k8s.otterize.com/v2beta1 +kind: ClientIntents +metadata: + name: client + namespace: otterize-tutorial-linkerd +spec: + workload: + name: client + targets: + - kubernetes: + name: nginx + kind: Deployment + http: + - path: /client-path + methods: [ GET ] \ No newline at end of file diff --git a/static/code-examples/linkerd-authorization-policies/resources/authpolicy.yaml b/static/code-examples/linkerd-authorization-policies/resources/authpolicy.yaml new file mode 100644 index 000000000..37f9acde1 --- /dev/null +++ b/static/code-examples/linkerd-authorization-policies/resources/authpolicy.yaml @@ -0,0 +1,20 @@ +apiVersion: policy.linkerd.io/v1alpha1 +kind: AuthorizationPolicy +metadata: + name: authpolicy-to-nginx-port-80-from-client-client-scmc2e2s + namespace: otterize-tutorial-linkerd +spec: + requiredAuthenticationRefs: + - group: policy.linkerd.io + kind: MeshTLSAuthentication + # highlight-next-line + # Automatically generated by Otterize + # highlight-next-line + name: meshtls-for-client-client + targetRef: + group: policy.linkerd.io + kind: HTTPRoute + # highlight-next-line + # Automatically generated by Otterize + # highlight-next-line + name: http-route-for-nginx-port-80-bc98e3 \ No newline at end of file diff --git a/static/code-examples/linkerd-authorization-policies/resources/httproute.yaml b/static/code-examples/linkerd-authorization-policies/resources/httproute.yaml new file mode 100644 index 000000000..010f437e7 --- /dev/null +++ b/static/code-examples/linkerd-authorization-policies/resources/httproute.yaml @@ -0,0 +1,16 @@ +apiVersion: policy.linkerd.io/v1beta3 +kind: HTTPRoute +metadata: + name: http-route-for-nginx-port-80-bc98e3 + namespace: otterize-tutorial-linkerd +spec: + parentRefs: + - group: policy.linkerd.io + kind: Server + name: server-for-nginx-port-80 + rules: + - matches: + - path: + type: PathPrefix + # highlight-next-line + value: /client-path diff --git a/static/code-examples/linkerd-authorization-policies/resources/meshtlsauth.yaml b/static/code-examples/linkerd-authorization-policies/resources/meshtlsauth.yaml new file mode 100644 index 000000000..ae99f2ce7 --- /dev/null +++ b/static/code-examples/linkerd-authorization-policies/resources/meshtlsauth.yaml @@ -0,0 +1,11 @@ +apiVersion: policy.linkerd.io/v1alpha1 +kind: MeshTLSAuthentication +metadata: + name: meshtls-for-client-client + namespace: otterize-tutorial-linkerd +spec: + identities: + # highlight-next-line + # Automatically determined by looking up the Kubernetes ServiceAccount for this client + # highlight-next-line + - client-service-account.otterize-tutorial-linkerd.serviceaccount.identity.linkerd.cluster.local \ No newline at end of file diff --git a/static/code-examples/linkerd-authorization-policies/resources/server.yaml b/static/code-examples/linkerd-authorization-policies/resources/server.yaml new file mode 100644 index 000000000..2bed70a57 --- /dev/null +++ b/static/code-examples/linkerd-authorization-policies/resources/server.yaml @@ -0,0 +1,18 @@ +apiVersion: policy.linkerd.io/v1beta3 +kind: Server +metadata: + name: server-for-nginx-port-80 + namespace: otterize-tutorial-linkerd +spec: + accessPolicy: deny + podSelector: + matchLabels: + # highlight-next-line + # Pods are automatically labeled by Otterize + # highlight-next-line + intents.otterize.com/service: nginx-otterize-tutorial-li-efa4db + # highlight-next-line + # Automatically determined by looking up the Kubernetes Service for this server + # highlight-next-line + port: 80 + proxyProtocol: unknown diff --git a/static/img/icons/linkerd-no-word-mark.svg b/static/img/icons/linkerd-no-word-mark.svg new file mode 100644 index 000000000..ef77791fa --- /dev/null +++ b/static/img/icons/linkerd-no-word-mark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/img/icons/linkerd.png b/static/img/icons/linkerd.png new file mode 100644 index 000000000..c0bfa0925 Binary files /dev/null and b/static/img/icons/linkerd.png differ diff --git a/static/img/quick-tutorials/linkerd/linkerd.png b/static/img/quick-tutorials/linkerd/linkerd.png new file mode 100644 index 000000000..102020884 Binary files /dev/null and b/static/img/quick-tutorials/linkerd/linkerd.png differ diff --git a/static/img/quick-tutorials/linkerd/linkerd_viz.png b/static/img/quick-tutorials/linkerd/linkerd_viz.png new file mode 100644 index 000000000..b738e0aec Binary files /dev/null and b/static/img/quick-tutorials/linkerd/linkerd_viz.png differ