Skip to content

Commit

Permalink
move values to vm spec/statuc
Browse files Browse the repository at this point in the history
  • Loading branch information
conradludgate committed Feb 13, 2025
1 parent 0a95ee6 commit 8b3d229
Show file tree
Hide file tree
Showing 10 changed files with 70 additions and 55 deletions.
3 changes: 0 additions & 3 deletions neonvm-controller/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,6 @@ func main() {
FailingRefreshInterval: failingRefreshInterval,
AtMostOnePod: atMostOnePod,
DefaultCPUScalingMode: defaultCpuScalingMode,
CertificateIssuer: "neon-ca-issuer",
CertificateDuration: 86400 * time.Second,
CertificateRenewal: 3600 * time.Second,
}

vmReconciler := &controllers.VMReconciler{
Expand Down
2 changes: 1 addition & 1 deletion neonvm-runner/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@ func monitorFiles(ctx context.Context, logger *zap.Logger, wg *sync.WaitGroup, v
}
}

if vmSpec.EnableTLS != nil && *vmSpec.EnableTLS {
if vmSpec.TlsCertificateIssuer != nil {
secrets["/vm/mounts/var/tls/..data"] = "/var/tls"
secretsOrd = append(secretsOrd, "/vm/mounts/var/tls/..data")
}
Expand Down
18 changes: 14 additions & 4 deletions neonvm/apis/neonvm/v1/virtualmachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,19 @@ type VirtualMachineSpec struct {
// +optional
EnableSSH *bool `json:"enableSSH,omitempty"`

// Enable TLS on the VM. It works only if the VM image is built using VM Builder that
// has TLS support (TODO: mention VM Builder version).
// +kubebuilder:default:=true
// The CertificateIssuer for the certificates issued to this VM
// +optional
TlsCertificateIssuer *string `json:"tlsCertificateIssuer,omitempty"`

// If a TlsCertificateIssuer is provided, this is required to set the duration that the certificate should
// be valid for before expiring
// +optional
EnableTLS *bool `json:"enableTLS,omitempty"`
TLSExpiration *metav1.Duration `json:"tlsExpiration,omitempty"`

// If a TlsCertificateIssuer is provided, this is required to set the duration before certificate expiration
// that the certificate is renewed
// +optional
TLSRenewal *metav1.Duration `json:"tlsRenewal,omitempty"`

// TargetRevision is the identifier set by external party to track when changes to the spec
// propagate to the VM.
Expand Down Expand Up @@ -609,6 +617,8 @@ type VirtualMachineStatus struct {
SSHSecretName string `json:"sshSecretName,omitempty"`
// +optional
TLSSecretName string `json:"tlsSecretName,omitempty"`
// +optional
TLSRenewal metav1.Time `json:"tlsRenewal,omitempty"`

// CurrentRevision is updated with Spec.TargetRevision's value once
// the changes are propagated to the VM.
Expand Down
17 changes: 14 additions & 3 deletions neonvm/apis/neonvm/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 17 additions & 6 deletions neonvm/config/crd/bases/vm.neon.tech_virtualmachines.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1219,12 +1219,6 @@ spec:
Enable SSH on the VM. It works only if the VM image is built using VM Builder that
has SSH support (TODO: mention VM Builder version).
type: boolean
enableTLS:
default: true
description: |-
Enable TLS on the VM. It works only if the VM image is built using VM Builder that
has TLS support (TODO: mention VM Builder version).
type: boolean
extraInitContainers:
description: Running init containers is costly, so InitScript field
should be preferred over ExtraInitContainers
Expand Down Expand Up @@ -3006,6 +3000,20 @@ spec:
default: 5
format: int64
type: integer
tlsCertificateIssuer:
description: The CertificateIssuer for the certificates issued to
this VM
type: string
tlsExpiration:
description: |-
If a TlsCertificateIssuer is provided, this is required to set the duration that the certificate should
be valid for before expiring
type: string
tlsRenewal:
description: |-
If a TlsCertificateIssuer is provided, this is required to set the duration before certificate expiration
that the certificate is renewed
type: string
tolerations:
items:
description: |-
Expand Down Expand Up @@ -3192,6 +3200,9 @@ spec:
type: integer
sshSecretName:
type: string
tlsRenewal:
format: date-time
type: string
tlsSecretName:
type: string
type: object
Expand Down
9 changes: 0 additions & 9 deletions pkg/neonvm/controllers/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,4 @@ type ReconcilerConfig struct {
AtMostOnePod bool
// DefaultCPUScalingMode is the default CPU scaling mode that will be used for VMs with empty spec.cpuScalingMode
DefaultCPUScalingMode vmv1.CpuScalingMode

// The name of the ClusterIssuer that will issue TLS certificates for the VM.
CertificateIssuer string

// Duration that certificates are valid for
CertificateDuration time.Duration

// How long before expiration should certificates be renewed.
CertificateRenewal time.Duration
}
3 changes: 0 additions & 3 deletions pkg/neonvm/controllers/functests/vm_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,6 @@ var _ = Describe("VirtualMachine controller", func() {
FailingRefreshInterval: 1 * time.Minute,
AtMostOnePod: false,
DefaultCPUScalingMode: vmv1.CpuScalingModeQMP,
CertificateIssuer: "neon-ca-issuer",
CertificateDuration: 86400 * time.Second,
CertificateRenewal: 3600 * time.Second,
},
}

Expand Down
44 changes: 21 additions & 23 deletions pkg/neonvm/controllers/vm_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,8 +407,7 @@ func (r *VMReconciler) doReconcile(ctx context.Context, vm *vmv1.VirtualMachine)
return errors.New("DIMMSlots memory provider is deprecated and disabled")
}

// NB: .Spec.EnableSSH guaranteed non-nil because the k8s API server sets the default for us.
enableTLS := *vm.Spec.EnableTLS
enableTLS := vm.Spec.TlsCertificateIssuer != nil

certSecret := &corev1.Secret{}

Expand All @@ -431,16 +430,9 @@ func (r *VMReconciler) doReconcile(ctx context.Context, vm *vmv1.VirtualMachine)
log.Error(err, "Failed to get vm-runner certificate Secret")
return err
} else {
// parse the certificate and see if it's close to expiration.
certs, err := pki.DecodeX509CertificateChainBytes(certSecret.Data[corev1.TLSCertKey])
if err != nil {
log.Error(err, "Failed to parse VM certificate")
return err
}

// if the certificate is close to expiry, update it
if time.Now().Add(r.Config.CertificateRenewal).After(certs[0].NotAfter) {
msg := fmt.Sprintf("VirtualMachine %s certificate secret %s close to expiration %v", vm.Name, vm.Status.TLSSecretName, certs[0].NotAfter)
if time.Now().After(vm.Status.TLSRenewal.Time) {
msg := fmt.Sprintf("VirtualMachine %s certificate secret %s is due for renewal", vm.Name, vm.Status.TLSSecretName)
r.Recorder.Event(vm, "Normal", "SigningCertificate", msg)
certSecret, err = r.doReconcileCertificateSecret(ctx, vm, certSecret)
if err != nil {
Expand Down Expand Up @@ -926,9 +918,9 @@ func (r *VMReconciler) doReconcileCertificateSecret(ctx context.Context, vm *vmv
}

if len(certificateReq.Status.Certificate) != 0 {
// we have a certificate and the corresponding private key
// create/update the proper certificate secret and delete the tmp secret
if certSecret == nil {
// we have a certificate and the corresponding private key
// create the proper certificate secret and delete the tmp secret
certSecret, err = r.certSecretForVirtualMachine(vm, key, certificateReq.Status.Certificate)
if err != nil {
log.Error(err, "Failed to define new certificate Secret resource for VirtualMachine")
Expand Down Expand Up @@ -961,6 +953,14 @@ func (r *VMReconciler) doReconcileCertificateSecret(ctx context.Context, vm *vmv
r.Recorder.Event(vm, "Normal", "Updated", msg)
}

// parse the certificate for the expiration time.
certs, err := pki.DecodeX509CertificateChainBytes(certSecret.Data[corev1.TLSCertKey])
if err != nil {
log.Error(err, "Failed to parse VM certificate")
return nil, err
}
vm.Status.TLSRenewal.Time = certs[0].NotAfter.Add(-vm.Spec.TLSRenewal.Duration)

err = r.Delete(ctx, tmpKeySecret)
if err != nil {
log.Info("Virtual Machine temporary certificate secret could not be deleted", "Secret.Namespace", tmpKeySecret.Namespace, "Secret.Name", tmpKeySecret.Name)
Expand Down Expand Up @@ -1329,7 +1329,7 @@ func (r *VMReconciler) certReqForVirtualMachine(
vm *vmv1.VirtualMachine,
key crypto.Signer,
) (*certv1.CertificateRequest, error) {
cert, err := certReqSpec(vm, r.Config, key)
cert, err := certReqSpec(vm, key)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -1844,7 +1844,7 @@ func podSpec(
}
}

if vm.Spec.EnableTLS != nil && *vm.Spec.EnableTLS {
if vm.Spec.TlsCertificateIssuer != nil {
// Add TLS secret
mnt := corev1.VolumeMount{
Name: "tls",
Expand Down Expand Up @@ -1885,7 +1885,6 @@ func podSpec(

func certSpec(
vm *vmv1.VirtualMachine,
config *ReconcilerConfig,
) *certv1.Certificate {
runnerVersion := api.RunnerProtoV1
labels := labelsForVirtualMachine(vm, &runnerVersion)
Expand All @@ -1894,7 +1893,7 @@ func certSpec(
commonName := fmt.Sprintf("%s.%s.svc.cluster.local", vm.Name, vm.Namespace)

issuer := cmmeta.ObjectReference{
Name: config.CertificateIssuer,
Name: *vm.Spec.TlsCertificateIssuer,
Kind: "ClusterIssuer",
Group: certmanager.GroupName,
}
Expand All @@ -1913,8 +1912,8 @@ func certSpec(
},
Usages: certv1.DefaultKeyUsages(),
IsCA: false,
Duration: &metav1.Duration{Duration: config.CertificateDuration},
RenewBefore: &metav1.Duration{Duration: config.CertificateRenewal},
Duration: &metav1.Duration{Duration: vm.Spec.TLSExpiration.Duration},
RenewBefore: &metav1.Duration{Duration: vm.Spec.TLSRenewal.Duration},
SecretTemplate: &certv1.CertificateSecretTemplate{
Labels: labels,
Annotations: annotations,
Expand Down Expand Up @@ -1991,20 +1990,19 @@ func certSecretSpec(

func certReqSpec(
vm *vmv1.VirtualMachine,
config *ReconcilerConfig,
key crypto.Signer,
) (*certv1.CertificateRequest, error) {
runnerVersion := api.RunnerProtoV1
labels := labelsForVirtualMachine(vm, &runnerVersion)
annotations := annotationsForVirtualMachine(vm)

issuer := cmmeta.ObjectReference{
Name: config.CertificateIssuer,
Name: *vm.Spec.TlsCertificateIssuer,
Kind: "ClusterIssuer",
Group: certmanager.GroupName,
}

cr, err := pki.GenerateCSR(certSpec(vm, config))
cr, err := pki.GenerateCSR(certSpec(vm))
if err != nil {
return nil, err
}
Expand All @@ -2021,7 +2019,7 @@ func certReqSpec(
}

certSpec := certv1.CertificateRequestSpec{
Duration: &metav1.Duration{Duration: config.CertificateDuration},
Duration: &metav1.Duration{Duration: vm.Spec.TLSExpiration.Duration},
IssuerRef: issuer,
Request: csrPEM.Bytes(),
IsCA: false,
Expand Down
3 changes: 0 additions & 3 deletions pkg/neonvm/controllers/vm_controller_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,6 @@ func newTestParams(t *testing.T) *testParams {
FailingRefreshInterval: time.Minute,
AtMostOnePod: false,
DefaultCPUScalingMode: vmv1.CpuScalingModeQMP,
CertificateIssuer: "neon-ca-issuer",
CertificateDuration: 86400 * time.Second,
CertificateRenewal: 3600 * time.Second,
},
Metrics: reconcilerMetrics,
}
Expand Down
3 changes: 3 additions & 0 deletions vm-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ spec:
schedulerName: autoscale-scheduler
enableNetworkMonitoring: true
enableSSH: true
tlsCertificateIssuer: "neon-ca-issuer"
tlsExpiration: 5m
tlsRenewal: 3m
guest:
cpus: { min: 0.25, use: 0.25, max: 1.25 }
memorySlotSize: 1Gi
Expand Down

0 comments on commit 8b3d229

Please sign in to comment.