From e9e963a617b89d341c19489cd95db976e9d5b3af Mon Sep 17 00:00:00 2001 From: John Howard Date: Thu, 21 May 2020 14:10:26 -0700 Subject: [PATCH] Add TLS origination doc test (#7367) * Add TLS origination doc test * Fix build * Add header * lint --- .../egress-gateway-tls-origination/index.md | 10 +- .../egress/egress-tls-origination/index.md | 30 ++-- .../egress/egress-tls-origination/snips.sh | 168 ++++++++++++++++++ go.mod | 5 +- pkg/test/istioio/script.go | 28 ++- tests/trafficmanagement/egress/main_test.go | 37 ++++ .../egress/scripts/tls_origination.sh | 36 ++++ .../egress/tls_origination_test.go | 43 +++++ 8 files changed, 327 insertions(+), 30 deletions(-) create mode 100644 content/en/docs/tasks/traffic-management/egress/egress-tls-origination/snips.sh create mode 100644 tests/trafficmanagement/egress/main_test.go create mode 100644 tests/trafficmanagement/egress/scripts/tls_origination.sh create mode 100644 tests/trafficmanagement/egress/tls_origination_test.go diff --git a/content/en/docs/tasks/traffic-management/egress/egress-gateway-tls-origination/index.md b/content/en/docs/tasks/traffic-management/egress/egress-gateway-tls-origination/index.md index 7879db439e..1bef568f60 100644 --- a/content/en/docs/tasks/traffic-management/egress/egress-gateway-tls-origination/index.md +++ b/content/en/docs/tasks/traffic-management/egress/egress-gateway-tls-origination/index.md @@ -79,7 +79,7 @@ be done by the egress gateway, as opposed to by the sidecar in the previous exam 1. Verify that your `ServiceEntry` was applied correctly by sending a request to [http://edition.cnn.com/politics](https://edition.cnn.com/politics). {{< text bash >}} - $ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics + $ kubectl exec $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics HTTP/1.1 301 Moved Permanently ... location: https://edition.cnn.com/politics @@ -179,7 +179,7 @@ be done by the egress gateway, as opposed to by the sidecar in the previous exam 1. Send an HTTP request to [http://edition.cnn.com/politics](https://edition.cnn.com/politics). {{< text bash >}} - $ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics + $ kubectl exec $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics HTTP/1.1 200 OK ... content-length: 150793 @@ -523,7 +523,7 @@ to hold the configuration of the NGINX server: Normally, a DNS entry exists for the destination hostname and you would not use the `--resolve` option of `curl`. {{< text bash >}} - $ kubectl exec -it $SOURCE_POD -c sleep -- curl -v --resolve nginx.example.com:443:1.1.1.1 --cacert /etc/nginx-ca-certs/ca-chain.cert.pem --cert /etc/nginx-client-certs/tls.crt --key /etc/nginx-client-certs/tls.key https://nginx.example.com + $ kubectl exec $SOURCE_POD -c sleep -- curl -v --resolve nginx.example.com:443:1.1.1.1 --cacert /etc/nginx-ca-certs/ca-chain.cert.pem --cert /etc/nginx-client-certs/tls.crt --key /etc/nginx-client-certs/tls.key https://nginx.example.com ... Server certificate: subject: C=US; ST=Denial; L=Springfield; O=Dis; CN=nginx.example.com @@ -550,7 +550,7 @@ to hold the configuration of the NGINX server: 1. Verify that the server requires the client's certificate: {{< text bash >}} - $ kubectl exec -it $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) -c sleep -- curl -k --resolve nginx.example.com:443:1.1.1.1 https://nginx.example.com + $ kubectl exec $(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) -c sleep -- curl -k --resolve nginx.example.com:443:1.1.1.1 https://nginx.example.com 400 No required SSL certificate was sent @@ -744,7 +744,7 @@ to hold the configuration of the NGINX server: 1. Send an HTTP request to `http://nginx.example.com`: {{< text bash >}} - $ kubectl exec -it $SOURCE_POD -c sleep -- curl -s --resolve nginx.example.com:80:1.1.1.1 http://nginx.example.com + $ kubectl exec $SOURCE_POD -c sleep -- curl -s --resolve nginx.example.com:80:1.1.1.1 http://nginx.example.com diff --git a/content/en/docs/tasks/traffic-management/egress/egress-tls-origination/index.md b/content/en/docs/tasks/traffic-management/egress/egress-tls-origination/index.md index 4b963ffdc1..6ecb106f45 100644 --- a/content/en/docs/tasks/traffic-management/egress/egress-tls-origination/index.md +++ b/content/en/docs/tasks/traffic-management/egress/egress-tls-origination/index.md @@ -3,6 +3,7 @@ title: Egress TLS Origination description: Describes how to configure Istio to perform TLS origination for traffic to external services. keywords: [traffic-management,egress] weight: 20 +test: true aliases: - /docs/examples/advanced-gateways/egress-tls-origination/ --- @@ -60,7 +61,7 @@ This time, however, use a single `ServiceEntry` to enable both HTTP and HTTPS ac 1. Create a `ServiceEntry` and `VirtualService` to enable access to `edition.cnn.com`: - {{< text bash >}} + {{< text syntax=bash snip_id=apply_simple >}} $ kubectl apply -f - <}} - $ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics + {{< text syntax=bash snip_id=curl_simple >}} + $ kubectl exec "${SOURCE_POD}" -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics HTTP/1.1 301 Moved Permanently ... location: https://edition.cnn.com/politics ... - HTTP/1.1 200 OK - Content-Type: text/html; charset=utf-8 - ... - Content-Length: 151654 + HTTP/2 200 ... {{< /text >}} @@ -137,7 +135,7 @@ Both of these issues can be resolved by configuring Istio to perform TLS origina 1. Redefine your `ServiceEntry` and `VirtualService` from the previous section to rewrite the HTTP request port and add a `DestinationRule` to perform TLS origination. - {{< text bash >}} + {{< text syntax=bash snip_id=apply_origination >}} $ kubectl apply -f - <}} - $ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics + {{< text syntax=bash snip_id=curl_origination_http >}} + $ kubectl exec "${SOURCE_POD}" -c sleep -- curl -sL -o /dev/null -D - http://edition.cnn.com/politics HTTP/1.1 200 OK - Content-Type: text/html; charset=utf-8 - ... - Content-Length: 151654 ... {{< /text >}} @@ -219,12 +214,9 @@ Both of these issues can be resolved by configuring Istio to perform TLS origina 1. Note that the applications that used HTTPS to access the external service continue to work as before: - {{< text bash >}} - $ kubectl exec -it $SOURCE_POD -c sleep -- curl -sL -o /dev/null -D - https://edition.cnn.com/politics - HTTP/1.1 200 OK - Content-Type: text/html; charset=utf-8 - ... - Content-Length: 151654 + {{< text syntax=bash snip_id=curl_origination_https >}} + $ kubectl exec "${SOURCE_POD}" -c sleep -- curl -sL -o /dev/null -D - https://edition.cnn.com/politics + HTTP/2 200 ... {{< /text >}} diff --git a/content/en/docs/tasks/traffic-management/egress/egress-tls-origination/snips.sh b/content/en/docs/tasks/traffic-management/egress/egress-tls-origination/snips.sh new file mode 100644 index 0000000000..b84674c645 --- /dev/null +++ b/content/en/docs/tasks/traffic-management/egress/egress-tls-origination/snips.sh @@ -0,0 +1,168 @@ +#!/bin/bash +# shellcheck disable=SC2034,SC2153,SC2155 + +# 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/traffic-management/egress/egress-tls-origination/index.md +#################################################################################################### + +snip_before_you_begin_1() { +kubectl apply -f samples/sleep/sleep.yaml +} + +snip_before_you_begin_2() { +kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml) +} + +snip_before_you_begin_3() { +export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}) +} + +snip_apply_simple() { +kubectl apply -f - < github.com/istio/viper v1.3.3-0.20190515210538 replace github.com/docker/docker => github.com/docker/engine v1.4.2-0.20191011211953-adfac697dc5b -require istio.io/istio v0.0.0-20200518170651-df8ea82bf434 +require ( + istio.io/istio v0.0.0-20200518170651-df8ea82bf434 + istio.io/pkg v0.0.0-20200511212725-7bfbbf968c23 +) replace github.com/Azure/go-autorest/autorest => github.com/Azure/go-autorest/autorest v0.9.0 diff --git a/pkg/test/istioio/script.go b/pkg/test/istioio/script.go index 17bc8dd2f8..8655d5c0b9 100644 --- a/pkg/test/istioio/script.go +++ b/pkg/test/istioio/script.go @@ -17,6 +17,7 @@ package istioio import ( "bytes" "fmt" + "io" "io/ioutil" "os" "os/exec" @@ -26,6 +27,7 @@ import ( "istio.io/istio/pkg/test/framework/resource/environment" "istio.io/istio/pkg/test/scopes" + "istio.io/pkg/log" ) const ( @@ -103,20 +105,36 @@ func (s Script) run(ctx Context) { cmd.Env = s.getEnv(ctx, fileName) cmd.Stdin = strings.NewReader(command) + // Output will be streamed to logs as well as to the output buffer (to be written to disk) + var output bytes.Buffer + cmd.Stdout = io.MultiWriter(&LogWriter{}, &output) + cmd.Stderr = io.MultiWriter(&LogWriter{}, &output) + // Run the command and get the output. - output, err := cmd.CombinedOutput() + cmdErr := cmd.Run() // Copy the command output from the script to workDir outputFileName := fileName + "_output.txt" - if err := ioutil.WriteFile(filepath.Join(ctx.WorkDir(), outputFileName), bytes.TrimSpace(output), 0644); err != nil { - ctx.Fatalf("failed copying output for command %s: %v", input.Name(), err) + if werr := ioutil.WriteFile(filepath.Join(ctx.WorkDir(), outputFileName), bytes.TrimSpace(output.Bytes()), 0644); werr != nil { + ctx.Fatalf("failed copying output for command %s: %v", input.Name(), werr) } - if err != nil { - ctx.Fatalf("script %s returned an error: %v. Output:\n%s", input.Name(), err, string(output)) + if cmdErr != nil { + ctx.Fatalf("script %s returned an error: %v. Output:\n%s", input.Name(), cmdErr, output.String()) } } +var scriptLog = log.RegisterScope("script", "output of test scripts", 0) + +type LogWriter struct{} + +func (l LogWriter) Write(p []byte) (n int, err error) { + scriptLog.Debugf("%v", strings.TrimSpace(string(p))) + return len(p), nil +} + +var _ io.Writer = &LogWriter{} + func (s Script) getWorkDir(ctx Context) string { if s.WorkDir != "" { // User-specified work dir for the script. diff --git a/tests/trafficmanagement/egress/main_test.go b/tests/trafficmanagement/egress/main_test.go new file mode 100644 index 0000000000..39fdb8b0d2 --- /dev/null +++ b/tests/trafficmanagement/egress/main_test.go @@ -0,0 +1,37 @@ +// 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. + +package egress + +import ( + "testing" + + "istio.io/istio/pkg/test/framework" + "istio.io/istio/pkg/test/framework/components/istio" + "istio.io/istio/pkg/test/framework/resource/environment" +) + +var ( + inst istio.Instance +) + +func TestMain(m *testing.M) { + // Integration test for Egress + framework. + NewSuite("trafficmanagement_egress", m). + SetupOnEnv(environment.Kube, istio.Setup(&inst, nil)). + RequireEnvironment(environment.Kube). + Run() + +} diff --git a/tests/trafficmanagement/egress/scripts/tls_origination.sh b/tests/trafficmanagement/egress/scripts/tls_origination.sh new file mode 100644 index 0000000000..2398a3bd5b --- /dev/null +++ b/tests/trafficmanagement/egress/scripts/tls_origination.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# shellcheck disable=SC1090,SC2154 + +# Copyright 2020 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. + +set -e +set -u +set -o pipefail + +source "${REPO_ROOT}/content/en/docs/tasks/traffic-management/egress/egress-tls-origination/snips.sh" +source "${REPO_ROOT}/tests/util/samples.sh" + +# Deploy sample and set up variable pointing to it +startup_sleep_sample +snip_before_you_begin_3 + +# Confirm we can access plain HTTP +snip_apply_simple +_run_and_verify_elided snip_curl_simple "$snip_curl_simple_out" + +# Apply TLS origination config, check http and https content is correct +snip_apply_origination +_run_and_verify_elided snip_curl_origination_http "$snip_curl_origination_http_out" +_run_and_verify_elided snip_curl_origination_https "$snip_curl_origination_https_out" diff --git a/tests/trafficmanagement/egress/tls_origination_test.go b/tests/trafficmanagement/egress/tls_origination_test.go new file mode 100644 index 0000000000..5c58288150 --- /dev/null +++ b/tests/trafficmanagement/egress/tls_origination_test.go @@ -0,0 +1,43 @@ +// 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. + +package egress + +import ( + "testing" + + "istio.io/istio/pkg/test/framework" + + "istio.io/istio.io/pkg/test/istioio" +) + +func TestTlsOrigination(t *testing.T) { + framework. + NewTest(t). + Run(istioio.NewBuilder("tasks__traffic_management__egress_tls_origination"). + Add(istioio.Script{ + Input: istioio.Path("scripts/tls_origination.sh"), + }). + Defer(istioio.Script{ + Input: istioio.Inline{ + FileName: "cleanup.sh", + Value: ` +set +e # ignore cleanup errors +source "${REPO_ROOT}/content/en/docs/tasks/traffic-management/egress/egress-tls-origination/snips.sh" +snip_cleanup_1 +snip_cleanup_2`, + }, + }). + Build()) +}