github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/internal/enforcer/applicationproxy/applicationproxy.go (about)

     1  package applicationproxy
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"crypto/x509"
     7  	"errors"
     8  	"fmt"
     9  	"net"
    10  	"strconv"
    11  	"sync"
    12  
    13  	"github.com/blang/semver"
    14  	"github.com/opentracing/opentracing-go"
    15  	"go.aporeto.io/enforcerd/trireme-lib/collector"
    16  	tcommon "go.aporeto.io/enforcerd/trireme-lib/common"
    17  	"go.aporeto.io/enforcerd/trireme-lib/controller/constants"
    18  	"go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/applicationproxy/common"
    19  	httpproxy "go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/applicationproxy/http"
    20  	"go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/applicationproxy/markedconn"
    21  	"go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/applicationproxy/protomux"
    22  	"go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/applicationproxy/serviceregistry"
    23  	"go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/applicationproxy/tcp"
    24  	"go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/nfqdatapath/tokenaccessor"
    25  	"go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/utils/ephemeralkeys"
    26  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/fqconfig"
    27  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/ipsetmanager"
    28  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/pucontext"
    29  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/secrets"
    30  	"go.aporeto.io/enforcerd/trireme-lib/policy"
    31  	"go.aporeto.io/enforcerd/trireme-lib/utils/cache"
    32  	"go.uber.org/zap"
    33  )
    34  
    35  // ServerInterface describes the methods required by an application processor.
    36  type ServerInterface interface {
    37  	UpdateSecrets(cert *tls.Certificate, ca *x509.CertPool, secrets secrets.Secrets, certPEM, keyPEM string)
    38  	ShutDown() error
    39  }
    40  
    41  type clientData struct {
    42  	protomux  *protomux.MultiplexedListener
    43  	netserver map[common.ListenerType]ServerInterface
    44  }
    45  
    46  // AppProxy maintains state for proxies connections from listen to backend.
    47  type AppProxy struct {
    48  	cert *tls.Certificate
    49  
    50  	tokenaccessor   tokenaccessor.TokenAccessor
    51  	collector       collector.EventCollector
    52  	puFromID        cache.DataStore
    53  	secrets         secrets.Secrets
    54  	datapathKeyPair ephemeralkeys.KeyAccessor
    55  	agentVersion    semver.Version
    56  
    57  	clients     cache.DataStore
    58  	tokenIssuer tcommon.ServiceTokenIssuer
    59  	sync.RWMutex
    60  }
    61  
    62  // NewAppProxy creates a new instance of the application proxy.
    63  func NewAppProxy(
    64  	tp tokenaccessor.TokenAccessor,
    65  	c collector.EventCollector,
    66  	puFromID cache.DataStore,
    67  	s secrets.Secrets,
    68  	t tcommon.ServiceTokenIssuer,
    69  	datapathKeyPair ephemeralkeys.KeyAccessor,
    70  	agentVersion semver.Version,
    71  ) (*AppProxy, error) {
    72  
    73  	return &AppProxy{
    74  		collector:       c,
    75  		tokenaccessor:   tp,
    76  		secrets:         s,
    77  		puFromID:        puFromID,
    78  		cert:            nil,
    79  		clients:         cache.NewCache("clients"),
    80  		tokenIssuer:     t,
    81  		datapathKeyPair: datapathKeyPair,
    82  		agentVersion:    agentVersion,
    83  	}, nil
    84  }
    85  
    86  // Run starts all the network side proxies. Application side proxies will
    87  // have to start during enforce in order to support multiple Linux processes.
    88  func (p *AppProxy) Run(ctx context.Context) error {
    89  
    90  	return nil
    91  }
    92  
    93  // Enforce implements enforcer.Enforcer interface. It will create the necessary
    94  // proxies for the particular PU. Enforce can be called multiple times, once
    95  // for every policy update.
    96  func (p *AppProxy) Enforce(ctx context.Context, puID string, puInfo *policy.PUInfo) error {
    97  
    98  	p.Lock()
    99  	defer p.Unlock()
   100  
   101  	span, tctx := opentracing.StartSpanFromContext(ctx, "applicationproxy.enforce")
   102  	defer span.Finish()
   103  
   104  	if puInfo.Policy.ServicesListeningPort() == "0" {
   105  		zap.L().Warn("Services listening port not specified - not activating proxy")
   106  		return nil
   107  	}
   108  
   109  	data, err := p.puFromID.Get(puID)
   110  	if err != nil || data == nil {
   111  		return fmt.Errorf("undefined PU - Context not found: %s", puID)
   112  	}
   113  
   114  	puContext, ok := data.(*pucontext.PUContext)
   115  	if !ok {
   116  		return fmt.Errorf("bad data types for puContext")
   117  	}
   118  
   119  	sctx, err := serviceregistry.Instance().Register(puID, puInfo, puContext, p.secrets)
   120  	if err != nil {
   121  		return fmt.Errorf("policy conflicts detected: %s", err)
   122  	}
   123  
   124  	caPool, err := p.expandCAPool(sctx.RootCA)
   125  	if err != nil {
   126  		return err
   127  	}
   128  
   129  	// For updates we need to update the certificates if we have new ones. Otherwise
   130  	// we return. There is nothing else to do in case of policy update.
   131  	if c, cerr := p.clients.Get(puID); cerr == nil {
   132  		if _, perr := p.processCertificateUpdates(puInfo, c.(*clientData), caPool); perr != nil {
   133  			zap.L().Error("unable to update certificates and services", zap.Error(perr))
   134  			return perr
   135  		}
   136  		return nil
   137  	}
   138  
   139  	// Create the network listener and cache it so that we can terminate it later.
   140  	l, err := p.createNetworkListener(tctx, ":"+puInfo.Policy.ServicesListeningPort())
   141  	if err != nil {
   142  		zap.L().Error("Failed to create network listener", zap.Error(err))
   143  		return fmt.Errorf("Cannot create listener on port %s: %s", puInfo.Policy.ServicesListeningPort(), err)
   144  	}
   145  
   146  	// Create a new client entry and start the servers.
   147  	client := &clientData{
   148  		netserver: map[common.ListenerType]ServerInterface{},
   149  	}
   150  	client.protomux = protomux.NewMultiplexedListener(l, constants.ProxyMarkInt, puID)
   151  
   152  	// Listen to HTTP requests from the clients
   153  	client.netserver[common.HTTPApplication], err = p.registerAndRun(tctx, puID, common.HTTPApplication, client.protomux, caPool, true)
   154  	if err != nil {
   155  		return fmt.Errorf("Cannot create listener type %d: %s", common.HTTPApplication, err)
   156  	}
   157  
   158  	// Listen to HTTPS requests on the network side.
   159  	client.netserver[common.HTTPSNetwork], err = p.registerAndRun(tctx, puID, common.HTTPSNetwork, client.protomux, caPool, false)
   160  	if err != nil {
   161  		return fmt.Errorf("Cannot create listener type %d: %s", common.HTTPSNetwork, err)
   162  	}
   163  
   164  	// Listen to HTTP requests on the network side - mainly used for health probes - completely insecure for
   165  	// anything else.
   166  	client.netserver[common.HTTPNetwork], err = p.registerAndRun(tctx, puID, common.HTTPNetwork, client.protomux, caPool, false)
   167  	if err != nil {
   168  		return fmt.Errorf("Cannot create listener type %d: %s", common.HTTPNetwork, err)
   169  	}
   170  
   171  	// TCP Requests for clients
   172  	client.netserver[common.TCPApplication], err = p.registerAndRun(tctx, puID, common.TCPApplication, client.protomux, caPool, true)
   173  	if err != nil {
   174  		return fmt.Errorf("Cannot create listener type %d: %s", common.TCPApplication, err)
   175  	}
   176  
   177  	// TCP Requests from the network side
   178  	client.netserver[common.TCPNetwork], err = p.registerAndRun(tctx, puID, common.TCPNetwork, client.protomux, caPool, false)
   179  	if err != nil {
   180  		return fmt.Errorf("Cannot create listener type %d: %s", common.TCPNetwork, err)
   181  	}
   182  
   183  	if _, err = p.processCertificateUpdates(puInfo, client, caPool); err != nil {
   184  		zap.L().Error("Failed to update certificates", zap.Error(err))
   185  		return fmt.Errorf("Certificates not updated: %s", err)
   186  	}
   187  
   188  	// Add the client to the cache
   189  	p.clients.AddOrUpdate(puID, client)
   190  
   191  	// Start the connection multiplexer
   192  	go client.protomux.Serve(tctx) // nolint
   193  
   194  	return nil
   195  }
   196  
   197  // Unenforce implements enforcer.Enforcer interface. It will shutdown the app side
   198  // of the proxy.
   199  func (p *AppProxy) Unenforce(ctx context.Context, puID string) error {
   200  	p.Lock()
   201  	defer p.Unlock()
   202  
   203  	// Remove pu from registry
   204  	if err := serviceregistry.Instance().Unregister(puID); err != nil {
   205  		return err
   206  	}
   207  
   208  	// Find the correct client.
   209  	c, err := p.clients.Get(puID)
   210  	if err != nil {
   211  		return fmt.Errorf("Unable to find client")
   212  	}
   213  	client := c.(*clientData)
   214  
   215  	// Terminate the connection multiplexer.
   216  	// Do it before shutting down servers below to avoid Accept() errors.
   217  	client.protomux.Close()
   218  
   219  	// Shutdown all the servers and unregister listeners.
   220  	for t, server := range client.netserver {
   221  		if err := client.protomux.UnregisterListener(t); err != nil {
   222  			zap.L().Error("Unable to unregister client", zap.Int("type", int(t)), zap.Error(err))
   223  		}
   224  		if err := server.ShutDown(); err != nil {
   225  			zap.L().Debug("Unable to shutdown client server", zap.Error(err))
   226  		}
   227  	}
   228  
   229  	// Remove the client from the cache.
   230  	return p.clients.Remove(puID)
   231  }
   232  
   233  // GetFilterQueue is a stub for TCP proxy
   234  func (p *AppProxy) GetFilterQueue() *fqconfig.FilterQueue {
   235  	return nil
   236  }
   237  
   238  // Ping runs ping to the given config based on the service type. Returns error on invalid types.
   239  func (p *AppProxy) Ping(ctx context.Context, contextID string, sctx *serviceregistry.ServiceContext, sdata *serviceregistry.DependentServiceData, pingConfig *policy.PingConfig) error {
   240  
   241  	if pingConfig == nil || sctx == nil || sdata == nil {
   242  		zap.L().Debug("unable to run ping",
   243  			zap.Reflect("pingconfig", pingConfig),
   244  			zap.Reflect("serviceCtx", sctx),
   245  			zap.Reflect("serviceData", sdata),
   246  		)
   247  
   248  		return nil
   249  	}
   250  
   251  	c, err := p.clients.Get(contextID)
   252  	if err != nil {
   253  		return fmt.Errorf("unable to find client with contextID: %s", contextID)
   254  	}
   255  	client := c.(*clientData)
   256  
   257  	switch sdata.ServiceObject.Type {
   258  	case policy.ServiceTCP:
   259  		return client.netserver[common.TCPApplication].(*tcp.Proxy).InitiatePing(ctx, sctx, sdata, pingConfig)
   260  	case policy.ServiceHTTP:
   261  		return client.netserver[common.HTTPApplication].(*httpproxy.Config).InitiatePing(ctx, sctx, sdata, pingConfig)
   262  	default:
   263  		return fmt.Errorf("unknown service type: %d", sdata.ServiceObject.Type)
   264  	}
   265  }
   266  
   267  // UpdateSecrets updates the secrets of running enforcers managed by trireme. Remote enforcers will
   268  // get the secret updates with the next policy push.
   269  func (p *AppProxy) UpdateSecrets(secret secrets.Secrets) error {
   270  	p.Lock()
   271  	defer p.Unlock()
   272  	p.secrets = secret
   273  	return nil
   274  }
   275  
   276  // registerAndRun registers a new listener of the given type and runs the corresponding server
   277  func (p *AppProxy) registerAndRun(ctx context.Context, puID string, ltype common.ListenerType, mux *protomux.MultiplexedListener, caPool *x509.CertPool, appproxy bool) (ServerInterface, error) {
   278  
   279  	// Create a new sub-ordinate listerner and register it for the requested type.
   280  	listener, err := mux.RegisterListener(ltype)
   281  	if err != nil {
   282  		return nil, fmt.Errorf("Cannot register listener: %s", err)
   283  	}
   284  
   285  	// Start the corresponding proxy
   286  	switch ltype {
   287  	case common.HTTPApplication, common.HTTPSApplication, common.HTTPNetwork, common.HTTPSNetwork:
   288  
   289  		// If the protocol is encrypted, wrap it with TLS.
   290  		encrypted := false
   291  		if ltype == common.HTTPSNetwork {
   292  			encrypted = true
   293  		}
   294  
   295  		c := httpproxy.NewHTTPProxy(p.collector, puID, caPool, appproxy, constants.ProxyMarkInt, p.secrets, p.tokenIssuer, p.datapathKeyPair, p.agentVersion)
   296  		return c, c.RunNetworkServer(ctx, listener, encrypted)
   297  
   298  	default:
   299  		c := tcp.NewTCPProxy(p.collector, puID, p.cert, caPool, p.agentVersion, constants.ProxyMarkInt)
   300  		return c, c.RunNetworkServer(ctx, listener)
   301  	}
   302  }
   303  
   304  // createNetworkListener starts a network listener (traffic from network to PUs)
   305  func (p *AppProxy) createNetworkListener(ctx context.Context, port string) (net.Listener, error) {
   306  	return markedconn.NewSocketListener(ctx, port, constants.ProxyMarkInt)
   307  }
   308  
   309  // processCertificateUpdates processes the certificate information and updates
   310  // the servers.
   311  func (p *AppProxy) processCertificateUpdates(puInfo *policy.PUInfo, client *clientData, caPool *x509.CertPool) (bool, error) { // nolint:unparam
   312  
   313  	// If there are certificates provided, we will need to update them for the
   314  	// services. If the certificates are nil, we ignore them.
   315  	certPEM, keyPEM, caPEM := puInfo.Policy.ServiceCertificates()
   316  	if certPEM == "" || keyPEM == "" {
   317  		return false, nil
   318  	}
   319  
   320  	// Process any updates on the cert pool
   321  	if caPEM != "" {
   322  		if !caPool.AppendCertsFromPEM([]byte(caPEM)) {
   323  			zap.L().Warn("Failed to add Services CA")
   324  		}
   325  	}
   326  
   327  	// Create the TLS certificate
   328  	tlsCert, err := tls.X509KeyPair([]byte(certPEM), []byte(keyPEM))
   329  	if err != nil {
   330  		return false, fmt.Errorf("Invalid certificates: %s", err)
   331  	}
   332  
   333  	for _, server := range client.netserver {
   334  		server.UpdateSecrets(&tlsCert, caPool, p.secrets, certPEM, keyPEM)
   335  	}
   336  	return true, nil
   337  }
   338  
   339  func (p *AppProxy) expandCAPool(externalCAs [][]byte) (*x509.CertPool, error) {
   340  
   341  	caPool := x509.NewCertPool()
   342  
   343  	if ok := caPool.AppendCertsFromPEM(p.secrets.CertAuthority()); !ok {
   344  		return nil, fmt.Errorf("cannot append secrets CA %s", string(p.secrets.CertAuthority()))
   345  	}
   346  
   347  	for _, ca := range externalCAs {
   348  		if ok := caPool.AppendCertsFromPEM(ca); !ok {
   349  			return nil, fmt.Errorf("cannot append external service ca %s ", string(ca))
   350  		}
   351  	}
   352  
   353  	return caPool, nil
   354  }
   355  
   356  // ServiceData returns the servicectx and dependentservice for the given ip:port.
   357  func (p *AppProxy) ServiceData(
   358  	contextID string,
   359  	ip net.IP,
   360  	port int,
   361  	serviceAddresses map[string][]string) (*serviceregistry.ServiceContext, *serviceregistry.DependentServiceData, error) {
   362  
   363  	if sctx, sdata, err := serviceregistry.Instance().RetrieveDependentServiceDataByIDAndNetwork(contextID, ip, port, ""); err == nil {
   364  		return sctx, sdata, nil
   365  	}
   366  
   367  	if len(serviceAddresses) == 0 {
   368  		return nil, nil, errors.New("no service context found")
   369  	}
   370  
   371  	sctx, err := serviceregistry.Instance().RetrieveServiceByID(contextID)
   372  	if err != nil {
   373  		return nil, nil, err
   374  	}
   375  
   376  	update := false
   377  	for _, svc := range sctx.PU.Policy.DependentServices() {
   378  
   379  		addrs, ok := serviceAddresses[svc.ID]
   380  		if !ok {
   381  			continue
   382  		}
   383  
   384  		min, max := svc.NetworkInfo.Ports.Range()
   385  
   386  		for _, addr := range addrs {
   387  
   388  			if ip := net.ParseIP(addr); ip.To4() == nil {
   389  				continue
   390  			}
   391  
   392  			if _, exists := svc.NetworkInfo.Addresses[addr+"/32"]; exists {
   393  				continue
   394  			}
   395  
   396  			_, ipNet, _ := net.ParseCIDR(addr + "/32")
   397  			for i := int(min); i <= int(max); i++ {
   398  				if err := ipsetmanager.V4().AddIPPortToDependentService(contextID, ipNet, strconv.Itoa(i)); err != nil {
   399  					zap.L().Debug("Error adding dependent service ip port to ipset", zap.Error(err))
   400  				}
   401  			}
   402  
   403  			update = true
   404  			svc.NetworkInfo.Addresses[ipNet.String()] = struct{}{}
   405  		}
   406  	}
   407  
   408  	if update {
   409  		if err := serviceregistry.Instance().UpdateDependentServicesByID(contextID); err != nil {
   410  			zap.L().Error("Error updating dependent services", zap.Error(err))
   411  		}
   412  	}
   413  
   414  	return serviceregistry.Instance().RetrieveDependentServiceDataByIDAndNetwork(contextID, ip, port, "")
   415  }