1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package httpchaos
17
18 import (
19 "context"
20 "crypto/tls"
21 "crypto/x509"
22 "embed"
23 "encoding/json"
24 "fmt"
25 "net/http"
26 "os"
27 "os/exec"
28 "time"
29
30 . "github.com/onsi/ginkgo/v2"
31 v1 "k8s.io/api/core/v1"
32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33 "k8s.io/apimachinery/pkg/util/wait"
34 "k8s.io/client-go/kubernetes"
35 "k8s.io/kubernetes/test/e2e/framework"
36 "sigs.k8s.io/controller-runtime/pkg/client"
37
38 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
39 "github.com/chaos-mesh/chaos-mesh/e2e-test/e2e/util"
40 )
41
42
43 var content embed.FS
44
45 type TLSServerKeys struct {
46 Cert []byte `json:"cert"`
47 Key []byte `json:"key"`
48 }
49
50 func setupHTTPS(cli *http.Client, serverIP string) (TLSServerKeys, []byte) {
51 c, err := content.ReadDir("keys")
52 framework.ExpectNoError(err, "read key dir error")
53 var key []byte
54 var ca []byte
55 for _, f := range c {
56 if f.IsDir() {
57 continue
58 }
59 b, err := content.ReadFile("keys/" + f.Name())
60 framework.ExpectNoError(err, "read key file error")
61 switch f.Name() {
62 case "server.key":
63 key = b
64 case "ca.crt":
65 ca = b
66 }
67 err = os.WriteFile(f.Name(), b, 0644)
68 framework.ExpectNoError(err, "write key file error")
69 }
70
71 f, err := os.OpenFile("server.ext", os.O_APPEND|os.O_WRONLY, 0644)
72 if err != nil {
73 framework.ExpectNoError(err, "open server.ext file error")
74 }
75 if _, err = f.WriteString(fmt.Sprint("IP.1 = " + serverIP)); err != nil {
76 framework.ExpectNoError(err, "write server.ext file error")
77 }
78 err = f.Close()
79 framework.ExpectNoError(err, "close server.ext file error")
80
81 cmdStr := "openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650 -sha256 -extfile server.ext"
82 cmd := exec.Command("bash", "-c", cmdStr)
83 output, err := cmd.CombinedOutput()
84 if err != nil {
85 framework.ExpectNoError(err, "run openssl cmd error: "+string(output))
86 }
87 crt, err := os.ReadFile("server.crt")
88 framework.ExpectNoError(err, "read server.crt file error")
89
90 roots := x509.NewCertPool()
91 caPk, err := os.ReadFile("ca.crt")
92 if err != nil {
93 panic(err)
94 }
95 ok := roots.AppendCertsFromPEM(caPk)
96 framework.ExpectEqual(ok, true, "failed to parse root certificate")
97
98 cli.Transport = &http.Transport{
99 TLSClientConfig: &tls.Config{
100 RootCAs: roots,
101 },
102 }
103
104 return TLSServerKeys{
105 Cert: crt,
106 Key: key,
107 }, ca
108 }
109
110 func TestcaseHttpTLSThenRecover(
111 ns string,
112 kubeCli kubernetes.Interface,
113 cli client.Client,
114 c HTTPE2EClient,
115 port uint16,
116 tlsPort uint16,
117 ) {
118 serverKeys, ca := setupHTTPS(c.C, c.IP)
119 ctx, cancel := context.WithCancel(context.Background())
120 defer cancel()
121
122 By("waiting on e2e helper ready")
123 err := util.WaitHTTPE2EHelperReady(*c.C, c.IP, port)
124 framework.ExpectNoError(err, "wait e2e helper ready error")
125 By("create http delay chaos CRD objects")
126
127 body, err := json.Marshal(serverKeys)
128 framework.ExpectNoError(err, "marshal server keys error")
129 err = util.SetupHTTPE2EHelperTLSConfig(*c.C, c.IP, port, tlsPort, body)
130 framework.ExpectNoError(err, "setup e2e helper tls config error")
131 delay := "1ms"
132
133 _, err = kubeCli.CoreV1().Secrets(ns).Create(ctx, &v1.Secret{
134 ObjectMeta: metav1.ObjectMeta{
135 Name: "http-tls",
136 Namespace: ns,
137 },
138 Data: map[string][]byte{
139 "ca.crt": ca,
140 "server.crt": serverKeys.Cert,
141 "server.key": serverKeys.Key,
142 },
143 }, metav1.CreateOptions{})
144 framework.ExpectNoError(err, "create secret error")
145 caName := "ca.crt"
146 httpChaos := &v1alpha1.HTTPChaos{
147 ObjectMeta: metav1.ObjectMeta{
148 Name: "http-chaos",
149 Namespace: ns,
150 },
151 Spec: v1alpha1.HTTPChaosSpec{
152 PodSelector: v1alpha1.PodSelector{
153 Selector: v1alpha1.PodSelectorSpec{
154 GenericSelectorSpec: v1alpha1.GenericSelectorSpec{
155 Namespaces: []string{ns},
156 LabelSelectors: map[string]string{"app": "http"},
157 },
158 },
159 Mode: v1alpha1.OneMode,
160 },
161 Port: 8081,
162 Target: "Request",
163 PodHttpChaosActions: v1alpha1.PodHttpChaosActions{
164 Delay: &delay,
165 },
166 TLS: &v1alpha1.PodHttpChaosTLS{
167 SecretName: "http-tls",
168 SecretNamespace: ns,
169 CertName: "server.crt",
170 KeyName: "server.key",
171 CAName: &caName,
172 },
173 },
174 }
175 err = cli.Create(ctx, httpChaos)
176 framework.ExpectNoError(err, "create http chaos error")
177
178 By("waiting for HTTP pong")
179 err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (bool, error) {
180 err := util.WaitHTTPE2EHelperTLSReady(*c.C, c.IP, tlsPort)
181 if err != nil {
182 return false, err
183 }
184 return true, nil
185 })
186 framework.ExpectNoError(err, "http chaos doesn't work as expected")
187 By("apply http chaos successfully")
188
189 By("delete chaos CRD objects")
190
191 err = cli.Delete(ctx, httpChaos)
192 framework.ExpectNoError(err, "failed to delete http chaos")
193 }
194