blob: de428c71a1ba7732bada182287ebf65149b14931 [file] [log] [blame]
//go:build integ
// +build integ
// 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 sdsegress
import (
"context"
"net/http"
"testing"
"time"
)
import (
epb "github.com/apache/dubbo-go-pixiu/pkg/test/echo/proto"
"github.com/apache/dubbo-go-pixiu/pkg/test/framework"
"github.com/apache/dubbo-go-pixiu/pkg/test/framework/components/echo"
"github.com/apache/dubbo-go-pixiu/pkg/test/framework/components/echo/check"
"github.com/apache/dubbo-go-pixiu/pkg/test/framework/components/echo/deployment"
"github.com/apache/dubbo-go-pixiu/pkg/test/framework/components/istio"
"github.com/apache/dubbo-go-pixiu/pkg/test/framework/components/namespace"
"github.com/apache/dubbo-go-pixiu/pkg/test/framework/components/prometheus"
"github.com/apache/dubbo-go-pixiu/pkg/test/util/retry"
"github.com/apache/dubbo-go-pixiu/tests/integration/security/util"
)
const (
// should be templated into YAML, and made interchangeable with other sites
externalURL = "http://bing.com"
externalReqCount = 2
egressName = "istio-egressgateway"
// paths to test configs
istioMutualTLSGatewayConfig = "testdata/istio-mutual-gateway-bing.yaml"
simpleTLSGatewayConfig = "testdata/simple-tls-gateway-bing.yaml"
)
// TestSdsEgressGatewayIstioMutual brings up an SDS enabled cluster and will ensure that the ISTIO_MUTUAL
// TLS mode allows secure communication between the egress and workloads. This test brings up an ISTIO_MUTUAL enabled
// gateway, and then, an incorrectly configured simple TLS gateway. The test will ensure that requests are routed
// securely through the egress gateway in the first case, and fail in the second case.
func TestSdsEgressGatewayIstioMutual(t *testing.T) {
// Turn it back on once issue is fixed.
t.Skip("https://github.com/istio/istio/issues/17933")
framework.NewTest(t).
Features("security.egress.mtls.sds").
Run(func(t framework.TestContext) {
istioCfg := istio.DefaultConfigOrFail(t, t)
namespace.ClaimOrFail(t, t, istioCfg.SystemNamespace)
ns := namespace.NewOrFail(t, t, namespace.Config{
Prefix: "sds-egress-gateway-workload",
Inject: true,
})
applySetupConfig(t, ns)
testCases := map[string]struct {
configPath string
code int
}{
"ISTIO_MUTUAL TLS mode requests are routed through egress succeed": {
configPath: istioMutualTLSGatewayConfig,
code: http.StatusOK,
},
"SIMPLE TLS mode requests are routed through gateway but fail with 503": {
configPath: simpleTLSGatewayConfig,
code: http.StatusServiceUnavailable,
},
}
for name, tc := range testCases {
t.NewSubTest(name).
Run(func(t framework.TestContext) {
doIstioMutualTest(t, ns, tc.configPath, tc.code)
})
}
})
}
func doIstioMutualTest(
ctx framework.TestContext, ns namespace.Instance, configPath string, expectedCode int) {
var client echo.Instance
deployment.New(ctx).
With(&client, util.EchoConfig("client", ns, false, nil)).
BuildOrFail(ctx)
ctx.ConfigIstio().File(ns.Name(), configPath).ApplyOrFail(ctx)
// give the configuration a moment to kick in
time.Sleep(time.Second * 20)
pretestReqCount := getEgressRequestCountOrFail(ctx, ns, prom)
for i := 0; i < externalReqCount; i++ {
w := client.WorkloadsOrFail(ctx)[0]
responses, err := w.ForwardEcho(context.TODO(), &epb.ForwardEchoRequest{
Url: externalURL,
Count: 1,
})
if err := check.And(
check.NoError(),
check.Status(expectedCode)).Check(echo.CallResult{
From: client,
Opts: echo.CallOptions{},
Responses: responses,
}, err); err != nil {
ctx.Fatal(err)
}
}
// give prometheus some time to ingest the metrics
posttestReqCount := getEgressRequestCountOrFail(ctx, ns, prom)
newGatewayReqs := posttestReqCount - pretestReqCount
if newGatewayReqs != externalReqCount {
ctx.Errorf("expected %d requests routed through egress, got %d",
externalReqCount, newGatewayReqs)
}
}
// sets up the destination rule to route through egress, virtual service, and service entry
func applySetupConfig(ctx framework.TestContext, ns namespace.Instance) {
ctx.Helper()
configFiles := []string{
"testdata/destination-rule-bing.yaml",
"testdata/rule-route-sidecar-to-egress-bing.yaml",
"testdata/service-entry-bing.yaml",
}
for _, c := range configFiles {
if err := ctx.ConfigIstio().File(ns.Name(), c).Apply(); err != nil {
ctx.Fatalf("failed to apply configuration file %s; err: %v", c, err)
}
}
}
func getEgressRequestCountOrFail(t framework.TestContext, ns namespace.Instance, prom prometheus.Instance) int {
t.Helper()
var res int
retry.UntilSuccessOrFail(t, func() error {
r, err := prom.QuerySum(t.Clusters().Default(), prometheus.Query{Metric: "istio_requests_total", Labels: map[string]string{
"destination_app": egressName,
"source_workload_namespace": ns.Name(),
}})
res = int(r)
return err
})
return res
}