istio

Форк
0
/
cacert_rotation_test.go 
171 строка · 6.1 Кб
1
//go:build integ
2
// +build integ
3

4
// Copyright Istio Authors
5
//
6
// Licensed under the Apache License, Version 2.0 (the "License");
7
// you may not use this file except in compliance with the License.
8
// You may obtain a copy of the License at
9
//
10
//     http://www.apache.org/licenses/LICENSE-2.0
11
//
12
// Unless required by applicable law or agreed to in writing, software
13
// distributed under the License is distributed on an "AS IS" BASIS,
14
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
// See the License for the specific language governing permissions and
16
// limitations under the License.
17

18
package ambient
19

20
import (
21
	"bytes"
22
	"crypto/x509"
23
	"encoding/base64"
24
	"encoding/json"
25
	"errors"
26
	"fmt"
27
	"strings"
28
	"testing"
29
	"time"
30

31
	v1 "k8s.io/api/core/v1"
32

33
	"istio.io/istio/istioctl/pkg/util/configdump"
34
	"istio.io/istio/pkg/test/framework"
35
	"istio.io/istio/pkg/test/framework/components/istio"
36
	"istio.io/istio/pkg/test/framework/components/istioctl"
37
	"istio.io/istio/pkg/test/framework/components/namespace"
38
	kubetest "istio.io/istio/pkg/test/kube"
39
	"istio.io/istio/pkg/test/util/assert"
40
	"istio.io/istio/pkg/test/util/retry"
41
	"istio.io/istio/security/pkg/pki/util"
42
	"istio.io/istio/tests/integration/security/util/cert"
43
)
44

45
func TestIntermediateCertificateRefresh(t *testing.T) {
46
	framework.NewTest(t).
47
		Features("security.peer.cacert-rotation").
48
		Run(func(t framework.TestContext) {
49
			t.Skip("https://github.com/istio/istio/issues/49648")
50
			istioCfg := istio.DefaultConfigOrFail(t, t)
51
			istioCtl := istioctl.NewOrFail(t, t, istioctl.Config{})
52
			namespace.ClaimOrFail(t, t, istioCfg.SystemNamespace)
53
			newX509 := getX509FromFile(t, "ca-cert-alt-2.pem")
54

55
			sa := apps.Captured[0].ServiceAccountName()
56

57
			// we do not know which ztunnel instance is located on the node as the workload, so we need to check all of them initially
58
			ztunnelPods, err := kubetest.NewPodFetch(t.AllClusters()[0], istioCfg.SystemNamespace, "app=ztunnel")()
59
			assert.NoError(t, err)
60

61
			originalWorkloadSecret, ztunnelPod, err := getWorkloadSecret(t, ztunnelPods, sa, istioCtl)
62
			if err != nil {
63
				t.Errorf("failed to get initial workload secret: %v", err)
64
			}
65

66
			// Update CA with new intermediate cert
67
			if err := cert.CreateCustomCASecret(t,
68
				"ca-cert-alt-2.pem", "ca-key-alt-2.pem",
69
				"cert-chain-alt-2.pem", "root-cert-alt.pem"); err != nil {
70
				t.Errorf("failed to update CA secret: %v", err)
71
			}
72

73
			// perform one retry to handle race condition where ztunnel cert is refreshed before Istiod certificates are reloaded
74
			retry.UntilSuccess(func() error {
75
				newWorkloadCert := waitForWorkloadCertUpdate(t, ztunnelPod, sa, istioCtl, originalWorkloadSecret)
76
				return verifyWorkloadCert(t, newWorkloadCert, newX509)
77
			}, retry.MaxAttempts(2), retry.Timeout(5*time.Minute))
78
		})
79
}
80

