Skip to content
Open
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
87 changes: 61 additions & 26 deletions pkg/controller/manager/manager_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ func Add(mgr manager.Manager, opts options.AddOptions) error {
// We need to watch for es-gateway certificate because ui-apis still creates a
// client to talk to elastic via es-gateway
render.ManagerTLSSecretName, relasticsearch.PublicCertSecret,
render.VoltronTunnelSecretName, render.ComplianceServerCertSecret, render.PacketCaptureServerCert,
render.VoltronTunnelSecretName, render.VoltronAdditionalTunnelSecretName,
render.ComplianceServerCertSecret, render.PacketCaptureServerCert,
render.ManagerInternalTLSSecretName, monitor.PrometheusServerTLSSecretName, certificatemanagement.CASecretName,
} {
if err = utils.AddSecretsWatch(c, secretName, namespace); err != nil {
Expand Down Expand Up @@ -660,32 +661,46 @@ func (r *ReconcileManager) Reconcile(ctx context.Context, request reconcile.Requ
}
}

// If an additional tunnel CA secret has been provisioned in the truth namespace, Voltron
// will mount it and serve TLS from it. This is only relevant for management clusters
// (Voltron is what consumes the additional CA). The secret is managed out-of-band; the
// controller just watches and consumes it.
var additionalTunnelServerCert certificatemanagement.KeyPairInterface
if managementCluster != nil {
additionalTunnelServerCert, err = r.resolveAdditionalTunnelCert(ctx, helper.TruthNamespace())
if err != nil {
r.status.SetDegraded(operatorv1.ResourceReadError, "Error resolving additional tunnel CA", err, logc)
return reconcile.Result{}, err
}
}

managerCfg := &render.ManagerConfiguration{
VoltronRouteConfig: routeConfig,
KeyValidatorConfig: keyValidatorConfig,
TrustedCertBundle: trustedBundle,
TLSKeyPair: tlsSecret,
VoltronLinseedKeyPair: linseedVoltronServerCert,
PullSecrets: pullSecrets,
OpenShift: r.provider.IsOpenShift(),
Installation: installation,
ManagementCluster: managementCluster,
NonClusterHost: nonclusterhost,
TunnelServerCert: tunnelServerCert,
InternalTLSKeyPair: internalTrafficSecret,
ClusterDomain: r.clusterDomain,
ESLicenseType: elasticLicenseType,
Replicas: replicas,
Compliance: complianceCR,
ComplianceLicenseActive: complianceLicenseFeatureActive,
ComplianceNamespace: utils.NewNamespaceHelper(r.multiTenant, render.ComplianceNamespace, request.Namespace).InstallNamespace(),
Namespace: helper.InstallNamespace(),
TruthNamespace: helper.TruthNamespace(),
Tenant: tenant,
ExternalElastic: r.elasticExternal,
BindingNamespaces: namespaces,
OSSTenantNamespaces: ossTenantNamespaces,
Manager: instance,
VoltronRouteConfig: routeConfig,
KeyValidatorConfig: keyValidatorConfig,
TrustedCertBundle: trustedBundle,
TLSKeyPair: tlsSecret,
VoltronLinseedKeyPair: linseedVoltronServerCert,
PullSecrets: pullSecrets,
OpenShift: r.provider.IsOpenShift(),
Installation: installation,
ManagementCluster: managementCluster,
NonClusterHost: nonclusterhost,
TunnelServerCert: tunnelServerCert,
AdditionalTunnelServerCert: additionalTunnelServerCert,
InternalTLSKeyPair: internalTrafficSecret,
ClusterDomain: r.clusterDomain,
ESLicenseType: elasticLicenseType,
Replicas: replicas,
Compliance: complianceCR,
ComplianceLicenseActive: complianceLicenseFeatureActive,
ComplianceNamespace: utils.NewNamespaceHelper(r.multiTenant, render.ComplianceNamespace, request.Namespace).InstallNamespace(),
Namespace: helper.InstallNamespace(),
TruthNamespace: helper.TruthNamespace(),
Tenant: tenant,
ExternalElastic: r.elasticExternal,
BindingNamespaces: namespaces,
OSSTenantNamespaces: ossTenantNamespaces,
Manager: instance,
}

// Render the desired objects from the CRD and create or update them.
Expand Down Expand Up @@ -714,6 +729,7 @@ func (r *ReconcileManager) Reconcile(ctx context.Context, request reconcile.Requ
rcertificatemanagement.NewKeyPairOption(linseedVoltronServerCert, true, true),
rcertificatemanagement.NewKeyPairOption(internalTrafficSecret, true, true),
rcertificatemanagement.NewKeyPairOption(tunnelServerCert, false, true),
rcertificatemanagement.NewKeyPairOption(additionalTunnelServerCert, false, true),
},
TrustedBundle: bundleMaker,
}),
Expand Down Expand Up @@ -808,3 +824,22 @@ func getVoltronRouteConfig(ctx context.Context, cli client.Client, managerNamesp

return builder.Build()
}

