mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-12 19:32:48 -06:00
Bind OPA server to localhost interface by default
Currently OPA binds to the 0.0.0.0 interface by default, which allows the OPA server to be exposed to services running outside of the same machine. Though not inherently insecure in a trusted environment, it's good practice to bind OPA to the localhost interface by default if OPA is not intended to be exposed to remote services. This change also adds a new feature flag to `opa run` to allow users to enable future OPA compatible behavior. Fixes: #6286 Signed-off-by: Ashutosh Narkar <anarkar4387@gmail.com>
This commit is contained in:
+12
-2
@@ -21,8 +21,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
defaultAddr = ":8181" // default listening address for server
|
||||
defaultHistoryFile = ".opa_history" // default filename for shell history
|
||||
defaultAddr = ":8181" // default listening address for server
|
||||
defaultLocalAddr = "localhost:8181" // default listening address for server bound to localhost
|
||||
defaultHistoryFile = ".opa_history" // default filename for shell history
|
||||
)
|
||||
|
||||
type runCmdParams struct {
|
||||
@@ -176,6 +177,10 @@ updates might cause them to be dropped by OPA.
|
||||
OPA will automatically perform type checking based on a schema inferred from known input documents and report any errors
|
||||
resulting from the schema check. Currently this check is performed on OPA's Authorization Policy Input document and will
|
||||
be expanded in the future. To disable this, use the --skip-known-schema-check flag.
|
||||
|
||||
The --future-compat flag can be used to opt-in to OPA features and behaviors that will be enabled by default in future OPA releases.
|
||||
Current behaviors enabled by this flag include:
|
||||
- setting OPA's listening address to "localhost:8181" by default.
|
||||
`,
|
||||
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
@@ -200,6 +205,7 @@ be expanded in the future. To disable this, use the --skip-known-schema-check fl
|
||||
runCommand.Flags().BoolVar(&cmdParams.rt.H2CEnabled, "h2c", false, "enable H2C for HTTP listeners")
|
||||
runCommand.Flags().StringVarP(&cmdParams.rt.OutputFormat, "format", "f", "pretty", "set shell output format, i.e, pretty, json")
|
||||
runCommand.Flags().BoolVarP(&cmdParams.rt.Watch, "watch", "w", false, "watch command line files for changes")
|
||||
runCommand.Flags().BoolVar(&cmdParams.rt.FutureCompatibility, "future-compat", false, "opt-in to OPA features and behaviors that will be enabled by default in future OPA releases")
|
||||
addMaxErrorsFlag(runCommand.Flags(), &cmdParams.rt.ErrorLimit)
|
||||
runCommand.Flags().BoolVar(&cmdParams.rt.PprofEnabled, "pprof", false, "enables pprof endpoints")
|
||||
runCommand.Flags().StringVar(&cmdParams.tlsCertFile, "tls-cert-file", "", "set path of TLS certificate file")
|
||||
@@ -333,6 +339,10 @@ func initRuntime(ctx context.Context, params runCmdParams, args []string, addrSe
|
||||
rt.SetDistributedTracingLogging()
|
||||
rt.Params.AddrSetByUser = addrSetByUser
|
||||
|
||||
if !addrSetByUser && rt.Params.FutureCompatibility {
|
||||
rt.Params.Addrs = &[]string{defaultLocalAddr}
|
||||
}
|
||||
|
||||
return rt, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,48 @@ func TestRunServerBase(t *testing.T) {
|
||||
<-done
|
||||
}
|
||||
|
||||
func TestRunServerBaseListenOnLocalhost(t *testing.T) {
|
||||
params := newTestRunParams()
|
||||
params.rt.FutureCompatibility = true
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
rt, err := initRuntime(ctx, params, nil, false)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
testRuntime := e2e.WrapRuntime(ctx, cancel, rt)
|
||||
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
err := rt.Serve(ctx)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error: %s", err)
|
||||
}
|
||||
done <- true
|
||||
}()
|
||||
|
||||
err = testRuntime.WaitForServer()
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %s", err)
|
||||
}
|
||||
|
||||
validateBasicServe(t, testRuntime)
|
||||
|
||||
if len(rt.Addrs()) != 1 {
|
||||
t.Fatalf("Expected 1 listening address but got %v", len(rt.Addrs()))
|
||||
}
|
||||
|
||||
expected := "127.0.0.1:8181"
|
||||
if rt.Addrs()[0] != expected {
|
||||
t.Fatalf("Expected listening address %v but got %v", expected, rt.Addrs()[0])
|
||||
}
|
||||
|
||||
cancel()
|
||||
<-done
|
||||
}
|
||||
|
||||
func TestRunServerWithDiagnosticAddr(t *testing.T) {
|
||||
params := newTestRunParams()
|
||||
params.rt.DiagnosticAddrs = &[]string{"localhost:0"}
|
||||
|
||||
@@ -1022,7 +1022,8 @@ You can start OPA as a server with `-s` or `--server`:
|
||||
|
||||
By default OPA listens for HTTP connections on `0.0.0.0:8181`. See `opa run
|
||||
--help` for a list of options to change the listening address, enable TLS, and
|
||||
more.
|
||||
more. For example, if the `--future-compat` flag is set, OPA will listen
|
||||
for HTTP connections on `localhost:8181` by default.
|
||||
|
||||
Inside of another terminal use `curl` (or a similar tool) to access OPA's HTTP
|
||||
API. When you query the `/v1/data` HTTP API you must wrap input data inside of a
|
||||
|
||||
@@ -33,6 +33,7 @@ command line arguments for OPA's server mode are:
|
||||
* `--addr` to set the listening address (default: `0.0.0.0:8181`).
|
||||
* `--log-level` (or `-l`) to set the log level (default: `"info"`).
|
||||
* `--log-format` to set the log format (default: `"json"`).
|
||||
* `--future-compat` to opt-in to OPA features and behaviors that will be enabled by default in future OPA releases. For example, setting the listening address to `localhost:8181` by default.
|
||||
|
||||
By default, OPA listens for normal HTTP connections on `0.0.0.0:8181`. To make
|
||||
OPA listen for HTTPS connections, see [Security](../security).
|
||||
|
||||
@@ -102,6 +102,10 @@ By default, OPA binds to the 0.0.0.0 interface, which allows the OPA server to b
|
||||
|
||||
In situations where OPA is not intended to be exposed to remote services, it is recommended to bind OPA to the localhost interface, which only allows connections from the same machine. If it is necessary to expose OPA to remote services, ensure to follow the security recommendations on this page, such as requiring authentication.
|
||||
|
||||
{{< info >}}
|
||||
The `--future-compat` flag can be set on `opa run` to opt-in to OPA features and behaviors that will be enabled by default in future OPA releases. For example, if the `--future-compat` flag is set, OPA will listen
|
||||
for HTTP connections on `localhost:8181` by default.
|
||||
{{< /info >}}
|
||||
|
||||
## Authentication and Authorization
|
||||
|
||||
|
||||
+6
-1
@@ -224,6 +224,11 @@ type Params struct {
|
||||
|
||||
// UnixSocketPerm specifies the permission for the Unix domain socket if used to listen for connections
|
||||
UnixSocketPerm *string
|
||||
|
||||
// FutureCompatibility will enable OPA features and behaviors that will be enabled by default in future OPA releases.
|
||||
// This flag allows users to opt-in to the new behavior and helps transition to a future release upon which
|
||||
// the new behavior will be enabled by default.
|
||||
FutureCompatibility bool
|
||||
}
|
||||
|
||||
// LoggingConfig stores the configuration for OPA's logging behaviour.
|
||||
@@ -472,7 +477,7 @@ func (rt *Runtime) Serve(ctx context.Context) error {
|
||||
}
|
||||
|
||||
serverInitializingMessage := "Initializing server."
|
||||
if !rt.Params.AddrSetByUser {
|
||||
if !rt.Params.AddrSetByUser && !rt.Params.FutureCompatibility {
|
||||
serverInitializingMessage += " OPA is running on a public (0.0.0.0) network interface. Unless you intend to expose OPA outside of the host, binding to the localhost interface (--addr localhost:8181) is recommended. See https://www.openpolicyagent.org/docs/latest/security/#interface-binding"
|
||||
}
|
||||
|
||||
|
||||
@@ -556,12 +556,15 @@ func getTestRuntime(ctx context.Context, t *testing.T, logger logging.Logger) *R
|
||||
|
||||
func TestAddrWarningMessage(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
addrSetByUser bool
|
||||
containsMsg bool
|
||||
name string
|
||||
addrSetByUser bool
|
||||
containsMsg bool
|
||||
futureCompatibility bool
|
||||
}{
|
||||
{"WarningMessage", false, true},
|
||||
{"NoWarningMessage", true, false},
|
||||
{"WarningMessage", false, true, false},
|
||||
{"NoWarningMessage", true, false, false},
|
||||
{"FutureCompatibilityEnabled", false, false, true},
|
||||
{"FutureCompatibilityDisabled", false, true, false},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@@ -578,6 +581,7 @@ func TestAddrWarningMessage(t *testing.T) {
|
||||
params.Addrs = &[]string{"localhost:8181"}
|
||||
params.AddrSetByUser = tc.addrSetByUser
|
||||
params.GracefulShutdownPeriod = 1
|
||||
params.FutureCompatibility = tc.futureCompatibility
|
||||
rt, err := NewRuntime(ctx, params)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v", err)
|
||||
|
||||
Reference in New Issue
Block a user