k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/e2e/auth/projected_clustertrustbundle.go (about) 1 /* 2 Copyright 2023 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package auth 18 19 import ( 20 "context" 21 "crypto/ed25519" 22 "crypto/rand" 23 "crypto/x509" 24 "crypto/x509/pkix" 25 "encoding/pem" 26 "fmt" 27 "math/big" 28 "os" 29 "regexp" 30 31 certificatesv1alpha1 "k8s.io/api/certificates/v1alpha1" 32 v1 "k8s.io/api/core/v1" 33 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 34 "k8s.io/apimachinery/pkg/util/uuid" 35 "k8s.io/kubernetes/test/e2e/feature" 36 "k8s.io/kubernetes/test/e2e/framework" 37 e2epodoutput "k8s.io/kubernetes/test/e2e/framework/pod/output" 38 imageutils "k8s.io/kubernetes/test/utils/image" 39 admissionapi "k8s.io/pod-security-admission/api" 40 "k8s.io/utils/ptr" 41 42 "github.com/onsi/ginkgo/v2" 43 ) 44 45 var _ = SIGDescribe(feature.ClusterTrustBundle, feature.ClusterTrustBundleProjection, func() { 46 f := framework.NewDefaultFramework("projected-clustertrustbundle") 47 f.NamespacePodSecurityLevel = admissionapi.LevelBaseline 48 49 goodCert1 := mustMakeCertificate(&x509.Certificate{ 50 SerialNumber: big.NewInt(0), 51 Subject: pkix.Name{ 52 CommonName: "root1", 53 }, 54 IsCA: true, 55 BasicConstraintsValid: true, 56 }) 57 58 goodCert1Block := string(mustMakePEMBlock("CERTIFICATE", nil, goodCert1)) 59 60 ginkgo.It("should be able to mount a single ClusterTrustBundle by name", func(ctx context.Context) { 61 62 ctb1 := &certificatesv1alpha1.ClusterTrustBundle{ 63 ObjectMeta: metav1.ObjectMeta{ 64 Name: "ctb1", 65 }, 66 Spec: certificatesv1alpha1.ClusterTrustBundleSpec{ 67 TrustBundle: goodCert1Block, 68 }, 69 } 70 71 if _, err := f.ClientSet.CertificatesV1alpha1().ClusterTrustBundles().Create(ctx, ctb1, metav1.CreateOptions{}); err != nil { 72 framework.Failf("Error while creating ClusterTrustBundle: %v", err) 73 } 74 75 pod := &v1.Pod{ 76 ObjectMeta: metav1.ObjectMeta{ 77 Name: "pod-projected-ctb-" + string(uuid.NewUUID()), 78 }, 79 Spec: v1.PodSpec{ 80 RestartPolicy: v1.RestartPolicyNever, 81 Containers: []v1.Container{ 82 { 83 Name: "projected-ctb-volume-test", 84 Image: imageutils.GetE2EImage(imageutils.Agnhost), 85 Args: []string{ 86 "mounttest", 87 "--file_content=/var/run/ctbtest/trust-anchors.pem", 88 "--file_mode=/var/run/ctbtest/trust-anchors.pem", 89 }, 90 VolumeMounts: []v1.VolumeMount{ 91 { 92 Name: "ctb-volume", 93 MountPath: "/var/run/ctbtest", 94 }, 95 }, 96 }, 97 }, 98 Volumes: []v1.Volume{ 99 { 100 Name: "ctb-volume", 101 VolumeSource: v1.VolumeSource{ 102 Projected: &v1.ProjectedVolumeSource{ 103 Sources: []v1.VolumeProjection{ 104 { 105 ClusterTrustBundle: &v1.ClusterTrustBundleProjection{ 106 Name: ptr.To("ctb1"), 107 Path: "trust-anchors.pem", 108 }, 109 }, 110 }, 111 }, 112 }, 113 }, 114 }, 115 }, 116 } 117 118 fileModeRegexp := getFileModeRegex("/var/run/ctbtest/trust-anchors.pem", nil) 119 expectedOutput := []string{ 120 regexp.QuoteMeta(goodCert1Block), 121 fileModeRegexp, 122 } 123 124 e2epodoutput.TestContainerOutputRegexp(ctx, f, "project cluster trust bundle", pod, 0, expectedOutput) 125 }) 126 }) 127 128 func mustMakeCertificate(template *x509.Certificate) []byte { 129 pub, priv, err := ed25519.GenerateKey(rand.Reader) 130 if err != nil { 131 framework.Failf("Error while generating key: %v", err) 132 } 133 134 cert, err := x509.CreateCertificate(rand.Reader, template, template, pub, priv) 135 if err != nil { 136 framework.Failf("Error while making certificate: %v", err) 137 } 138 139 return cert 140 } 141 142 func mustMakePEMBlock(blockType string, headers map[string]string, data []byte) string { 143 return string(pem.EncodeToMemory(&pem.Block{ 144 Type: blockType, 145 Headers: headers, 146 Bytes: data, 147 })) 148 } 149 150 // getFileModeRegex returns a file mode related regex which should be matched by the mounttest pods' output. 151 // If the given mask is nil, then the regex will contain the default OS file modes, which are 0644 for Linux and 0775 for Windows. 152 func getFileModeRegex(filePath string, mask *int32) string { 153 var ( 154 linuxMask int32 155 windowsMask int32 156 ) 157 if mask == nil { 158 linuxMask = int32(0644) 159 windowsMask = int32(0775) 160 } else { 161 linuxMask = *mask 162 windowsMask = *mask 163 } 164 165 linuxOutput := fmt.Sprintf("mode of file \"%s\": %v", filePath, os.FileMode(linuxMask)) 166 windowsOutput := fmt.Sprintf("mode of Windows file \"%v\": %s", filePath, os.FileMode(windowsMask)) 167 168 return fmt.Sprintf("(%s|%s)", linuxOutput, windowsOutput) 169 }