From 9b2815658458ebc971aa2cbb8262d8c368d56cbc Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Mon, 24 Nov 2025 09:03:09 -0800 Subject: [PATCH] [api] TLSCertificate --- api/core/v1alpha2/tlscertificate_types.go | 144 +++++++++++ api/core/v1alpha2/tlscertificate_validate.go | 178 ++++++++++++++ .../v1alpha2/tlscertificate_validate_test.go | 230 ++++++++++++++++++ api/core/v1alpha2/zz_generated.deepcopy.go | 113 +++++++++ api/core/v1alpha2/zz_generated.register.go | 2 + api/generated/zz_generated.openapi.go | 200 +++++++++++++++ client/informers/core/v1alpha2/interface.go | 7 + .../informers/core/v1alpha2/tlscertificate.go | 88 +++++++ client/informers/generic.go | 2 + .../core/v1alpha2/expansion_generated.go | 4 + .../listers/core/v1alpha2/tlscertificate.go | 67 +++++ .../typed/core/v1alpha2/core_client.go | 5 + .../core/v1alpha2/fake/fake_core_client.go | 4 + .../core/v1alpha2/fake/fake_tlscertificate.go | 131 ++++++++++ .../core/v1alpha2/generated_expansion.go | 2 + .../typed/core/v1alpha2/tlscertificate.go | 183 ++++++++++++++ pkg/apiserver/manager.go | 1 + 17 files changed, 1361 insertions(+) create mode 100644 api/core/v1alpha2/tlscertificate_types.go create mode 100644 api/core/v1alpha2/tlscertificate_validate.go create mode 100644 api/core/v1alpha2/tlscertificate_validate_test.go create mode 100644 client/informers/core/v1alpha2/tlscertificate.go create mode 100644 client/listers/core/v1alpha2/tlscertificate.go create mode 100644 client/versioned/typed/core/v1alpha2/fake/fake_tlscertificate.go create mode 100644 client/versioned/typed/core/v1alpha2/tlscertificate.go diff --git a/api/core/v1alpha2/tlscertificate_types.go b/api/core/v1alpha2/tlscertificate_types.go new file mode 100644 index 00000000..0c61b1bd --- /dev/null +++ b/api/core/v1alpha2/tlscertificate_types.go @@ -0,0 +1,144 @@ +package v1alpha2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/registry/rest" + "sigs.k8s.io/apiserver-runtime/pkg/builder/resource" +) + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TLSCertificate represents a TLS certificate and private key pair. +// This matches the Kubernetes TLS secret type but is specific to that use case. +// The public/private key pair must exist beforehand. +// The public key certificate must be PEM encoded and match the given private key. +type TLSCertificate struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec TLSCertificateSpec `json:"spec,omitempty"` + Status TLSCertificateStatus `json:"status,omitempty"` +} + +// TLSCertificateSpec defines the desired state of TLSCertificate +type TLSCertificateSpec struct { + // Certificate is the PEM-encoded TLS certificate. + // This should contain one or more certificate blocks. + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength=1 + Certificate string `json:"certificate"` + + // PrivateKey is the PEM-encoded private key corresponding to the certificate. + // This must match the public key in the certificate. + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength=1 + PrivateKey string `json:"privateKey"` +} + +// TLSCertificateStatus defines the observed state of TLSCertificate +type TLSCertificateStatus struct { + // NotBefore is the time before which the certificate is not valid. + // +optional + NotBefore *metav1.Time `json:"notBefore,omitempty"` + + // NotAfter is the time after which the certificate is not valid. + // +optional + NotAfter *metav1.Time `json:"notAfter,omitempty"` + + // Issuer is the issuer of the certificate. + // +optional + Issuer string `json:"issuer,omitempty"` + + // Subject is the subject of the certificate. + // +optional + Subject string `json:"subject,omitempty"` + + // DNSNames is the list of DNS names in the certificate's Subject Alternative Names. + // +optional + DNSNames []string `json:"dnsNames,omitempty"` + + // Conditions represent the latest available observations of the TLSCertificate's state. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TLSCertificateList contains a list of TLSCertificate +type TLSCertificateList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []TLSCertificate `json:"items"` +} + +// GetGroupVersionResource returns the GroupVersionResource for TLSCertificate. +func (in *TLSCertificate) GetGroupVersionResource() schema.GroupVersionResource { + return schema.GroupVersionResource{ + Group: GroupVersion.Group, + Version: GroupVersion.Version, + Resource: "tlscertificates", + } +} + +// GetObjectMeta returns the object metadata for TLSCertificate. +func (in *TLSCertificate) GetObjectMeta() *metav1.ObjectMeta { + return &in.ObjectMeta +} + +// IsStorageVersion returns true if TLSCertificate is the storage version. +func (in *TLSCertificate) IsStorageVersion() bool { + return true +} + +// NamespaceScoped returns false as TLSCertificate is cluster-scoped. +func (in *TLSCertificate) NamespaceScoped() bool { + return false +} + +// New returns a new TLSCertificate. +func (in *TLSCertificate) New() runtime.Object { + return &TLSCertificate{} +} + +// NewList returns a new TLSCertificateList. +func (in *TLSCertificate) NewList() runtime.Object { + return &TLSCertificateList{} +} + +// GetStatus returns the status of the TLSCertificate. +func (in *TLSCertificate) GetStatus() resource.StatusSubResource { + return in.Status +} + +// TLSCertificateStatus implements the StatusSubResource interface. +var _ resource.StatusSubResource = &TLSCertificateStatus{} + +func (in TLSCertificateStatus) SubResourceName() string { + return "status" +} + +// CopyTo copies the status to the given parent resource. +func (in TLSCertificateStatus) CopyTo(parent resource.ObjectWithStatusSubResource) { + parent.(*TLSCertificate).Status = in +} + +var _ resource.Object = &TLSCertificate{} +var _ resource.ObjectList = &TLSCertificateList{} +var _ resource.ObjectWithStatusSubResource = &TLSCertificate{} + +// GetListMeta returns the list metadata. +func (in *TLSCertificateList) GetListMeta() *metav1.ListMeta { + return &in.ListMeta +} + +// TableConvertor returns a TableConvertor for TLSCertificate. +func (in *TLSCertificate) TableConvertor() rest.TableConvertor { + return nil +} diff --git a/api/core/v1alpha2/tlscertificate_validate.go b/api/core/v1alpha2/tlscertificate_validate.go new file mode 100644 index 00000000..1ee8016a --- /dev/null +++ b/api/core/v1alpha2/tlscertificate_validate.go @@ -0,0 +1,178 @@ +package v1alpha2 + +import ( + "context" + "crypto" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + "sigs.k8s.io/apiserver-runtime/pkg/builder/resource" + "sigs.k8s.io/apiserver-runtime/pkg/builder/resource/resourcestrategy" +) + +var _ resourcestrategy.Defaulter = &TLSCertificate{} +var _ resourcestrategy.Validater = &TLSCertificate{} +var _ resourcestrategy.ValidateUpdater = &TLSCertificate{} + +// Default sets the default values for a TLSCertificate. +func (r *TLSCertificate) Default() { + // Parse certificate to populate status fields + if r.Spec.Certificate != "" { + if cert, err := parseCertificate(r.Spec.Certificate); err == nil { + r.Status.NotBefore = &metav1.Time{Time: cert.NotBefore} + r.Status.NotAfter = &metav1.Time{Time: cert.NotAfter} + r.Status.Issuer = cert.Issuer.String() + r.Status.Subject = cert.Subject.String() + r.Status.DNSNames = cert.DNSNames + } + } +} + +func (r *TLSCertificate) Validate(ctx context.Context) field.ErrorList { + return r.validate() +} + +func (r *TLSCertificate) ValidateUpdate(ctx context.Context, obj runtime.Object) field.ErrorList { + t := &TLSCertificate{} + // XXX: Conversion needs to happen in apiserver-runtime before validation hooks are called. + if mv, ok := obj.(resource.MultiVersionObject); ok { + mv.ConvertToStorageVersion(t) + } else if t, ok = obj.(*TLSCertificate); !ok { + return field.ErrorList{ + field.Invalid(field.NewPath("kind"), obj.GetObjectKind().GroupVersionKind().Kind, "expected TLSCertificate"), + } + } + + return t.validate() +} + +func (r *TLSCertificate) validate() field.ErrorList { + errs := field.ErrorList{} + + // Validate certificate is PEM encoded + cert, err := parseCertificate(r.Spec.Certificate) + if err != nil { + errs = append(errs, field.Invalid( + field.NewPath("spec", "certificate"), + "", + fmt.Sprintf("invalid PEM-encoded certificate: %v", err), + )) + return errs + } + + // Validate private key is PEM encoded + privateKey, err := parsePrivateKey(r.Spec.PrivateKey) + if err != nil { + errs = append(errs, field.Invalid( + field.NewPath("spec", "privateKey"), + "", + fmt.Sprintf("invalid PEM-encoded private key: %v", err), + )) + return errs + } + + // Validate that the private key matches the certificate's public key + if err := validateKeyPair(cert, privateKey); err != nil { + errs = append(errs, field.Invalid( + field.NewPath("spec", "privateKey"), + "", + fmt.Sprintf("private key does not match certificate public key: %v", err), + )) + } + + return errs +} + +// parseCertificate parses a PEM-encoded certificate and returns the first certificate found. +func parseCertificate(certPEM string) (*x509.Certificate, error) { + block, _ := pem.Decode([]byte(certPEM)) + if block == nil { + return nil, fmt.Errorf("failed to decode PEM block containing certificate") + } + + if block.Type != "CERTIFICATE" { + return nil, fmt.Errorf("PEM block type must be CERTIFICATE, got %s", block.Type) + } + + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, fmt.Errorf("failed to parse certificate: %w", err) + } + + return cert, nil +} + +// parsePrivateKey parses a PEM-encoded private key and returns the private key. +// Supports RSA, ECDSA, and Ed25519 keys. +func parsePrivateKey(keyPEM string) (crypto.PrivateKey, error) { + block, _ := pem.Decode([]byte(keyPEM)) + if block == nil { + return nil, fmt.Errorf("failed to decode PEM block containing private key") + } + + // Try parsing as PKCS8 first (most common format) + if key, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil { + return key, nil + } + + // Try parsing as PKCS1 RSA private key + if key, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil { + return key, nil + } + + // Try parsing as EC private key + if key, err := x509.ParseECPrivateKey(block.Bytes); err == nil { + return key, nil + } + + return nil, fmt.Errorf("failed to parse private key: unsupported key type or format") +} + +// validateKeyPair validates that the private key matches the certificate's public key. +func validateKeyPair(cert *x509.Certificate, privateKey crypto.PrivateKey) error { + switch pub := cert.PublicKey.(type) { + case *rsa.PublicKey: + priv, ok := privateKey.(*rsa.PrivateKey) + if !ok { + return fmt.Errorf("certificate has RSA public key but private key is not RSA") + } + if pub.N.Cmp(priv.N) != 0 || pub.E != priv.E { + return fmt.Errorf("RSA private key does not match certificate public key") + } + + case *ecdsa.PublicKey: + priv, ok := privateKey.(*ecdsa.PrivateKey) + if !ok { + return fmt.Errorf("certificate has ECDSA public key but private key is not ECDSA") + } + if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 { + return fmt.Errorf("ECDSA private key does not match certificate public key") + } + + case ed25519.PublicKey: + priv, ok := privateKey.(ed25519.PrivateKey) + if !ok { + return fmt.Errorf("certificate has Ed25519 public key but private key is not Ed25519") + } + // Ed25519 private key contains the public key in the last 32 bytes + if len(priv) != ed25519.PrivateKeySize { + return fmt.Errorf("invalid Ed25519 private key size") + } + derivedPub := priv.Public().(ed25519.PublicKey) + if !derivedPub.Equal(pub) { + return fmt.Errorf("Ed25519 private key does not match certificate public key") + } + + default: + return fmt.Errorf("unsupported public key type: %T", pub) + } + + return nil +} diff --git a/api/core/v1alpha2/tlscertificate_validate_test.go b/api/core/v1alpha2/tlscertificate_validate_test.go new file mode 100644 index 00000000..1dc7d6c6 --- /dev/null +++ b/api/core/v1alpha2/tlscertificate_validate_test.go @@ -0,0 +1,230 @@ +package v1alpha2 + +import ( + "context" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "testing" + "time" +) + +// generateTestCertificate generates a self-signed certificate and private key for testing +func generateTestCertificate(keyType string) (certPEM, keyPEM string, err error) { + var privateKey interface{} + var privateKeyBytes []byte + var keyPEMType string + + switch keyType { + case "rsa": + key, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return "", "", err + } + privateKey = key + privateKeyBytes = x509.MarshalPKCS1PrivateKey(key) + keyPEMType = "RSA PRIVATE KEY" + + case "ecdsa": + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return "", "", err + } + privateKey = key + privateKeyBytes, err = x509.MarshalECPrivateKey(key) + if err != nil { + return "", "", err + } + keyPEMType = "EC PRIVATE KEY" + + default: + return "", "", nil + } + + // Create certificate template + template := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Organization: []string{"Test Org"}, + CommonName: "test.example.com", + }, + DNSNames: []string{"test.example.com", "*.test.example.com"}, + NotBefore: time.Now(), + NotAfter: time.Now().Add(365 * 24 * time.Hour), + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + // Create self-signed certificate + var publicKey interface{} + switch k := privateKey.(type) { + case *rsa.PrivateKey: + publicKey = &k.PublicKey + case *ecdsa.PrivateKey: + publicKey = &k.PublicKey + } + + certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey, privateKey) + if err != nil { + return "", "", err + } + + // Encode certificate to PEM + certPEMBlock := pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", + Bytes: certBytes, + }) + + // Encode private key to PEM + keyPEMBlock := pem.EncodeToMemory(&pem.Block{ + Type: keyPEMType, + Bytes: privateKeyBytes, + }) + + return string(certPEMBlock), string(keyPEMBlock), nil +} + +func TestTLSCertificateValidation(t *testing.T) { + ctx := context.Background() + + t.Run("valid RSA certificate", func(t *testing.T) { + certPEM, keyPEM, err := generateTestCertificate("rsa") + if err != nil { + t.Fatalf("failed to generate test certificate: %v", err) + } + + tlsCert := &TLSCertificate{ + Spec: TLSCertificateSpec{ + Certificate: certPEM, + PrivateKey: keyPEM, + }, + } + + errs := tlsCert.Validate(ctx) + if len(errs) > 0 { + t.Errorf("expected no validation errors, got: %v", errs) + } + }) + + t.Run("valid ECDSA certificate", func(t *testing.T) { + certPEM, keyPEM, err := generateTestCertificate("ecdsa") + if err != nil { + t.Fatalf("failed to generate test certificate: %v", err) + } + + tlsCert := &TLSCertificate{ + Spec: TLSCertificateSpec{ + Certificate: certPEM, + PrivateKey: keyPEM, + }, + } + + errs := tlsCert.Validate(ctx) + if len(errs) > 0 { + t.Errorf("expected no validation errors, got: %v", errs) + } + }) + + t.Run("invalid certificate PEM", func(t *testing.T) { + tlsCert := &TLSCertificate{ + Spec: TLSCertificateSpec{ + Certificate: "not a valid PEM", + PrivateKey: "not a valid PEM", + }, + } + + errs := tlsCert.Validate(ctx) + if len(errs) == 0 { + t.Error("expected validation errors for invalid PEM") + } + }) + + t.Run("mismatched certificate and key", func(t *testing.T) { + // Generate two different certificates + certPEM1, _, err := generateTestCertificate("rsa") + if err != nil { + t.Fatalf("failed to generate test certificate: %v", err) + } + + _, keyPEM2, err := generateTestCertificate("rsa") + if err != nil { + t.Fatalf("failed to generate test certificate: %v", err) + } + + tlsCert := &TLSCertificate{ + Spec: TLSCertificateSpec{ + Certificate: certPEM1, + PrivateKey: keyPEM2, + }, + } + + errs := tlsCert.Validate(ctx) + if len(errs) == 0 { + t.Error("expected validation errors for mismatched certificate and key") + } + }) + + t.Run("wrong key type", func(t *testing.T) { + // Generate RSA certificate but ECDSA key + certPEM, _, err := generateTestCertificate("rsa") + if err != nil { + t.Fatalf("failed to generate test certificate: %v", err) + } + + _, keyPEM, err := generateTestCertificate("ecdsa") + if err != nil { + t.Fatalf("failed to generate test certificate: %v", err) + } + + tlsCert := &TLSCertificate{ + Spec: TLSCertificateSpec{ + Certificate: certPEM, + PrivateKey: keyPEM, + }, + } + + errs := tlsCert.Validate(ctx) + if len(errs) == 0 { + t.Error("expected validation errors for wrong key type") + } + }) +} + +func TestTLSCertificateDefault(t *testing.T) { + certPEM, keyPEM, err := generateTestCertificate("rsa") + if err != nil { + t.Fatalf("failed to generate test certificate: %v", err) + } + + tlsCert := &TLSCertificate{ + Spec: TLSCertificateSpec{ + Certificate: certPEM, + PrivateKey: keyPEM, + }, + } + + tlsCert.Default() + + // Check that status fields were populated + if tlsCert.Status.NotBefore == nil { + t.Error("expected NotBefore to be set") + } + if tlsCert.Status.NotAfter == nil { + t.Error("expected NotAfter to be set") + } + if tlsCert.Status.Issuer == "" { + t.Error("expected Issuer to be set") + } + if tlsCert.Status.Subject == "" { + t.Error("expected Subject to be set") + } + if len(tlsCert.Status.DNSNames) == 0 { + t.Error("expected DNSNames to be set") + } +} diff --git a/api/core/v1alpha2/zz_generated.deepcopy.go b/api/core/v1alpha2/zz_generated.deepcopy.go index bf9233cb..daf9f4e2 100644 --- a/api/core/v1alpha2/zz_generated.deepcopy.go +++ b/api/core/v1alpha2/zz_generated.deepcopy.go @@ -1303,6 +1303,119 @@ func (in *ShutdownConfig) DeepCopy() *ShutdownConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSCertificate) DeepCopyInto(out *TLSCertificate) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSCertificate. +func (in *TLSCertificate) DeepCopy() *TLSCertificate { + if in == nil { + return nil + } + out := new(TLSCertificate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TLSCertificate) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSCertificateList) DeepCopyInto(out *TLSCertificateList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TLSCertificate, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSCertificateList. +func (in *TLSCertificateList) DeepCopy() *TLSCertificateList { + if in == nil { + return nil + } + out := new(TLSCertificateList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TLSCertificateList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSCertificateSpec) DeepCopyInto(out *TLSCertificateSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSCertificateSpec. +func (in *TLSCertificateSpec) DeepCopy() *TLSCertificateSpec { + if in == nil { + return nil + } + out := new(TLSCertificateSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSCertificateStatus) DeepCopyInto(out *TLSCertificateStatus) { + *out = *in + if in.NotBefore != nil { + in, out := &in.NotBefore, &out.NotBefore + *out = (*in).DeepCopy() + } + if in.NotAfter != nil { + in, out := &in.NotAfter, &out.NotAfter + *out = (*in).DeepCopy() + } + if in.DNSNames != nil { + in, out := &in.DNSNames, &out.DNSNames + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSCertificateStatus. +func (in *TLSCertificateStatus) DeepCopy() *TLSCertificateStatus { + if in == nil { + return nil + } + out := new(TLSCertificateStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ThirdPartySinks) DeepCopyInto(out *ThirdPartySinks) { *out = *in diff --git a/api/core/v1alpha2/zz_generated.register.go b/api/core/v1alpha2/zz_generated.register.go index fce6d696..59bed9a4 100644 --- a/api/core/v1alpha2/zz_generated.register.go +++ b/api/core/v1alpha2/zz_generated.register.go @@ -70,6 +70,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &DomainZoneList{}, &Proxy{}, &ProxyList{}, + &TLSCertificate{}, + &TLSCertificateList{}, &Tunnel{}, &TunnelAgent{}, &TunnelAgentList{}, diff --git a/api/generated/zz_generated.openapi.go b/api/generated/zz_generated.openapi.go index 39671eb4..307d9489 100644 --- a/api/generated/zz_generated.openapi.go +++ b/api/generated/zz_generated.openapi.go @@ -136,6 +136,10 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/apoxy-dev/apoxy/api/core/v1alpha2.RegistrationConfig": schema_apoxy_api_core_v1alpha2_RegistrationConfig(ref), "github.com/apoxy-dev/apoxy/api/core/v1alpha2.RegistrationStatus": schema_apoxy_api_core_v1alpha2_RegistrationStatus(ref), "github.com/apoxy-dev/apoxy/api/core/v1alpha2.ShutdownConfig": schema_apoxy_api_core_v1alpha2_ShutdownConfig(ref), + "github.com/apoxy-dev/apoxy/api/core/v1alpha2.TLSCertificate": schema_apoxy_api_core_v1alpha2_TLSCertificate(ref), + "github.com/apoxy-dev/apoxy/api/core/v1alpha2.TLSCertificateList": schema_apoxy_api_core_v1alpha2_TLSCertificateList(ref), + "github.com/apoxy-dev/apoxy/api/core/v1alpha2.TLSCertificateSpec": schema_apoxy_api_core_v1alpha2_TLSCertificateSpec(ref), + "github.com/apoxy-dev/apoxy/api/core/v1alpha2.TLSCertificateStatus": schema_apoxy_api_core_v1alpha2_TLSCertificateStatus(ref), "github.com/apoxy-dev/apoxy/api/core/v1alpha2.ThirdPartySinks": schema_apoxy_api_core_v1alpha2_ThirdPartySinks(ref), "github.com/apoxy-dev/apoxy/api/core/v1alpha2.Tunnel": schema_apoxy_api_core_v1alpha2_Tunnel(ref), "github.com/apoxy-dev/apoxy/api/core/v1alpha2.TunnelAgent": schema_apoxy_api_core_v1alpha2_TunnelAgent(ref), @@ -5200,6 +5204,202 @@ func schema_apoxy_api_core_v1alpha2_ShutdownConfig(ref common.ReferenceCallback) } } +func schema_apoxy_api_core_v1alpha2_TLSCertificate(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TLSCertificate represents a TLS certificate and private key pair. This matches the Kubernetes TLS secret type but is specific to that use case. The public/private key pair must exist beforehand. The public key certificate must be PEM encoded and match the given private key.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/apoxy-dev/apoxy/api/core/v1alpha2.TLSCertificateSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/apoxy-dev/apoxy/api/core/v1alpha2.TLSCertificateStatus"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/apoxy-dev/apoxy/api/core/v1alpha2.TLSCertificateSpec", "github.com/apoxy-dev/apoxy/api/core/v1alpha2.TLSCertificateStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_apoxy_api_core_v1alpha2_TLSCertificateList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TLSCertificateList contains a list of TLSCertificate", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/apoxy-dev/apoxy/api/core/v1alpha2.TLSCertificate"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/apoxy-dev/apoxy/api/core/v1alpha2.TLSCertificate", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + +func schema_apoxy_api_core_v1alpha2_TLSCertificateSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TLSCertificateSpec defines the desired state of TLSCertificate", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "certificate": { + SchemaProps: spec.SchemaProps{ + Description: "Certificate is the PEM-encoded TLS certificate. This should contain one or more certificate blocks.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "privateKey": { + SchemaProps: spec.SchemaProps{ + Description: "PrivateKey is the PEM-encoded private key corresponding to the certificate. This must match the public key in the certificate.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"certificate", "privateKey"}, + }, + }, + } +} + +func schema_apoxy_api_core_v1alpha2_TLSCertificateStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TLSCertificateStatus defines the observed state of TLSCertificate", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "notBefore": { + SchemaProps: spec.SchemaProps{ + Description: "NotBefore is the time before which the certificate is not valid.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "notAfter": { + SchemaProps: spec.SchemaProps{ + Description: "NotAfter is the time after which the certificate is not valid.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "issuer": { + SchemaProps: spec.SchemaProps{ + Description: "Issuer is the issuer of the certificate.", + Type: []string{"string"}, + Format: "", + }, + }, + "subject": { + SchemaProps: spec.SchemaProps{ + Description: "Subject is the subject of the certificate.", + Type: []string{"string"}, + Format: "", + }, + }, + "dnsNames": { + SchemaProps: spec.SchemaProps{ + Description: "DNSNames is the list of DNS names in the certificate's Subject Alternative Names.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "conditions": { + SchemaProps: spec.SchemaProps{ + Description: "Conditions represent the latest available observations of the TLSCertificate's state.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Condition"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Condition", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + func schema_apoxy_api_core_v1alpha2_ThirdPartySinks(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/client/informers/core/v1alpha2/interface.go b/client/informers/core/v1alpha2/interface.go index 34adb811..e970bfe1 100644 --- a/client/informers/core/v1alpha2/interface.go +++ b/client/informers/core/v1alpha2/interface.go @@ -33,6 +33,8 @@ type Interface interface { DomainZones() DomainZoneInformer // Proxies returns a ProxyInformer. Proxies() ProxyInformer + // TLSCertificates returns a TLSCertificateInformer. + TLSCertificates() TLSCertificateInformer // Tunnels returns a TunnelInformer. Tunnels() TunnelInformer // TunnelAgents returns a TunnelAgentInformer. @@ -75,6 +77,11 @@ func (v *version) Proxies() ProxyInformer { return &proxyInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} } +// TLSCertificates returns a TLSCertificateInformer. +func (v *version) TLSCertificates() TLSCertificateInformer { + return &tLSCertificateInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + // Tunnels returns a TunnelInformer. func (v *version) Tunnels() TunnelInformer { return &tunnelInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} diff --git a/client/informers/core/v1alpha2/tlscertificate.go b/client/informers/core/v1alpha2/tlscertificate.go new file mode 100644 index 00000000..4e18ada0 --- /dev/null +++ b/client/informers/core/v1alpha2/tlscertificate.go @@ -0,0 +1,88 @@ +/* +Copyright 2025 Apoxy, Inc. + +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. +*/ +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + "context" + time "time" + + corev1alpha2 "github.com/apoxy-dev/apoxy/api/core/v1alpha2" + internalinterfaces "github.com/apoxy-dev/apoxy/client/informers/internalinterfaces" + v1alpha2 "github.com/apoxy-dev/apoxy/client/listers/core/v1alpha2" + versioned "github.com/apoxy-dev/apoxy/client/versioned" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// TLSCertificateInformer provides access to a shared informer and lister for +// TLSCertificates. +type TLSCertificateInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha2.TLSCertificateLister +} + +type tLSCertificateInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewTLSCertificateInformer constructs a new informer for TLSCertificate type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTLSCertificateInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTLSCertificateInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredTLSCertificateInformer constructs a new informer for TLSCertificate type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTLSCertificateInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.CoreV1alpha2().TLSCertificates().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.CoreV1alpha2().TLSCertificates().Watch(context.TODO(), options) + }, + }, + &corev1alpha2.TLSCertificate{}, + resyncPeriod, + indexers, + ) +} + +func (f *tLSCertificateInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTLSCertificateInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *tLSCertificateInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&corev1alpha2.TLSCertificate{}, f.defaultInformer) +} + +func (f *tLSCertificateInformer) Lister() v1alpha2.TLSCertificateLister { + return v1alpha2.NewTLSCertificateLister(f.Informer().GetIndexer()) +} diff --git a/client/informers/generic.go b/client/informers/generic.go index be04c7ae..a6e2d728 100644 --- a/client/informers/generic.go +++ b/client/informers/generic.go @@ -85,6 +85,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Core().V1alpha2().DomainZones().Informer()}, nil case v1alpha2.SchemeGroupVersion.WithResource("proxies"): return &genericInformer{resource: resource.GroupResource(), informer: f.Core().V1alpha2().Proxies().Informer()}, nil + case v1alpha2.SchemeGroupVersion.WithResource("tlscertificates"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Core().V1alpha2().TLSCertificates().Informer()}, nil case v1alpha2.SchemeGroupVersion.WithResource("tunnels"): return &genericInformer{resource: resource.GroupResource(), informer: f.Core().V1alpha2().Tunnels().Informer()}, nil case v1alpha2.SchemeGroupVersion.WithResource("tunnelagents"): diff --git a/client/listers/core/v1alpha2/expansion_generated.go b/client/listers/core/v1alpha2/expansion_generated.go index 413b5e45..ac053eb5 100644 --- a/client/listers/core/v1alpha2/expansion_generated.go +++ b/client/listers/core/v1alpha2/expansion_generated.go @@ -37,6 +37,10 @@ type DomainZoneListerExpansion interface{} // ProxyLister. type ProxyListerExpansion interface{} +// TLSCertificateListerExpansion allows custom methods to be added to +// TLSCertificateLister. +type TLSCertificateListerExpansion interface{} + // TunnelListerExpansion allows custom methods to be added to // TunnelLister. type TunnelListerExpansion interface{} diff --git a/client/listers/core/v1alpha2/tlscertificate.go b/client/listers/core/v1alpha2/tlscertificate.go new file mode 100644 index 00000000..b443f158 --- /dev/null +++ b/client/listers/core/v1alpha2/tlscertificate.go @@ -0,0 +1,67 @@ +/* +Copyright 2025 Apoxy, Inc. + +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. +*/ +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + v1alpha2 "github.com/apoxy-dev/apoxy/api/core/v1alpha2" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// TLSCertificateLister helps list TLSCertificates. +// All objects returned here must be treated as read-only. +type TLSCertificateLister interface { + // List lists all TLSCertificates in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha2.TLSCertificate, err error) + // Get retrieves the TLSCertificate from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha2.TLSCertificate, error) + TLSCertificateListerExpansion +} + +// tLSCertificateLister implements the TLSCertificateLister interface. +type tLSCertificateLister struct { + indexer cache.Indexer +} + +// NewTLSCertificateLister returns a new TLSCertificateLister. +func NewTLSCertificateLister(indexer cache.Indexer) TLSCertificateLister { + return &tLSCertificateLister{indexer: indexer} +} + +// List lists all TLSCertificates in the indexer. +func (s *tLSCertificateLister) List(selector labels.Selector) (ret []*v1alpha2.TLSCertificate, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha2.TLSCertificate)) + }) + return ret, err +} + +// Get retrieves the TLSCertificate from the index for a given name. +func (s *tLSCertificateLister) Get(name string) (*v1alpha2.TLSCertificate, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha2.Resource("tlscertificate"), name) + } + return obj.(*v1alpha2.TLSCertificate), nil +} diff --git a/client/versioned/typed/core/v1alpha2/core_client.go b/client/versioned/typed/core/v1alpha2/core_client.go index 85ca893b..81592cb2 100644 --- a/client/versioned/typed/core/v1alpha2/core_client.go +++ b/client/versioned/typed/core/v1alpha2/core_client.go @@ -32,6 +32,7 @@ type CoreV1alpha2Interface interface { DomainsGetter DomainZonesGetter ProxiesGetter + TLSCertificatesGetter TunnelsGetter TunnelAgentsGetter } @@ -61,6 +62,10 @@ func (c *CoreV1alpha2Client) Proxies() ProxyInterface { return newProxies(c) } +func (c *CoreV1alpha2Client) TLSCertificates() TLSCertificateInterface { + return newTLSCertificates(c) +} + func (c *CoreV1alpha2Client) Tunnels() TunnelInterface { return newTunnels(c) } diff --git a/client/versioned/typed/core/v1alpha2/fake/fake_core_client.go b/client/versioned/typed/core/v1alpha2/fake/fake_core_client.go index 8a3a61b6..717910f4 100644 --- a/client/versioned/typed/core/v1alpha2/fake/fake_core_client.go +++ b/client/versioned/typed/core/v1alpha2/fake/fake_core_client.go @@ -47,6 +47,10 @@ func (c *FakeCoreV1alpha2) Proxies() v1alpha2.ProxyInterface { return &FakeProxies{c} } +func (c *FakeCoreV1alpha2) TLSCertificates() v1alpha2.TLSCertificateInterface { + return &FakeTLSCertificates{c} +} + func (c *FakeCoreV1alpha2) Tunnels() v1alpha2.TunnelInterface { return &FakeTunnels{c} } diff --git a/client/versioned/typed/core/v1alpha2/fake/fake_tlscertificate.go b/client/versioned/typed/core/v1alpha2/fake/fake_tlscertificate.go new file mode 100644 index 00000000..fc800443 --- /dev/null +++ b/client/versioned/typed/core/v1alpha2/fake/fake_tlscertificate.go @@ -0,0 +1,131 @@ +/* +Copyright 2025 Apoxy, Inc. + +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. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha2 "github.com/apoxy-dev/apoxy/api/core/v1alpha2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeTLSCertificates implements TLSCertificateInterface +type FakeTLSCertificates struct { + Fake *FakeCoreV1alpha2 +} + +var tlscertificatesResource = v1alpha2.SchemeGroupVersion.WithResource("tlscertificates") + +var tlscertificatesKind = v1alpha2.SchemeGroupVersion.WithKind("TLSCertificate") + +// Get takes name of the tLSCertificate, and returns the corresponding tLSCertificate object, and an error if there is any. +func (c *FakeTLSCertificates) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha2.TLSCertificate, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(tlscertificatesResource, name), &v1alpha2.TLSCertificate{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.TLSCertificate), err +} + +// List takes label and field selectors, and returns the list of TLSCertificates that match those selectors. +func (c *FakeTLSCertificates) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha2.TLSCertificateList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(tlscertificatesResource, tlscertificatesKind, opts), &v1alpha2.TLSCertificateList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha2.TLSCertificateList{ListMeta: obj.(*v1alpha2.TLSCertificateList).ListMeta} + for _, item := range obj.(*v1alpha2.TLSCertificateList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested tLSCertificates. +func (c *FakeTLSCertificates) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(tlscertificatesResource, opts)) +} + +// Create takes the representation of a tLSCertificate and creates it. Returns the server's representation of the tLSCertificate, and an error, if there is any. +func (c *FakeTLSCertificates) Create(ctx context.Context, tLSCertificate *v1alpha2.TLSCertificate, opts v1.CreateOptions) (result *v1alpha2.TLSCertificate, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(tlscertificatesResource, tLSCertificate), &v1alpha2.TLSCertificate{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.TLSCertificate), err +} + +// Update takes the representation of a tLSCertificate and updates it. Returns the server's representation of the tLSCertificate, and an error, if there is any. +func (c *FakeTLSCertificates) Update(ctx context.Context, tLSCertificate *v1alpha2.TLSCertificate, opts v1.UpdateOptions) (result *v1alpha2.TLSCertificate, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(tlscertificatesResource, tLSCertificate), &v1alpha2.TLSCertificate{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.TLSCertificate), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTLSCertificates) UpdateStatus(ctx context.Context, tLSCertificate *v1alpha2.TLSCertificate, opts v1.UpdateOptions) (*v1alpha2.TLSCertificate, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(tlscertificatesResource, "status", tLSCertificate), &v1alpha2.TLSCertificate{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.TLSCertificate), err +} + +// Delete takes name of the tLSCertificate and deletes it. Returns an error if one occurs. +func (c *FakeTLSCertificates) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(tlscertificatesResource, name, opts), &v1alpha2.TLSCertificate{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTLSCertificates) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(tlscertificatesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha2.TLSCertificateList{}) + return err +} + +// Patch applies the patch and returns the patched tLSCertificate. +func (c *FakeTLSCertificates) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha2.TLSCertificate, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(tlscertificatesResource, name, pt, data, subresources...), &v1alpha2.TLSCertificate{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.TLSCertificate), err +} diff --git a/client/versioned/typed/core/v1alpha2/generated_expansion.go b/client/versioned/typed/core/v1alpha2/generated_expansion.go index ada8c3de..03eb0171 100644 --- a/client/versioned/typed/core/v1alpha2/generated_expansion.go +++ b/client/versioned/typed/core/v1alpha2/generated_expansion.go @@ -27,6 +27,8 @@ type DomainZoneExpansion interface{} type ProxyExpansion interface{} +type TLSCertificateExpansion interface{} + type TunnelExpansion interface{} type TunnelAgentExpansion interface{} diff --git a/client/versioned/typed/core/v1alpha2/tlscertificate.go b/client/versioned/typed/core/v1alpha2/tlscertificate.go new file mode 100644 index 00000000..03ec0c69 --- /dev/null +++ b/client/versioned/typed/core/v1alpha2/tlscertificate.go @@ -0,0 +1,183 @@ +/* +Copyright 2025 Apoxy, Inc. + +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. +*/ +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + "context" + "time" + + v1alpha2 "github.com/apoxy-dev/apoxy/api/core/v1alpha2" + scheme "github.com/apoxy-dev/apoxy/client/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// TLSCertificatesGetter has a method to return a TLSCertificateInterface. +// A group's client should implement this interface. +type TLSCertificatesGetter interface { + TLSCertificates() TLSCertificateInterface +} + +// TLSCertificateInterface has methods to work with TLSCertificate resources. +type TLSCertificateInterface interface { + Create(ctx context.Context, tLSCertificate *v1alpha2.TLSCertificate, opts v1.CreateOptions) (*v1alpha2.TLSCertificate, error) + Update(ctx context.Context, tLSCertificate *v1alpha2.TLSCertificate, opts v1.UpdateOptions) (*v1alpha2.TLSCertificate, error) + UpdateStatus(ctx context.Context, tLSCertificate *v1alpha2.TLSCertificate, opts v1.UpdateOptions) (*v1alpha2.TLSCertificate, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha2.TLSCertificate, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha2.TLSCertificateList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha2.TLSCertificate, err error) + TLSCertificateExpansion +} + +// tLSCertificates implements TLSCertificateInterface +type tLSCertificates struct { + client rest.Interface +} + +// newTLSCertificates returns a TLSCertificates +func newTLSCertificates(c *CoreV1alpha2Client) *tLSCertificates { + return &tLSCertificates{ + client: c.RESTClient(), + } +} + +// Get takes name of the tLSCertificate, and returns the corresponding tLSCertificate object, and an error if there is any. +func (c *tLSCertificates) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha2.TLSCertificate, err error) { + result = &v1alpha2.TLSCertificate{} + err = c.client.Get(). + Resource("tlscertificates"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of TLSCertificates that match those selectors. +func (c *tLSCertificates) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha2.TLSCertificateList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha2.TLSCertificateList{} + err = c.client.Get(). + Resource("tlscertificates"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested tLSCertificates. +func (c *tLSCertificates) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("tlscertificates"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a tLSCertificate and creates it. Returns the server's representation of the tLSCertificate, and an error, if there is any. +func (c *tLSCertificates) Create(ctx context.Context, tLSCertificate *v1alpha2.TLSCertificate, opts v1.CreateOptions) (result *v1alpha2.TLSCertificate, err error) { + result = &v1alpha2.TLSCertificate{} + err = c.client.Post(). + Resource("tlscertificates"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(tLSCertificate). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a tLSCertificate and updates it. Returns the server's representation of the tLSCertificate, and an error, if there is any. +func (c *tLSCertificates) Update(ctx context.Context, tLSCertificate *v1alpha2.TLSCertificate, opts v1.UpdateOptions) (result *v1alpha2.TLSCertificate, err error) { + result = &v1alpha2.TLSCertificate{} + err = c.client.Put(). + Resource("tlscertificates"). + Name(tLSCertificate.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(tLSCertificate). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *tLSCertificates) UpdateStatus(ctx context.Context, tLSCertificate *v1alpha2.TLSCertificate, opts v1.UpdateOptions) (result *v1alpha2.TLSCertificate, err error) { + result = &v1alpha2.TLSCertificate{} + err = c.client.Put(). + Resource("tlscertificates"). + Name(tLSCertificate.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(tLSCertificate). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the tLSCertificate and deletes it. Returns an error if one occurs. +func (c *tLSCertificates) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("tlscertificates"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *tLSCertificates) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("tlscertificates"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched tLSCertificate. +func (c *tLSCertificates) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha2.TLSCertificate, err error) { + result = &v1alpha2.TLSCertificate{} + err = c.client.Patch(pt). + Resource("tlscertificates"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/apiserver/manager.go b/pkg/apiserver/manager.go index 7d34b6f1..f76e32f6 100644 --- a/pkg/apiserver/manager.go +++ b/pkg/apiserver/manager.go @@ -334,6 +334,7 @@ func defaultResources() []resource.Object { &corev1alpha2.Domain{}, &corev1alpha2.DomainZone{}, &corev1alpha2.Proxy{}, + &corev1alpha2.TLSCertificate{}, &corev1alpha2.Tunnel{}, &corev1alpha2.TunnelAgent{},