Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(reports): configure TLS for reports service #365

Merged
merged 3 commits into from
Apr 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion internal/controllers/certmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,23 @@ func (r *CryostatReconciler) setupTLS(ctx context.Context, cr *operatorv1beta1.C
return nil, err
}

// Create a certificate for the reports generator signed by the Cryostat CA
reportsCert := resources.NewReportsCert(cr)
err = r.createOrUpdateCertificate(ctx, reportsCert, cr)
if err != nil {
return nil, err
}

// Update owner references of TLS secrets created by cert-manager to ensure proper cleanup
err = r.setCertSecretOwner(ctx, cr, caCert, cryostatCert, grafanaCert)
err = r.setCertSecretOwner(ctx, cr, caCert, cryostatCert, grafanaCert, reportsCert)
if err != nil {
return nil, err
}

return &resources.TLSConfig{
CryostatSecret: cryostatCert.Spec.SecretName,
GrafanaSecret: grafanaCert.Spec.SecretName,
ReportsSecret: reportsCert.Spec.SecretName,
KeystorePassSecret: cryostatCert.Spec.Keystores.PKCS12.PasswordSecretRef.Name,
}, nil
}
Expand Down
24 changes: 24 additions & 0 deletions internal/controllers/common/resource_definitions/certificates.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,27 @@ func NewGrafanaCert(cr *operatorv1beta1.Cryostat) *certv1.Certificate {
},
}
}

func NewReportsCert(cr *operatorv1beta1.Cryostat) *certv1.Certificate {
return &certv1.Certificate{
ObjectMeta: metav1.ObjectMeta{
Name: cr.Name + "-reports",
Namespace: cr.Namespace,
},
Spec: certv1.CertificateSpec{
CommonName: fmt.Sprintf("%s-reports.%s.svc", cr.Name, cr.Namespace),
DNSNames: []string{
cr.Name + "-reports",
fmt.Sprintf("%s-reports.%s.svc", cr.Name, cr.Namespace),
fmt.Sprintf("%s-reports.%s.svc.cluster.local", cr.Name, cr.Namespace),
},
SecretName: cr.Name + "-reports-tls",
IssuerRef: certMeta.ObjectReference{
Name: cr.Name + "-ca",
},
Usages: append(certv1.DefaultKeyUsages(),
certv1.UsageServerAuth,
),
},
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ type TLSConfig struct {
CryostatSecret string
// Name of the TLS secret for Grafana
GrafanaSecret string
// Name of the TLS secret for Reports Generator
ReportsSecret string
// Name of the secret containing the password for the keystore in CryostatSecret
KeystorePassSecret string
}
Expand Down Expand Up @@ -175,7 +177,7 @@ func NewDeploymentForCR(cr *operatorv1beta1.Cryostat, specs *ServiceSpecs, image
}
}

func NewDeploymentForReports(cr *operatorv1beta1.Cryostat, imageTags *ImageTags) *appsv1.Deployment {
func NewDeploymentForReports(cr *operatorv1beta1.Cryostat, imageTags *ImageTags, tls *TLSConfig) *appsv1.Deployment {
if cr.Spec.ReportOptions == nil {
cr.Spec.ReportOptions = &operatorv1beta1.ReportConfiguration{Replicas: 0}
}
Expand Down Expand Up @@ -212,7 +214,7 @@ func NewDeploymentForReports(cr *operatorv1beta1.Cryostat, imageTags *ImageTags)
"component": "reports",
},
},
Spec: *NewPodForReports(cr, imageTags),
Spec: *NewPodForReports(cr, imageTags, tls),
},
Replicas: &replicas,
},
Expand Down Expand Up @@ -369,7 +371,7 @@ func NewPodForCR(cr *operatorv1beta1.Cryostat, specs *ServiceSpecs, imageTags *I
}
}

