From ca13f9a618c503fd553099037e7849f4fdf7f2a2 Mon Sep 17 00:00:00 2001 From: shankgan Date: Thu, 6 May 2021 10:29:50 -0700 Subject: [PATCH 1/2] task cert-management/custom-ca-k8s: preliminary doc tests --- .../cert-management/custom-ca-k8s/index.md | 43 ++--- .../cert-management/custom-ca-k8s/snips.sh | 155 ++++++++++++++++++ .../cert-management/custom-ca-k8s/test.sh | 34 ++++ 3 files changed, 200 insertions(+), 32 deletions(-) create mode 100644 content/en/docs/tasks/security/cert-management/custom-ca-k8s/snips.sh create mode 100644 content/en/docs/tasks/security/cert-management/custom-ca-k8s/test.sh diff --git a/content/en/docs/tasks/security/cert-management/custom-ca-k8s/index.md b/content/en/docs/tasks/security/cert-management/custom-ca-k8s/index.md index 66fc3b7d9d16e..46b32a1714272 100644 --- a/content/en/docs/tasks/security/cert-management/custom-ca-k8s/index.md +++ b/content/en/docs/tasks/security/cert-management/custom-ca-k8s/index.md @@ -6,7 +6,7 @@ keywords: [security,certificate] aliases: - /docs/tasks/security/custom-ca-k8s/ owner: istio/wg-security-maintainers -test: no +test: yes --- {{< boilerplate experimental >}} @@ -45,57 +45,36 @@ Note that this example should only be used for basic evaluation. The use of the # Tells Istiod to use the Kubernetes legacy CA Signer - name: K8S_SIGNER value: kubernetes.io/legacy-unknown - EOF + EOF $ istioctl install --set profile=demo -f ./istio.yaml {{< /text >}} -1. Deploy the `bookinfo` sample application in the bookinfo namespace. - Ensure that the following commands are executed in the Istio root directory. - - {{< text bash >}} - $ kubectl create ns bookinfo - $ kubectl apply -f <(istioctl kube-inject -f samples/bookinfo/platform/kube/bookinfo.yaml) -n bookinfo - {{< /text >}} - ### Verify that the certificates installed are correct When the workloads are deployed, above, they send CSR Requests to Istiod which forwards them to the Kubernetes CA for signing. If all goes well, the signed certificates are sent back to the workloads where they are then installed. To verify that they have been signed by the Kubernetes CA, you need to first extract the signed certificates. -1. Dump all pods running in the namespace. - - {{< text bash >}} - $ kubectl get pods -n bookinfo - {{< /text >}} - - Pick any one of the running pods for the next step. - 1. Get the certificate chain and CA root certificate used by the Istio proxies for mTLS. {{< text bash >}} - $ istioctl pc secret -o json > proxy_secret + $ ingress_pod="$(kubectl get pod -l app=istio-ingressgateway -n istio-system -o jsonpath="{.items[0].metadata.name}")" + $ istioctl pc secret "$ingress_pod" -o json | jq .dynamicActiveSecrets[1].secret.validationContext.trustedCa.inlineBytes | sed 's/\"//g' | base64 -d {{< /text >}} The proxy_secret json file contains the CA root certificate for mTLS in the `trustedCA` field. Note that this certificate is base64 encoded. -1. The certificate used by the Kubernetes CA (specifically the `kubernetes.io/legacy-unknown` signer) is loaded onto the secret associated with every service account in the bookinfo namespace. +2. The certificate used by the Kubernetes CA (specifically the `kubernetes.io/legacy-unknown` signer) is loaded onto the secret associated with every service account in the bookinfo namespace. k get secret/$secret -n istio-system -o json | jq '.data."ca.crt"' | sed 's/\"//g' | base64 -d {{< text bash >}} - $ kubectl get secrets -n bookinfo + $ secret="$(kubectl get secrets -n istio-system -o json | jq '.items[].metadata.name' | grep "account-token" | head -1 | sed 's/\"//g')" + $ kubectl get secret/"$secret" -n istio-system -o json | jq '.data."ca.crt"' | sed 's/\"//g' | base64 -d {{< /text >}} - Pick a secret-name that is associated with any of the service-accounts. These have a "token" in their name. + +3. Compare the certs obtained from step 1 and step 2. These two should be the same. - {{< text bash >}} - $ kubectl get secrets -n bookinfo -o json - {{< /text >}} - - The `ca.crt` field in the output contains the base64 encoded Kubernetes CA certificate. - -1. Compare the `ca.cert` obtained in the previous step with the contents of the `TrustedCA` field in the step before. These two should be the same. - -1. (Optional) Follow the rest of the steps in the [bookinfo example](/docs/examples/bookinfo/) to ensure that communication between services is working as expected. +4. (Optional) Follow the rest of the steps in the [bookinfo example](/docs/examples/bookinfo/) to ensure that communication between services is working as expected. ### Cleanup Part 1 @@ -154,7 +133,7 @@ Refer to the [Kubernetes CSR documentation](https://kubernetes.io/docs/reference namespace: istio-system data: root-cert.pem: - EOF + EOF $ kubectl apply -f external-ca-secret.yaml {{< /text >}} diff --git a/content/en/docs/tasks/security/cert-management/custom-ca-k8s/snips.sh b/content/en/docs/tasks/security/cert-management/custom-ca-k8s/snips.sh new file mode 100644 index 0000000000000..573ed36bd2fd9 --- /dev/null +++ b/content/en/docs/tasks/security/cert-management/custom-ca-k8s/snips.sh @@ -0,0 +1,155 @@ +#!/bin/bash +# shellcheck disable=SC2034,SC2153,SC2155,SC2164 + +# Copyright Istio Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#################################################################################################### +# WARNING: THIS IS AN AUTO-GENERATED FILE, DO NOT EDIT. PLEASE MODIFY THE ORIGINAL MARKDOWN FILE: +# docs/tasks/security/cert-management/custom-ca-k8s/index.md +#################################################################################################### + +snip_deploying_istio_with_kubernetes_ca_1() { +cat < ./istio.yaml + apiVersion: install.istio.io/v1alpha1 + kind: IstioOperator + spec: + pilot: + k8s: + env: + # Indicate to Istiod that we use an Custom Certificate Authority + - name: EXTERNAL_CA + value: ISTIOD_RA_KUBERNETES_API + # Tells Istiod to use the Kubernetes legacy CA Signer + - name: K8S_SIGNER + value: kubernetes.io/legacy-unknown +EOF +istioctl install --set profile=demo -f ./istio.yaml +} + +snip_verify_that_the_certificates_installed_are_correct_1() { +ingress_pod="$(kubectl get pod -l app=istio-ingressgateway -n istio-system -o jsonpath="{.items[0].metadata.name}")" +istioctl pc secret "$ingress_pod" -o json | jq .dynamicActiveSecrets[1].secret.validationContext.trustedCa.inlineBytes | sed 's/\"//g' | base64 -d +} + +snip_verify_that_the_certificates_installed_are_correct_2() { +secret="$(kubectl get secrets -n istio-system -o json | jq '.items[].metadata.name' | grep "account-token" | head -1 | sed 's/\"//g')" +kubectl get secret/"$secret" -n istio-system -o json | jq '.data."ca.crt"' | sed 's/\"//g' | base64 -d +} + +snip_cleanup_part_1_1() { +kubectl delete ns istio-system +kubectl delete ns bookinfo +} + +snip_deploy_custom_ca_controller_in_the_kubernetes_cluster_1() { +kubectl apply -f local-ca.yaml +} + +snip_deploy_custom_ca_controller_in_the_kubernetes_cluster_2() { +kubectl get services -n signer-ca-system +} + +! read -r -d '' snip_deploy_custom_ca_controller_in_the_kubernetes_cluster_2_out <<\ENDSNIP + NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE + signer-ca-controller-manager-metrics-service ClusterIP 10.8.9.25 none 8443/TCP 72s +ENDSNIP + +snip_deploy_custom_ca_controller_in_the_kubernetes_cluster_3() { +kubectl get secrets signer-ca-5hff5h74hm -o json +} + +snip_load_the_ca_root_certificate_into_a_secret_that_istiod_can_access_1() { +cat < ./external-ca-secret.yaml + apiVersion: v1 + kind: Secret + metadata: + name: external-ca-cert + namespace: istio-system + data: + root-cert.pem: +EOF +kubectl apply -f external-ca-secret.yaml +} + +snip_deploying_istio_1() { +cat < ./istio.yaml +apiVersion: install.istio.io/v1alpha1 +kind: IstioOperator +spec: + components: + base: + k8s: + overlays: + # Amend ClusterRole to add permission for istiod to approve certificate signing by custom signer + - kind: ClusterRole + name: istiod-istio-system + patches: + - path: rules[-1] + value: | + apiGroups: + - certificates.k8s.io + resourceNames: + # Name of k8s external Signer in this example + - example.com/foo + resources: + - signers + verbs: + - approve + pilot: + k8s: + env: + # Indicate to Istiod that we use an external signer + - name: EXTERNAL_CA + value: ISTIOD_RA_KUBERNETES_API + # Indicate to Istiod the external k8s Signer Name + - name: K8S_SIGNER + value: example.com/foo + overlays: + - kind: Deployment + name: istiod + patches: + - path: spec.template.spec.containers[0].volumeMounts[-1] + value: | + # Mount external CA certificate into Istiod + name: external-ca-cert + mountPath: /etc/external-ca-cert + readOnly: true + - path: spec.template.spec.volumes[-1] + value: | + name: external-ca-cert + secret: + secretName: external-ca-cert + optional: true +EOF +istioctl install --set profile=demo -f ./istio.yaml +} + +snip_deploying_istio_2() { +kubectl create ns bookinfo +kubectl apply -f <(istioctl kube-inject -f samples/bookinfo/platform/kube/bookinfo.yaml) -n bookinfo +} + +snip_verify_that_custom_ca_certificates_installed_are_correct_1() { +kubectl get pods -n bookinfo +} + +snip_verify_that_custom_ca_certificates_installed_are_correct_2() { +istioctl pc secret -o json > proxy_secret +} + +snip_cleanup_part_2_1() { +kubectl delete ns istio-system +kubectl delete ns bookinfo +} diff --git a/content/en/docs/tasks/security/cert-management/custom-ca-k8s/test.sh b/content/en/docs/tasks/security/cert-management/custom-ca-k8s/test.sh new file mode 100644 index 0000000000000..031542a722bdf --- /dev/null +++ b/content/en/docs/tasks/security/cert-management/custom-ca-k8s/test.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# shellcheck disable=SC1090,SC2154 + +# Copyright Istio Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# shellcheck disable=SC2001 + +set -e +set -u +set -o pipefail + +# @setup profile=none + +echo y | snip_deploying_istio_with_kubernetes_ca_1 + +_wait_for_deployment istio-system istio +_wait_for_deployment istio-system istio-ingressgateway + +_verify_same snip_verify_that_the_certificates_installed_are_correct_1 snip_verify_that_the_certificates_installed_are_correct_2 + +# @cleanup +snip_cleanup_1 From 9e52193205c3b20eb456d5809186cd4e0afa5097 Mon Sep 17 00:00:00 2001 From: shankgan Date: Tue, 11 May 2021 08:30:37 -0700 Subject: [PATCH 2/2] Incorporating review comment --- .../cert-management/custom-ca-k8s/index.md | 27 ++++++++++--------- .../cert-management/custom-ca-k8s/snips.sh | 21 ++++++++------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/content/en/docs/tasks/security/cert-management/custom-ca-k8s/index.md b/content/en/docs/tasks/security/cert-management/custom-ca-k8s/index.md index 46b32a1714272..68fb9e552f90c 100644 --- a/content/en/docs/tasks/security/cert-management/custom-ca-k8s/index.md +++ b/content/en/docs/tasks/security/cert-management/custom-ca-k8s/index.md @@ -36,15 +36,16 @@ Note that this example should only be used for basic evaluation. The use of the apiVersion: install.istio.io/v1alpha1 kind: IstioOperator spec: - pilot: - k8s: - env: - # Indicate to Istiod that we use an Custom Certificate Authority - - name: EXTERNAL_CA - value: ISTIOD_RA_KUBERNETES_API - # Tells Istiod to use the Kubernetes legacy CA Signer - - name: K8S_SIGNER - value: kubernetes.io/legacy-unknown + components: + pilot: + k8s: + env: + # Indicate to Istiod that we use an Custom Certificate Authority + - name: EXTERNAL_CA + value: ISTIOD_RA_KUBERNETES_API + # Tells Istiod to use the Kubernetes legacy CA Signer + - name: K8S_SIGNER + value: kubernetes.io/legacy-unknown EOF $ istioctl install --set profile=demo -f ./istio.yaml {{< /text >}} @@ -59,12 +60,12 @@ To verify that they have been signed by the Kubernetes CA, you need to first ext {{< text bash >}} $ ingress_pod="$(kubectl get pod -l app=istio-ingressgateway -n istio-system -o jsonpath="{.items[0].metadata.name}")" - $ istioctl pc secret "$ingress_pod" -o json | jq .dynamicActiveSecrets[1].secret.validationContext.trustedCa.inlineBytes | sed 's/\"//g' | base64 -d + $ istioctl pc secret "$ingress_pod".istio-system -o json | jq .dynamicActiveSecrets[1].secret.validationContext.trustedCa.inlineBytes | sed 's/\"//g' | base64 -d {{< /text >}} The proxy_secret json file contains the CA root certificate for mTLS in the `trustedCA` field. Note that this certificate is base64 encoded. -2. The certificate used by the Kubernetes CA (specifically the `kubernetes.io/legacy-unknown` signer) is loaded onto the secret associated with every service account in the bookinfo namespace. k get secret/$secret -n istio-system -o json | jq '.data."ca.crt"' | sed 's/\"//g' | base64 -d +1. The certificate used by the Kubernetes CA (specifically the `kubernetes.io/legacy-unknown` signer) is loaded onto the secret associated with every service account in the bookinfo namespace. {{< text bash >}} $ secret="$(kubectl get secrets -n istio-system -o json | jq '.items[].metadata.name' | grep "account-token" | head -1 | sed 's/\"//g')" @@ -72,9 +73,9 @@ To verify that they have been signed by the Kubernetes CA, you need to first ext {{< /text >}} -3. Compare the certs obtained from step 1 and step 2. These two should be the same. +1. Compare the certs obtained from step 1 and step 2. These two should be the same. -4. (Optional) Follow the rest of the steps in the [bookinfo example](/docs/examples/bookinfo/) to ensure that communication between services is working as expected. +1. (Optional) Follow the rest of the steps in the [bookinfo example](/docs/examples/bookinfo/) to ensure that communication between services is working as expected. ### Cleanup Part 1 diff --git a/content/en/docs/tasks/security/cert-management/custom-ca-k8s/snips.sh b/content/en/docs/tasks/security/cert-management/custom-ca-k8s/snips.sh index 573ed36bd2fd9..b072f1ce7cf8d 100644 --- a/content/en/docs/tasks/security/cert-management/custom-ca-k8s/snips.sh +++ b/content/en/docs/tasks/security/cert-management/custom-ca-k8s/snips.sh @@ -25,22 +25,23 @@ cat < ./istio.yaml apiVersion: install.istio.io/v1alpha1 kind: IstioOperator spec: - pilot: - k8s: - env: - # Indicate to Istiod that we use an Custom Certificate Authority - - name: EXTERNAL_CA - value: ISTIOD_RA_KUBERNETES_API - # Tells Istiod to use the Kubernetes legacy CA Signer - - name: K8S_SIGNER - value: kubernetes.io/legacy-unknown + components: + pilot: + k8s: + env: + # Indicate to Istiod that we use an Custom Certificate Authority + - name: EXTERNAL_CA + value: ISTIOD_RA_KUBERNETES_API + # Tells Istiod to use the Kubernetes legacy CA Signer + - name: K8S_SIGNER + value: kubernetes.io/legacy-unknown EOF istioctl install --set profile=demo -f ./istio.yaml } snip_verify_that_the_certificates_installed_are_correct_1() { ingress_pod="$(kubectl get pod -l app=istio-ingressgateway -n istio-system -o jsonpath="{.items[0].metadata.name}")" -istioctl pc secret "$ingress_pod" -o json | jq .dynamicActiveSecrets[1].secret.validationContext.trustedCa.inlineBytes | sed 's/\"//g' | base64 -d +istioctl pc secret "$ingress_pod".istio-system -o json | jq .dynamicActiveSecrets[1].secret.validationContext.trustedCa.inlineBytes | sed 's/\"//g' | base64 -d } snip_verify_that_the_certificates_installed_are_correct_2() {