81
func getWorkloadSecret(t framework.TestContext, zPods []v1.Pod, serviceAccount string, ctl istioctl.Instance) (*configdump.CertsDump, v1.Pod, error) {
82
	for _, ztunnel := range zPods {
83
		podName := fmt.Sprintf("%s.%s", ztunnel.Name, ztunnel.Namespace)
84
		out, errOut, err := ctl.Invoke([]string{"pc", "s", podName, "-o", "json"})
85
		if err != nil || errOut != "" {
86
			t.Errorf("failed to retrieve pod secrets from %s, err: %v errOut: %s", podName, err, errOut)
87
		}
88

89
		dump := []configdump.CertsDump{}
90
		if err := json.Unmarshal([]byte(out), &dump); err != nil {
91
			t.Errorf("failed to unmarshal secret dump: %v", err)
92
		}
93

94
		for _, s := range dump {
95
			if strings.Contains(s.Identity, serviceAccount) {
96
				if len(s.CertChain) == 0 {
97
					t.Fatalf("cert chain missing in %v for identity: %v", ztunnel.Name, s.Identity)
98
				}
99
				return &s, ztunnel, nil
100
			}
101
		}
102
	}
103
	return nil, v1.Pod{}, errors.New("failed to find workload secret")
104
}
105

106
// Abstracted function to wait for workload cert to be updated
107
func waitForWorkloadCertUpdate(t framework.TestContext, ztunnelPod v1.Pod, serviceAccount string,
108
	istioCtl istioctl.Instance, originalCert *configdump.CertsDump,
109
) *configdump.CertsDump {
110
	var newSecret *configdump.CertsDump
111
	retry.UntilOrFail(t, func() bool {
112
		updatedCert, _, err := getWorkloadSecret(t, []v1.Pod{ztunnelPod}, serviceAccount, istioCtl)
113
		if err != nil {
114
			t.Logf("failed to get current workload secret: %v", err)
115
			return false
116
		}
117

118
		// retry when workload cert is not updated
119
		if originalCert.CertChain[0].ValidFrom != updatedCert.CertChain[0].ValidFrom {
120
			newSecret = updatedCert
121
			t.Logf("workload cert is updated")
122
			return true
123
		}
124

125
		return false
126
	}, retry.Timeout(5*time.Minute), retry.Delay(10*time.Second))
127
	return newSecret
128
}
129

130
func verifyWorkloadCert(t framework.TestContext, workloadSecret *configdump.CertsDump, caX590 *x509.Certificate) error {
131
	intermediateCert, err := base64.StdEncoding.DecodeString(workloadSecret.CertChain[1].Pem)
132
	if err != nil {
133
		t.Errorf("failed to decode intermediate certificate: %v", err)
134
	}
135
	intermediateX509 := parseCert(t, intermediateCert)
136
	// verify the correct intermediate cert is in the certificate chain
137
	if intermediateX509.SerialNumber.String() != caX590.SerialNumber.String() {
138
		return fmt.Errorf("intermediate certificate serial numbers do not match: got %v, wanted %v",
139
			intermediateX509.SerialNumber.String(), caX590.SerialNumber.String())
140
	}
141

142
	workloadCert, err := base64.StdEncoding.DecodeString(workloadSecret.CertChain[0].Pem)
143
	if err != nil {
144
		return fmt.Errorf("failed to decode workload certificate: %v", err)
145
	}
146
	workloadX509 := parseCert(t, workloadCert)
147

148
	// verify workload cert contains the correct intermediate cert
149
	if !bytes.Equal(workloadX509.AuthorityKeyId, caX590.SubjectKeyId) {
150
		return fmt.Errorf("workload certificate did not have expected authority key id: got %v wanted %v",
151
			string(workloadX509.AuthorityKeyId), string(caX590.SubjectKeyId))
152
	}
153

154
	return nil
155
}
156

157
func getX509FromFile(t framework.TestContext, caCertFile string) *x509.Certificate {
158
	certBytes, err := cert.ReadSampleCertFromFile(caCertFile)
159
	if err != nil {
160
		t.Errorf("failed to read %s file: %v", caCertFile, err)
161
	}
162
	return parseCert(t, certBytes)
163
}
164

165
func parseCert(t framework.TestContext, certBytes []byte) *x509.Certificate {
166
	parsedCert, err := util.ParsePemEncodedCertificate(certBytes)
167
	if err != nil {
168
		t.Errorf("failed to parse certificate pem file: %v", err)
169
	}
170
	return parsedCert
171
}
172

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.