Skip to content

Commit

Permalink
⚠️ Remove migration to new VPN filters (#83)
Browse files Browse the repository at this point in the history
* Add flag to disable migration to new vpn filters.

* Fix tests.

* Remove migration code that migrates from legacy vpn envoy filter.

* Remove unsused BuildLegacyVPNEnvoyFilterSpecForHelmChart.

* Remove CreateLegacyVPNConfigPatchFromRule.

* Drop more unused code

---------

Co-authored-by: Tim Ebert <[email protected]>
  • Loading branch information
axel7born and timebertt authored Oct 10, 2024
1 parent 8ef9a17 commit 6d9684d
Show file tree
Hide file tree
Showing 6 changed files with 8 additions and 560 deletions.
7 changes: 0 additions & 7 deletions docs/adr/06_seperate_vpn_filter.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,3 @@ The resulting filter chain in envoy looks like this:
...
]
```

During the migration from the legacy shared EnvoyFilter to individual EnvoyFilters, we check during a reconciliation of a shoot if the new VPN EnvoyFilter is present.
In such instances, the shoot-specific component of this shoot is removed from the legacy filter.
Once the new VPN EnvoyFilter is created for all shoots, the legacy VPN EnvoyFilter will be deleted.
As the creation of the new EnvoyFilter by the GardenerResourceManager takes some time, two shoot reconciliations are needed before the shoot-specific component is fully removed from the legacy filter.
Throughout this process, the VPN endpoint remains protected by envoy filter rules.
Between the first and second reconciliation, the rules are duplicated in the envoy configuration, but this should not pose any issues.
178 changes: 0 additions & 178 deletions pkg/controller/actuator.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import (
istionetworkv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
appsv1 "k8s.io/api/apps/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/types"
Expand All @@ -55,14 +54,10 @@ import (
)

const (
// ActuatorName is only used for the logger instance
ActuatorName = "acl-actuator"
// ResourceNameSeed is name of the managedResource object
ResourceNameSeed = "acl-seed"
// ChartNameSeed name of the helm chart
ChartNameSeed = "seed"
// IngressNamespace is the namespace of the istio
IngressNamespace = "istio-ingress"
// HashAnnotationName name of annotation for triggering the envoyfilter webhook
// DEPRECATED: Remove after annotation has been removed from all EnvoyFilters
HashAnnotationName = "acl-ext-rule-hash"
Expand All @@ -81,7 +76,6 @@ var (
ErrSpecRule = errors.New("rule must be present")
ErrSpecType = errors.New("type must either be 'direct_remote_ip', 'remote_ip' or 'source_ip'")
ErrSpecCIDR = errors.New("CIDRs must not be empty")
ErrNoExtensionsFound = errors.New("could not list any extensions")
ErrNoAdvertisedAddresses = errors.New("advertised addresses are not available, likely because cluster creation has not yet completed")
)

Expand Down Expand Up @@ -197,17 +191,6 @@ func (a *actuator) Reconcile(ctx context.Context, log logr.Logger, ex *extension
return err
}

if err := a.reconcileVPNEnvoyFilter(ctx, alwaysAllowedCIDRs, istioNamespace, istioLabels); err != nil {
return err
}

if extState.IstioNamespace != nil && *extState.IstioNamespace != istioNamespace {
// we need to cleanup the old vpn object if the istioNamespace changed
if err := a.reconcileVPNEnvoyFilter(ctx, alwaysAllowedCIDRs, *extState.IstioNamespace, nil); err != nil {
return err
}
}

extState.IstioNamespace = &istioNamespace

return a.updateStatus(ctx, ex, extState)
Expand Down Expand Up @@ -303,58 +286,6 @@ func (a *actuator) Migrate(ctx context.Context, log logr.Logger, ex *extensionsv
return a.Delete(ctx, log, ex)
}

func (a *actuator) reconcileVPNEnvoyFilter(
ctx context.Context,
alwaysAllowedCIDRs []string,
istioNamespace string,
istioLabels map[string]string,
) error {
aclMappings, istioLabelsFromExt, err := a.getAllShootsWithACLExtension(ctx, istioNamespace)
if err != nil {
return err
}

// build EnvoyFilter object as map[string]interface{}
// because the actual EnvoyFilter struct is a pain to type
name := "acl-vpn"

// build EnvoyFilter object as map[string]interface{}
// because the actual EnvoyFilter struct is a pain to type
envoyFilter := &unstructured.Unstructured{}
envoyFilter.SetGroupVersionKind(istionetworkv1alpha3.SchemeGroupVersion.WithKind("EnvoyFilter"))
envoyFilter.SetNamespace(istioNamespace)
envoyFilter.SetName(name)

if len(aclMappings) == 0 {
// no shoot in this namespace with the ACL extension, so we can delete the config
err = a.client.Delete(ctx, envoyFilter)
return client.IgnoreNotFound(err)
}
if istioLabels == nil {
istioLabels = istioLabelsFromExt
}

vpnEnvoyFilterSpec, err := envoyfilters.BuildLegacyVPNEnvoyFilterSpecForHelmChart(
aclMappings, alwaysAllowedCIDRs, istioLabels,
)
if err != nil {
return err
}

err = a.client.Get(ctx, client.ObjectKeyFromObject(envoyFilter), envoyFilter)
if client.IgnoreNotFound(err) != nil {
return err
}

envoyFilter.Object["spec"] = vpnEnvoyFilterSpec

if apierrors.IsNotFound(err) {
return a.client.Create(ctx, envoyFilter)
}

return a.client.Update(ctx, envoyFilter)
}

func (a *actuator) createSeedResources(
ctx context.Context,
log logr.Logger,
Expand Down Expand Up @@ -525,115 +456,6 @@ func (a *actuator) triggerWebhook(ctx context.Context, shootName, istioNamespace
return a.client.Patch(ctx, envoyFilter, client.RawPatch(types.MergePatchType, []byte("{}")))
}

// getAllShootsWithACLExtension returns a list of all shoots that have the ACL
// extension enabled, together with their rule.
func (a *actuator) getAllShootsWithACLExtension(
ctx context.Context, istioNamespace string,
) ([]envoyfilters.ACLMapping, map[string]string, error) {
extensions := &extensionsv1alpha1.ExtensionList{}
err := a.client.List(ctx, extensions)
if err != client.IgnoreNotFound(err) {
return nil, nil, err
}

if len(extensions.Items) < 1 {
return nil, nil, ErrNoExtensionsFound
}

mappings := []envoyfilters.ACLMapping{}

var istioLabels map[string]string

for i := range extensions.Items {
ex := &extensions.Items[i]
if ex.Spec.Type != Type {
continue
}

var shootIstioNamespace string
var shootIstioLabels map[string]string

shootIstioNamespace, shootIstioLabels, err = a.findIstioNamespaceForExtension(ctx, &extensions.Items[i])
if client.IgnoreNotFound(err) != nil {
return nil, nil, err
}
// If we don't find a Gateway object to get the Istio Namespace from, we
// try the extension status as a fallback. If both aren't available, we
// ignore the Shoot's ACL rules entirely in this pass. This can only
// occur when the ACL extension for the Shoot in question itself has
// never been reconciled before.
if apierrors.IsNotFound(err) {
extState, err := getExtensionState(ex)
if err != nil {
return nil, nil, err
}
if extState.IstioNamespace == nil {
continue
}

shootIstioNamespace = *extState.IstioNamespace
}

if istioNamespace != shootIstioNamespace {
continue
}

if istioLabels == nil {
istioLabels = shootIstioLabels
}

extSpec := &extensionspec.ExtensionSpec{}
if ex.Spec.ProviderConfig != nil && ex.Spec.ProviderConfig.Raw != nil {
if err := json.Unmarshal(ex.Spec.ProviderConfig.Raw, &extSpec); err != nil {
return nil, nil, err
}
}

cluster, err := controller.GetCluster(ctx, a.client, ex.GetNamespace())
if err != nil {
return nil, nil, err
}

var shootSpecificCIDRs []string

// Gardener supports workerless Shoots. These don't have an associated
// Infrastructure object and don't need Node- or Pod-specific CIDRs to be
// allowed. Therefore, skip these steps for workerless Shoots.
if !v1beta1helper.IsWorkerless(cluster.Shoot) {
infra := &extensionsv1alpha1.Infrastructure{}
namespacedName := types.NamespacedName{
Namespace: ex.GetNamespace(),
Name: cluster.Shoot.Name,
}

if err := a.client.Get(ctx, namespacedName, infra); err != nil {
return nil, nil, err
}

shootSpecificCIDRs = append(shootSpecificCIDRs, helper.GetShootNodeSpecificAllowedCIDRs(cluster.Shoot)...)
providerSpecificCIRDs, err := helper.GetProviderSpecificAllowedCIDRs(infra)
if err != nil {
return nil, nil, err
}
shootSpecificCIDRs = append(shootSpecificCIDRs, providerSpecificCIRDs...)
}

envoyFilter := &istionetworkv1alpha3.EnvoyFilter{}
name := "acl-vpn-" + ex.Namespace
err = a.client.Get(ctx, types.NamespacedName{Name: name, Namespace: istioNamespace}, envoyFilter)
if apierrors.IsNotFound(err) {
mappings = append(mappings, envoyfilters.ACLMapping{
ShootName: ex.Namespace,
Rule: *extSpec.Rule,
ShootSpecificCIDRs: shootSpecificCIDRs,
})
} else if err != nil {
return nil, nil, err
}
}
return mappings, istioLabels, nil
}

// findIstioNamespaceForExtension finds the Istio namespace by the Istio Gateway
// object named "kube-apiserver", which is expected to be present in every
// Shoot namespace (except when the Shoot is hibernated - in this case, the
Expand Down
Loading

0 comments on commit 6d9684d

Please sign in to comment.