Skip to content

Commit

Permalink
adapt shoot_cert_service actuator for deployment on runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinWeindel committed Dec 11, 2024
1 parent 479665d commit c11d626
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 34 deletions.
6 changes: 6 additions & 0 deletions pkg/apis/service/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ const CertManagementResourceNameSeed = "extension-shoot-cert-service-seed"
// CertManagementResourceNameShoot is the name for Cert-Management resources in the shoot.
const CertManagementResourceNameShoot = "extension-shoot-cert-service-shoot"

// CertManagementResourceNameRuntime is the name for Cert-Management resources in the runtime cluster.
const CertManagementResourceNameRuntime = "extension-shoot-cert-service-runtime"

// CertManagementImageName is the name of the Cert-Management image in the image vector.
const CertManagementImageName = "cert-management"

Expand All @@ -29,6 +32,9 @@ const CertManagementChartNameSeed = "shoot-cert-management-seed"
// CertManagementChartNameShoot is the name of the chart for Cert-Management in the shoot.
const CertManagementChartNameShoot = "shoot-cert-management-shoot"

// CertManagementChartNameRuntime is the name of the chart for Cert-Management in the runtime cluster.
const CertManagementChartNameRuntime = "cert-management-garden-runtime"

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

Expand Down
20 changes: 20 additions & 0 deletions pkg/apis/service/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,26 @@ import (
// ValidateCertConfig validates the passed configuration instance.
func ValidateCertConfig(config *service.CertConfig, cluster *controller.Cluster) field.ErrorList {
allErrs := field.ErrorList{}

if cluster == nil {
if len(config.Issuers) > 0 {
allErrs = append(allErrs, field.Forbidden(field.NewPath("issuers"), "issuers are not allowed in extension on runtime cluster. Please add issuer in the Helm values of the gardener-extension-shoot-cert-service extension"))
}
if config.PrecheckNameservers != nil {
allErrs = append(allErrs, field.Forbidden(field.NewPath("precheckNameservers"), "precheckNameservers are not allowed in extension on runtime cluster."))
}
if config.DNSChallengeOnShoot != nil {
allErrs = append(allErrs, field.Forbidden(field.NewPath("dnsChallengeOnShoot"), "dnsChallengeOnShoot is not allowed in extension on runtime cluster."))
}
if config.ShootIssuers != nil {
allErrs = append(allErrs, field.Forbidden(field.NewPath("shootIssuers"), "shootIssuers is not allowed in extension on runtime cluster."))
}
if config.Alerting != nil {
allErrs = append(allErrs, field.Forbidden(field.NewPath("alerting"), "alerting is not allowed in extension on runtime cluster."))
}
return allErrs
}

allErrs = append(allErrs, validateIssuers(cluster, config.Issuers, field.NewPath("issuers"))...)

allErrs = append(allErrs, validateDNSChallengeOnShoot(config.DNSChallengeOnShoot, field.NewPath("dnsChallengeOnShoot"))...)
Expand Down
60 changes: 59 additions & 1 deletion pkg/apis/service/validation/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ var _ = Describe("Validation", func() {
},
}
)
DescribeTable("#ValidateCertConfig",
DescribeTable("#ValidateCertConfigShoot",
func(config service.CertConfig, match gomegatypes.GomegaMatcher) {
err := validation.ValidateCertConfig(&config, cluster)
Expect(err).To(match)
Expand Down Expand Up @@ -291,4 +291,62 @@ var _ = Describe("Validation", func() {
})),
)),
)
DescribeTable("#ValidateCertConfigRuntimeCluster",
func(config service.CertConfig, match gomegatypes.GomegaMatcher) {
err := validation.ValidateCertConfig(&config, nil)
Expect(err).To(match)
},
Entry("No issuers", service.CertConfig{}, BeEmpty()),
Entry("Unsupported issuer", service.CertConfig{
Issuers: []service.IssuerConfig{
{
Name: "issuer",
Server: "https://acme-v02.api.letsencrypt.org/directory",
Email: "[email protected]",
},
},
}, ConsistOf(
PointTo(MatchFields(IgnoreExtras, Fields{
"Type": Equal(field.ErrorTypeForbidden),
"Field": Equal("issuers"),
})),
)),
Entry("Unsupported DNSChallengeOnShoot", service.CertConfig{
DNSChallengeOnShoot: &service.DNSChallengeOnShoot{
Enabled: true,
Namespace: "kube-system",
},
}, ConsistOf(
PointTo(MatchFields(IgnoreExtras, Fields{
"Type": Equal(field.ErrorTypeForbidden),
"Field": Equal("dnsChallengeOnShoot"),
})),
)),
Entry("Unsupported PrecheckNameservers", service.CertConfig{
PrecheckNameservers: &nameservers,
}, ConsistOf(
PointTo(MatchFields(IgnoreExtras, Fields{
"Type": Equal(field.ErrorTypeForbidden),
"Field": Equal("precheckNameservers"),
})),
)),
Entry("Unsupported ShootIssuer", service.CertConfig{
ShootIssuers: &service.ShootIssuers{
Enabled: true,
},
}, ConsistOf(
PointTo(MatchFields(IgnoreExtras, Fields{
"Type": Equal(field.ErrorTypeForbidden),
"Field": Equal("shootIssuers"),
})),
)),
Entry("Unsupported Alerting", service.CertConfig{
Alerting: &service.Alerting{},
}, ConsistOf(
PointTo(MatchFields(IgnoreExtras, Fields{
"Type": Equal(field.ErrorTypeForbidden),
"Field": Equal("alerting"),
})),
)),
)
})
127 changes: 94 additions & 33 deletions pkg/controller/actuator.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ type actuator struct {

// Reconcile the Extension resource.
func (a *actuator) Reconcile(ctx context.Context, log logr.Logger, ex *extensionsv1alpha1.Extension) error {
if a.extensionClass == extensionsv1alpha1.ExtensionClassGarden {
return a.reconcileOnRuntimeCluster(ctx, log, ex)
}

namespace := ex.GetNamespace()

cluster, err := controller.GetCluster(ctx, a.client, namespace)
Expand Down Expand Up @@ -103,6 +107,10 @@ func (a *actuator) Reconcile(ctx context.Context, log logr.Logger, ex *extension

// Delete the Extension resource.
func (a *actuator) Delete(ctx context.Context, log logr.Logger, ex *extensionsv1alpha1.Extension) error {
if a.extensionClass == extensionsv1alpha1.ExtensionClassGarden {
return a.deleteOnRuntimeCluster(ctx, log, ex)
}

namespace := ex.GetNamespace()
a.logger.Info("Component is being deleted", "component", "cert-management", "namespace", namespace)
if err := a.deleteShootResources(ctx, namespace); err != nil {
Expand Down Expand Up @@ -250,44 +258,54 @@ func (a *actuator) createSeedResources(ctx context.Context, certConfig *service.
return err
}

dnsChallengeOnShoot, err := createDNSChallengeOnShootValues(certConfig.DNSChallengeOnShoot)
if err != nil {
return err
}
var (
restricted bool
restrictedDomains *string
replicaCount = 1
)

if cluster.Shoot.Spec.DNS == nil || cluster.Shoot.Spec.DNS.Domain == nil {
a.logger.Info("no domain given for shoot %s/%s - aborting", cluster.Shoot.Name, cluster.Shoot.Namespace)
return nil
if cluster != nil {
replicaCount = controller.GetReplicas(cluster, 1)
if cluster.Shoot.Spec.DNS == nil || cluster.Shoot.Spec.DNS.Domain == nil {
a.logger.Info("no domain given for shoot %s/%s - aborting", cluster.Shoot.Name, cluster.Shoot.Namespace)
return nil
}
restricted = *a.serviceConfig.RestrictIssuer
restrictedDomains = cluster.Shoot.Spec.DNS.Domain
}

var propagationTimeout string
if a.serviceConfig.ACME != nil && a.serviceConfig.ACME.PropagationTimeout != nil {
propagationTimeout = a.serviceConfig.ACME.PropagationTimeout.Duration.String()
}

var (
shootIssuers = a.createShootIssuersValues(certConfig)
certManagementConfig = map[string]interface{}{
"replicaCount": controller.GetReplicas(cluster, 1),
"defaultIssuer": map[string]interface{}{
"name": a.serviceConfig.IssuerName,
"restricted": *a.serviceConfig.RestrictIssuer,
"domains": cluster.Shoot.Spec.DNS.Domain,
},
"issuers": issuers,
"configuration": map[string]interface{}{
"propagationTimeout": propagationTimeout,
},
"dnsChallengeOnShoot": dnsChallengeOnShoot,
"shootIssuers": shootIssuers,
"genericTokenKubeconfigSecretName": extensions.GenericTokenKubeconfigSecretNameFromCluster(cluster),
certManagementConfig := map[string]interface{}{
"replicaCount": replicaCount,
"defaultIssuer": map[string]interface{}{
"name": a.serviceConfig.IssuerName,
"restricted": restricted,
"domains": restrictedDomains,
},
"issuers": issuers,
"configuration": map[string]interface{}{
"propagationTimeout": propagationTimeout,
},
}

if cluster != nil {
dnsChallengeOnShoot, err := createDNSChallengeOnShootValues(certConfig.DNSChallengeOnShoot)
if err != nil {
return err
}
)
certManagementConfig["shootIssuers"] = a.createShootIssuersValues(certConfig)
certManagementConfig["dnsChallengeOnShoot"] = dnsChallengeOnShoot
if err := gutil.NewShootAccessSecret(v1alpha1.ShootAccessSecretName, namespace).Reconcile(ctx, a.client); err != nil {
return err
}
certManagementConfig["genericTokenKubeconfigSecretName"] = extensions.GenericTokenKubeconfigSecretNameFromCluster(cluster)

if err := gutil.NewShootAccessSecret(v1alpha1.ShootAccessSecretName, namespace).Reconcile(ctx, a.client); err != nil {
return err
certManagementConfig["shootClusterSecret"] = gutil.SecretNamePrefixShootAccess + v1alpha1.ShootAccessSecretName
}
certManagementConfig["shootClusterSecret"] = gutil.SecretNamePrefixShootAccess + v1alpha1.ShootAccessSecretName

cfg := certManagementConfig["configuration"].(map[string]interface{})
if a.serviceConfig.DefaultRequestsPerDayQuota != nil {
Expand Down Expand Up @@ -336,13 +354,15 @@ func (a *actuator) createSeedResources(ctx context.Context, certConfig *service.
}

// TODO(rfranzke): Delete this after August 2024.
gep19Monitoring := a.client.Get(ctx, client.ObjectKey{Name: "prometheus-shoot", Namespace: namespace}, &appsv1.StatefulSet{}) == nil
if gep19Monitoring {
if err := kutil.DeleteObject(ctx, a.client, &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "cert-controller-manager-observability-config", Namespace: namespace}}); err != nil {
return fmt.Errorf("failed deleting cert-controller-manager-observability-config ConfigMap: %w", err)
if cluster != nil {
gep19Monitoring := a.client.Get(ctx, client.ObjectKey{Name: "prometheus-shoot", Namespace: namespace}, &appsv1.StatefulSet{}) == nil
if gep19Monitoring {
if err := kutil.DeleteObject(ctx, a.client, &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "cert-controller-manager-observability-config", Namespace: namespace}}); err != nil {
return fmt.Errorf("failed deleting cert-controller-manager-observability-config ConfigMap: %w", err)
}
}
certManagementConfig["gep19Monitoring"] = gep19Monitoring
}
certManagementConfig["gep19Monitoring"] = gep19Monitoring

certManagementConfig, err = chart.InjectImages(certManagementConfig, imagevector.ImageVector(), []string{v1alpha1.CertManagementImageName})
if err != nil {
Expand All @@ -356,7 +376,13 @@ func (a *actuator) createSeedResources(ctx context.Context, certConfig *service.

a.logger.Info("Component is being applied", "component", "cert-management", "namespace", namespace)

return a.createManagedResource(ctx, namespace, v1alpha1.CertManagementResourceNameSeed, "seed", renderer, v1alpha1.CertManagementChartNameSeed, namespace, certManagementConfig, nil)
resourceName := v1alpha1.CertManagementResourceNameSeed
chartName := v1alpha1.CertManagementChartNameSeed
if cluster == nil {
resourceName = v1alpha1.CertManagementResourceNameRuntime
chartName = v1alpha1.CertManagementChartNameRuntime
}
return a.createManagedResource(ctx, namespace, resourceName, "seed", renderer, chartName, namespace, certManagementConfig, nil)
}

func (a *actuator) createShootResources(ctx context.Context, certConfig *service.CertConfig, cluster *controller.Cluster, namespace string) error {
Expand Down Expand Up @@ -452,6 +478,41 @@ func (a *actuator) createShootIssuersValues(certConfig *service.CertConfig) map[
}
}

func (a *actuator) reconcileOnRuntimeCluster(ctx context.Context, _ logr.Logger, ex *extensionsv1alpha1.Extension) error {
namespace := ex.GetNamespace()

certConfig := &service.CertConfig{}
if ex.Spec.ProviderConfig != nil {
if _, _, err := a.decoder.Decode(ex.Spec.ProviderConfig.Raw, nil, certConfig); err != nil {
return fmt.Errorf("failed to decode provider config: %+v", err)
}
if errs := validation.ValidateCertConfig(certConfig, nil); len(errs) > 0 {
return errs.ToAggregate()
}
}

if err := a.createSeedResources(ctx, certConfig, nil, namespace); err != nil {
return err
}

return a.updateStatus(ctx, ex, certConfig)
}

func (a *actuator) deleteOnRuntimeCluster(ctx context.Context, logger logr.Logger, ex *extensionsv1alpha1.Extension) error {
namespace := ex.GetNamespace()
a.logger.Info("Component is being deleted", "component", "cert-management", "namespace", namespace)

a.logger.Info("Deleting managed resource for runtime", "namespace", namespace)

if err := managedresources.Delete(ctx, a.client, namespace, v1alpha1.CertManagementResourceNameRuntime, false); err != nil {
return err
}

timeoutCtx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
return managedresources.WaitUntilDeleted(timeoutCtx, a.client, namespace, v1alpha1.CertManagementResourceNameRuntime)
}

func mergeServers(serversList ...string) string {
existing := map[string]struct{}{}
merged := []string{}
Expand Down

0 comments on commit c11d626

Please sign in to comment.