// resolveAdditionalTunnelCert looks up the additional tunnel CA secret in the truth namespace.
// When the secret is present, a KeyPair is returned so that Voltron mounts the CA and gets the
// corresponding environment variables set. When the secret is absent, (nil, nil) is returned and
// Voltron runs without the additional CA. The secret is created and rotated out-of-band; this
// controller only consumes it.
func (r *ReconcileManager) resolveAdditionalTunnelCert(
ctx context.Context,
truthNamespace string,
) (certificatemanagement.KeyPairInterface, error) {
secret, err := utils.GetSecret(ctx, r.client, render.VoltronAdditionalTunnelSecretName, truthNamespace)
if err != nil {
return nil, fmt.Errorf("failed to read %s secret: %w", render.VoltronAdditionalTunnelSecretName, err)
}
if secret == nil {
return nil, nil
}
return certificatemanagement.NewKeyPair(secret, nil, ""), nil
}
34 changes: 34 additions & 0 deletions pkg/render/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ const (
DashboardAPIPort = "8444"
DashboardAPIHealthPort = "8090"
DashboardAPIName = "calico-dashboard-api"

// VoltronAdditionalTunnelSecretName is the name of an optional, pre-provisioned secret
// in the truth namespace that holds an additional CA used by Voltron for tunnel server
// certificates. When the secret is present the manager controller wires it into the
// Voltron deployment. It is managed out-of-band; the operator only consumes it.
VoltronAdditionalTunnelSecretName = "calico-management-additional-cluster-connection"
)

// Manager returns a component for rendering namespaced manager resources.
Expand Down Expand Up @@ -138,6 +144,9 @@ func Manager(cfg *ManagerConfiguration) (Component, error) {
tlsAnnotations[cfg.InternalTLSKeyPair.HashAnnotationKey()] = cfg.InternalTLSKeyPair.HashAnnotationValue()
if cfg.ManagementCluster != nil {
tlsAnnotations[cfg.TunnelServerCert.HashAnnotationKey()] = cfg.TunnelServerCert.HashAnnotationValue()
if cfg.AdditionalTunnelServerCert != nil {
tlsAnnotations[cfg.AdditionalTunnelServerCert.HashAnnotationKey()] = cfg.AdditionalTunnelServerCert.HashAnnotationValue()
}
}

return &managerComponent{
Expand Down Expand Up @@ -169,6 +178,12 @@ type ManagerConfiguration struct {
// KeyPair used by Voltron as the server certificate when establishing an mTLS tunnel with Guardian.
TunnelServerCert certificatemanagement.KeyPairInterface

// AdditionalTunnelServerCert is an optional additional CA used by Voltron for tunnel server
// certificates. It is populated by the manager controller when a pre-provisioned secret named
// VoltronAdditionalTunnelSecretName exists in the truth namespace, and is mounted into the
// Voltron container so Voltron can serve TLS from it.
AdditionalTunnelServerCert certificatemanagement.KeyPairInterface

// TLS KeyPair used by both Voltron and ui-apis, presented by each as part of the mTLS handshake with
// other services within the cluster. This is used in both management and standalone clusters.
InternalTLSKeyPair certificatemanagement.KeyPairInterface
Expand Down Expand Up @@ -412,6 +427,9 @@ func (c *managerComponent) managerVolumes() []corev1.Volume {
c.cfg.TunnelServerCert.Volume(),
c.cfg.VoltronLinseedKeyPair.Volume(),
)
if c.cfg.AdditionalTunnelServerCert != nil {
v = append(v, c.cfg.AdditionalTunnelServerCert.Volume())
}
}
if c.cfg.KeyValidatorConfig != nil {
v = append(v, c.cfg.KeyValidatorConfig.RequiredVolumes()...)
Expand Down Expand Up @@ -581,6 +599,15 @@ func (c *managerComponent) voltronContainer() corev1.Container {
env = append(env, corev1.EnvVar{Name: "VOLTRON_USE_HTTPS_CERT_ON_TUNNEL", Value: strconv.FormatBool(c.cfg.ManagementCluster.Spec.TLS != nil && c.cfg.ManagementCluster.Spec.TLS.SecretName == ManagerTLSSecretName)})
env = append(env, corev1.EnvVar{Name: "VOLTRON_LINSEED_SERVER_KEY", Value: linseedKeyPath})
env = append(env, corev1.EnvVar{Name: "VOLTRON_LINSEED_SERVER_CERT", Value: linseedCertPath})
if c.cfg.AdditionalTunnelServerCert != nil {
// Voltron scans a single parent directory for additional cert/key pairs. Each
// cert/key pair is mounted into its own subdirectory so multiple can coexist.
// The tls.crt from each pair is also used as an additional CA to verify
// client (guardian) connections.
env = append(env,
corev1.EnvVar{Name: "VOLTRON_ADDITIONAL_CERT_KEY_PAIRS_PATH", Value: "/additional-tunnel-certificates"},
)
}
}

if c.cfg.KeyValidatorConfig != nil {
Expand All @@ -597,6 +624,13 @@ func (c *managerComponent) voltronContainer() corev1.Container {
if c.cfg.ManagementCluster != nil {
mounts = append(mounts, c.cfg.TunnelServerCert.VolumeMount(c.SupportedOSType()))
mounts = append(mounts, c.cfg.VoltronLinseedKeyPair.VolumeMount(c.SupportedOSType()))
if c.cfg.AdditionalTunnelServerCert != nil {
mounts = append(mounts, corev1.VolumeMount{
Name: c.cfg.AdditionalTunnelServerCert.GetName(),
MountPath: fmt.Sprintf("/additional-tunnel-certificates/%s", c.cfg.AdditionalTunnelServerCert.GetName()),
ReadOnly: true,
})
}
}
}

Expand Down
Loading