diff --git a/api/v1alpha1/constants.go b/api/v1/constants.go similarity index 51% rename from api/v1alpha1/constants.go rename to api/v1/constants.go index 1f3a6724..ab6958e0 100644 --- a/api/v1alpha1/constants.go +++ b/api/v1/constants.go @@ -1,6 +1,6 @@ -package v1alpha1 +package v1 const ( Group = "token.kubevirt.io" - Version = "v1alpha1" + Version = "v1" ) diff --git a/api/v1/types.go b/api/v1/types.go new file mode 100644 index 00000000..c5d33fae --- /dev/null +++ b/api/v1/types.go @@ -0,0 +1,31 @@ +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// TokenResponse is the response object from /token endpoint. +type TokenResponse struct { + Token string `json:"token"` + ExpirationTimestamp metav1.Time `json:"expirationTimestamp"` +} + +// TlsProfile is the TLS configuration for the proxy. +type TlsProfile struct { + Ciphers []string `json:"ciphers,omitempty"` + MinTLSVersion TLSProtocolVersion `json:"minTLSVersion,omitempty"` +} + +// TLSProtocolVersion is a way to specify the protocol version used for TLS connections. +type TLSProtocolVersion string + +const ( + // VersionTLS10 is version 1.0 of the TLS security protocol. + VersionTLS10 TLSProtocolVersion = "VersionTLS10" + // VersionTLS11 is version 1.1 of the TLS security protocol. + VersionTLS11 TLSProtocolVersion = "VersionTLS11" + // VersionTLS12 is version 1.2 of the TLS security protocol. + VersionTLS12 TLSProtocolVersion = "VersionTLS12" + // VersionTLS13 is version 1.3 of the TLS security protocol. + VersionTLS13 TLSProtocolVersion = "VersionTLS13" +) diff --git a/api/v1alpha1/types.go b/api/v1alpha1/types.go deleted file mode 100644 index ae61127c..00000000 --- a/api/v1alpha1/types.go +++ /dev/null @@ -1,13 +0,0 @@ -package v1alpha1 - -import ( - ocpv1 "github.com/openshift/api/config/v1" -) - -// TokenResponse is the response object from /token endpoint. -type TokenResponse struct { - Token string `json:"token"` -} - -// TlsSecurityProfile is the TLS configuration for the proxy. -type TlsSecurityProfile = ocpv1.TLSSecurityProfile diff --git a/docs/api.md b/docs/api.md index 2ab077a8..5a55ac96 100644 --- a/docs/api.md +++ b/docs/api.md @@ -4,7 +4,7 @@ A temporary token can be generated using: ``` -GET /apis/token.kubevirt.io/v1alpha1/namespaces/${VMI_NAMESPACE}/virtualmachines/${VMI_NAME}/vnc +GET /apis/token.kubevirt.io/v1/namespaces/${VMI_NAMESPACE}/virtualmachines/${VMI_NAME}/vnc ``` Where `${VMI_NAMESPACE}` and `${VMI_NAME}` are the namespace and name of a running VMI. @@ -28,7 +28,7 @@ Result is a JSON object containing the token: ### Example ```bash curl --header "Authorization: Bearer ${KUBERNETES_USER_TOKEN}" \ - "https://${K8S_API_URL}/apis/token.kubevirt.io/v1alpha1/namespaces/${VMI_NAMESPACE}/virtualmachines/${VMI_NAME}/vnc?duration=${DURATION}" + "https://${K8S_API_URL}/apis/token.kubevirt.io/v1/namespaces/${VMI_NAMESPACE}/virtualmachines/${VMI_NAME}/vnc?duration=${DURATION}" ``` In this example, we use a bearer token to authenticate the user with the Kubernetes API server. diff --git a/go.mod b/go.mod index 03eda228..c5151870 100644 --- a/go.mod +++ b/go.mod @@ -9,8 +9,6 @@ require ( github.com/golang/mock v1.6.0 github.com/onsi/ginkgo/v2 v2.19.0 github.com/onsi/gomega v1.33.1 - github.com/openshift/api v0.0.0-20240717221938-8da8de571496 // release-4.17 - github.com/openshift/library-go v0.0.0-20240715191351-e0aa70d55678 // release-4.17 k8s.io/api v0.30.3 k8s.io/apimachinery v0.30.3 k8s.io/client-go v0.30.3 @@ -51,6 +49,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/openshift/api v0.0.0-20240717221938-8da8de571496 // indirect github.com/openshift/client-go v0.0.0-20240528061634-b054aa794d87 // indirect github.com/openshift/custom-resource-status v1.1.2 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -68,7 +67,6 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.30.3 // indirect - k8s.io/apiserver v0.30.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.30.1 // indirect kubevirt.io/containerized-data-importer-api v1.59.0 // indirect diff --git a/go.sum b/go.sum index 990b32d5..8339e305 100644 --- a/go.sum +++ b/go.sum @@ -290,8 +290,6 @@ github.com/openshift/client-go v0.0.0-20240528061634-b054aa794d87 h1:JtLhaGpSEco github.com/openshift/client-go v0.0.0-20240528061634-b054aa794d87/go.mod h1:3IPD4U0qyovZS4EFady2kqY32m8lGcbs/Wx+yprg9z8= github.com/openshift/custom-resource-status v1.1.2 h1:C3DL44LEbvlbItfd8mT5jWrqPfHnSOQoQf/sypqA6A4= github.com/openshift/custom-resource-status v1.1.2/go.mod h1:DB/Mf2oTeiAmVVX1gN+NEqweonAPY0TKUwADizj8+ZA= -github.com/openshift/library-go v0.0.0-20240715191351-e0aa70d55678 h1:H08EzrqjY63m1jlZ+D4sTy9fSGlHsPwViyxFrWTIh4A= -github.com/openshift/library-go v0.0.0-20240715191351-e0aa70d55678/go.mod h1:PdASVamWinll2BPxiUpXajTwZxV8A1pQbWEsCN1od7I= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -683,8 +681,6 @@ k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlm k8s.io/apimachinery v0.23.3/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc= k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= -k8s.io/apiserver v0.30.3 h1:QZJndA9k2MjFqpnyYv/PH+9PE0SHhx3hBho4X0vE65g= -k8s.io/apiserver v0.30.3/go.mod h1:6Oa88y1CZqnzetd2JdepO0UXzQX4ZnOekx2/PtEjrOg= k8s.io/client-go v0.19.0/go.mod h1:H9E/VT95blcFQnlyShFgnFT9ZnJOAceiUHM3MlRC+mU= k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k= k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U= diff --git a/manifests/api_service.yaml b/manifests/api_service.yaml index 4e9916cd..44c7af74 100644 --- a/manifests/api_service.yaml +++ b/manifests/api_service.yaml @@ -1,12 +1,12 @@ apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: - name: v1alpha1.token.kubevirt.io + name: v1.token.kubevirt.io annotations: service.beta.openshift.io/inject-cabundle: "true" spec: group: token.kubevirt.io - version: v1alpha1 + version: v1 groupPriorityMinimum: 2000 versionPriority: 10 service: diff --git a/manifests/config_map.yaml b/manifests/config_map.yaml index 83dde3ba..693c05ae 100644 --- a/manifests/config_map.yaml +++ b/manifests/config_map.yaml @@ -3,6 +3,4 @@ kind: ConfigMap metadata: name: vm-console-proxy data: - tls-profile-v1alpha1.yaml: | - type: Intermediate - intermediate: {} + tls-profile-v1.yaml: "{}" diff --git a/pkg/console/console.go b/pkg/console/console.go index 33e3d598..30c43aae 100644 --- a/pkg/console/console.go +++ b/pkg/console/console.go @@ -6,7 +6,7 @@ import ( "net/http" "github.com/emicklei/go-restful/v3" - api "github.com/kubevirt/vm-console-proxy/api/v1alpha1" + api "github.com/kubevirt/vm-console-proxy/api/v1" "github.com/kubevirt/vm-console-proxy/pkg/console/authConfig" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "kubevirt.io/client-go/kubecli" @@ -26,7 +26,7 @@ const ( keyName = "tls.key" configDir = "/config" - TlsProfileFile = "tls-profile-v1alpha1.yaml" + TlsProfileFile = "tls-profile-v1.yaml" ) func Run() error { diff --git a/pkg/console/service/service.go b/pkg/console/service/service.go index 4457ea73..6e5363ae 100644 --- a/pkg/console/service/service.go +++ b/pkg/console/service/service.go @@ -21,7 +21,7 @@ import ( kubevirtv1 "kubevirt.io/api/core/v1" "kubevirt.io/client-go/kubecli" - "github.com/kubevirt/vm-console-proxy/api/v1alpha1" + "github.com/kubevirt/vm-console-proxy/api/v1" "github.com/kubevirt/vm-console-proxy/pkg/console/authConfig" ) @@ -79,14 +79,15 @@ func (s *service) TokenHandler(request *restful.Request, response *restful.Respo return } - token, err := s.requestToken(request.Request.Context(), vm.Namespace, resourceName, params.duration) + tokenRequestStatus, err := s.requestToken(request.Request.Context(), vm.Namespace, resourceName, params.duration) if err != nil { _ = response.WriteError(http.StatusInternalServerError, fmt.Errorf("failed to request token: %w", err)) return } - _ = response.WriteAsJson(&v1alpha1.TokenResponse{ - Token: token, + _ = response.WriteAsJson(&v1.TokenResponse{ + Token: tokenRequestStatus.Token, + ExpirationTimestamp: tokenRequestStatus.ExpirationTimestamp, }) } @@ -272,7 +273,7 @@ func (s *service) createResources(ctx context.Context, name string, vm *kubevirt return nil } -func (s *service) requestToken(ctx context.Context, serviceAccountNamespace string, serviceAccountName string, duration time.Duration) (string, error) { +func (s *service) requestToken(ctx context.Context, serviceAccountNamespace string, serviceAccountName string, duration time.Duration) (*authnv1.TokenRequestStatus, error) { durationSeconds := int64(duration.Seconds()) tokenRequest := &authnv1.TokenRequest{ Spec: authnv1.TokenRequestSpec{ @@ -289,9 +290,9 @@ func (s *service) requestToken(ctx context.Context, serviceAccountNamespace stri metav1.CreateOptions{}, ) if err != nil { - return "", err + return nil, err } - return tokenRequest.Status.Token, nil + return &tokenRequest.Status, nil } type tokenRequestParams struct { diff --git a/pkg/console/service/service_test.go b/pkg/console/service/service_test.go index 01b59432..6d3e3f6f 100644 --- a/pkg/console/service/service_test.go +++ b/pkg/console/service/service_test.go @@ -8,6 +8,7 @@ import ( "net/http/httptest" "net/url" "testing" + "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -24,7 +25,7 @@ import ( v1 "kubevirt.io/api/core/v1" "kubevirt.io/client-go/kubecli" - api "github.com/kubevirt/vm-console-proxy/api/v1alpha1" + api "github.com/kubevirt/vm-console-proxy/api/v1" "github.com/kubevirt/vm-console-proxy/pkg/console/authConfig" fakeAuth "github.com/kubevirt/vm-console-proxy/pkg/console/authConfig/fake" ) @@ -51,6 +52,8 @@ var _ = Describe("Service", func() { request *restful.Request response *restful.Response recorder *httptest.ResponseRecorder + + testExpirationTimestamp metav1.Time ) BeforeEach(func() { @@ -103,10 +106,14 @@ var _ = Describe("Service", func() { return true, sar, nil }) + testExpirationTimestamp = metav1.Date(2024, 7, 1, 0, 0, 0, 0, time.UTC) + apiClient.Fake.PrependReactor("create", "serviceaccounts/token", func(action k8stesting.Action) (bool, runtime.Object, error) { createAction := action.(k8stesting.CreateAction) tokenRequest := createAction.GetObject().(*authnv1.TokenRequest) tokenRequest.Status.Token = testToken + tokenRequest.Status.ExpirationTimestamp = testExpirationTimestamp + return true, tokenRequest, nil }) @@ -281,6 +288,7 @@ var _ = Describe("Service", func() { Expect(json.NewDecoder(recorder.Body).Decode(tokenResponse)).To(Succeed()) Expect(tokenResponse.Token).To(Equal(testToken)) + Expect(&tokenResponse.ExpirationTimestamp).To(Satisfy(testExpirationTimestamp.Equal)) }) It("should fail if duration parameter fails to parse", func() { diff --git a/pkg/console/tlsconfig/tlsconfig.go b/pkg/console/tlsconfig/tlsconfig.go index 2f48ee18..71854338 100644 --- a/pkg/console/tlsconfig/tlsconfig.go +++ b/pkg/console/tlsconfig/tlsconfig.go @@ -9,13 +9,11 @@ import ( "strings" "sync" - ocpconfigv1 "github.com/openshift/api/config/v1" - "github.com/openshift/library-go/pkg/crypto" "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/client-go/util/cert" "kubevirt.io/client-go/log" - "github.com/kubevirt/vm-console-proxy/api/v1alpha1" + "github.com/kubevirt/vm-console-proxy/api/v1" "github.com/kubevirt/vm-console-proxy/pkg/console/authConfig" "github.com/kubevirt/vm-console-proxy/pkg/filewatch" ) @@ -120,10 +118,21 @@ func (w *watch) reloadTlsProfile() { { // TODO: only compute human readable strings on debug level. // For now, there is no easy way to test for logging level. - cipherNames := crypto.CipherSuitesToNamesOrDie(ciphers) - minVersionName := crypto.TLSVersionToNameOrDie(minVersion) - log.Log.V(1).Infof("Set min TLS version: %s", minVersionName) - log.Log.V(1).Infof("Set ciphers: %s", strings.Join(cipherNames, ", ")) + if minVersion == 0 { + log.Log.V(1).Infof("Min TLS version was not set in the config file. Using default.") + } else { + log.Log.V(1).Infof("Set min TLS version: %s", tls.VersionName(minVersion)) + } + + if ciphers == nil { + log.Log.V(1).Infof("Ciphers were not set in the config file. Using default.") + } else { + cipherNames := make([]string, 0, len(ciphers)) + for _, cipher := range ciphers { + cipherNames = append(cipherNames, tls.CipherSuiteName(cipher)) + } + log.Log.V(1).Infof("Set ciphers: %s", strings.Join(cipherNames, ", ")) + } } w.ciphers = ciphers @@ -154,15 +163,20 @@ func loadCipherSuitesAndMinVersion(configPath string) ([]uint16, uint16, error) return nil, 0, fmt.Errorf("could not load tls config: %w", err) } - ciphers, minVersion, err := getTlsCiphersAndMinVersion(tlsProfile) + ciphers, err := getCipherSuites(tlsProfile.Ciphers) if err != nil { - return nil, 0, err + return nil, 0, fmt.Errorf("could not get cipher suite numbers: %w", err) + } + + minVersion, err := getMinTlsVersion(tlsProfile.MinTLSVersion) + if err != nil { + return nil, 0, fmt.Errorf("could not get minimum TLS version: %w", err) } return ciphers, minVersion, nil } -func loadTlsProfile(profilePath string) (*v1alpha1.TlsSecurityProfile, error) { +func loadTlsProfile(profilePath string) (*v1.TlsProfile, error) { file, err := os.Open(profilePath) if err != nil { return nil, fmt.Errorf("error opening file: %w", err) @@ -170,7 +184,7 @@ func loadTlsProfile(profilePath string) (*v1alpha1.TlsSecurityProfile, error) { // It's ok to ignore error on close, because the file is opened of reading defer func() { _ = file.Close() }() - result := &v1alpha1.TlsSecurityProfile{} + result := &v1.TlsProfile{} err = yaml.NewYAMLToJSONDecoder(file).Decode(result) if err != nil { return nil, fmt.Errorf("error decoding tls config: %w", err) @@ -178,44 +192,43 @@ func loadTlsProfile(profilePath string) (*v1alpha1.TlsSecurityProfile, error) { return result, nil } -func getTlsCiphersAndMinVersion(tlsProfile *v1alpha1.TlsSecurityProfile) ([]uint16, uint16, error) { - var profile *ocpconfigv1.TLSProfileSpec - if tlsProfile.Type == ocpconfigv1.TLSProfileCustomType { - if tlsProfile.Custom == nil { - return nil, 0, fmt.Errorf("tls profile \"custom\" field is nil") - } - profile = &tlsProfile.Custom.TLSProfileSpec - } else { - var exists bool - profile, exists = ocpconfigv1.TLSProfiles[tlsProfile.Type] - if !exists { - return nil, 0, fmt.Errorf("unknown profile type: %s", tlsProfile.Type) - } +func getCipherSuites(cipherNames []string) ([]uint16, error) { + if len(cipherNames) == 0 { + // nil value has means default cipher suites will be used + return nil, nil } - ciphers := getCipherSuites(profile) - minVersion, err := crypto.TLSVersion(string(profile.MinTLSVersion)) - if err != nil { - return nil, 0, err + result := make([]uint16, 0, len(cipherNames)) + +outerLoop: + for _, cipherName := range cipherNames { + for _, cipherSuite := range tls.CipherSuites() { + if cipherName == cipherSuite.Name { + result = append(result, cipherSuite.ID) + continue outerLoop + } + } + return nil, fmt.Errorf("unknown cipher suite: %v", cipherName) } - return ciphers, minVersion, nil + return result, nil } -func getCipherSuites(profileSpec *ocpconfigv1.TLSProfileSpec) []uint16 { - tlsCiphers := make(map[string]*tls.CipherSuite, len(tls.CipherSuites())) - for _, suite := range tls.CipherSuites() { - tlsCiphers[suite.Name] = suite +func getMinTlsVersion(version v1.TLSProtocolVersion) (uint16, error) { + switch version { + case "": + return 0, nil + case v1.VersionTLS10: + return tls.VersionTLS10, nil + case v1.VersionTLS11: + return tls.VersionTLS11, nil + case v1.VersionTLS12: + return tls.VersionTLS12, nil + case v1.VersionTLS13: + return tls.VersionTLS13, nil + default: + return 0, fmt.Errorf("unsupported TLS version: %s", version) } - - cipherIds := make([]uint16, 0, len(profileSpec.Ciphers)) - for _, ianaCipher := range crypto.OpenSSLToIANACipherSuites(profileSpec.Ciphers) { - if cipher, found := tlsCiphers[ianaCipher]; found { - cipherIds = append(cipherIds, cipher.ID) - } - } - - return cipherIds } func LoadCertificates(certPath, keyPath string) (*tls.Certificate, error) { diff --git a/pkg/console/tlsconfig/tlsconfig_test.go b/pkg/console/tlsconfig/tlsconfig_test.go index fb697210..632f508a 100644 --- a/pkg/console/tlsconfig/tlsconfig_test.go +++ b/pkg/console/tlsconfig/tlsconfig_test.go @@ -13,11 +13,10 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - ocpconfigv1 "github.com/openshift/api/config/v1" "k8s.io/client-go/util/cert" "sigs.k8s.io/yaml" - "github.com/kubevirt/vm-console-proxy/api/v1alpha1" + "github.com/kubevirt/vm-console-proxy/api/v1" fakeAuth "github.com/kubevirt/vm-console-proxy/pkg/console/authConfig/fake" "github.com/kubevirt/vm-console-proxy/pkg/filewatch" ) @@ -28,6 +27,9 @@ var _ = Describe("TlsConfig", func() { ) var ( + testCiphersNames []string + testCipherIds []uint16 + configDir string tlsConfigPath string @@ -42,9 +44,27 @@ var _ = Describe("TlsConfig", func() { ) BeforeEach(func() { - tlsProfile := &v1alpha1.TlsSecurityProfile{ - Type: ocpconfigv1.TLSProfileIntermediateType, - Intermediate: &ocpconfigv1.IntermediateTLSProfile{}, + testCiphersNames = []string{ + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + } + + testCipherIds = []uint16{ + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + } + + tlsProfile := &v1.TlsProfile{ + Ciphers: testCiphersNames, + MinTLSVersion: v1.VersionTLS12, } tlsProfileYaml, err := yaml.Marshal(tlsProfile) Expect(err).ToNot(HaveOccurred()) @@ -101,17 +121,45 @@ var _ = Describe("TlsConfig", func() { config, err := configWatch.GetConfig() Expect(err).ToNot(HaveOccurred()) - Expect(config.CipherSuites).To(ConsistOf( - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - )) + Expect(config.CipherSuites).To(ConsistOf(testCipherIds)) + Expect(config.MinVersion).To(Equal(uint16(tls.VersionTLS12))) + }) + + It("should use default ciphers, if ciphers are not sepcified", func() { + tlsConfig := &v1.TlsProfile{ + MinTLSVersion: v1.VersionTLS12, + } + tlsConfigYaml, err := yaml.Marshal(tlsConfig) + Expect(err).ToNot(HaveOccurred()) + Expect(os.WriteFile(tlsConfigPath, tlsConfigYaml, 0666)).To(Succeed()) + + configWatch.Reload() + + config, err := configWatch.GetConfig() + Expect(err).ToNot(HaveOccurred()) + + // Testing for nil specifically, because nil means default configuration. + Expect(config.CipherSuites).To(BeNil()) Expect(config.MinVersion).To(Equal(uint16(tls.VersionTLS12))) }) + It("should use default tls version, if MinTLSVersion is not specified", func() { + tlsConfig := &v1.TlsProfile{ + Ciphers: testCiphersNames, + } + tlsConfigYaml, err := yaml.Marshal(tlsConfig) + Expect(err).ToNot(HaveOccurred()) + Expect(os.WriteFile(tlsConfigPath, tlsConfigYaml, 0666)).To(Succeed()) + + configWatch.Reload() + + config, err := configWatch.GetConfig() + Expect(err).ToNot(HaveOccurred()) + + Expect(config.CipherSuites).To(ConsistOf(testCipherIds)) + Expect(config.MinVersion).To(BeZero()) + }) + It("should use default config if file does not exist", func() { Expect(os.Remove(tlsConfigPath)).ToNot(HaveOccurred()) configWatch.Reload() @@ -119,7 +167,8 @@ var _ = Describe("TlsConfig", func() { config, err := configWatch.GetConfig() Expect(err).ToNot(HaveOccurred()) - Expect(config.CipherSuites).To(BeEmpty()) + // Testing for nil specifically, because nil means default configuration. + Expect(config.CipherSuites).To(BeNil()) Expect(config.MinVersion).To(BeZero()) }) @@ -149,21 +198,17 @@ var _ = Describe("TlsConfig", func() { originalConfig, err := configWatch.GetConfig() Expect(err).ToNot(HaveOccurred()) - func() { - configFile, err := os.Create(tlsConfigPath) - Expect(err).ToNot(HaveOccurred()) - defer configFile.Close() - - tlsProfile := &v1alpha1.TlsSecurityProfile{ - Type: ocpconfigv1.TLSProfileModernType, - Modern: &ocpconfigv1.ModernTLSProfile{}, - } - tlsProfileYaml, err := yaml.Marshal(tlsProfile) - Expect(err).ToNot(HaveOccurred()) - - _, err = configFile.Write(tlsProfileYaml) - Expect(err).ToNot(HaveOccurred()) - }() + tlsProfile := &v1.TlsProfile{ + Ciphers: []string{ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256", + }, + MinTLSVersion: v1.VersionTLS13, + } + tlsProfileYaml, err := yaml.Marshal(tlsProfile) + Expect(err).ToNot(HaveOccurred()) + Expect(os.WriteFile(tlsConfigPath, tlsProfileYaml, 0666)).To(Succeed()) mockWatch.Trigger(configDir) @@ -173,18 +218,16 @@ var _ = Describe("TlsConfig", func() { Expect(config.CipherSuites).ToNot(Equal(originalConfig.CipherSuites)) Expect(config.MinVersion).ToNot(Equal(originalConfig.MinVersion)) - Expect(config.CipherSuites).To(BeEmpty()) + Expect(config.CipherSuites).To(ConsistOf( + tls.TLS_AES_128_GCM_SHA256, + tls.TLS_AES_256_GCM_SHA384, + tls.TLS_CHACHA20_POLY1305_SHA256, + )) Expect(config.MinVersion).To(Equal(uint16(tls.VersionTLS13))) }) It("should fail if config is invalid", func() { - func() { - configFile, err := os.Create(tlsConfigPath) - Expect(err).ToNot(HaveOccurred()) - defer configFile.Close() - _, err = configFile.WriteString("This is definitely not a valid YAML") - Expect(err).ToNot(HaveOccurred()) - }() + Expect(os.WriteFile(tlsConfigPath, []byte("This is definitely not a valid YAML"), 0666)).To(Succeed()) mockWatch.Trigger(configDir) @@ -197,21 +240,8 @@ var _ = Describe("TlsConfig", func() { certBytes, keyBytes, err := cert.GenerateSelfSignedCertKey(newDnsName, nil, nil) Expect(err).ToNot(HaveOccurred()) - func() { - certFile, err := os.Create(certPath) - Expect(err).ToNot(HaveOccurred()) - defer certFile.Close() - - _, err = certFile.Write(certBytes) - Expect(err).ToNot(HaveOccurred()) - - keyFile, err := os.Create(keyPath) - Expect(err).ToNot(HaveOccurred()) - defer keyFile.Close() - - _, err = keyFile.Write(keyBytes) - Expect(err).ToNot(HaveOccurred()) - }() + Expect(os.WriteFile(certPath, certBytes, 0666)).To(Succeed()) + Expect(os.WriteFile(keyPath, keyBytes, 0666)).To(Succeed()) mockWatch.Trigger(certAndKeyDir) @@ -222,14 +252,7 @@ var _ = Describe("TlsConfig", func() { }) It("should fail if certificate is invalid", func() { - func() { - certFile, err := os.Create(certPath) - Expect(err).ToNot(HaveOccurred()) - defer certFile.Close() - - _, err = certFile.WriteString("This is invalid certificate file") - Expect(err).ToNot(HaveOccurred()) - }() + Expect(os.WriteFile(certPath, []byte("This is invalid certificate file"), 0666)).To(Succeed()) mockWatch.Trigger(certAndKeyDir) diff --git a/tests/proxy_test.go b/tests/proxy_test.go index b247ce5c..a79cdea6 100644 --- a/tests/proxy_test.go +++ b/tests/proxy_test.go @@ -3,6 +3,7 @@ package tests import ( "context" "encoding/json" + "fmt" "net/http" "path" "time" @@ -22,7 +23,7 @@ import ( "k8s.io/utils/pointer" kubevirtcorev1 "kubevirt.io/api/core/v1" - api "github.com/kubevirt/vm-console-proxy/api/v1alpha1" + api "github.com/kubevirt/vm-console-proxy/api/v1" ) var _ = Describe("Kubevirt proxy", func() { @@ -117,6 +118,11 @@ var _ = Describe("Kubevirt proxy", func() { It("should get token with default duration", func() { tokenUrl := getTokenUrl(vmName) + + // Default duration is 10 minutes. + // Removing smaller intervals than seconds, because the timestamp in JSON is only accurate to seconds. + expectedExpirationTimestamp := time.Now().Add(10 * time.Minute).Truncate(time.Second) + code, body, err := httpGet(tokenUrl, saToken, TestHttpClient) Expect(err).ToNot(HaveOccurred()) Expect(code).To(Equal(http.StatusOK)) @@ -124,11 +130,18 @@ var _ = Describe("Kubevirt proxy", func() { tokenResponse := &api.TokenResponse{} Expect(json.Unmarshal(body, tokenResponse)).To(Succeed()) Expect(tokenResponse.Token).ToNot(BeEmpty()) + + Expect(tokenResponse.ExpirationTimestamp.Time.Before(expectedExpirationTimestamp)).To(BeFalse(), + fmt.Sprintf("expiration timestamp %v, should be equal or later than %v", tokenResponse.ExpirationTimestamp.Time, expectedExpirationTimestamp), + ) }) It("should get token with specified duration", func() { tokenUrl := getTokenUrl(vmName) + // Removing smaller intervals than seconds, because the timestamp in JSON is only accurate to seconds. + expectedExpirationTimestamp := time.Now().Add(24 * time.Hour).Truncate(time.Second) + code, body, err := httpGet(tokenUrl+"?duration=24h", saToken, TestHttpClient) Expect(err).ToNot(HaveOccurred()) Expect(code).To(Equal(http.StatusOK)) @@ -136,6 +149,9 @@ var _ = Describe("Kubevirt proxy", func() { tokenResponse := &api.TokenResponse{} Expect(json.Unmarshal(body, tokenResponse)).To(Succeed()) Expect(tokenResponse.Token).ToNot(BeEmpty()) + Expect(tokenResponse.ExpirationTimestamp.Time.Before(expectedExpirationTimestamp)).To(BeFalse(), + fmt.Sprintf("expiration timestamp %v, should be equal or later than %v", tokenResponse.ExpirationTimestamp.Time, expectedExpirationTimestamp), + ) claims := &jwt.RegisteredClaims{} _, _, err = jwt.NewParser().ParseUnverified(tokenResponse.Token, claims) diff --git a/tests/tests_suite_test.go b/tests/tests_suite_test.go index 69e233af..7e155d0e 100644 --- a/tests/tests_suite_test.go +++ b/tests/tests_suite_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - api "github.com/kubevirt/vm-console-proxy/api/v1alpha1" + api "github.com/kubevirt/vm-console-proxy/api/v1" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" core "k8s.io/api/core/v1" diff --git a/tests/tlsconfig_test.go b/tests/tlsconfig_test.go index 6bb3e2e5..28b6e011 100644 --- a/tests/tlsconfig_test.go +++ b/tests/tlsconfig_test.go @@ -10,8 +10,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - api "github.com/kubevirt/vm-console-proxy/api/v1alpha1" - ocpconfigv1 "github.com/openshift/api/config/v1" + api "github.com/kubevirt/vm-console-proxy/api/v1" core "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -20,35 +19,19 @@ import ( var _ = Describe("TLS config", func() { - It("should read config from ConfigMap", func() { - Eventually(func(g Gomega) { - connState, err := getTlsConnectionState() - Expect(err).ToNot(HaveOccurred()) - - Expect(connState.CipherSuite).To(BeElementOf( - tls.TLS_AES_128_GCM_SHA256, - tls.TLS_AES_256_GCM_SHA384, - tls.TLS_CHACHA20_POLY1305_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - )) - Expect(connState.Version).To(BeNumerically(">=", tls.VersionTLS12)) - }, 1*time.Minute, time.Second).Should(Succeed()) - }) - Context("with changed ConfigMap", func() { AfterEach(func() { RevertToOriginalConfigMap() }) It("should reload config at runtime", func() { - tlsProfile := &api.TlsSecurityProfile{ - Type: ocpconfigv1.TLSProfileModernType, - Modern: &ocpconfigv1.ModernTLSProfile{}, + tlsProfile := &api.TlsProfile{ + Ciphers: []string{ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256", + }, + MinTLSVersion: api.VersionTLS13, } tlsProfileYaml, err := yaml.Marshal(tlsProfile) @@ -103,18 +86,13 @@ var _ = Describe("TLS config", func() { }, 1*time.Minute, time.Second).Should(Succeed()) // Recreate file - tlsProfile := &api.TlsSecurityProfile{ - Type: ocpconfigv1.TLSProfileCustomType, - Custom: &ocpconfigv1.CustomTLSProfile{ - TLSProfileSpec: ocpconfigv1.TLSProfileSpec{ - Ciphers: []string{ - "TLS_AES_128_GCM_SHA256", - "TLS_AES_256_GCM_SHA384", - "TLS_CHACHA20_POLY1305_SHA256", - }, - MinTLSVersion: ocpconfigv1.VersionTLS13, - }, + tlsProfile := &api.TlsProfile{ + Ciphers: []string{ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256", }, + MinTLSVersion: api.VersionTLS13, } tlsProfileYaml, err := yaml.Marshal(tlsProfile) diff --git a/tests/user-role_test.go b/tests/user-role_test.go index 83e7e683..96e3046c 100644 --- a/tests/user-role_test.go +++ b/tests/user-role_test.go @@ -13,7 +13,7 @@ import ( rbac "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - proxy "github.com/kubevirt/vm-console-proxy/api/v1alpha1" + proxy "github.com/kubevirt/vm-console-proxy/api/v1" ) var _ = Describe("Role for token generation", func() { diff --git a/vendor/github.com/openshift/library-go/LICENSE b/vendor/github.com/openshift/library-go/LICENSE deleted file mode 100644 index 261eeb9e..00000000 --- a/vendor/github.com/openshift/library-go/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/vendor/github.com/openshift/library-go/pkg/crypto/OWNERS b/vendor/github.com/openshift/library-go/pkg/crypto/OWNERS deleted file mode 100644 index 4d4ce5ab..00000000 --- a/vendor/github.com/openshift/library-go/pkg/crypto/OWNERS +++ /dev/null @@ -1,4 +0,0 @@ -reviewers: - - stlaz -approvers: - - stlaz diff --git a/vendor/github.com/openshift/library-go/pkg/crypto/crypto.go b/vendor/github.com/openshift/library-go/pkg/crypto/crypto.go deleted file mode 100644 index 63184d2e..00000000 --- a/vendor/github.com/openshift/library-go/pkg/crypto/crypto.go +++ /dev/null @@ -1,1221 +0,0 @@ -package crypto - -import ( - "bytes" - "crypto" - "crypto/ecdsa" - "crypto/rand" - "crypto/rsa" - "crypto/sha1" - "crypto/tls" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "errors" - "fmt" - "io" - "math/big" - mathrand "math/rand" - "net" - "os" - "path/filepath" - "reflect" - "sort" - "strconv" - "sync" - "time" - - "k8s.io/klog/v2" - - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/apiserver/pkg/authentication/user" - "k8s.io/client-go/util/cert" -) - -// TLS versions that are known to golang. Go 1.13 adds support for -// TLS 1.3 that's opt-out with a build flag. -var versions = map[string]uint16{ - "VersionTLS10": tls.VersionTLS10, - "VersionTLS11": tls.VersionTLS11, - "VersionTLS12": tls.VersionTLS12, - "VersionTLS13": tls.VersionTLS13, -} - -// TLS versions that are enabled. -var supportedVersions = map[string]uint16{ - "VersionTLS10": tls.VersionTLS10, - "VersionTLS11": tls.VersionTLS11, - "VersionTLS12": tls.VersionTLS12, - "VersionTLS13": tls.VersionTLS13, -} - -// TLSVersionToNameOrDie given a tls version as an int, return its readable name -func TLSVersionToNameOrDie(intVal uint16) string { - matches := []string{} - for key, version := range versions { - if version == intVal { - matches = append(matches, key) - } - } - - if len(matches) == 0 { - panic(fmt.Sprintf("no name found for %d", intVal)) - } - if len(matches) > 1 { - panic(fmt.Sprintf("multiple names found for %d: %v", intVal, matches)) - } - return matches[0] -} - -func TLSVersion(versionName string) (uint16, error) { - if len(versionName) == 0 { - return DefaultTLSVersion(), nil - } - if version, ok := versions[versionName]; ok { - return version, nil - } - return 0, fmt.Errorf("unknown tls version %q", versionName) -} -func TLSVersionOrDie(versionName string) uint16 { - version, err := TLSVersion(versionName) - if err != nil { - panic(err) - } - return version -} - -// TLS versions that are known to golang, but may not necessarily be enabled. -func GolangTLSVersions() []string { - supported := []string{} - for k := range versions { - supported = append(supported, k) - } - sort.Strings(supported) - return supported -} - -// Returns the build enabled TLS versions. -func ValidTLSVersions() []string { - validVersions := []string{} - for k := range supportedVersions { - validVersions = append(validVersions, k) - } - sort.Strings(validVersions) - return validVersions -} -func DefaultTLSVersion() uint16 { - // Can't use SSLv3 because of POODLE and BEAST - // Can't use TLSv1.0 because of POODLE and BEAST using CBC cipher - // Can't use TLSv1.1 because of RC4 cipher usage - return tls.VersionTLS12 -} - -// ciphersTLS13 copies golang 1.13 implementation, where TLS1.3 suites are not -// configurable (cipherSuites field is ignored for TLS1.3 flows and all of the -// below three - and none other - are used) -var ciphersTLS13 = map[string]uint16{ - "TLS_AES_128_GCM_SHA256": tls.TLS_AES_128_GCM_SHA256, - "TLS_AES_256_GCM_SHA384": tls.TLS_AES_256_GCM_SHA384, - "TLS_CHACHA20_POLY1305_SHA256": tls.TLS_CHACHA20_POLY1305_SHA256, -} - -var ciphers = map[string]uint16{ - "TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA, - "TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, - "TLS_RSA_WITH_AES_128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA, - "TLS_RSA_WITH_AES_256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA, - "TLS_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256, - "TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256, - "TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384, - "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - "TLS_ECDHE_RSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, - "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, -} - -// openSSLToIANACiphersMap maps OpenSSL cipher suite names to IANA names -// ref: https://www.iana.org/assignments/tls-parameters/tls-parameters.xml -var openSSLToIANACiphersMap = map[string]string{ - // TLS 1.3 ciphers - not configurable in go 1.13, all of them are used in TLSv1.3 flows - // "TLS_AES_128_GCM_SHA256": "TLS_AES_128_GCM_SHA256", // 0x13,0x01 - // "TLS_AES_256_GCM_SHA384": "TLS_AES_256_GCM_SHA384", // 0x13,0x02 - // "TLS_CHACHA20_POLY1305_SHA256": "TLS_CHACHA20_POLY1305_SHA256", // 0x13,0x03 - - // TLS 1.2 - "ECDHE-ECDSA-AES128-GCM-SHA256": "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // 0xC0,0x2B - "ECDHE-RSA-AES128-GCM-SHA256": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", // 0xC0,0x2F - "ECDHE-ECDSA-AES256-GCM-SHA384": "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", // 0xC0,0x2C - "ECDHE-RSA-AES256-GCM-SHA384": "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", // 0xC0,0x30 - "ECDHE-ECDSA-CHACHA20-POLY1305": "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", // 0xCC,0xA9 - "ECDHE-RSA-CHACHA20-POLY1305": "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", // 0xCC,0xA8 - "ECDHE-ECDSA-AES128-SHA256": "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", // 0xC0,0x23 - "ECDHE-RSA-AES128-SHA256": "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", // 0xC0,0x27 - "AES128-GCM-SHA256": "TLS_RSA_WITH_AES_128_GCM_SHA256", // 0x00,0x9C - "AES256-GCM-SHA384": "TLS_RSA_WITH_AES_256_GCM_SHA384", // 0x00,0x9D - "AES128-SHA256": "TLS_RSA_WITH_AES_128_CBC_SHA256", // 0x00,0x3C - - // TLS 1 - "ECDHE-ECDSA-AES128-SHA": "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", // 0xC0,0x09 - "ECDHE-RSA-AES128-SHA": "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", // 0xC0,0x13 - "ECDHE-ECDSA-AES256-SHA": "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", // 0xC0,0x0A - "ECDHE-RSA-AES256-SHA": "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", // 0xC0,0x14 - - // SSL 3 - "AES128-SHA": "TLS_RSA_WITH_AES_128_CBC_SHA", // 0x00,0x2F - "AES256-SHA": "TLS_RSA_WITH_AES_256_CBC_SHA", // 0x00,0x35 - "DES-CBC3-SHA": "TLS_RSA_WITH_3DES_EDE_CBC_SHA", // 0x00,0x0A -} - -// CipherSuitesToNamesOrDie given a list of cipher suites as ints, return their readable names -func CipherSuitesToNamesOrDie(intVals []uint16) []string { - ret := []string{} - for _, intVal := range intVals { - ret = append(ret, CipherSuiteToNameOrDie(intVal)) - } - - return ret -} - -// CipherSuiteToNameOrDie given a cipher suite as an int, return its readable name -func CipherSuiteToNameOrDie(intVal uint16) string { - // The following suite ids appear twice in the cipher map (with - // and without the _SHA256 suffix) for the purposes of backwards - // compatibility. Always return the current rather than the legacy - // name. - switch intVal { - case tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: - return "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" - case tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: - return "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" - } - - matches := []string{} - for key, version := range ciphers { - if version == intVal { - matches = append(matches, key) - } - } - - if len(matches) == 0 { - panic(fmt.Sprintf("no name found for %d", intVal)) - } - if len(matches) > 1 { - panic(fmt.Sprintf("multiple names found for %d: %v", intVal, matches)) - } - return matches[0] -} - -func CipherSuite(cipherName string) (uint16, error) { - if cipher, ok := ciphers[cipherName]; ok { - return cipher, nil - } - - if _, ok := ciphersTLS13[cipherName]; ok { - return 0, fmt.Errorf("all golang TLSv1.3 ciphers are always used for TLSv1.3 flows") - } - - return 0, fmt.Errorf("unknown cipher name %q", cipherName) -} - -func CipherSuitesOrDie(cipherNames []string) []uint16 { - if len(cipherNames) == 0 { - return DefaultCiphers() - } - cipherValues := []uint16{} - for _, cipherName := range cipherNames { - cipher, err := CipherSuite(cipherName) - if err != nil { - panic(err) - } - cipherValues = append(cipherValues, cipher) - } - return cipherValues -} -func ValidCipherSuites() []string { - validCipherSuites := []string{} - for k := range ciphers { - validCipherSuites = append(validCipherSuites, k) - } - sort.Strings(validCipherSuites) - return validCipherSuites -} -func DefaultCiphers() []uint16 { - // HTTP/2 mandates TLS 1.2 or higher with an AEAD cipher - // suite (GCM, Poly1305) and ephemeral key exchange (ECDHE, DHE) for - // perfect forward secrecy. Servers may provide additional cipher - // suites for backwards compatibility with HTTP/1.1 clients. - // See RFC7540, section 9.2 (Use of TLS Features) and Appendix A - // (TLS 1.2 Cipher Suite Black List). - return []uint16{ - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, // required by http/2 - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, // forbidden by http/2, not flagged by http2isBadCipher() in go1.8 - tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, // forbidden by http/2, not flagged by http2isBadCipher() in go1.8 - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, // forbidden by http/2 - tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, // forbidden by http/2 - tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, // forbidden by http/2 - tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, // forbidden by http/2 - tls.TLS_RSA_WITH_AES_128_GCM_SHA256, // forbidden by http/2 - tls.TLS_RSA_WITH_AES_256_GCM_SHA384, // forbidden by http/2 - // the next one is in the intermediate suite, but go1.8 http2isBadCipher() complains when it is included at the recommended index - // because it comes after ciphers forbidden by the http/2 spec - // tls.TLS_RSA_WITH_AES_128_CBC_SHA256, - // tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, // forbidden by http/2, disabled to mitigate SWEET32 attack - // tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, // forbidden by http/2, disabled to mitigate SWEET32 attack - tls.TLS_RSA_WITH_AES_128_CBC_SHA, // forbidden by http/2 - tls.TLS_RSA_WITH_AES_256_CBC_SHA, // forbidden by http/2 - } -} - -// SecureTLSConfig enforces the default minimum security settings for the cluster. -func SecureTLSConfig(config *tls.Config) *tls.Config { - if config.MinVersion == 0 { - config.MinVersion = DefaultTLSVersion() - } - - config.PreferServerCipherSuites = true - if len(config.CipherSuites) == 0 { - config.CipherSuites = DefaultCiphers() - } - return config -} - -// OpenSSLToIANACipherSuites maps input OpenSSL Cipher Suite names to their -// IANA counterparts. -// Unknown ciphers are left out. -func OpenSSLToIANACipherSuites(ciphers []string) []string { - ianaCiphers := make([]string, 0, len(ciphers)) - - for _, c := range ciphers { - ianaCipher, found := openSSLToIANACiphersMap[c] - if found { - ianaCiphers = append(ianaCiphers, ianaCipher) - } - } - - return ianaCiphers -} - -type TLSCertificateConfig struct { - Certs []*x509.Certificate - Key crypto.PrivateKey -} - -type TLSCARoots struct { - Roots []*x509.Certificate -} - -func (c *TLSCertificateConfig) WriteCertConfigFile(certFile, keyFile string) error { - // ensure parent dir - if err := os.MkdirAll(filepath.Dir(certFile), os.FileMode(0755)); err != nil { - return err - } - certFileWriter, err := os.OpenFile(certFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) - if err != nil { - return err - } - if err := os.MkdirAll(filepath.Dir(keyFile), os.FileMode(0755)); err != nil { - return err - } - keyFileWriter, err := os.OpenFile(keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) - if err != nil { - return err - } - - if err := writeCertificates(certFileWriter, c.Certs...); err != nil { - return err - } - if err := writeKeyFile(keyFileWriter, c.Key); err != nil { - return err - } - - if err := certFileWriter.Close(); err != nil { - return err - } - if err := keyFileWriter.Close(); err != nil { - return err - } - - return nil -} - -func (c *TLSCertificateConfig) WriteCertConfig(certFile, keyFile io.Writer) error { - if err := writeCertificates(certFile, c.Certs...); err != nil { - return err - } - if err := writeKeyFile(keyFile, c.Key); err != nil { - return err - } - return nil -} - -func (c *TLSCertificateConfig) GetPEMBytes() ([]byte, []byte, error) { - certBytes, err := EncodeCertificates(c.Certs...) - if err != nil { - return nil, nil, err - } - keyBytes, err := EncodeKey(c.Key) - if err != nil { - return nil, nil, err - } - - return certBytes, keyBytes, nil -} - -func GetTLSCertificateConfig(certFile, keyFile string) (*TLSCertificateConfig, error) { - if len(certFile) == 0 { - return nil, errors.New("certFile missing") - } - if len(keyFile) == 0 { - return nil, errors.New("keyFile missing") - } - - certPEMBlock, err := os.ReadFile(certFile) - if err != nil { - return nil, err - } - certs, err := cert.ParseCertsPEM(certPEMBlock) - if err != nil { - return nil, fmt.Errorf("Error reading %s: %s", certFile, err) - } - - keyPEMBlock, err := os.ReadFile(keyFile) - if err != nil { - return nil, err - } - keyPairCert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock) - if err != nil { - return nil, err - } - key := keyPairCert.PrivateKey - - return &TLSCertificateConfig{certs, key}, nil -} - -func GetTLSCertificateConfigFromBytes(certBytes, keyBytes []byte) (*TLSCertificateConfig, error) { - if len(certBytes) == 0 { - return nil, errors.New("certFile missing") - } - if len(keyBytes) == 0 { - return nil, errors.New("keyFile missing") - } - - certs, err := cert.ParseCertsPEM(certBytes) - if err != nil { - return nil, fmt.Errorf("Error reading cert: %s", err) - } - - keyPairCert, err := tls.X509KeyPair(certBytes, keyBytes) - if err != nil { - return nil, err - } - key := keyPairCert.PrivateKey - - return &TLSCertificateConfig{certs, key}, nil -} - -const ( - DefaultCertificateLifetimeInDays = 365 * 2 // 2 years - DefaultCACertificateLifetimeInDays = 365 * 5 // 5 years - - // Default keys are 2048 bits - keyBits = 2048 -) - -type CA struct { - Config *TLSCertificateConfig - - SerialGenerator SerialGenerator -} - -// SerialGenerator is an interface for getting a serial number for the cert. It MUST be thread-safe. -type SerialGenerator interface { - Next(template *x509.Certificate) (int64, error) -} - -// SerialFileGenerator returns a unique, monotonically increasing serial number and ensures the CA on disk records that value. -type SerialFileGenerator struct { - SerialFile string - - // lock guards access to the Serial field - lock sync.Mutex - Serial int64 -} - -func NewSerialFileGenerator(serialFile string) (*SerialFileGenerator, error) { - // read serial file, it must already exist - serial, err := fileToSerial(serialFile) - if err != nil { - return nil, err - } - - generator := &SerialFileGenerator{ - Serial: serial, - SerialFile: serialFile, - } - - // 0 is unused and 1 is reserved for the CA itself - // Thus we need to guarantee that the first external call to SerialFileGenerator.Next returns 2+ - // meaning that SerialFileGenerator.Serial must not be less than 1 (it is guaranteed to be non-negative) - if generator.Serial < 1 { - // fake a call to Next so the file stays in sync and Serial is incremented - if _, err := generator.Next(&x509.Certificate{}); err != nil { - return nil, err - } - } - - return generator, nil -} - -// Next returns a unique, monotonically increasing serial number and ensures the CA on disk records that value. -func (s *SerialFileGenerator) Next(template *x509.Certificate) (int64, error) { - s.lock.Lock() - defer s.lock.Unlock() - - // do a best effort check to make sure concurrent external writes are not occurring to the underlying serial file - serial, err := fileToSerial(s.SerialFile) - if err != nil { - return 0, err - } - if serial != s.Serial { - return 0, fmt.Errorf("serial file %s out of sync ram=%d disk=%d", s.SerialFile, s.Serial, serial) - } - - next := s.Serial + 1 - s.Serial = next - - // Output in hex, padded to multiples of two characters for OpenSSL's sake - serialText := fmt.Sprintf("%X", next) - if len(serialText)%2 == 1 { - serialText = "0" + serialText - } - // always add a newline at the end to have a valid file - serialText += "\n" - - if err := os.WriteFile(s.SerialFile, []byte(serialText), os.FileMode(0640)); err != nil { - return 0, err - } - return next, nil -} - -func fileToSerial(serialFile string) (int64, error) { - serialData, err := os.ReadFile(serialFile) - if err != nil { - return 0, err - } - - // read the file as a single hex number after stripping any whitespace - serial, err := strconv.ParseInt(string(bytes.TrimSpace(serialData)), 16, 64) - if err != nil { - return 0, err - } - - if serial < 0 { - return 0, fmt.Errorf("invalid negative serial %d in serial file %s", serial, serialFile) - } - - return serial, nil -} - -// RandomSerialGenerator returns a serial based on time.Now and the subject -type RandomSerialGenerator struct { -} - -func (s *RandomSerialGenerator) Next(template *x509.Certificate) (int64, error) { - return randomSerialNumber(), nil -} - -// randomSerialNumber returns a random int64 serial number based on -// time.Now. It is defined separately from the generator interface so -// that the caller doesn't have to worry about an input template or -// error - these are unnecessary when creating a random serial. -func randomSerialNumber() int64 { - r := mathrand.New(mathrand.NewSource(time.Now().UTC().UnixNano())) - return r.Int63() -} - -// EnsureCA returns a CA, whether it was created (as opposed to pre-existing), and any error -// if serialFile is empty, a RandomSerialGenerator will be used -func EnsureCA(certFile, keyFile, serialFile, name string, expireDays int) (*CA, bool, error) { - if ca, err := GetCA(certFile, keyFile, serialFile); err == nil { - return ca, false, err - } - ca, err := MakeSelfSignedCA(certFile, keyFile, serialFile, name, expireDays) - return ca, true, err -} - -// if serialFile is empty, a RandomSerialGenerator will be used -func GetCA(certFile, keyFile, serialFile string) (*CA, error) { - caConfig, err := GetTLSCertificateConfig(certFile, keyFile) - if err != nil { - return nil, err - } - - var serialGenerator SerialGenerator - if len(serialFile) > 0 { - serialGenerator, err = NewSerialFileGenerator(serialFile) - if err != nil { - return nil, err - } - } else { - serialGenerator = &RandomSerialGenerator{} - } - - return &CA{ - SerialGenerator: serialGenerator, - Config: caConfig, - }, nil -} - -func GetCAFromBytes(certBytes, keyBytes []byte) (*CA, error) { - caConfig, err := GetTLSCertificateConfigFromBytes(certBytes, keyBytes) - if err != nil { - return nil, err - } - - return &CA{ - SerialGenerator: &RandomSerialGenerator{}, - Config: caConfig, - }, nil -} - -// if serialFile is empty, a RandomSerialGenerator will be used -func MakeSelfSignedCA(certFile, keyFile, serialFile, name string, expireDays int) (*CA, error) { - klog.V(2).Infof("Generating new CA for %s cert, and key in %s, %s", name, certFile, keyFile) - - caConfig, err := MakeSelfSignedCAConfig(name, expireDays) - if err != nil { - return nil, err - } - if err := caConfig.WriteCertConfigFile(certFile, keyFile); err != nil { - return nil, err - } - - var serialGenerator SerialGenerator - if len(serialFile) > 0 { - // create / overwrite the serial file with a zero padded hex value (ending in a newline to have a valid file) - if err := os.WriteFile(serialFile, []byte("00\n"), 0644); err != nil { - return nil, err - } - serialGenerator, err = NewSerialFileGenerator(serialFile) - if err != nil { - return nil, err - } - } else { - serialGenerator = &RandomSerialGenerator{} - } - - return &CA{ - SerialGenerator: serialGenerator, - Config: caConfig, - }, nil -} - -func MakeSelfSignedCAConfig(name string, expireDays int) (*TLSCertificateConfig, error) { - subject := pkix.Name{CommonName: name} - return MakeSelfSignedCAConfigForSubject(subject, expireDays) -} - -func MakeSelfSignedCAConfigForSubject(subject pkix.Name, expireDays int) (*TLSCertificateConfig, error) { - var caLifetimeInDays = DefaultCACertificateLifetimeInDays - if expireDays > 0 { - caLifetimeInDays = expireDays - } - - if caLifetimeInDays > DefaultCACertificateLifetimeInDays { - warnAboutCertificateLifeTime(subject.CommonName, DefaultCACertificateLifetimeInDays) - } - - caLifetime := time.Duration(caLifetimeInDays) * 24 * time.Hour - return makeSelfSignedCAConfigForSubjectAndDuration(subject, time.Now, caLifetime) -} - -func MakeSelfSignedCAConfigForDuration(name string, caLifetime time.Duration) (*TLSCertificateConfig, error) { - subject := pkix.Name{CommonName: name} - return makeSelfSignedCAConfigForSubjectAndDuration(subject, time.Now, caLifetime) -} - -func UnsafeMakeSelfSignedCAConfigForDurationAtTime(name string, currentTime func() time.Time, caLifetime time.Duration) (*TLSCertificateConfig, error) { - subject := pkix.Name{CommonName: name} - return makeSelfSignedCAConfigForSubjectAndDuration(subject, currentTime, caLifetime) -} - -func makeSelfSignedCAConfigForSubjectAndDuration(subject pkix.Name, currentTime func() time.Time, caLifetime time.Duration) (*TLSCertificateConfig, error) { - // Create CA cert - rootcaPublicKey, rootcaPrivateKey, publicKeyHash, err := newKeyPairWithHash() - if err != nil { - return nil, err - } - // AuthorityKeyId and SubjectKeyId should match for a self-signed CA - authorityKeyId := publicKeyHash - subjectKeyId := publicKeyHash - rootcaTemplate := newSigningCertificateTemplateForDuration(subject, caLifetime, currentTime, authorityKeyId, subjectKeyId) - rootcaCert, err := signCertificate(rootcaTemplate, rootcaPublicKey, rootcaTemplate, rootcaPrivateKey) - if err != nil { - return nil, err - } - caConfig := &TLSCertificateConfig{ - Certs: []*x509.Certificate{rootcaCert}, - Key: rootcaPrivateKey, - } - return caConfig, nil -} - -func MakeCAConfigForDuration(name string, caLifetime time.Duration, issuer *CA) (*TLSCertificateConfig, error) { - // Create CA cert - signerPublicKey, signerPrivateKey, publicKeyHash, err := newKeyPairWithHash() - if err != nil { - return nil, err - } - authorityKeyId := issuer.Config.Certs[0].SubjectKeyId - subjectKeyId := publicKeyHash - signerTemplate := newSigningCertificateTemplateForDuration(pkix.Name{CommonName: name}, caLifetime, time.Now, authorityKeyId, subjectKeyId) - signerCert, err := issuer.SignCertificate(signerTemplate, signerPublicKey) - if err != nil { - return nil, err - } - signerConfig := &TLSCertificateConfig{ - Certs: append([]*x509.Certificate{signerCert}, issuer.Config.Certs...), - Key: signerPrivateKey, - } - return signerConfig, nil -} - -// EnsureSubCA returns a subCA signed by the `ca`, whether it was created -// (as opposed to pre-existing), and any error that might occur during the subCA -// creation. -// If serialFile is an empty string, a RandomSerialGenerator will be used. -func (ca *CA) EnsureSubCA(certFile, keyFile, serialFile, name string, expireDays int) (*CA, bool, error) { - if subCA, err := GetCA(certFile, keyFile, serialFile); err == nil { - return subCA, false, err - } - subCA, err := ca.MakeAndWriteSubCA(certFile, keyFile, serialFile, name, expireDays) - return subCA, true, err -} - -// MakeAndWriteSubCA returns a new sub-CA configuration. New cert/key pair is generated -// while using this function. -// If serialFile is an empty string, a RandomSerialGenerator will be used. -func (ca *CA) MakeAndWriteSubCA(certFile, keyFile, serialFile, name string, expireDays int) (*CA, error) { - klog.V(4).Infof("Generating sub-CA certificate in %s, key in %s, serial in %s", certFile, keyFile, serialFile) - - subCAConfig, err := MakeCAConfigForDuration(name, time.Duration(expireDays)*time.Hour*24, ca) - if err != nil { - return nil, err - } - - if err := subCAConfig.WriteCertConfigFile(certFile, keyFile); err != nil { - return nil, err - } - - var serialGenerator SerialGenerator - if len(serialFile) > 0 { - // create / overwrite the serial file with a zero padded hex value (ending in a newline to have a valid file) - if err := os.WriteFile(serialFile, []byte("00\n"), 0644); err != nil { - return nil, err - } - - serialGenerator, err = NewSerialFileGenerator(serialFile) - if err != nil { - return nil, err - } - } else { - serialGenerator = &RandomSerialGenerator{} - } - - return &CA{ - Config: subCAConfig, - SerialGenerator: serialGenerator, - }, nil -} - -func (ca *CA) EnsureServerCert(certFile, keyFile string, hostnames sets.Set[string], expireDays int) (*TLSCertificateConfig, bool, error) { - certConfig, err := GetServerCert(certFile, keyFile, hostnames) - if err != nil { - certConfig, err = ca.MakeAndWriteServerCert(certFile, keyFile, hostnames, expireDays) - return certConfig, true, err - } - - return certConfig, false, nil -} - -func GetServerCert(certFile, keyFile string, hostnames sets.Set[string]) (*TLSCertificateConfig, error) { - server, err := GetTLSCertificateConfig(certFile, keyFile) - if err != nil { - return nil, err - } - - cert := server.Certs[0] - certNames := sets.New[string]() - for _, ip := range cert.IPAddresses { - certNames.Insert(ip.String()) - } - certNames.Insert(cert.DNSNames...) - if hostnames.Equal(certNames) { - klog.V(4).Infof("Found existing server certificate in %s", certFile) - return server, nil - } - - return nil, fmt.Errorf("Existing server certificate in %s does not match required hostnames.", certFile) -} - -func (ca *CA) MakeAndWriteServerCert(certFile, keyFile string, hostnames sets.Set[string], expireDays int) (*TLSCertificateConfig, error) { - klog.V(4).Infof("Generating server certificate in %s, key in %s", certFile, keyFile) - - server, err := ca.MakeServerCert(hostnames, expireDays) - if err != nil { - return nil, err - } - if err := server.WriteCertConfigFile(certFile, keyFile); err != nil { - return server, err - } - return server, nil -} - -// CertificateExtensionFunc is passed a certificate that it may extend, or return an error -// if the extension attempt failed. -type CertificateExtensionFunc func(*x509.Certificate) error - -func (ca *CA) MakeServerCert(hostnames sets.Set[string], expireDays int, fns ...CertificateExtensionFunc) (*TLSCertificateConfig, error) { - serverPublicKey, serverPrivateKey, publicKeyHash, _ := newKeyPairWithHash() - authorityKeyId := ca.Config.Certs[0].SubjectKeyId - subjectKeyId := publicKeyHash - serverTemplate := newServerCertificateTemplate(pkix.Name{CommonName: sets.List(hostnames)[0]}, sets.List(hostnames), expireDays, time.Now, authorityKeyId, subjectKeyId) - for _, fn := range fns { - if err := fn(serverTemplate); err != nil { - return nil, err - } - } - serverCrt, err := ca.SignCertificate(serverTemplate, serverPublicKey) - if err != nil { - return nil, err - } - server := &TLSCertificateConfig{ - Certs: append([]*x509.Certificate{serverCrt}, ca.Config.Certs...), - Key: serverPrivateKey, - } - return server, nil -} - -func (ca *CA) MakeServerCertForDuration(hostnames sets.Set[string], lifetime time.Duration, fns ...CertificateExtensionFunc) (*TLSCertificateConfig, error) { - serverPublicKey, serverPrivateKey, publicKeyHash, _ := newKeyPairWithHash() - authorityKeyId := ca.Config.Certs[0].SubjectKeyId - subjectKeyId := publicKeyHash - serverTemplate := newServerCertificateTemplateForDuration(pkix.Name{CommonName: sets.List(hostnames)[0]}, sets.List(hostnames), lifetime, time.Now, authorityKeyId, subjectKeyId) - for _, fn := range fns { - if err := fn(serverTemplate); err != nil { - return nil, err - } - } - serverCrt, err := ca.SignCertificate(serverTemplate, serverPublicKey) - if err != nil { - return nil, err - } - server := &TLSCertificateConfig{ - Certs: append([]*x509.Certificate{serverCrt}, ca.Config.Certs...), - Key: serverPrivateKey, - } - return server, nil -} - -func (ca *CA) EnsureClientCertificate(certFile, keyFile string, u user.Info, expireDays int) (*TLSCertificateConfig, bool, error) { - certConfig, err := GetClientCertificate(certFile, keyFile, u) - if err != nil { - certConfig, err = ca.MakeClientCertificate(certFile, keyFile, u, expireDays) - return certConfig, true, err // true indicates we wrote the files. - } - return certConfig, false, nil -} - -func GetClientCertificate(certFile, keyFile string, u user.Info) (*TLSCertificateConfig, error) { - certConfig, err := GetTLSCertificateConfig(certFile, keyFile) - if err != nil { - return nil, err - } - - if subject := certConfig.Certs[0].Subject; subjectChanged(subject, UserToSubject(u)) { - return nil, fmt.Errorf("existing client certificate in %s was issued for a different Subject (%s)", - certFile, subject) - } - - return certConfig, nil -} - -func subjectChanged(existing, expected pkix.Name) bool { - sort.Strings(existing.Organization) - sort.Strings(expected.Organization) - - return existing.CommonName != expected.CommonName || - existing.SerialNumber != expected.SerialNumber || - !reflect.DeepEqual(existing.Organization, expected.Organization) -} - -func (ca *CA) MakeClientCertificate(certFile, keyFile string, u user.Info, expireDays int) (*TLSCertificateConfig, error) { - klog.V(4).Infof("Generating client cert in %s and key in %s", certFile, keyFile) - // ensure parent dirs - if err := os.MkdirAll(filepath.Dir(certFile), os.FileMode(0755)); err != nil { - return nil, err - } - if err := os.MkdirAll(filepath.Dir(keyFile), os.FileMode(0755)); err != nil { - return nil, err - } - - clientPublicKey, clientPrivateKey, _ := NewKeyPair() - clientTemplate := NewClientCertificateTemplate(UserToSubject(u), expireDays, time.Now) - clientCrt, err := ca.SignCertificate(clientTemplate, clientPublicKey) - if err != nil { - return nil, err - } - - certData, err := EncodeCertificates(clientCrt) - if err != nil { - return nil, err - } - keyData, err := EncodeKey(clientPrivateKey) - if err != nil { - return nil, err - } - - if err = os.WriteFile(certFile, certData, os.FileMode(0644)); err != nil { - return nil, err - } - if err = os.WriteFile(keyFile, keyData, os.FileMode(0600)); err != nil { - return nil, err - } - - return GetTLSCertificateConfig(certFile, keyFile) -} - -func (ca *CA) MakeClientCertificateForDuration(u user.Info, lifetime time.Duration) (*TLSCertificateConfig, error) { - clientPublicKey, clientPrivateKey, _ := NewKeyPair() - clientTemplate := NewClientCertificateTemplateForDuration(UserToSubject(u), lifetime, time.Now) - clientCrt, err := ca.SignCertificate(clientTemplate, clientPublicKey) - if err != nil { - return nil, err - } - - certData, err := EncodeCertificates(clientCrt) - if err != nil { - return nil, err - } - keyData, err := EncodeKey(clientPrivateKey) - if err != nil { - return nil, err - } - - return GetTLSCertificateConfigFromBytes(certData, keyData) -} - -type sortedForDER []string - -func (s sortedForDER) Len() int { - return len(s) -} -func (s sortedForDER) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} -func (s sortedForDER) Less(i, j int) bool { - l1 := len(s[i]) - l2 := len(s[j]) - if l1 == l2 { - return s[i] < s[j] - } - return l1 < l2 -} - -func UserToSubject(u user.Info) pkix.Name { - // Ok we are going to order groups in a peculiar way here to workaround a - // 2 bugs, 1 in golang (https://github.com/golang/go/issues/24254) which - // incorrectly encodes Multivalued RDNs and another in GNUTLS clients - // which are too picky (https://gitlab.com/gnutls/gnutls/issues/403) - // and try to "correct" this issue when reading client certs. - // - // This workaround should be killed once Golang's pkix module is fixed to - // generate a correct DER encoding. - // - // The workaround relies on the fact that the first octect that differs - // between the encoding of two group RDNs will end up being the encoded - // length which is directly related to the group name's length. So we'll - // sort such that shortest names come first. - ugroups := u.GetGroups() - groups := make([]string, len(ugroups)) - copy(groups, ugroups) - sort.Sort(sortedForDER(groups)) - - return pkix.Name{ - CommonName: u.GetName(), - SerialNumber: u.GetUID(), - Organization: groups, - } -} - -func (ca *CA) SignCertificate(template *x509.Certificate, requestKey crypto.PublicKey) (*x509.Certificate, error) { - // Increment and persist serial - serial, err := ca.SerialGenerator.Next(template) - if err != nil { - return nil, err - } - template.SerialNumber = big.NewInt(serial) - return signCertificate(template, requestKey, ca.Config.Certs[0], ca.Config.Key) -} - -func NewKeyPair() (crypto.PublicKey, crypto.PrivateKey, error) { - return newRSAKeyPair() -} - -func newKeyPairWithHash() (crypto.PublicKey, crypto.PrivateKey, []byte, error) { - publicKey, privateKey, err := newRSAKeyPair() - var publicKeyHash []byte - if err == nil { - hash := sha1.New() - hash.Write(publicKey.N.Bytes()) - publicKeyHash = hash.Sum(nil) - } - return publicKey, privateKey, publicKeyHash, err -} - -func newRSAKeyPair() (*rsa.PublicKey, *rsa.PrivateKey, error) { - privateKey, err := rsa.GenerateKey(rand.Reader, keyBits) - if err != nil { - return nil, nil, err - } - return &privateKey.PublicKey, privateKey, nil -} - -// Can be used for CA or intermediate signing certs -func newSigningCertificateTemplateForDuration(subject pkix.Name, caLifetime time.Duration, currentTime func() time.Time, authorityKeyId, subjectKeyId []byte) *x509.Certificate { - return &x509.Certificate{ - Subject: subject, - - SignatureAlgorithm: x509.SHA256WithRSA, - - NotBefore: currentTime().Add(-1 * time.Second), - NotAfter: currentTime().Add(caLifetime), - - // Specify a random serial number to avoid the same issuer+serial - // number referring to different certs in a chain of trust if the - // signing certificate is ever rotated. - SerialNumber: big.NewInt(randomSerialNumber()), - - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, - BasicConstraintsValid: true, - IsCA: true, - - AuthorityKeyId: authorityKeyId, - SubjectKeyId: subjectKeyId, - } -} - -// Can be used for ListenAndServeTLS -func newServerCertificateTemplate(subject pkix.Name, hosts []string, expireDays int, currentTime func() time.Time, authorityKeyId, subjectKeyId []byte) *x509.Certificate { - var lifetimeInDays = DefaultCertificateLifetimeInDays - if expireDays > 0 { - lifetimeInDays = expireDays - } - - if lifetimeInDays > DefaultCertificateLifetimeInDays { - warnAboutCertificateLifeTime(subject.CommonName, DefaultCertificateLifetimeInDays) - } - - lifetime := time.Duration(lifetimeInDays) * 24 * time.Hour - - return newServerCertificateTemplateForDuration(subject, hosts, lifetime, currentTime, authorityKeyId, subjectKeyId) -} - -// Can be used for ListenAndServeTLS -func newServerCertificateTemplateForDuration(subject pkix.Name, hosts []string, lifetime time.Duration, currentTime func() time.Time, authorityKeyId, subjectKeyId []byte) *x509.Certificate { - template := &x509.Certificate{ - Subject: subject, - - SignatureAlgorithm: x509.SHA256WithRSA, - - NotBefore: currentTime().Add(-1 * time.Second), - NotAfter: currentTime().Add(lifetime), - SerialNumber: big.NewInt(1), - - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - - AuthorityKeyId: authorityKeyId, - SubjectKeyId: subjectKeyId, - } - - template.IPAddresses, template.DNSNames = IPAddressesDNSNames(hosts) - - return template -} - -func IPAddressesDNSNames(hosts []string) ([]net.IP, []string) { - ips := []net.IP{} - dns := []string{} - for _, host := range hosts { - if ip := net.ParseIP(host); ip != nil { - ips = append(ips, ip) - } else { - dns = append(dns, host) - } - } - - // Include IP addresses as DNS subjectAltNames in the cert as well, for the sake of Python, Windows (< 10), and unnamed other libraries - // Ensure these technically invalid DNS subjectAltNames occur after the valid ones, to avoid triggering cert errors in Firefox - // See https://bugzilla.mozilla.org/show_bug.cgi?id=1148766 - for _, ip := range ips { - dns = append(dns, ip.String()) - } - - return ips, dns -} - -func CertsFromPEM(pemCerts []byte) ([]*x509.Certificate, error) { - ok := false - certs := []*x509.Certificate{} - for len(pemCerts) > 0 { - var block *pem.Block - block, pemCerts = pem.Decode(pemCerts) - if block == nil { - break - } - if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { - continue - } - - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return certs, err - } - - certs = append(certs, cert) - ok = true - } - - if !ok { - return certs, errors.New("Could not read any certificates") - } - return certs, nil -} - -// Can be used as a certificate in http.Transport TLSClientConfig -func NewClientCertificateTemplate(subject pkix.Name, expireDays int, currentTime func() time.Time) *x509.Certificate { - var lifetimeInDays = DefaultCertificateLifetimeInDays - if expireDays > 0 { - lifetimeInDays = expireDays - } - - if lifetimeInDays > DefaultCertificateLifetimeInDays { - warnAboutCertificateLifeTime(subject.CommonName, DefaultCertificateLifetimeInDays) - } - - lifetime := time.Duration(lifetimeInDays) * 24 * time.Hour - - return NewClientCertificateTemplateForDuration(subject, lifetime, currentTime) -} - -// Can be used as a certificate in http.Transport TLSClientConfig -func NewClientCertificateTemplateForDuration(subject pkix.Name, lifetime time.Duration, currentTime func() time.Time) *x509.Certificate { - return &x509.Certificate{ - Subject: subject, - - SignatureAlgorithm: x509.SHA256WithRSA, - - NotBefore: currentTime().Add(-1 * time.Second), - NotAfter: currentTime().Add(lifetime), - SerialNumber: big.NewInt(1), - - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, - BasicConstraintsValid: true, - } -} - -func warnAboutCertificateLifeTime(name string, defaultLifetimeInDays int) { - defaultLifetimeInYears := defaultLifetimeInDays / 365 - fmt.Fprintf(os.Stderr, "WARNING: Validity period of the certificate for %q is greater than %d years!\n", name, defaultLifetimeInYears) - fmt.Fprintln(os.Stderr, "WARNING: By security reasons it is strongly recommended to change this period and make it smaller!") -} - -func signCertificate(template *x509.Certificate, requestKey crypto.PublicKey, issuer *x509.Certificate, issuerKey crypto.PrivateKey) (*x509.Certificate, error) { - derBytes, err := x509.CreateCertificate(rand.Reader, template, issuer, requestKey, issuerKey) - if err != nil { - return nil, err - } - certs, err := x509.ParseCertificates(derBytes) - if err != nil { - return nil, err - } - if len(certs) != 1 { - return nil, errors.New("Expected a single certificate") - } - return certs[0], nil -} - -func EncodeCertificates(certs ...*x509.Certificate) ([]byte, error) { - b := bytes.Buffer{} - for _, cert := range certs { - if err := pem.Encode(&b, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}); err != nil { - return []byte{}, err - } - } - return b.Bytes(), nil -} -func EncodeKey(key crypto.PrivateKey) ([]byte, error) { - b := bytes.Buffer{} - switch key := key.(type) { - case *ecdsa.PrivateKey: - keyBytes, err := x509.MarshalECPrivateKey(key) - if err != nil { - return []byte{}, err - } - if err := pem.Encode(&b, &pem.Block{Type: "EC PRIVATE KEY", Bytes: keyBytes}); err != nil { - return b.Bytes(), err - } - case *rsa.PrivateKey: - if err := pem.Encode(&b, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}); err != nil { - return []byte{}, err - } - default: - return []byte{}, errors.New("Unrecognized key type") - - } - return b.Bytes(), nil -} - -func writeCertificates(f io.Writer, certs ...*x509.Certificate) error { - bytes, err := EncodeCertificates(certs...) - if err != nil { - return err - } - if _, err := f.Write(bytes); err != nil { - return err - } - - return nil -} -func writeKeyFile(f io.Writer, key crypto.PrivateKey) error { - bytes, err := EncodeKey(key) - if err != nil { - return err - } - if _, err := f.Write(bytes); err != nil { - return err - } - - return nil -} diff --git a/vendor/github.com/openshift/library-go/pkg/crypto/rotation.go b/vendor/github.com/openshift/library-go/pkg/crypto/rotation.go deleted file mode 100644 index 0aa12703..00000000 --- a/vendor/github.com/openshift/library-go/pkg/crypto/rotation.go +++ /dev/null @@ -1,20 +0,0 @@ -package crypto - -import ( - "crypto/x509" - "time" -) - -// FilterExpiredCerts checks are all certificates in the bundle valid, i.e. they have not expired. -// The function returns new bundle with only valid certificates or error if no valid certificate is found. -func FilterExpiredCerts(certs ...*x509.Certificate) []*x509.Certificate { - currentTime := time.Now() - var validCerts []*x509.Certificate - for _, c := range certs { - if c.NotAfter.After(currentTime) { - validCerts = append(validCerts, c) - } - } - - return validCerts -} diff --git a/vendor/k8s.io/apiserver/LICENSE b/vendor/k8s.io/apiserver/LICENSE deleted file mode 100644 index d6456956..00000000 --- a/vendor/k8s.io/apiserver/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/vendor/k8s.io/apiserver/pkg/authentication/user/doc.go b/vendor/k8s.io/apiserver/pkg/authentication/user/doc.go deleted file mode 100644 index 3d87fd72..00000000 --- a/vendor/k8s.io/apiserver/pkg/authentication/user/doc.go +++ /dev/null @@ -1,19 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors. - -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 user contains utilities for dealing with simple user exchange in the auth -// packages. The user.Info interface defines an interface for exchanging that info. -package user // import "k8s.io/apiserver/pkg/authentication/user" diff --git a/vendor/k8s.io/apiserver/pkg/authentication/user/user.go b/vendor/k8s.io/apiserver/pkg/authentication/user/user.go deleted file mode 100644 index 4d6ec098..00000000 --- a/vendor/k8s.io/apiserver/pkg/authentication/user/user.go +++ /dev/null @@ -1,84 +0,0 @@ -/* -Copyright 2014 The Kubernetes Authors. - -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 user - -// Info describes a user that has been authenticated to the system. -type Info interface { - // GetName returns the name that uniquely identifies this user among all - // other active users. - GetName() string - // GetUID returns a unique value for a particular user that will change - // if the user is removed from the system and another user is added with - // the same name. - GetUID() string - // GetGroups returns the names of the groups the user is a member of - GetGroups() []string - - // GetExtra can contain any additional information that the authenticator - // thought was interesting. One example would be scopes on a token. - // Keys in this map should be namespaced to the authenticator or - // authenticator/authorizer pair making use of them. - // For instance: "example.org/foo" instead of "foo" - // This is a map[string][]string because it needs to be serializeable into - // a SubjectAccessReviewSpec.authorization.k8s.io for proper authorization - // delegation flows - // In order to faithfully round-trip through an impersonation flow, these keys - // MUST be lowercase. - GetExtra() map[string][]string -} - -// DefaultInfo provides a simple user information exchange object -// for components that implement the UserInfo interface. -type DefaultInfo struct { - Name string - UID string - Groups []string - Extra map[string][]string -} - -func (i *DefaultInfo) GetName() string { - return i.Name -} - -func (i *DefaultInfo) GetUID() string { - return i.UID -} - -func (i *DefaultInfo) GetGroups() []string { - return i.Groups -} - -func (i *DefaultInfo) GetExtra() map[string][]string { - return i.Extra -} - -// well-known user and group names -const ( - SystemPrivilegedGroup = "system:masters" - NodesGroup = "system:nodes" - MonitoringGroup = "system:monitoring" - AllUnauthenticated = "system:unauthenticated" - AllAuthenticated = "system:authenticated" - - Anonymous = "system:anonymous" - APIServerUser = "system:apiserver" - - // core kubernetes process identities - KubeProxy = "system:kube-proxy" - KubeControllerManager = "system:kube-controller-manager" - KubeScheduler = "system:kube-scheduler" -) diff --git a/vendor/modules.txt b/vendor/modules.txt index f99ba7df..0260a1ad 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -171,9 +171,6 @@ github.com/openshift/client-go/security/clientset/versioned/typed/security/v1 # github.com/openshift/custom-resource-status v1.1.2 ## explicit; go 1.12 github.com/openshift/custom-resource-status/conditions/v1 -# github.com/openshift/library-go v0.0.0-20240715191351-e0aa70d55678 -## explicit; go 1.22.0 -github.com/openshift/library-go/pkg/crypto # github.com/pkg/errors v0.9.1 ## explicit github.com/pkg/errors @@ -403,9 +400,6 @@ k8s.io/apimachinery/pkg/watch k8s.io/apimachinery/third_party/forked/golang/json k8s.io/apimachinery/third_party/forked/golang/netutil k8s.io/apimachinery/third_party/forked/golang/reflect -# k8s.io/apiserver v0.30.3 -## explicit; go 1.22.0 -k8s.io/apiserver/pkg/authentication/user # k8s.io/client-go v0.30.3 ## explicit; go 1.22.0 k8s.io/client-go/applyconfigurations/admissionregistration/v1