From d9b05f175de79f8d2be78db8ea2e2389f7b0855e Mon Sep 17 00:00:00 2001 From: Torin Sandall Date: Sat, 11 Mar 2017 20:55:28 -0800 Subject: [PATCH] Add support for additional HTTP listener Fixes #289 --- cmd/run.go | 1 + runtime/runtime.go | 19 ++++++++- server/server.go | 40 ++++++++++++++----- .../references/security/index.md | 5 ++- 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/cmd/run.go b/cmd/run.go index 3042bd027c..ab5485183c 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -134,6 +134,7 @@ to delete policies will remove the definition file. runCommand.Flags().StringVarP(¶ms.HistoryPath, "history", "H", historyPath(), "set path of history file") runCommand.Flags().StringVarP(¶ms.PolicyDir, "policy-dir", "p", "", "set directory to store policy definitions") runCommand.Flags().StringVarP(¶ms.Addr, "addr", "a", defaultAddr, "set listening address of the server") + runCommand.Flags().StringVarP(¶ms.InsecureAddr, "insecure-addr", "", "", "set insecure listening address of the server") runCommand.Flags().StringVarP(¶ms.OutputFormat, "format", "f", "pretty", "set shell output format, i.e, pretty, json") runCommand.Flags().BoolVarP(¶ms.Watch, "watch", "w", false, "watch command line files for changes") runCommand.Flags().StringVarP(&tlsCertFile, "tls-cert-file", "", "", "set path of TLS certificate file") diff --git a/runtime/runtime.go b/runtime/runtime.go index 150cd1532c..202618110a 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -32,6 +32,10 @@ type Params struct { // Addr is the listening address that the OPA server will bind to. Addr string + // InsecureAddr is the listening address that the OPA server will bind to + // in addition to Addr if TLS is enabled. + InsecureAddr string + // Authentication is the type of authentication scheme to use. Authentication server.AuthenticationScheme @@ -164,7 +168,8 @@ func (rt *Runtime) startServer(ctx context.Context, params *Params) { setupLogging(params.Logging) logrus.WithFields(logrus.Fields{ - "addr": params.Addr, + "addr": params.Addr, + "insecure_addr": params.InsecureAddr, }).Infof("First line of log stream.") persist := len(params.PolicyDir) > 0 @@ -172,6 +177,7 @@ func (rt *Runtime) startServer(ctx context.Context, params *Params) { s, err := server.New(). WithStorage(rt.Store). WithAddress(params.Addr). + WithInsecureAddress(params.InsecureAddr). WithPersist(persist). WithCertificate(params.Certificate). WithAuthentication(params.Authentication). @@ -184,7 +190,16 @@ func (rt *Runtime) startServer(ctx context.Context, params *Params) { s.Handler = NewLoggingHandler(s.Handler) - if err := s.Loop(); err != nil { + loop1, loop2 := s.Listeners() + if loop2 != nil { + go func() { + if err := loop2(); err != nil { + logrus.WithField("err", err).Fatalf("Server exiting.") + } + }() + } + + if err := loop1(); err != nil { logrus.WithField("err", err).Fatalf("Server exiting.") } } diff --git a/server/server.go b/server/server.go index ab7e266e95..f4dd4895df 100644 --- a/server/server.go +++ b/server/server.go @@ -59,6 +59,7 @@ type Server struct { Handler http.Handler addr string + insecureAddr string authentication AuthenticationScheme authorization AuthorizationScheme cert *tls.Certificate @@ -133,6 +134,12 @@ func (s *Server) WithAddress(addr string) *Server { return s } +// WithInsecureAddress sets the listening address that the server will bind to. +func (s *Server) WithInsecureAddress(addr string) *Server { + s.insecureAddr = addr + return s +} + // WithAuthentication sets authentication scheme to use on the server. func (s *Server) WithAuthentication(scheme AuthenticationScheme) *Server { s.authentication = scheme @@ -175,26 +182,37 @@ func (s *Server) Compiler() *ast.Compiler { return s.compiler } -// Loop starts the server. This function does not return. -func (s *Server) Loop() error { - httpServer := http.Server{ +// Listeners returns functions that listen and serve connections. +func (s *Server) Listeners() (func() error, func() error) { + + server1 := http.Server{ Addr: s.addr, Handler: s.Handler, } - if s.cert != nil { - httpServer.TLSConfig = &tls.Config{ + loop1 := func() error { return server1.ListenAndServe() } + + if s.cert == nil { + return loop1, nil + } + + server2 := http.Server{ + Addr: s.addr, + Handler: s.Handler, + TLSConfig: &tls.Config{ Certificates: []tls.Certificate{*s.cert}, - } + }, } - if httpServer.TLSConfig == nil { - return httpServer.ListenAndServe() + loop2 := func() error { return server2.ListenAndServeTLS("", "") } + + if s.insecureAddr == "" { + return loop2, nil } - // http.Server will ignore the cert and key file params if the - // TLSConfig.Certificates field is set. - return httpServer.ListenAndServeTLS("", "") + server1.Addr = s.insecureAddr + + return loop2, loop1 } func (s *Server) execQuery(ctx context.Context, compiler *ast.Compiler, txn storage.Transaction, query ast.Body, explainMode types.ExplainModeV1) (types.QueryResponseV1, error) { diff --git a/site/documentation/references/security/index.md b/site/documentation/references/security/index.md index c348f1b4c2..9e997de643 100644 --- a/site/documentation/references/security/index.md +++ b/site/documentation/references/security/index.md @@ -39,8 +39,9 @@ startup: OPA will exit immediately with a non-zero status code if only one of these flags is specified. -When TLS credentials are provided, OPA will ignore normal/insecure incoming HTTP -connections. +By default, OPA ignores insecure HTTP connections when TLS is enabled. To allow +insecure HTTP connections in addition to HTTPS connections, provide another +listening address with `--insecure-addr`. #### 1. Generate the TLS credentials for OPA (Example)