Skip to content

Commit

Permalink
routes - move all routes from <service>.<fqdn> to <fqdn>/<service>
Browse files Browse the repository at this point in the history
- zuul: https://<fqdn>/zuul
- nodepool: https://<fqdn>/nodepool/(builds|api)
- logserver: https://<fqdn>/logs

Extra Routes from Prometheus and Gerrit still use <service>.<fqdn>.

This change also updates:

- static certificate management
- LE certificate management

Change-Id: I228d1d124ccbc8350ca6b23ae907f81d6c1aba6e
  • Loading branch information
morucci committed Dec 15, 2023
1 parent 1898d1a commit 0b1bb42
Show file tree
Hide file tree
Showing 38 changed files with 152 additions and 184 deletions.
2 changes: 1 addition & 1 deletion api/v1/logserver_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

// LogServerSpec defines the desired state of LogServer
type LogServerSpec struct {
// The fully qualified domain name to use with the log server. Logs will be served at https://logserver.`FQDN`
// The fully qualified domain name to use with the log server. Logs will be served at https://`FQDN`/logs
FQDN string `json:"fqdn"`
// LetsEncrypt settings for enabling using LetsEncrypt for Routes/TLS
LetsEncrypt *LetsEncryptSpec `json:"LetsEncrypt,omitempty"`
Expand Down
4 changes: 2 additions & 2 deletions cli/sfconfig/cmd/gerrit/gerrit.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@ func (g *GerritCMDContext) ensureGerritSTS() {

func (g *GerritCMDContext) ensureGerritIngresses() {
name := "gerrit"
route := base.MkHTTPSRoute(name, g.env.Ns, name,
gerritHTTPDPortName, "/", gerritHTTPDPort, map[string]string{}, g.fqdn, nil)
route := base.MkHTTPSRoute(name, g.env.Ns, name+"."+g.fqdn,
gerritHTTPDPortName, "/", gerritHTTPDPort, map[string]string{}, nil)
g.ensureRoute(name, route)
}

Expand Down
2 changes: 1 addition & 1 deletion cli/sfconfig/cmd/sfprometheus/sfprometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ func EnsurePrometheusService(env *utils.ENV) {

func (p *PromCMDContext) EnsurePrometheusRoute() {
route := base.MkHTTPSRoute(
prometheusName, p.env.Ns, prometheusName, prometheusName, "/", prometheusPort, map[string]string{}, p.fqdn, nil)
prometheusName, p.env.Ns, prometheusName+"."+p.fqdn, prometheusName, "/", prometheusPort, map[string]string{}, nil)
err := p.env.Cli.Get(p.env.Ctx, client.ObjectKey{
Name: prometheusName,
Namespace: p.env.Ns,
Expand Down
17 changes: 6 additions & 11 deletions cli/sfconfig/cmd/ssl/create_ssl_cert.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@ import (
)

func ensureSSLSecret(env *utils.ENV, serviceCAContent []byte,
serviceCertContent []byte, serviceKeyContent []byte, serviceName string,
) {
serviceCertContent []byte, serviceKeyContent []byte) {
var secret apiv1.Secret
secretName := sf.GetCustomRouteSSLSecretName(serviceName)
secretName := sf.CustomSSLSecretName
data := map[string][]byte{
"CA": serviceCAContent,
"crt": serviceCertContent,
Expand Down Expand Up @@ -89,7 +88,7 @@ func verifySSLCert(serviceCAContent []byte, serviceCertContent []byte,
}

func CreateServiceCertSecret(sfEnv *utils.ENV, sfNamespace string,
serviceName string, sfServiceCA string, sfServiceCert string,
sfServiceCA string, sfServiceCert string,
sfServiceKey string, serverName string,
) {
kubernetesEnv := utils.ENV{Cli: sfEnv.Cli, Ctx: sfEnv.Ctx, Ns: sfNamespace}
Expand Down Expand Up @@ -117,7 +116,7 @@ func CreateServiceCertSecret(sfEnv *utils.ENV, sfNamespace string,
}

ensureSSLSecret(&kubernetesEnv, serviceCAContent, serviceCertContent,
serviceKeyContent, serviceName)
serviceKeyContent)

}

Expand All @@ -129,7 +128,6 @@ var CreateCertificateCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
sfNamespace, _ := cmd.Flags().GetString("sf-namespace")
sfContext, _ := cmd.Flags().GetString("sf-context")
serviceName, _ := cmd.Flags().GetString("sf-service-name")
sfServiceCA, _ := cmd.Flags().GetString("sf-service-ca")
sfServiceCert, _ := cmd.Flags().GetString("sf-service-cert")
sfServiceKey, _ := cmd.Flags().GetString("sf-service-key")
Expand All @@ -139,9 +137,8 @@ var CreateCertificateCmd = &cobra.Command{
Ns: sfNamespace,
}
conf := config.GetSFConfigOrDie()
serverName := serviceName + "." + conf.FQDN
CreateServiceCertSecret(&sfEnv, sfNamespace, serviceName, sfServiceCA,
sfServiceCert, sfServiceKey, serverName)
CreateServiceCertSecret(&sfEnv, sfNamespace, sfServiceCA,
sfServiceCert, sfServiceKey, conf.FQDN)

},
}
Expand All @@ -151,8 +148,6 @@ func init() {
"Name of the namespace to copy the kubeconfig, or '-' for stdout")
CreateCertificateCmd.Flags().StringP("sf-context", "", "",
"The kubeconfig context of the sf-namespace, use the default context by default")
CreateCertificateCmd.Flags().StringP("sf-service-name", "", "",
"The SF service name for the SSL cert like Zuul, Gerrit, Logserver etc.")
CreateCertificateCmd.Flags().StringP("sf-service-ca", "", "",
"Path for the service CA certificate")
CreateCertificateCmd.Flags().StringP("sf-service-cert", "", "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ spec:
type: string
fqdn:
description: The fully qualified domain name to use with the log server.
Logs will be served at https://logserver.`FQDN`
Logs will be served at https://`FQDN`/logs
type: string
settings:
description: General runtime settings for the log server
Expand Down
4 changes: 2 additions & 2 deletions controllers/libs/base/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ func MkHeadlessServicePod(name string, ns string, podName string, ports []int32,
// MkHTTPSRoute produces a Route on top of a Service
func MkHTTPSRoute(
name string, ns string, host string, serviceName string, path string,
port int, annotations map[string]string, fqdn string, customTLS *apiroutev1.TLSConfig) apiroutev1.Route {
port int, annotations map[string]string, customTLS *apiroutev1.TLSConfig) apiroutev1.Route {
tls := apiroutev1.TLSConfig{
InsecureEdgeTerminationPolicy: apiroutev1.InsecureEdgeTerminationPolicyRedirect,
Termination: apiroutev1.TLSTerminationEdge,
Expand All @@ -289,7 +289,7 @@ func MkHTTPSRoute(
},
Spec: apiroutev1.RouteSpec{
TLS: &tls,
Host: host + "." + fqdn,
Host: host,
To: apiroutev1.RouteTargetReference{
Kind: "Service",
Name: serviceName,
Expand Down
6 changes: 4 additions & 2 deletions controllers/logserver_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,10 @@ func (r *LogServerController) DeployLogserver() sfv1.LogServerStatus {
pvcReadiness := r.reconcileExpandPVC(logserverIdent+"-"+logserverIdent+"-0", r.cr.Spec.Settings.Storage)

routeReady := r.ensureHTTPSRoute(
r.cr.Name+"-logserver", logserverIdent,
logserverIdent, "/", httpdPort, map[string]string{}, r.cr.Spec.FQDN, r.cr.Spec.LetsEncrypt)
r.cr.Name+"-logserver", r.cr.Spec.FQDN,
logserverIdent, "/logs/", httpdPort, map[string]string{
"haproxy.router.openshift.io/rewrite-target": "/",
}, r.cr.Spec.LetsEncrypt)

// TODO(mhu) We may want to open an ingress to port 9100 for an external prometheus instance.
// TODO(mhu) we may want to include monitoring objects' status in readiness computation
Expand Down
12 changes: 8 additions & 4 deletions controllers/nodepool.go
Original file line number Diff line number Diff line change
Expand Up @@ -603,8 +603,10 @@ func (r *SFController) DeployNodepoolBuilder(statsdExporterVolume apiv1.Volume,

pvcReadiness := r.reconcileExpandPVC(builderIdent+"-"+builderIdent+"-0", r.cr.Spec.Nodepool.Builder.Storage)

routeReady := r.ensureHTTPSRoute(r.cr.Name+"-nodepool-builder", "nodepool", builderIdent, "/builds",
buildLogsHttpdPort, map[string]string{}, r.cr.Spec.FQDN, r.cr.Spec.LetsEncrypt)
routeReady := r.ensureHTTPSRoute(r.cr.Name+"-nodepool-builder", r.cr.Spec.FQDN, builderIdent, "/nodepool/builds",
buildLogsHttpdPort, map[string]string{
"haproxy.router.openshift.io/rewrite-target": "/builds/",
}, r.cr.Spec.LetsEncrypt)

var isReady = r.IsStatefulSetReady(current) && routeReady && pvcReadiness

Expand Down Expand Up @@ -733,8 +735,10 @@ func (r *SFController) DeployNodepoolLauncher(statsdExporterVolume apiv1.Volume,
srv := base.MkService(launcherIdent, r.ns, launcherIdent, []int32{launcherPort}, launcherIdent)
r.GetOrCreate(&srv)

routeReady := r.ensureHTTPSRoute(r.cr.Name+"-nodepool-launcher", "nodepool", launcherIdent, "/",
launcherPort, map[string]string{}, r.cr.Spec.FQDN, r.cr.Spec.LetsEncrypt)
routeReady := r.ensureHTTPSRoute(r.cr.Name+"-nodepool-launcher", r.cr.Spec.FQDN, launcherIdent, "/nodepool/api",
launcherPort, map[string]string{
"haproxy.router.openshift.io/rewrite-target": "/",
}, r.cr.Spec.LetsEncrypt)

isDeploymentReady := r.IsDeploymentReady(&current)
conds.UpdateConditions(&r.cr.Status.Conditions, launcherIdent, isDeploymentReady)
Expand Down
15 changes: 10 additions & 5 deletions controllers/softwarefactory_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

apiroutev1 "github.com/openshift/api/route/v1"
sfv1 "github.com/softwarefactory-project/sf-operator/api/v1"
"github.com/softwarefactory-project/sf-operator/controllers/libs/conds"
sfmonitoring "github.com/softwarefactory-project/sf-operator/controllers/libs/monitoring"
Expand Down Expand Up @@ -147,6 +148,14 @@ func (r *SFController) cleanup() {
if r.GetM("zuul-monitor", &currentZPM) {
r.DeleteR(&currentZPM)
}

// remove a legacy Route definition for Zuul
r.DeleteR(&apiroutev1.Route{
ObjectMeta: metav1.ObjectMeta{
Namespace: r.ns,
Name: r.cr.Spec.FQDN + "-zuul-red",
},
})
}

func (r *SFController) Step() sfv1.SoftwareFactoryStatus {
Expand Down Expand Up @@ -383,11 +392,7 @@ func (r *SoftwareFactoryReconciler) SetupWithManager(mgr ctrl.Manager) error {
switch updatedResourceName := a.GetName(); updatedResourceName {
case NodepoolProvidersSecretsName:
return req
case GetCustomRouteSSLSecretName("logserver"):
return req
case GetCustomRouteSSLSecretName("nodepool"):
return req
case GetCustomRouteSSLSecretName("zuul"):
case CustomSSLSecretName:
return req
default:
// Discover secrets for github and gitlab connections
Expand Down
4 changes: 2 additions & 2 deletions controllers/static/git-server/update-system-config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ cat << EOF > playbooks/base/pre.yaml
- import_role:
name: log-inventory
vars:
zuul_log_url: "https://logserver.${FQDN}/"
zuul_log_url: "https://${FQDN}/logs"
- hosts: all
tasks:
Expand Down Expand Up @@ -83,7 +83,7 @@ cat << EOF > playbooks/base/post.yaml
name: buildset-artifacts-location
vars:
zuul_log_compress: true
zuul_log_url: "https://logserver.${FQDN}/"
zuul_log_url: "https://${FQDN}/logs"
zuul_logserver_root: "{{ site_sflogs.path }}"
zuul_log_verbose: true
EOF
Expand Down
43 changes: 21 additions & 22 deletions controllers/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ import (
sfv1 "github.com/softwarefactory-project/sf-operator/api/v1"
)

const BusyboxImage = "quay.io/software-factory/sf-op-busybox:1.5-3"
const (
BusyboxImage = "quay.io/software-factory/sf-op-busybox:1.5-3"
CustomSSLSecretName = "sf-ssl-cert"
)

// HTTPDImage uses pinned/ubi8 based image for httpd
// https://catalog.redhat.com/software/containers/ubi8/httpd-24/6065b844aee24f523c207943?q=httpd&architecture=amd64&image=651f274c8ce9242f7bb3e011
Expand Down Expand Up @@ -325,19 +328,19 @@ func (r *SFUtilContext) ensureRoute(route apiroutev1.Route, name string) bool {
// the route setting changed.
func (r *SFUtilContext) ensureHTTPSRoute(
name string, host string, serviceName string, path string,
port int, annotations map[string]string, fqdn string, le *sfv1.LetsEncryptSpec) bool {
port int, annotations map[string]string, le *sfv1.LetsEncryptSpec) bool {

tlsDataReady := true
var sslCA, sslCrt, sslKey []byte

if le == nil {
// Letsencrypt config has not been set so we check the `customSSLSecretName` Secret
// for any custom TLS data to setup the Route
sslCA, sslCrt, sslKey = r.extractStaticTLSFromSecret(name, host)
sslCA, sslCrt, sslKey = r.extractStaticTLSFromSecret()
} else {
// Letsencrypt config has been set so we ensure we set a Certificate via the
// cert-manager Issuer and then we'll setup the Route based on the Certificate's Secret
tlsDataReady, sslCA, sslCrt, sslKey = r.extractTLSFromLECertificateSecret(name, host, fqdn, *le)
tlsDataReady, sslCA, sslCrt, sslKey = r.extractTLSFromLECertificateSecret(host, *le)
}

if !tlsDataReady {
Expand All @@ -356,9 +359,9 @@ func (r *SFUtilContext) ensureHTTPSRoute(
Key: string(sslKey),
CACertificate: string(sslCA),
}
route = base.MkHTTPSRoute(name, r.ns, host, serviceName, path, port, annotations, fqdn, &tls)
route = base.MkHTTPSRoute(name, r.ns, host, serviceName, path, port, annotations, &tls)
} else {
route = base.MkHTTPSRoute(name, r.ns, host, serviceName, path, port, annotations, fqdn, nil)
route = base.MkHTTPSRoute(name, r.ns, host, serviceName, path, port, annotations, nil)
}
return r.ensureRoute(route, name)
}
Expand Down Expand Up @@ -494,39 +497,35 @@ func (r *SFUtilContext) DebugStatefulSet(name string) {
r.log.V(1).Info("Debugging service", "name", name)
}

func GetCustomRouteSSLSecretName(host string) string {
return host + "-ssl-cert"
}

func (r *SFUtilContext) extractStaticTLSFromSecret(name string, host string) ([]byte, []byte, []byte) {
func (r *SFUtilContext) extractStaticTLSFromSecret() ([]byte, []byte, []byte) {
var customSSLSecret apiv1.Secret
customSSLSecretName := GetCustomRouteSSLSecretName(host)

if !r.GetM(customSSLSecretName, &customSSLSecret) {
if !r.GetM(CustomSSLSecretName, &customSSLSecret) {
return nil, nil, nil
} else {
// Fetching secret expected TLS Keys content
return customSSLSecret.Data["CA"], customSSLSecret.Data["crt"], customSSLSecret.Data["key"]
}
}

func (r *SFUtilContext) extractTLSFromLECertificateSecret(name string, host string, fqdn string, le sfv1.LetsEncryptSpec) (bool, []byte, []byte, []byte) {
func (r *SFUtilContext) extractTLSFromLECertificateSecret(host string, le sfv1.LetsEncryptSpec) (bool, []byte, []byte, []byte) {
_, issuerName := getLetsEncryptServer(le)
dnsNames := []string{host + "." + fqdn}
certificate := cert.MkCertificate(name, r.ns, issuerName, dnsNames, name+"-tls", nil)
const sfLECertName = "sf-le-certificate"
dnsNames := []string{host}
certificate := cert.MkCertificate(sfLECertName, r.ns, issuerName, dnsNames, sfLECertName+"-tls", nil)

current := certv1.Certificate{}

found := r.GetM(name, &current)
found := r.GetM(sfLECertName, &current)
if !found {
r.log.V(1).Info("Creating Cert-Manager LetsEncrypt Certificate ...", "name", name)
r.log.V(1).Info("Creating Cert-Manager LetsEncrypt Certificate ...", "name", sfLECertName)
r.CreateR(&certificate)
return false, nil, nil, nil
} else {
if current.Spec.IssuerRef.Name != certificate.Spec.IssuerRef.Name ||
!reflect.DeepEqual(current.Spec.DNSNames, certificate.Spec.DNSNames) {
// We need to update the Certficate
r.log.V(1).Info("Updating Cert-Manager LetsEncrypt Certificate ...", "name", name)
r.log.V(1).Info("Updating Cert-Manager LetsEncrypt Certificate ...", "name", sfLECertName)
current.Spec = *certificate.Spec.DeepCopy()
r.UpdateR(&current)
return false, nil, nil, nil
Expand All @@ -536,7 +535,7 @@ func (r *SFUtilContext) extractTLSFromLECertificateSecret(name string, host stri
ready := cert.IsCertificateReady(&current)

if ready {
r.log.V(1).Info("Cert-Manager LetsEncrypt Certificate is Ready ...", "name", name)
r.log.V(1).Info("Cert-Manager LetsEncrypt Certificate is Ready ...", "name", sfLECertName)
var leSSLSecret apiv1.Secret
if r.GetM(current.Spec.SecretName, &leSSLSecret) {
// Extract the TLS material
Expand All @@ -545,12 +544,12 @@ func (r *SFUtilContext) extractTLSFromLECertificateSecret(name string, host stri
} else {
// We are not able to find the Certificate's secret
r.log.V(1).Info("Cert-Manager LetsEncrypt Certificate is Ready but waiting for the Secret ...",
"name", name, "secret", current.Spec.SecretName)
"name", sfLECertName, "secret", current.Spec.SecretName)
return false, nil, nil, nil
}
} else {
// Return false to force a new Reconcile as the certificate is not Ready yet
r.log.V(1).Info("Cert-Manager LetsEncrypt Certificate is not Ready yet ...", "name", name)
r.log.V(1).Info("Cert-Manager LetsEncrypt Certificate is not Ready yet ...", "name", sfLECertName)
return false, nil, nil, nil
}
}
Expand Down
19 changes: 7 additions & 12 deletions controllers/zuul.go
Original file line number Diff line number Diff line change
Expand Up @@ -969,7 +969,7 @@ func (r *SFController) DeployZuul() bool {
cfgINI.Section(srv).NewKey("prometheus_port", strconv.Itoa(zuulPrometheusPort))
}
// Set Zuul web public URL
cfgINI.Section("web").NewKey("root", "https://zuul."+r.cr.Spec.FQDN)
cfgINI.Section("web").NewKey("root", "https://"+r.cr.Spec.FQDN+"/zuul/")

// Set Zuul Merger Configurations
if r.cr.Spec.Zuul.Merger.GitUserName != "" {
Expand Down Expand Up @@ -1031,15 +1031,10 @@ func (r *SFController) runZuulInternalTenantReconfigure() bool {
}

func (r *SFController) setupZuulIngress() bool {
route1Ready := r.ensureHTTPSRoute(r.cr.Name+"-zuul", "zuul", "zuul-web", "/", zuulWEBPort,
map[string]string{}, r.cr.Spec.FQDN, r.cr.Spec.LetsEncrypt)

// Zuul ingress is special because the zuul-web container expect the
// the files to be served at `/zuul/`, but it is listening on `/`.
// Thus this ingress remove the `/zuul/` so that the javascript loads as
// expected
route2Ready := r.ensureHTTPSRoute(r.cr.Name+"-zuul-red", "zuul", "zuul-web", "/zuul", zuulWEBPort, map[string]string{
"haproxy.router.openshift.io/rewrite-target": "/",
}, r.cr.Spec.FQDN, r.cr.Spec.LetsEncrypt)
return route1Ready && route2Ready
route1Ready := r.ensureHTTPSRoute(r.cr.Name+"-zuul", r.cr.Spec.FQDN, "zuul-web", "/zuul", zuulWEBPort,
map[string]string{
"haproxy.router.openshift.io/rewrite-target": "/",
}, r.cr.Spec.LetsEncrypt)

return route1Ready
}
Loading

0 comments on commit 0b1bb42

Please sign in to comment.