func NewPodForReports(cr *operatorv1beta1.Cryostat, imageTags *ImageTags) *corev1.PodSpec {
func NewPodForReports(cr *operatorv1beta1.Cryostat, imageTags *ImageTags, tls *TLSConfig) *corev1.PodSpec {
resources := corev1.ResourceRequirements{}
if cr.Spec.ReportOptions != nil {
resources = cr.Spec.ReportOptions.Resources
Expand All @@ -387,10 +389,75 @@ func NewPodForReports(cr *operatorv1beta1.Cryostat, imageTags *ImageTags) *corev
}
javaOpts := fmt.Sprintf("-XX:+PrintCommandLineFlags -XX:ActiveProcessorCount=%d -Dorg.openjdk.jmc.flightrecorder.parser.singlethreaded=%t", cpus, cpus < 2)

envs := []corev1.EnvVar{
{
Name: "QUARKUS_HTTP_HOST",
Value: "0.0.0.0",
},
{
Name: "JAVA_OPTIONS",
Value: javaOpts,
},
}
mounts := []corev1.VolumeMount{}
volumes := []corev1.Volume{}

// Configure TLS key/cert if enabled
livenessProbeScheme := corev1.URISchemeHTTP
if tls != nil {
tlsEnvs := []corev1.EnvVar{
{
Name: "QUARKUS_HTTP_SSL_PORT",
Value: strconv.Itoa(int(reportsContainerPort)),
},
{
Name: "QUARKUS_HTTP_SSL_CERTIFICATE_KEY_FILE",
Value: fmt.Sprintf("/var/run/secrets/operator.cryostat.io/%s/%s", tls.ReportsSecret, corev1.TLSPrivateKeyKey),
},
{
Name: "QUARKUS_HTTP_SSL_CERTIFICATE_FILE",
Value: fmt.Sprintf("/var/run/secrets/operator.cryostat.io/%s/%s", tls.ReportsSecret, corev1.TLSCertKey),
},
{
Name: "QUARKUS_HTTP_INSECURE_REQUESTS",
Value: "disabled",
},
}

tlsSecretMount := corev1.VolumeMount{
Name: "reports-tls-secret",
MountPath: "/var/run/secrets/operator.cryostat.io/" + tls.ReportsSecret,
ReadOnly: true,
}

secretVolume := corev1.Volume{
Name: "reports-tls-secret",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: tls.ReportsSecret,
},
},
}

envs = append(envs, tlsEnvs...)
mounts = append(mounts, tlsSecretMount)
volumes = append(volumes, secretVolume)

// Use HTTPS for liveness probe
livenessProbeScheme = corev1.URISchemeHTTPS

} else {
envs = append(envs, corev1.EnvVar{
Name: "QUARKUS_HTTP_PORT",
Value: strconv.Itoa(int(reportsContainerPort)),
})
}

probeHandler := corev1.Handler{
HTTPGet: &corev1.HTTPGetAction{
Port: intstr.IntOrString{IntVal: reportsContainerPort},
Path: "/health",
Scheme: livenessProbeScheme,
Port: intstr.IntOrString{IntVal: reportsContainerPort},
Path: "/health",
},
}
return &corev1.PodSpec{
Expand All @@ -405,21 +472,9 @@ func NewPodForReports(cr *operatorv1beta1.Cryostat, imageTags *ImageTags) *corev
ContainerPort: reportsContainerPort,
},
},
Env: []corev1.EnvVar{
{
Name: "QUARKUS_HTTP_HOST",
Value: "0.0.0.0",
},
{
Name: "QUARKUS_HTTP_PORT",
Value: strconv.Itoa(int(reportsContainerPort)),
},
{
Name: "JAVA_OPTIONS",
Value: javaOpts,
},
},
Resources: resources,
Env: envs,
VolumeMounts: mounts,
Resources: resources,
LivenessProbe: &corev1.Probe{
Handler: probeHandler,
},
Expand All @@ -428,6 +483,7 @@ func NewPodForReports(cr *operatorv1beta1.Cryostat, imageTags *ImageTags) *corev
},
},
},
Volumes: volumes,
}
}

Expand Down
15 changes: 10 additions & 5 deletions internal/controllers/cryostat_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ func (r *CryostatReconciler) Reconcile(ctx context.Context, request ctrl.Request
return reconcile.Result{}, err
}

reportsResult, err := r.reconcileReports(ctx, reqLogger, instance, routeTLS, imageTags, serviceSpecs)
reportsResult, err := r.reconcileReports(ctx, reqLogger, instance, tlsConfig, imageTags, serviceSpecs)
if err != nil {
return reportsResult, err
}
Expand Down Expand Up @@ -453,15 +453,15 @@ func (r *CryostatReconciler) SetupWithManager(mgr ctrl.Manager) error {
}

func (r *CryostatReconciler) reconcileReports(ctx context.Context, reqLogger logr.Logger, instance *operatorv1beta1.Cryostat,
routeTLS *openshiftv1.TLSConfig, imageTags *resources.ImageTags, serviceSpecs *resources.ServiceSpecs) (reconcile.Result, error) {
tls *resources.TLSConfig, imageTags *resources.ImageTags, serviceSpecs *resources.ServiceSpecs) (reconcile.Result, error) {
reqLogger.Info("Spec", "Reports", instance.Spec.ReportOptions)

if instance.Spec.ReportOptions == nil {
instance.Spec.ReportOptions = &operatorv1beta1.ReportConfiguration{Replicas: 0}
}
desired := instance.Spec.ReportOptions.Replicas

deployment := resources.NewDeploymentForReports(instance, imageTags)
deployment := resources.NewDeploymentForReports(instance, imageTags, tls)
if desired == 0 {
svc := resources.NewReportService(instance)
if err := r.Client.Delete(ctx, svc); err != nil && !errors.IsNotFound(err) {
Expand Down Expand Up @@ -503,9 +503,14 @@ func (r *CryostatReconciler) reconcileReports(ctx context.Context, reqLogger log
if err != nil {
return reconcile.Result{}, err
}

scheme := "https"
if tls == nil {
scheme = "http"
}
serviceSpecs.ReportsURL = &url.URL{
Scheme: "http",
Host: deployment.ObjectMeta.Name + ":" + strconv.Itoa(int(svc.Spec.Ports[0].Port)),
Scheme: scheme,
Host: svc.Name + ":" + strconv.Itoa(int(svc.Spec.Ports[0].Port)),
}
reqLogger.Info(fmt.Sprintf("Reports Deployment %s", op))

Expand Down
Loading