blob: 10ecf81dfff33dda07a91ae3bff6982151d39f35 [file] [log] [blame]
//go:build integ
// +build integ
// 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.
package stackdriver
import (
"context"
"net/http"
"testing"
)
import (
"golang.org/x/sync/errgroup"
)
import (
"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/stackdriver"
"github.com/apache/dubbo-go-pixiu/pkg/test/framework/resource"
"github.com/apache/dubbo-go-pixiu/pkg/test/util/retry"
"github.com/apache/dubbo-go-pixiu/tests/integration/telemetry"
)
const (
dryRunAuthorizationPolicyAllow = "testdata/security_authz_dry_run/policy_allow.yaml.tmpl"
dryRunAuthorizationPolicyDeny = "testdata/security_authz_dry_run/policy_deny.yaml.tmpl"
dryRunServerLogEntryAllowNoPolicy = "testdata/security_authz_dry_run/server_access_log_allow_no_policy.json.tmpl"
dryRunServerLogEntryAllowWithPolicy = "testdata/security_authz_dry_run/server_access_log_allow_with_policy.json.tmpl"
dryRunServerLogEntryDenyNoPolicy = "testdata/security_authz_dry_run/server_access_log_deny_no_policy.json.tmpl"
dryRunServerLogEntryDenyWithPolicy = "testdata/security_authz_dry_run/server_access_log_deny_with_policy.json.tmpl"
)
type dryRunCase struct {
name string
headers http.Header
wantLog string
}
func testDryRunHTTP(t *testing.T, policies []string, cases []dryRunCase) {
testDryRun(t, policies, cases, false)
}
func testDryRunTCP(t *testing.T, policies []string, cases []dryRunCase) {
testDryRun(t, policies, cases, true)
}
func testDryRun(t *testing.T, policies []string, cases []dryRunCase, isTCP bool) {
framework.NewTest(t).
Features("observability.telemetry.stackdriver").
Run(func(t framework.TestContext) {
for _, policy := range policies {
createDryRunPolicy(t, policy)
}
for _, tc := range cases {
t.NewSubTest(tc.name).Run(func(ctx framework.TestContext) {
g, _ := errgroup.WithContext(context.Background())
for _, cltInstance := range Clt {
cltInstance := cltInstance
g.Go(func() error {
err := retry.UntilSuccess(func() error {
if err := SendTraffic(cltInstance, tc.headers, isTCP); err != nil {
return err
}
return verifyAccessLog(ctx, cltInstance, tc.wantLog)
}, retry.Delay(framework.TelemetryRetryDelay), retry.Timeout(framework.TelemetryRetryTimeout))
if err != nil {
return err
}
return nil
})
}
if err := g.Wait(); err != nil {
ctx.Fatalf("test failed: %v", err)
}
})
}
})
}
// TestStackdriverAuthzDryRun_Deny verifies that stackdriver WASM filter exports dry-run logs with expected labels
// when there are only deny authorization policy.
func TestStackdriverAuthzDryRun_Deny(t *testing.T) {
// DENY policy:
// 1. matched -> AuthzDenied + deny policy name
// 2. notMatched -> AuthzAllowed
testDryRunHTTP(t, []string{dryRunAuthorizationPolicyDeny}, []dryRunCase{
{
name: "matched",
headers: http.Header{"Dry-Run-Deny": []string{"matched"}},
wantLog: dryRunServerLogEntryDenyWithPolicy,
},
{
name: "notMatched",
headers: http.Header{"Dry-Run-Deny": []string{"notMatched"}},
wantLog: dryRunServerLogEntryAllowNoPolicy,
},
})
}
// TestStackdriverAuthzDryRun_Allow verifies that stackdriver WASM filter exports dry-run logs with expected labels
// when there are only allow authorization policy.
func TestStackdriverAuthzDryRun_Allow(t *testing.T) {
// ALLOW policy:
// 1. matched -> AuthzAllowed + allow policy name
// 2. notMatched -> AuthzDenied
testDryRunHTTP(t, []string{dryRunAuthorizationPolicyAllow}, []dryRunCase{
{
name: "matched",
headers: http.Header{"Dry-Run-Allow": []string{"matched"}},
wantLog: dryRunServerLogEntryAllowWithPolicy,
},
{
name: "notMatched",
headers: http.Header{"Dry-Run-Allow": []string{"notMatched"}},
wantLog: dryRunServerLogEntryDenyNoPolicy,
},
})
}
// TestStackdriverAuthzDryRun_DenyAndAllow verifies that stackdriver WASM filter exports dry-run logs with expected labels
// when there are both allow and deny authorization policy.
func TestStackdriverAuthzDryRun_DenyAndAllow(t *testing.T) {
// DENY and ALLOW policy:
// 1. DENY matched, ALLOW matched -> AuthzDenied + deny policy name
// 2. DENY matched, ALLOW notMatched -> AuthzDenied + deny policy name
// 3. DENY notMatched, ALLOW matched -> AuthzAllowed + allow policy name
// 4. DENY notMatched, ALLOW notMatched -> AuthzDenied
testDryRunHTTP(t, []string{dryRunAuthorizationPolicyDeny, dryRunAuthorizationPolicyAllow}, []dryRunCase{
{
name: "matchedBoth",
headers: http.Header{"Dry-Run-Deny": []string{"matched"}, "Dry-Run-Allow": []string{"matched"}},
wantLog: dryRunServerLogEntryDenyWithPolicy,
},
{
name: "matchedDeny",
headers: http.Header{"Dry-Run-Deny": []string{"matched"}, "Dry-Run-Allow": []string{"notMatched"}},
wantLog: dryRunServerLogEntryDenyWithPolicy,
},
{
name: "matchedAllow",
headers: http.Header{"Dry-Run-Deny": []string{"notMatched"}, "Dry-Run-Allow": []string{"matched"}},
wantLog: dryRunServerLogEntryAllowWithPolicy,
},
{
name: "notMatched",
headers: http.Header{"Dry-Run-Deny": []string{"notMatched"}, "Dry-Run-Allow": []string{"notMatched"}},
wantLog: dryRunServerLogEntryDenyNoPolicy,
},
})
}
// TestTCPStackdriverAuthzDryRun_Deny verifies that stackdriver WASM filter exports dry-run logs with expected labels for TCP traffic
// when there is only deny authorization policy.
func TestTCPStackdriverAuthzDryRun_Deny(t *testing.T) {
testDryRunTCP(t, []string{"testdata/security_authz_dry_run/tcp_policy_deny_matched.yaml.tmpl"}, []dryRunCase{
{
name: "matchedDeny",
wantLog: "testdata/security_authz_dry_run/tcp_server_access_log_deny_matched.json.tmpl",
},
})
}
// TestTCPStackdriverAuthzDryRun_Allow verifies that stackdriver WASM filter exports dry-run logs with expected labels for TCP traffic
// when there is only allow authorization policy.
func TestTCPStackdriverAuthzDryRun_Allow(t *testing.T) {
testDryRunTCP(t, []string{"testdata/security_authz_dry_run/tcp_policy_allow_matched.yaml.tmpl"}, []dryRunCase{
{
name: "matchedAllow",
wantLog: "testdata/security_authz_dry_run/tcp_server_access_log_allow_matched.json.tmpl",
},
})
}
// TestTCPStackdriverAuthzDryRun_DenyAndAllow verifies that stackdriver WASM filter exports dry-run logs with expected labels for TCP traffic
// when there are both allow and deny authorization policy.
func TestTCPStackdriverAuthzDryRun_DenyAndAllow(t *testing.T) {
testDryRunTCP(t, []string{"testdata/security_authz_dry_run/tcp_policy_both_matched.yaml.tmpl"}, []dryRunCase{
{
name: "matchedBoth",
wantLog: "testdata/security_authz_dry_run/tcp_server_access_log_both_matched.json.tmpl",
},
})
}
func createDryRunPolicy(t framework.TestContext, authz string) {
t.Helper()
ns := EchoNsInst.Name()
args := map[string]string{"Namespace": ns}
t.ConfigIstio().EvalFile(ns, args, authz).ApplyOrFail(t, resource.Wait)
}
func verifyAccessLog(t framework.TestContext, cltInstance echo.Instance, wantLog string) error {
t.Helper()
t.Logf("Validating for cluster %v", cltInstance.Config().Cluster.Name())
clName := cltInstance.Config().Cluster.Name()
trustDomain := telemetry.GetTrustDomain(cltInstance.Config().Cluster, Ist.Settings().SystemNamespace)
if err := ValidateLogs(t, wantLog, clName, trustDomain, stackdriver.ServerAccessLog); err != nil {
return err
}
return nil
}