istio.io/istio@v0.0.0-20240520182934-d79c90f27776/tests/integration/security/util/cert/cert.go (about) 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 cert 19 20 import ( 21 "context" 22 "encoding/json" 23 "os" 24 "path" 25 26 v1 "k8s.io/api/core/v1" 27 "k8s.io/apimachinery/pkg/api/errors" 28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 30 "istio.io/istio/pkg/log" 31 "istio.io/istio/pkg/test" 32 "istio.io/istio/pkg/test/echo/common/scheme" 33 "istio.io/istio/pkg/test/env" 34 "istio.io/istio/pkg/test/framework/components/echo" 35 "istio.io/istio/pkg/test/framework/components/echo/check" 36 "istio.io/istio/pkg/test/framework/components/istio" 37 "istio.io/istio/pkg/test/framework/resource" 38 "istio.io/istio/security/pkg/pki/ca" 39 ) 40 41 // DumpCertFromSidecar gets the certificates served by the destination. 42 func DumpCertFromSidecar(t test.Failer, from echo.Instance, to echo.Target, port string) []string { 43 result := from.CallOrFail(t, echo.CallOptions{ 44 To: to, 45 Count: 1, 46 Port: echo.Port{ 47 Name: port, 48 }, 49 Scheme: scheme.TLS, 50 TLS: echo.TLS{ 51 Alpn: []string{"istio"}, 52 }, 53 Check: check.NoError(), 54 }) 55 if result.Responses.Len() != 1 { 56 t.Fatalf("dump cert failed, no responses") 57 } 58 var certs []string 59 for _, rr := range result.Responses[0].Body() { 60 var s string 61 if err := json.Unmarshal([]byte(rr), &s); err != nil { 62 t.Fatalf("failed to unmarshal: %v", err) 63 } 64 certs = append(certs, s) 65 } 66 return certs 67 } 68 69 // CreateCASecret creates a k8s secret "cacerts" to store the CA key and cert. 70 func CreateCASecret(ctx resource.Context) error { 71 return CreateCustomCASecret(ctx, 72 "ca-cert.pem", "ca-key.pem", 73 "cert-chain.pem", "root-cert.pem") 74 } 75 76 // CreateCASecretAlt creates a k8s secret "cacerts" to store the CA key and cert using an alternative set of certs. 77 func CreateCASecretAlt(ctx resource.Context) error { 78 return CreateCustomCASecret(ctx, 79 "ca-cert-alt.pem", "ca-key-alt.pem", 80 "cert-chain-alt.pem", "root-cert-alt.pem") 81 } 82 83 func CreateCustomCASecret(ctx resource.Context, caCertFile, caKeyFile, certChainFile, rootCertFile string) error { 84 name := "cacerts" 85 systemNs, err := istio.ClaimSystemNamespace(ctx) 86 if err != nil { 87 return err 88 } 89 90 var caCert, caKey, certChain, rootCert []byte 91 if caCert, err = ReadSampleCertFromFile(caCertFile); err != nil { 92 return err 93 } 94 if caKey, err = ReadSampleCertFromFile(caKeyFile); err != nil { 95 return err 96 } 97 if certChain, err = ReadSampleCertFromFile(certChainFile); err != nil { 98 return err 99 } 100 if rootCert, err = ReadSampleCertFromFile(rootCertFile); err != nil { 101 return err 102 } 103 104 for _, cluster := range ctx.AllClusters() { 105 secret := &v1.Secret{ 106 ObjectMeta: metav1.ObjectMeta{ 107 Name: name, 108 Namespace: systemNs.Name(), 109 }, 110 Data: map[string][]byte{ 111 ca.CACertFile: caCert, 112 ca.CAPrivateKeyFile: caKey, 113 ca.CertChainFile: certChain, 114 ca.RootCertFile: rootCert, 115 }, 116 } 117 118 if _, err := cluster.Kube().CoreV1().Secrets(systemNs.Name()).Create(context.TODO(), secret, metav1.CreateOptions{}); err != nil { 119 if errors.IsAlreadyExists(err) { 120 if _, err := cluster.Kube().CoreV1().Secrets(systemNs.Name()).Update(context.TODO(), secret, metav1.UpdateOptions{}); err != nil { 121 return err 122 } 123 } else { 124 return err 125 } 126 } 127 128 // If there is a configmap storing the CA cert from a previous 129 // integration test, remove it. Ideally, CI should delete all 130 // resources from a previous integration test, but sometimes 131 // the resources from a previous integration test are not deleted. 132 configMapName := "istio-ca-root-cert" 133 err = cluster.Kube().CoreV1().ConfigMaps(systemNs.Name()).Delete(context.TODO(), configMapName, 134 metav1.DeleteOptions{}) 135 if err == nil { 136 log.Infof("configmap %v is deleted", configMapName) 137 } else { 138 log.Infof("configmap %v may not exist and the deletion returns err (%v)", 139 configMapName, err) 140 } 141 } 142 143 return nil 144 } 145 146 func ReadSampleCertFromFile(f string) ([]byte, error) { 147 filename := f 148 if !path.IsAbs(filename) { 149 filename = path.Join(env.IstioSrc, "samples/certs", f) 150 } 151 b, err := os.ReadFile(filename) 152 if err != nil { 153 return nil, err 154 } 155 return b, nil 156 } 157 158 // CreateCustomEgressSecret creates a k8s secret "cacerts" to store egress gateways CA key and cert. 159 func CreateCustomEgressSecret(ctx resource.Context) error { 160 name := "egress-gw-cacerts" 161 systemNs, err := istio.ClaimSystemNamespace(ctx) 162 if err != nil { 163 return err 164 } 165 166 var caKey, certChain, rootCert, fakeRootCert []byte 167 if caKey, err = ReadCustomCertFromFile("key.pem"); err != nil { 168 return err 169 } 170 if certChain, err = ReadCustomCertFromFile("cert-chain.pem"); err != nil { 171 return err 172 } 173 if rootCert, err = ReadCustomCertFromFile("root-cert.pem"); err != nil { 174 return err 175 } 176 if fakeRootCert, err = ReadCustomCertFromFile("fake-root-cert.pem"); err != nil { 177 return err 178 } 179 180 secret := &v1.Secret{ 181 ObjectMeta: metav1.ObjectMeta{ 182 Name: name, 183 Namespace: systemNs.Name(), 184 }, 185 Data: map[string][]byte{ 186 "key.pem": caKey, 187 "cert-chain.pem": certChain, 188 "root-cert.pem": rootCert, 189 "fake-root-cert.pem": fakeRootCert, 190 }, 191 } 192 for _, cluster := range ctx.Clusters() { 193 _, err = cluster.Kube().CoreV1().Secrets(systemNs.Name()).Create(context.TODO(), secret, metav1.CreateOptions{}) 194 if err != nil { 195 if errors.IsAlreadyExists(err) { 196 _, err = cluster.Kube().CoreV1().Secrets(systemNs.Name()).Update(context.TODO(), secret, metav1.UpdateOptions{}) 197 return err 198 } 199 return err 200 } 201 } 202 return nil 203 } 204 205 func ReadCustomCertFromFile(f string) ([]byte, error) { 206 b, err := os.ReadFile(path.Join(env.IstioSrc, "tests/testdata/certs/dns", f)) 207 if err != nil { 208 return nil, err 209 } 210 return b, nil 211 } 212 213 func LoadCert(filename string) (string, error) { 214 data, err := ReadSampleCertFromFile(filename) 215 if err != nil { 216 return "", err 217 } 218 return string(data), nil 219 }