github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/pkg/remoteenforcer/remoteenforcer_linux.go (about)

     1  // +build linux
     2  
     3  package remoteenforcer
     4  
     5  /*
     6  #cgo CFLAGS: -Wall
     7  #include <stdlib.h>
     8  */
     9  import "C"
    10  
    11  import (
    12  	"context"
    13  	"fmt"
    14  	"os"
    15  	"os/exec"
    16  	"os/signal"
    17  	"strings"
    18  	"sync"
    19  	"syscall"
    20  
    21  	"github.com/blang/semver"
    22  	"go.aporeto.io/enforcerd/internal/diagnostics"
    23  	"go.aporeto.io/enforcerd/internal/logging/remotelog"
    24  	"go.aporeto.io/enforcerd/trireme-lib/controller/constants"
    25  	"go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer"
    26  	_ "go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/utils/nsenter" // nolint
    27  	"go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/utils/rpcwrapper"
    28  	"go.aporeto.io/enforcerd/trireme-lib/controller/internal/supervisor"
    29  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/fqconfig"
    30  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/remoteenforcer/internal/client"
    31  	reports "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/remoteenforcer/internal/client/reportsclient"
    32  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/remoteenforcer/internal/client/statsclient"
    33  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/remoteenforcer/internal/statscollector"
    34  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/remoteenforcer/internal/tokenissuer"
    35  	"go.aporeto.io/enforcerd/trireme-lib/controller/pkg/secrets/rpc"
    36  	"go.aporeto.io/enforcerd/trireme-lib/policy"
    37  	"go.uber.org/zap"
    38  	"golang.org/x/sys/unix"
    39  )
    40  
    41  // Initialization functions as variables in order to enable testing.
    42  var (
    43  	createEnforcer = enforcer.New
    44  
    45  	createSupervisor = supervisor.NewSupervisor
    46  )
    47  
    48  var cmdLock sync.Mutex
    49  
    50  // newRemoteEnforcer starts a new server
    51  func newRemoteEnforcer(
    52  	ctx context.Context,
    53  	rpcHandle rpcwrapper.RPCServer,
    54  	secret string,
    55  	statsClient client.Reporter,
    56  	collector statscollector.Collector,
    57  	reportsClient client.Reporter,
    58  	tokenIssuer tokenissuer.TokenClient,
    59  	logLevel string,
    60  	logFormat string,
    61  	logID string,
    62  	numQueues int,
    63  	enforcerType policy.EnforcerType,
    64  	agentVersion semver.Version,
    65  ) (*RemoteEnforcer, error) {
    66  
    67  	var err error
    68  
    69  	if collector == nil {
    70  		collector = statscollector.NewCollector()
    71  	}
    72  
    73  	if statsClient == nil {
    74  		statsClient, err = statsclient.NewStatsClient(collector)
    75  		if err != nil {
    76  			return nil, err
    77  		}
    78  	}
    79  
    80  	if reportsClient == nil {
    81  		reportsClient, err = reports.NewClient(collector)
    82  		if err != nil {
    83  			return nil, err
    84  		}
    85  	}
    86  
    87  	if tokenIssuer == nil {
    88  		tokenIssuer, err = tokenissuer.NewClient()
    89  		if err != nil {
    90  			return nil, err
    91  		}
    92  
    93  	}
    94  
    95  	procMountPoint := os.Getenv(constants.EnvMountPoint)
    96  	if procMountPoint == "" {
    97  		procMountPoint = constants.DefaultProcMountPoint
    98  	}
    99  
   100  	fqConfig := fqconfig.NewFilterQueue(
   101  		numQueues,
   102  		[]string{"0.0.0.0/0"},
   103  	)
   104  
   105  	return &RemoteEnforcer{
   106  		collector:      collector,
   107  		rpcSecret:      secret,
   108  		rpcHandle:      rpcHandle,
   109  		procMountPoint: procMountPoint,
   110  		statsClient:    statsClient,
   111  		reportsClient:  reportsClient,
   112  		ctx:            ctx,
   113  		exit:           make(chan bool),
   114  		tokenIssuer:    tokenIssuer,
   115  		enforcerType:   enforcerType,
   116  		agentVersion:   agentVersion,
   117  		config:         logConfig{logLevel: logLevel, logFormat: logFormat, logID: logID},
   118  		fqConfig:       fqConfig,
   119  	}, nil
   120  }
   121  
   122  // InitEnforcer is a function called from the controller using RPC. It intializes
   123  // data structure required by the remote enforcer
   124  func (s *RemoteEnforcer) InitEnforcer(req rpcwrapper.Request, resp *rpcwrapper.Response) error {
   125  
   126  	zap.L().Debug("Configuring remote enforcer")
   127  
   128  	if !s.rpcHandle.CheckValidity(&req, s.rpcSecret) {
   129  		resp.Status = fmt.Sprintf("init message authentication failed") // nolint:gosimple
   130  		return fmt.Errorf(resp.Status)
   131  	}
   132  	cmdLock.Lock()
   133  	defer cmdLock.Unlock()
   134  
   135  	payload, ok := req.Payload.(rpcwrapper.InitRequestPayload)
   136  	if !ok {
   137  		resp.Status = fmt.Sprintf("invalid request payload") // nolint:gosimple
   138  		return fmt.Errorf(resp.Status)
   139  	}
   140  
   141  	if s.supervisor != nil || s.enforcer != nil {
   142  		resp.Status = fmt.Sprintf("remote enforcer is already initialized") // nolint:gosimple
   143  		return fmt.Errorf(resp.Status)
   144  	}
   145  
   146  	var err error
   147  
   148  	defer func() {
   149  		if err != nil {
   150  			s.cleanup()
   151  		}
   152  	}()
   153  
   154  	if err = s.setupEnforcer(&payload); err != nil {
   155  		resp.Status = err.Error()
   156  		return fmt.Errorf(resp.Status)
   157  	}
   158  
   159  	if err = s.setupSupervisor(&payload); err != nil {
   160  		resp.Status = err.Error()
   161  		return fmt.Errorf(resp.Status)
   162  	}
   163  
   164  	if err = s.enforcer.Run(s.ctx); err != nil {
   165  		resp.Status = err.Error()
   166  		return fmt.Errorf(resp.Status)
   167  	}
   168  
   169  	if err = s.statsClient.Run(s.ctx); err != nil {
   170  		resp.Status = err.Error()
   171  		return fmt.Errorf(resp.Status)
   172  	}
   173  
   174  	if err = s.supervisor.Run(s.ctx); err != nil {
   175  		resp.Status = err.Error()
   176  		return fmt.Errorf(resp.Status)
   177  	}
   178  
   179  	if err = s.reportsClient.Run(s.ctx); err != nil {
   180  		resp.Status = "ReportsClient" + err.Error()
   181  		return fmt.Errorf(resp.Status)
   182  	}
   183  
   184  	if err = s.tokenIssuer.Run(s.ctx); err != nil {
   185  		resp.Status = "TokenIssuer" + err.Error()
   186  		return fmt.Errorf(resp.Status)
   187  	}
   188  
   189  	resp.Status = ""
   190  
   191  	return nil
   192  }
   193  
   194  // Enforce this method calls the enforce method on the enforcer created during initenforcer
   195  func (s *RemoteEnforcer) Enforce(req rpcwrapper.Request, resp *rpcwrapper.Response) error {
   196  
   197  	if !s.rpcHandle.CheckValidity(&req, s.rpcSecret) {
   198  		resp.Status = "enforce message auth failed"
   199  		return fmt.Errorf(resp.Status)
   200  	}
   201  
   202  	cmdLock.Lock()
   203  	defer cmdLock.Unlock()
   204  
   205  	payload, ok := req.Payload.(rpcwrapper.EnforcePayload)
   206  	if !ok {
   207  		resp.Status = "invalid enforcer payload"
   208  		return fmt.Errorf(resp.Status)
   209  	}
   210  
   211  	plc, err := payload.Policy.ToPrivatePolicy(s.ctx, true)
   212  	if err != nil {
   213  		return err
   214  	}
   215  
   216  	runtime := policy.NewPURuntimeWithDefaults()
   217  
   218  	puInfo := &policy.PUInfo{
   219  		ContextID: payload.ContextID,
   220  		Policy:    plc,
   221  		Runtime:   runtime,
   222  	}
   223  
   224  	if s.enforcer == nil || s.supervisor == nil {
   225  		resp.Status = "enforcer not initialized - cannot enforce"
   226  		return fmt.Errorf(resp.Status)
   227  	}
   228  
   229  	// If any error happens, cleanup everything on exit so that we can recover
   230  	// by launcing a new remote.
   231  	defer func() {
   232  		if err != nil {
   233  			s.cleanup()
   234  		}
   235  	}()
   236  
   237  	if err = s.supervisor.Supervise(payload.ContextID, puInfo); err != nil {
   238  		resp.Status = err.Error()
   239  		return err
   240  	}
   241  
   242  	if err = s.enforcer.Enforce(s.ctx, payload.ContextID, puInfo); err != nil {
   243  		resp.Status = err.Error()
   244  		return err
   245  	}
   246  
   247  	resp.Status = ""
   248  
   249  	return nil
   250  }
   251  
   252  // Unenforce this method calls the unenforce method on the enforcer created from initenforcer
   253  func (s *RemoteEnforcer) Unenforce(req rpcwrapper.Request, resp *rpcwrapper.Response) error {
   254  
   255  	if !s.rpcHandle.CheckValidity(&req, s.rpcSecret) {
   256  		resp.Status = "unenforce message auth failed"
   257  		return fmt.Errorf(resp.Status)
   258  	}
   259  
   260  	cmdLock.Lock()
   261  	defer cmdLock.Unlock()
   262  
   263  	s.statsClient.Send() // nolint: errcheck
   264  
   265  	payload, ok := req.Payload.(rpcwrapper.UnEnforcePayload)
   266  	if !ok {
   267  		resp.Status = "invalid unenforcer payload"
   268  		return fmt.Errorf(resp.Status)
   269  	}
   270  
   271  	var err error
   272  
   273  	// If any error happens, cleanup everything on exit so that we can recover
   274  	// by launcing a new remote.
   275  	defer func() {
   276  		if err != nil {
   277  			s.cleanup()
   278  		}
   279  	}()
   280  
   281  	if err = s.supervisor.Unsupervise(payload.ContextID); err != nil {
   282  		resp.Status = err.Error()
   283  		return fmt.Errorf("unable to clean supervisor: %s", err)
   284  	}
   285  
   286  	if err = s.enforcer.Unenforce(s.ctx, payload.ContextID); err != nil {
   287  		resp.Status = err.Error()
   288  		return fmt.Errorf("unable to stop enforcer: %s", err)
   289  	}
   290  
   291  	return nil
   292  }
   293  
   294  // SetTargetNetworks calls the same method on the actual enforcer
   295  func (s *RemoteEnforcer) SetTargetNetworks(req rpcwrapper.Request, resp *rpcwrapper.Response) error {
   296  
   297  	var err error
   298  	if !s.rpcHandle.CheckValidity(&req, s.rpcSecret) {
   299  		resp.Status = "SetTargetNetworks message auth failed" // nolint
   300  		return fmt.Errorf(resp.Status)
   301  	}
   302  
   303  	cmdLock.Lock()
   304  	defer cmdLock.Unlock()
   305  
   306  	if s.enforcer == nil || s.supervisor == nil {
   307  		return fmt.Errorf(resp.Status)
   308  	}
   309  
   310  	payload := req.Payload.(rpcwrapper.SetTargetNetworksPayload)
   311  
   312  	// If any error happens, cleanup everything on exit so that we can recover
   313  	// by launcing a new remote.
   314  	defer func() {
   315  		if err != nil {
   316  			s.cleanup()
   317  		}
   318  	}()
   319  
   320  	if err = s.enforcer.SetTargetNetworks(payload.Configuration); err != nil {
   321  		return err
   322  	}
   323  
   324  	err = s.supervisor.SetTargetNetworks(payload.Configuration)
   325  
   326  	return err
   327  }
   328  
   329  // EnforcerExit is processing messages from the remote that are requesting an exit. In this
   330  // case we simply cancel the context.
   331  func (s *RemoteEnforcer) EnforcerExit(req rpcwrapper.Request, resp *rpcwrapper.Response) error {
   332  
   333  	s.cleanup()
   334  
   335  	s.exit <- true
   336  
   337  	return nil
   338  }
   339  
   340  // UpdateSecrets updates the secrets used by the remote enforcer
   341  func (s *RemoteEnforcer) UpdateSecrets(req rpcwrapper.Request, resp *rpcwrapper.Response) error {
   342  	var err error
   343  	if !s.rpcHandle.CheckValidity(&req, s.rpcSecret) {
   344  		resp.Status = "updatesecrets auth failed"
   345  		return fmt.Errorf(resp.Status)
   346  	}
   347  
   348  	cmdLock.Lock()
   349  	defer cmdLock.Unlock()
   350  	if s.enforcer == nil {
   351  		return fmt.Errorf(resp.Status)
   352  	}
   353  
   354  	// If any error happens, cleanup everything on exit so that we can recover
   355  	// by launcing a new remote.
   356  	defer func() {
   357  		if err != nil {
   358  			s.cleanup()
   359  		}
   360  	}()
   361  
   362  	payload := req.Payload.(rpcwrapper.UpdateSecretsPayload)
   363  	s.secrets, err = rpc.NewSecrets(payload.Secrets)
   364  	if err != nil {
   365  		return err
   366  	}
   367  
   368  	err = s.enforcer.UpdateSecrets(s.secrets)
   369  
   370  	return err
   371  }
   372  
   373  // EnableDatapathPacketTracing enable nfq datapath packet tracing
   374  func (s *RemoteEnforcer) EnableDatapathPacketTracing(req rpcwrapper.Request, resp *rpcwrapper.Response) error {
   375  
   376  	if !s.rpcHandle.CheckValidity(&req, s.rpcSecret) {
   377  		resp.Status = "enable datapath packet tracing auth failed"
   378  		return fmt.Errorf(resp.Status)
   379  	}
   380  
   381  	cmdLock.Lock()
   382  	defer cmdLock.Unlock()
   383  
   384  	payload := req.Payload.(rpcwrapper.EnableDatapathPacketTracingPayLoad)
   385  
   386  	if err := s.enforcer.EnableDatapathPacketTracing(s.ctx, payload.ContextID, payload.Direction, payload.Interval); err != nil {
   387  		resp.Status = err.Error()
   388  		return err
   389  	}
   390  
   391  	resp.Status = ""
   392  	return nil
   393  }
   394  
   395  // EnableIPTablesPacketTracing enables iptables trace packet tracing
   396  func (s *RemoteEnforcer) EnableIPTablesPacketTracing(req rpcwrapper.Request, resp *rpcwrapper.Response) error {
   397  
   398  	if !s.rpcHandle.CheckValidity(&req, s.rpcSecret) {
   399  		resp.Status = "enable iptable packet tracing auth failed"
   400  		return fmt.Errorf(resp.Status)
   401  	}
   402  
   403  	cmdLock.Lock()
   404  	defer cmdLock.Unlock()
   405  
   406  	payload := req.Payload.(rpcwrapper.EnableIPTablesPacketTracingPayLoad)
   407  
   408  	if err := s.supervisor.EnableIPTablesPacketTracing(s.ctx, payload.ContextID, payload.Interval); err != nil {
   409  		resp.Status = err.Error()
   410  		return err
   411  	}
   412  
   413  	resp.Status = ""
   414  	return nil
   415  }
   416  
   417  // Ping runs ping to the given config
   418  func (s *RemoteEnforcer) Ping(req rpcwrapper.Request, resp *rpcwrapper.Response) error {
   419  
   420  	if !s.rpcHandle.CheckValidity(&req, s.rpcSecret) {
   421  		resp.Status = "ping auth failed"
   422  		return fmt.Errorf(resp.Status)
   423  	}
   424  
   425  	cmdLock.Lock()
   426  	defer cmdLock.Unlock()
   427  
   428  	payload := req.Payload.(rpcwrapper.PingPayload)
   429  
   430  	if err := s.enforcer.Ping(s.ctx, payload.ContextID, payload.PingConfig); err != nil {
   431  		resp.Status = err.Error()
   432  		return err
   433  	}
   434  
   435  	resp.Status = ""
   436  	return nil
   437  }
   438  
   439  // DebugCollect collects the desired debug information
   440  func (s *RemoteEnforcer) DebugCollect(req rpcwrapper.Request, resp *rpcwrapper.Response) error {
   441  
   442  	if !s.rpcHandle.CheckValidity(&req, s.rpcSecret) {
   443  		resp.Status = "debug collect auth failed"
   444  		return fmt.Errorf(resp.Status)
   445  	}
   446  
   447  	cmdLock.Lock()
   448  	defer cmdLock.Unlock()
   449  
   450  	payload := req.Payload.(rpcwrapper.DebugCollectPayload)
   451  
   452  	var commandOutput string
   453  	var pid int
   454  
   455  	if payload.CommandExec != "" {
   456  		if values := strings.Split(payload.CommandExec, " "); len(values) >= 1 {
   457  			cmd := exec.CommandContext(s.ctx, values[0], values[1:]...)
   458  			output, err := cmd.CombinedOutput()
   459  			if err != nil {
   460  				resp.Status = err.Error()
   461  				return err
   462  			}
   463  			commandOutput = string(output)
   464  		}
   465  	} else if payload.PcapFilePath != "" {
   466  		cmd, err := diagnostics.StartTcpdump(s.ctx, payload.PcapFilePath, payload.PcapFilter)
   467  		if err != nil {
   468  			resp.Status = err.Error()
   469  			return err
   470  		}
   471  
   472  		// spawn goroutine to call Wait() so we don't have defunct child process
   473  		go func() {
   474  			if err := cmd.Wait(); err != nil {
   475  				zap.L().Warn("DebugCollect Wait failed on tcpdump process", zap.Error(err))
   476  			}
   477  		}()
   478  
   479  		pid = cmd.Process.Pid
   480  	} else {
   481  		// otherwise, return pid of remote enforcer
   482  		pid = os.Getpid()
   483  	}
   484  
   485  	resp.Status = ""
   486  	resp.Payload = rpcwrapper.DebugCollectResponsePayload{
   487  		ContextID:     payload.ContextID,
   488  		PID:           pid,
   489  		CommandOutput: commandOutput,
   490  	}
   491  	return nil
   492  }
   493  
   494  // SetLogLevel sets log level.
   495  func (s *RemoteEnforcer) SetLogLevel(req rpcwrapper.Request, resp *rpcwrapper.Response) error {
   496  
   497  	if !s.rpcHandle.CheckValidity(&req, s.rpcSecret) {
   498  		resp.Status = "set log level auth failed"
   499  		return fmt.Errorf(resp.Status)
   500  	}
   501  
   502  	cmdLock.Lock()
   503  	defer cmdLock.Unlock()
   504  	if s.enforcer == nil {
   505  		return fmt.Errorf(resp.Status)
   506  	}
   507  
   508  	payload := req.Payload.(rpcwrapper.SetLogLevelPayload)
   509  
   510  	newLevel := triremeLogLevelToString(payload.Level)
   511  	if payload.Level != "" && s.config.logLevel != newLevel {
   512  		remotelog.SetupRemoteLogger(newLevel, s.config.logFormat, s.config.logID) // nolint: errcheck
   513  		s.config.logLevel = newLevel
   514  
   515  		if err := s.enforcer.SetLogLevel(payload.Level); err != nil {
   516  			resp.Status = err.Error()
   517  			return err
   518  		}
   519  	}
   520  
   521  	resp.Status = ""
   522  	return nil
   523  }
   524  
   525  func triremeLogLevelToString(level constants.LogLevel) string {
   526  	switch level {
   527  	case constants.Debug:
   528  		return "debug"
   529  	case constants.Trace:
   530  		return "trace"
   531  	case constants.Error:
   532  		return "error"
   533  	case constants.Info:
   534  		return "info"
   535  	case constants.Warn:
   536  		return "warn"
   537  	default:
   538  		return "info"
   539  	}
   540  }
   541  
   542  // setup an enforcer
   543  func (s *RemoteEnforcer) setupEnforcer(payload *rpcwrapper.InitRequestPayload) error {
   544  
   545  	var err error
   546  
   547  	s.secrets, err = rpc.NewSecrets(payload.Secrets)
   548  	if err != nil {
   549  		return err
   550  	}
   551  
   552  	// we are usually always starting RemoteContainer enforcers,
   553  	// however, if envoy is requested, we change the mode to RemoteContainerEnvoyAuthorizer
   554  	mode := constants.RemoteContainer
   555  	if s.enforcerType == policy.EnvoyAuthorizerEnforcer {
   556  		mode = constants.RemoteContainerEnvoyAuthorizer
   557  	}
   558  
   559  	if s.enforcer, err = createEnforcer(
   560  		payload.MutualAuth,
   561  		s.fqConfig,
   562  		s.collector,
   563  		s.secrets,
   564  		payload.ServerID,
   565  		payload.Validity,
   566  		mode,
   567  		s.procMountPoint,
   568  		payload.ExternalIPCacheTimeout,
   569  		payload.PacketLogs,
   570  		payload.Configuration,
   571  		s.tokenIssuer,
   572  		payload.IsBPFEnabled,
   573  		s.agentVersion,
   574  		payload.ServiceMeshType,
   575  	); err != nil || s.enforcer == nil {
   576  		return fmt.Errorf("Error while initializing remote enforcer, %s", err)
   577  	}
   578  
   579  	return nil
   580  }
   581  
   582  func (s *RemoteEnforcer) setupSupervisor(payload *rpcwrapper.InitRequestPayload) error {
   583  
   584  	// we are usually always starting RemoteContainer enforcers,
   585  	// however, if envoy is requested, we change the mode to RemoteContainerEnvoyAuthorizer
   586  	mode := constants.RemoteContainer
   587  	if s.enforcerType == policy.EnvoyAuthorizerEnforcer {
   588  		mode = constants.RemoteContainerEnvoyAuthorizer
   589  	}
   590  
   591  	h, err := createSupervisor(
   592  		s.collector,
   593  		s.enforcer,
   594  		mode,
   595  		payload.Configuration,
   596  		payload.IPv6Enabled,
   597  		payload.IPTablesLockfile,
   598  	)
   599  	if err != nil {
   600  		return fmt.Errorf("unable to setup supervisor: %s", err)
   601  	}
   602  	s.supervisor = h
   603  
   604  	return nil
   605  }
   606  
   607  // cleanup cleans all the acls and any state of the local enforcer.
   608  func (s *RemoteEnforcer) cleanup() {
   609  
   610  	if s.supervisor != nil {
   611  		if err := s.supervisor.CleanUp(); err != nil {
   612  			zap.L().Error("unable to clean supervisor state", zap.Error(err))
   613  		}
   614  	}
   615  
   616  	if s.enforcer != nil {
   617  		if err := s.enforcer.CleanUp(); err != nil {
   618  			zap.L().Error("unable to clean enforcer state", zap.Error(err))
   619  		}
   620  	}
   621  
   622  	if s.service != nil {
   623  		if err := s.service.Stop(); err != nil {
   624  			zap.L().Error("unable to clean service state", zap.Error(err))
   625  		}
   626  	}
   627  }
   628  
   629  // LaunchRemoteEnforcer launches a remote enforcer
   630  func LaunchRemoteEnforcer(ctx context.Context, logLevel, logFormat, logID string, numQueues int, agentVersion semver.Version) error {
   631  
   632  	// Before doing anything validate that we are in the right namespace.
   633  	if err := validateNamespace(); err != nil {
   634  		return err
   635  	}
   636  
   637  	namedPipe := os.Getenv(constants.EnvContextSocket)
   638  	secret := os.Getenv(constants.EnvRPCClientSecret)
   639  	if secret == "" {
   640  		zap.L().Fatal("No secret found")
   641  	}
   642  	os.Setenv(constants.EnvRPCClientSecret, "") // nolint: errcheck
   643  
   644  	flag := unix.SIGHUP
   645  	if err := unix.Prctl(unix.PR_SET_PDEATHSIG, uintptr(flag), 0, 0, 0); err != nil {
   646  		return err
   647  	}
   648  
   649  	enforcerType, err := policy.EnforcerTypeFromString(os.Getenv(constants.EnvEnforcerType))
   650  	if err != nil {
   651  		return err
   652  	}
   653  
   654  	rpcHandle := rpcwrapper.NewRPCServer()
   655  	re, err := newRemoteEnforcer(ctx, rpcHandle, secret, nil, nil, nil, nil, logLevel, logFormat, logID, numQueues, enforcerType, agentVersion)
   656  	if err != nil {
   657  		return err
   658  	}
   659  
   660  	go func() {
   661  		if err := rpcHandle.StartServer(ctx, "unix", namedPipe, re); err != nil {
   662  			zap.L().Fatal("Failed to start the RPC server", zap.Error(err))
   663  		}
   664  	}()
   665  
   666  	c := make(chan os.Signal, 1)
   667  	signal.Notify(c, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT)
   668  
   669  	select {
   670  
   671  	case <-re.exit:
   672  		zap.L().Info("Remote enforcer exiting ...")
   673  
   674  	case sig := <-c:
   675  		zap.L().Warn("Remote enforcer received a signal. exiting ...", zap.Any("signal", sig))
   676  		re.cleanup()
   677  		// TODO would be useful to set and return an exit code (instead of nil) to indicate the signal received
   678  
   679  	case <-ctx.Done():
   680  		re.cleanup()
   681  	}
   682  
   683  	return nil
   684  }
   685  
   686  // getCEnvVariable returns an environment variable set in the c context
   687  func getCEnvVariable(name string) string {
   688  
   689  	val := C.getenv(C.CString(name))
   690  	if val == nil {
   691  		return ""
   692  	}
   693  
   694  	return C.GoString(val)
   695  }
   696  
   697  func validateNamespace() error {
   698  	// Check if successfully switched namespace
   699  	nsEnterState := getCEnvVariable(constants.EnvNsenterErrorState)
   700  	nsEnterLogMsg := getCEnvVariable(constants.EnvNsenterLogs)
   701  	if nsEnterState != "" {
   702  		return fmt.Errorf("nsErr: %s nsLogs: %s", nsEnterState, nsEnterLogMsg)
   703  	}
   704  
   705  	return nil
   706  }