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 }