mirror of https://github.com/istio/istio.io.git
Rewrite mtls migration instructions. (#6589)
* rewrite mtls migration doc. * migrate out the comment out ones * more service/wl swap, one level title up * Update content/en/docs/tasks/security/authentication/mtls-migration/index.md Co-Authored-By: Frank Budinsky <frankb@ca.ibm.com> * lint fix, lockdown * refer ns in lckdown * reworded beginnig sec * remove the global.mtls.enabled. * lint fix * Apply suggestions from code review Co-Authored-By: Frank Budinsky <frankb@ca.ibm.com> * suggestion batch2. Co-Authored-By: Frank Budinsky <frankb@ca.ibm.com> * address turn3 Co-Authored-By: Frank Budinsky <frankb@ca.ibm.com> * ns create separtae. Co-authored-by: Frank Budinsky <frankb@ca.ibm.com>
This commit is contained in:
parent
ad802b7818
commit
6fb12b9c8e
|
@ -7,104 +7,34 @@ aliases:
|
|||
- /docs/tasks/security/mtls-migration/
|
||||
---
|
||||
|
||||
This task shows how to migrate your existing Istio services' traffic from plain
|
||||
text to mutual TLS without breaking live traffic.
|
||||
This task shows how to ensure your workloads only communicate using mutual TLS as they are migrated to
|
||||
Istio.
|
||||
|
||||
In the scenario where there are many services communicating over the network, it
|
||||
may be desirable to gradually migrate them to Istio. During the migration, some services have Envoy
|
||||
sidecars while some do not. For a service with a sidecar, if you enable
|
||||
mutual TLS on the service, the connections from legacy clients (i.e., clients without
|
||||
Envoy) will lose communication since they do not have Envoy sidecars and client certificates.
|
||||
To solve this issue, Istio authentication policy provides a `PERMISSIVE` mode to solve
|
||||
this problem. When `PERMISSIVE` mode is enabled, a service can take both HTTP
|
||||
and mutual TLS traffic.
|
||||
Istio automatically configures workload sidecars to use [mutual TLS](/docs/tasks/security/authentication/authn-policy/#auto-mutual-tls) when calling other workloads. By default, Istio configures the destination workloads using `PERMISSIVE` mode.
|
||||
When `PERMISSIVE` mode is enabled, a service can accept both plain text and mutual TLS traffic. In order to only allow
|
||||
mutual TLS traffic, the configuration needs to be changed to `STRICT` mode.
|
||||
|
||||
You can configure Istio services to send mutual
|
||||
TLS traffic to that service while connections from legacy services will not
|
||||
lose communication. Moreover, you can use the
|
||||
[Grafana dashboard](/docs/tasks/observability/metrics/using-istio-dashboard/) to check which services are
|
||||
still sending plaintext traffic to the service in `PERMISSIVE` mode and choose to lock
|
||||
You can use the [Grafana dashboard](/docs/tasks/observability/metrics/using-istio-dashboard/) to
|
||||
check which workloads are still sending plaintext traffic to the workloads in `PERMISSIVE` mode and choose to lock
|
||||
them down once the migration is done.
|
||||
|
||||
## Before you begin
|
||||
|
||||
<!-- TODO: update the link after other PRs are merged -->
|
||||
|
||||
* Understand Istio [authentication policy](/docs/concepts/security/#authentication-policies) and related [mutual TLS authentication](/docs/concepts/security/#mutual-tls-authentication) concepts.
|
||||
|
||||
* Read the [authentication policy task](/docs/tasks/security/authentication/authn-policy) to
|
||||
learn how to configure authentication policy.
|
||||
|
||||
* Have a Kubernetes cluster with Istio installed, without global mutual TLS enabled (e.g use the demo configuration profile as described in
|
||||
[installation steps](/docs/setup/getting-started), or set the `global.mtls.enabled` installation option to false).
|
||||
* Have a Kubernetes cluster with Istio installed, without global mutual TLS enabled (e.g use the demo configuration profile as described in [installation steps](/docs/setup/getting-started).
|
||||
|
||||
* Ensure that your cluster is in `PERMISSIVE` mode before migrating to mutual TLS.
|
||||
Run the following command to check:
|
||||
|
||||
{{< text bash >}}
|
||||
$ kubectl get meshpolicy default -o yaml
|
||||
...
|
||||
spec:
|
||||
peers:
|
||||
- mtls:
|
||||
mode: PERMISSIVE
|
||||
{{< /text >}}
|
||||
|
||||
If the output is the same as above, you can skip the next step.
|
||||
|
||||
* Run the following command to enable `PERMISSIVE` mode for the cluster. In general, this operation
|
||||
does not cause any interruption to your workloads, but note the warning message below.
|
||||
|
||||
{{< warning >}}
|
||||
In `PERMISSIVE` mode, the Envoy sidecar relies on the
|
||||
[ALPN](https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation) value `istio` to
|
||||
decide whether to terminate the mutual TLS traffic. If your workloads (without Envoy sidecar)
|
||||
have enabled mutual TLS directly to the services with Envoy sidecars, enabling `PERMISSIVE` mode
|
||||
may cause these connections to fail.
|
||||
{{< /warning >}}
|
||||
|
||||
{{< text bash >}}
|
||||
$ kubectl apply -f - <<EOF
|
||||
apiVersion: "authentication.istio.io/v1alpha1"
|
||||
kind: "MeshPolicy"
|
||||
metadata:
|
||||
name: "default"
|
||||
spec:
|
||||
peers:
|
||||
- mtls:
|
||||
mode: PERMISSIVE
|
||||
EOF
|
||||
{{< /text >}}
|
||||
|
||||
{{< tip >}}
|
||||
You can use the following command to show the mutual TLS configuration of all connections from one pod:
|
||||
|
||||
{{< text bash >}}
|
||||
$ istioctl authn tls-check <YOUR_POD> -n <YOUR_NAMESPACE>
|
||||
{{< /text >}}
|
||||
|
||||
{{< /tip >}}
|
||||
|
||||
The rest of this task is divided into two parts.
|
||||
|
||||
* If you want to enable mutual TLS for your workloads one by one, refer to
|
||||
[gradually enable mutual TLS for services](/docs/tasks/security/authentication/mtls-migration/#option-1-gradually-enable-mutual-tls-for-services),
|
||||
which describes the process using simple examples.
|
||||
|
||||
* If you want to enable mutual TLS for the entire cluster, refer to
|
||||
[globally enable mutual TLS for the cluster](/docs/tasks/security/authentication/mtls-migration/#option-2-globally-enable-mutual-tls-for-the-cluster).
|
||||
|
||||
## Option 1: gradually enable mutual TLS for services
|
||||
|
||||
In this section, you can try out the migration process by creating sample workloads and modifying
|
||||
In this task, you can try out the migration process by creating sample workloads and modifying
|
||||
the policies to enforce STRICT mutual TLS between the workloads.
|
||||
|
||||
### Set up the cluster
|
||||
## Set up the cluster
|
||||
|
||||
* Create the following namespaces and deploy [httpbin]({{< github_tree >}}/samples/httpbin) and [sleep]({{< github_tree >}}/samples/sleep) with sidecars on both of them.
|
||||
* `foo`
|
||||
* `bar`
|
||||
|
||||
* Create the following namespace and deploy [sleep]({{< github_tree >}}/samples/sleep) without a sidecar
|
||||
* `legacy`
|
||||
* Create two namespaces, `foo` and `bar`, and deploy [httpbin]({{< github_tree >}}/samples/httpbin) and [sleep]({{< github_tree >}}/samples/sleep) with sidecars on both of them:
|
||||
|
||||
{{< text bash >}}
|
||||
$ kubectl create ns foo
|
||||
|
@ -113,6 +43,11 @@ the policies to enforce STRICT mutual TLS between the workloads.
|
|||
$ kubectl create ns bar
|
||||
$ kubectl apply -f <(istioctl kube-inject -f @samples/httpbin/httpbin.yaml@) -n bar
|
||||
$ kubectl apply -f <(istioctl kube-inject -f @samples/sleep/sleep.yaml@) -n bar
|
||||
{{< /text >}}
|
||||
|
||||
* Create another namespace, `legacy`, and deploy [sleep]({{< github_tree >}}/samples/sleep) without a sidecar:
|
||||
|
||||
{{< text bash >}}
|
||||
$ kubectl create ns legacy
|
||||
$ kubectl apply -f @samples/sleep/sleep.yaml@ -n legacy
|
||||
{{< /text >}}
|
||||
|
@ -120,179 +55,88 @@ the policies to enforce STRICT mutual TLS between the workloads.
|
|||
* Verify setup by sending an http request (using curl command) from any sleep pod (among those in namespace `foo`, `bar` or `legacy`) to `httpbin.foo`. All requests should success with HTTP code 200.
|
||||
|
||||
{{< text bash >}}
|
||||
$ for from in "foo" "bar" "legacy"; do kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl http://httpbin.foo:8000/ip -s -o /dev/null -w "sleep.${from} to httpbin.foo: %{http_code}\n"; done
|
||||
$ for from in "foo" "bar" "legacy"; do for to in "foo" "bar"; do kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl http://httpbin.${to}:8000/ip -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
|
||||
sleep.foo to httpbin.foo: 200
|
||||
sleep.foo to httpbin.bar: 200
|
||||
sleep.bar to httpbin.foo: 200
|
||||
sleep.bar to httpbin.bar: 200
|
||||
sleep.legacy to httpbin.foo: 200
|
||||
sleep.legacy to httpbin.bar: 200
|
||||
{{< /text >}}
|
||||
|
||||
* Also verify that there are no authentication policies or destination rules (except control plane's) in the system:
|
||||
* Also verify that there are no authentication policies or destination rules (except control plane ones) in the system:
|
||||
|
||||
{{< text bash >}}
|
||||
$ kubectl get policies.authentication.istio.io --all-namespaces
|
||||
NAMESPACE NAME AGE
|
||||
istio-system grafana-ports-mtls-disabled 3m
|
||||
$ kubectl get peerauthentication --all-namespaces
|
||||
No resources found
|
||||
{{< /text >}}
|
||||
|
||||
{{< text bash >}}
|
||||
$ kubectl get destinationrule --all-namespaces
|
||||
NAMESPACE NAME HOST AGE
|
||||
istio-system istio-multicluster-destinationrule *.global 35s
|
||||
istio-system istio-policy istio-policy.istio-system.svc.cluster.local 35s
|
||||
istio-system istio-telemetry istio-telemetry.istio-system.svc.cluster.local 33s
|
||||
No resources found
|
||||
{{< /text >}}
|
||||
|
||||
### Configure clients to send mutual TLS traffic
|
||||
## Lock down to mutual TLS by namespace
|
||||
|
||||
Configure Istio services to send mutual TLS traffic by setting `DestinationRule`.
|
||||
After migrating all clients to Istio and injecting the Envoy sidecar, you can lock down workloads in the `foo` namespace
|
||||
to only accept mutual TLS traffic.
|
||||
|
||||
{{< text bash >}}
|
||||
$ cat <<EOF | kubectl apply -n foo -f -
|
||||
apiVersion: "networking.istio.io/v1alpha3"
|
||||
kind: "DestinationRule"
|
||||
$ kubectl apply -n foo -f - << EOF
|
||||
apiVersion: "security.istio.io/v1beta1"
|
||||
kind: "PeerAuthentication"
|
||||
metadata:
|
||||
name: "example-httpbin-istio-client-mtls"
|
||||
name: "default"
|
||||
spec:
|
||||
host: httpbin.foo.svc.cluster.local
|
||||
trafficPolicy:
|
||||
tls:
|
||||
mode: ISTIO_MUTUAL
|
||||
mtls:
|
||||
mode: STRICT
|
||||
EOF
|
||||
{{< /text >}}
|
||||
|
||||
`sleep.foo` and `sleep.bar` should start sending mutual TLS traffic to `httpbin.foo`. And `sleep.legacy` still sends plaintext
|
||||
traffic to `httpbin.foo` since it does not have sidecar thus `DestinationRule` does not apply.
|
||||
|
||||
Now we confirm all requests to `httpbin.foo` still succeed.
|
||||
Now, you should see the request from `sleep.legacy` to `httpbin.foo` failing.
|
||||
|
||||
{{< text bash >}}
|
||||
$ for from in "foo" "bar" "legacy"; do kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl http://httpbin.foo:8000/ip -s -o /dev/null -w "sleep.${from} to httpbin.foo: %{http_code}\n"; done
|
||||
$ for from in "foo" "bar" "legacy"; do for to in "foo" "bar"; do kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl http://httpbin.${to}:8000/ip -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
|
||||
sleep.foo to httpbin.foo: 200
|
||||
sleep.foo to httpbin.bar: 200
|
||||
sleep.bar to httpbin.foo: 200
|
||||
sleep.legacy to httpbin.foo: 200
|
||||
sleep.bar to httpbin.bar: 200
|
||||
sleep.legacy to httpbin.foo: 000
|
||||
command terminated with exit code 56
|
||||
sleep.legacy to httpbin.bar: 200
|
||||
{{< /text >}}
|
||||
|
||||
You can also specify a subset of the clients' request to use `ISTIO_MUTUAL` mutual TLS in
|
||||
[`DestinationRule`](/docs/reference/config/networking/destination-rule/).
|
||||
After verifying it works by checking [Grafana to monitor](/docs/tasks/observability/metrics/using-istio-dashboard/),
|
||||
then increase the rollout scope and finally apply to all Istio client services.
|
||||
|
||||
### Lock down to mutual TLS
|
||||
|
||||
After migrating all clients to Istio services and injecting the Envoy sidecar, we can lock down the `httpbin.foo` to only accept mutual TLS traffic.
|
||||
|
||||
{{< text bash >}}
|
||||
$ cat <<EOF | kubectl apply -n foo -f -
|
||||
apiVersion: "authentication.istio.io/v1alpha1"
|
||||
kind: "Policy"
|
||||
metadata:
|
||||
name: "example-httpbin-strict"
|
||||
namespace: foo
|
||||
spec:
|
||||
targets:
|
||||
- name: httpbin
|
||||
peers:
|
||||
- mtls:
|
||||
mode: STRICT
|
||||
EOF
|
||||
{{< /text >}}
|
||||
|
||||
Now, you should see the request from `sleep.legacy` fail.
|
||||
|
||||
{{< text bash >}}
|
||||
$ for from in "foo" "bar" "legacy"; do kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl http://httpbin.foo:8000/ip -s -o /dev/null -w "sleep.${from} to httpbin.foo: %{http_code}\n"; done
|
||||
sleep.foo to httpbin.foo: 200
|
||||
sleep.bar to httpbin.foo: 200
|
||||
sleep.legacy to httpbin.foo: 503
|
||||
{{< /text >}}
|
||||
|
||||
If you can't migrate all your services to Istio (injecting Envoy sidecar), you have to stay at `PERMISSIVE` mode.
|
||||
If you can't migrate all your services to Istio (i.e., inject Envoy sidecar in all of them), you will need to continue to use `PERMISSIVE` mode.
|
||||
However, when configured with `PERMISSIVE` mode, no authentication or authorization checks will be performed for plaintext traffic by default.
|
||||
We recommend you use [Istio Authorization](/docs/tasks/security/authorization/authz-http/) to configure different paths with different authorization policies.
|
||||
|
||||
### Clean up the example
|
||||
## Lock down mutual TLS for the entire mesh
|
||||
|
||||
To remove all resources created in this section:
|
||||
{{< text bash >}}
|
||||
$ kubectl apply -n istio-system -f - << EOF
|
||||
apiVersion: "security.istio.io/v1beta1"
|
||||
kind: "PeerAuthentication"
|
||||
metadata:
|
||||
name: "default"
|
||||
spec:
|
||||
mtls:
|
||||
mode: STRICT
|
||||
EOF
|
||||
{{< /text >}}
|
||||
|
||||
Now, both the `foo` and `bar` namespaces enforce mutual TLS only traffic, so you should see requests from `sleep.legacy`
|
||||
failing for both.
|
||||
|
||||
{{< text bash >}}
|
||||
$ for from in "foo" "bar" "legacy"; do for to in "foo" "bar"; do kubectl exec $(kubectl get pod -l app=sleep -n ${from} -o jsonpath={.items..metadata.name}) -c sleep -n ${from} -- curl http://httpbin.${to}:8000/ip -s -o /dev/null -w "sleep.${from} to httpbin.${to}: %{http_code}\n"; done; done
|
||||
{{< /text >}}
|
||||
|
||||
## Clean up the example
|
||||
|
||||
To remove all resources created in this task:
|
||||
|
||||
{{< text bash >}}
|
||||
$ kubectl delete ns foo bar legacy
|
||||
Namespaces foo bar legacy deleted.
|
||||
$ kubectl delete peerauthentication --all-namespaces --all
|
||||
{{< /text >}}
|
||||
|
||||
## Option 2: globally enable mutual TLS for the cluster
|
||||
|
||||
This section describes how to apply the configuration to enforce mutual TLS for a cluster. For more
|
||||
details, see the
|
||||
[Authentication policy](/docs/tasks/security/authentication/authn-policy/#globally-enabling-istio-mutual-tls-in-strict-mode)
|
||||
task.
|
||||
|
||||
{{< warning >}}
|
||||
If you have special TLS configurations for your services or you have
|
||||
services without Envoy sidecars, we recommend that you
|
||||
[enable mutual TLS service by service](/docs/tasks/security/authentication/mtls-migration/#option-1-gradually-enable-mutual-tls-for-services).
|
||||
{{< /warning >}}
|
||||
|
||||
### Configure all clients to send mutual TLS traffic
|
||||
|
||||
Run the following command to enable all Envoy sidecars to send mutual TLS traffic to the servers.
|
||||
|
||||
{{< text bash >}}
|
||||
$ kubectl apply -f - <<EOF
|
||||
apiVersion: "networking.istio.io/v1alpha3"
|
||||
kind: "DestinationRule"
|
||||
metadata:
|
||||
name: "default"
|
||||
namespace: "istio-system"
|
||||
spec:
|
||||
host: "*.local"
|
||||
trafficPolicy:
|
||||
tls:
|
||||
mode: ISTIO_MUTUAL
|
||||
EOF
|
||||
{{< /text >}}
|
||||
|
||||
The connections between services should not be interrupted.
|
||||
|
||||
### Lock down to mutual TLS for the entire cluster
|
||||
|
||||
Run the following command to enforce all Envoy sidecars to only receive mutual TLS traffic.
|
||||
|
||||
{{< text bash >}}
|
||||
$ kubectl apply -f - <<EOF
|
||||
apiVersion: "authentication.istio.io/v1alpha1"
|
||||
kind: "MeshPolicy"
|
||||
metadata:
|
||||
name: "default"
|
||||
spec:
|
||||
peers:
|
||||
- mtls: {}
|
||||
EOF
|
||||
{{< /text >}}
|
||||
|
||||
The connections between services should not be interrupted.
|
||||
|
||||
### Clean up global mutual TLS configuration
|
||||
|
||||
Choose one of the following, depending on the mode you want to switch to:
|
||||
|
||||
* To switch to `PERMISSIVE` mode for the cluster:
|
||||
|
||||
{{< text bash >}}
|
||||
$ kubectl apply -f - <<EOF
|
||||
apiVersion: "authentication.istio.io/v1alpha1"
|
||||
kind: "MeshPolicy"
|
||||
metadata:
|
||||
name: "default"
|
||||
spec:
|
||||
peers:
|
||||
- mtls:
|
||||
mode: PERMISSIVE
|
||||
EOF
|
||||
{{< /text >}}
|
||||
|
||||
* To disable the global mutual TLS and switch to plaintext only:
|
||||
|
||||
{{< text bash >}}
|
||||
$ kubectl delete meshpolicy default
|
||||
$ kubectl delete destinationrule default -n istio-system
|
||||
{{< /text >}}
|
||||
|
|
Loading…
Reference in New Issue