...

Source file src/github.com/emissary-ingress/emissary/v3/cmd/entrypoint/syntheticauth.go

Documentation: github.com/emissary-ingress/emissary/v3/cmd/entrypoint

     1  package entrypoint
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/datawire/dlib/dlog"
     8  	"github.com/emissary-ingress/emissary/v3/pkg/api/getambassador.io/v3alpha1"
     9  	"github.com/emissary-ingress/emissary/v3/pkg/emissaryutil"
    10  	"github.com/emissary-ingress/emissary/v3/pkg/kates"
    11  )
    12  
    13  // Checks if the provided string is a loopback IP address with port 8500
    14  func IsLocalhost8500(svcStr string) bool {
    15  	_, hostname, port, err := emissaryutil.ParseServiceName(svcStr)
    16  	return err == nil && port == 8500 && emissaryutil.IsLocalhost(hostname)
    17  }
    18  
    19  func iterateOverAuthServices(sh *SnapshotHolder, cb func(
    20  	authService *v3alpha1.AuthService, // duh
    21  	name string, // name to unambiguously refer to the authService by; might be more complex than "name.namespace" if it's an annotation
    22  	parentName string, // name of the thing that the annotation is on (or empty if not an annotation)
    23  	idx int, // index of the authService; either in sh.k8sSnapshot.AuthServices or in sh.k8sSnapshot.Annotations[parentName]
    24  )) {
    25  	envAmbID := GetAmbassadorID()
    26  
    27  	for i, authService := range sh.k8sSnapshot.AuthServices {
    28  		if authService.Spec.AmbassadorID.Matches(envAmbID) {
    29  			name := authService.TypeMeta.Kind + "/" + authService.ObjectMeta.Name + "." + authService.ObjectMeta.Namespace
    30  			cb(authService, name, "", i)
    31  		}
    32  	}
    33  	for parentName, list := range sh.k8sSnapshot.Annotations {
    34  		for i, obj := range list {
    35  			if authService, ok := obj.(*v3alpha1.AuthService); ok && authService.Spec.AmbassadorID.Matches(envAmbID) {
    36  				name := fmt.Sprintf("%s#%d", parentName, i)
    37  				cb(authService, name, parentName, i)
    38  			}
    39  		}
    40  	}
    41  }
    42  
    43  // This is a gross hack to remove all AuthServices using protocol_version: v2 only when running Edge-Stack and then inject an
    44  // AuthService with protocol_version: v3 if needed. The purpose of this hack is to prevent Edge-Stack 2.3 from
    45  // using any other AuthService than the default one running as part of amb-sidecar and force the protocol version to v3.
    46  func ReconcileAuthServices(ctx context.Context, sh *SnapshotHolder, deltas *[]*kates.Delta) error {
    47  	// We only want to remove AuthServices if this is an instance of Edge-Stack
    48  	if isEdgeStack, err := IsEdgeStack(); err != nil {
    49  		return fmt.Errorf("ReconcileAuthServices: %w", err)
    50  	} else if !isEdgeStack {
    51  		return nil
    52  	}
    53  
    54  	// using a name with underscores prevents it from colliding with anything real in the
    55  	// cluster--Kubernetes resources can't have underscores in their name.
    56  	const syntheticAuthServiceName = "synthetic_edge_stack_auth"
    57  
    58  	var (
    59  		numAuthServices  uint64
    60  		syntheticAuth    *v3alpha1.AuthService
    61  		syntheticAuthIdx int
    62  	)
    63  	iterateOverAuthServices(sh, func(authService *v3alpha1.AuthService, name, parentName string, i int) {
    64  		numAuthServices++
    65  		if IsLocalhost8500(authService.Spec.AuthService) {
    66  			if parentName == "" && authService.ObjectMeta.Name == syntheticAuthServiceName {
    67  				syntheticAuth = authService
    68  				syntheticAuthIdx = i
    69  			}
    70  			if authService.Spec.ProtocolVersion != "v3" {
    71  				// Force the Edge Stack AuthService to be protocol_version=v3.  This
    72  				// is important so that <2.3 and >=2.3 installations can coexist.
    73  				// This is important, because for zero-downtime upgrades, they must
    74  				// coexist briefly while the new Deployment is getting rolled out.
    75  				dlog.Debugf(ctx, "ReconcileAuthServices: Forcing protocol_version=v3 on %s", name)
    76  				authService.Spec.ProtocolVersion = "v3"
    77  			}
    78  		}
    79  	})
    80  
    81  	switch {
    82  	case numAuthServices == 0: // add the synthetic auth service
    83  		dlog.Debug(ctx, "ReconcileAuthServices: No user-provided AuthServices detected; injecting synthetic AuthService")
    84  		syntheticAuth = &v3alpha1.AuthService{
    85  			TypeMeta: kates.TypeMeta{
    86  				Kind:       "AuthService",
    87  				APIVersion: "getambassador.io/v3alpha1",
    88  			},
    89  			ObjectMeta: kates.ObjectMeta{
    90  				Name:      syntheticAuthServiceName,
    91  				Namespace: GetAmbassadorNamespace(),
    92  			},
    93  			Spec: v3alpha1.AuthServiceSpec{
    94  				AmbassadorID:    []string{GetAmbassadorID()},
    95  				AuthService:     "127.0.0.1:8500",
    96  				Proto:           "grpc",
    97  				ProtocolVersion: "v3",
    98  			},
    99  		}
   100  		sh.k8sSnapshot.AuthServices = append(sh.k8sSnapshot.AuthServices, syntheticAuth)
   101  		*deltas = append(*deltas, &kates.Delta{
   102  			TypeMeta:   syntheticAuth.TypeMeta,
   103  			ObjectMeta: syntheticAuth.ObjectMeta,
   104  			DeltaType:  kates.ObjectAdd,
   105  		})
   106  	case numAuthServices > 1 && syntheticAuth != nil: // remove the synthetic auth service
   107  		dlog.Debugf(ctx, "ReconcileAuthServices: %d user-provided AuthServices detected; removing synthetic AuthService", numAuthServices-1)
   108  		sh.k8sSnapshot.AuthServices = append(
   109  			sh.k8sSnapshot.AuthServices[:syntheticAuthIdx],
   110  			sh.k8sSnapshot.AuthServices[syntheticAuthIdx+1:]...)
   111  		*deltas = append(*deltas, &kates.Delta{
   112  			TypeMeta:   syntheticAuth.TypeMeta,
   113  			ObjectMeta: syntheticAuth.ObjectMeta,
   114  			DeltaType:  kates.ObjectDelete,
   115  		})
   116  	}
   117  
   118  	return nil
   119  }
   120  

View as plain text