Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions cmd/secrets/common/gateway/url.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package gateway

import (
"fmt"
"net"
"net/url"
"strings"
)

// ValidateGatewayURL rejects vault gateway URLs that are not HTTPS with a host,
// except for HTTP on loopback hosts used by local development and integration tests.
func ValidateGatewayURL(raw string) error {
u, err := url.Parse(strings.TrimSpace(raw))
if err != nil {
return fmt.Errorf("invalid vault gateway URL: %w", err)
}
if u.Scheme == "" {
return fmt.Errorf("invalid vault gateway URL")
}
if u.Host == "" {
return fmt.Errorf("vault gateway URL is missing a host")
}

host := u.Hostname()
switch u.Scheme {
case "https":
return nil
case "http":
if isLoopbackHost(host) {
return nil
}
return fmt.Errorf("vault gateway URL must use https://, got %q", u.Scheme)
default:
return fmt.Errorf("vault gateway URL must use https://, got %q", u.Scheme)
}
}

func isLoopbackHost(host string) bool {
if host == "localhost" {
return true
}
ip := net.ParseIP(host)
return ip != nil && ip.IsLoopback()
}
35 changes: 35 additions & 0 deletions cmd/secrets/common/gateway/url_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package gateway

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestValidateGatewayURL(t *testing.T) {
require.NoError(t, ValidateGatewayURL("https://gateway.example.com/"))
require.NoError(t, ValidateGatewayURL("https://gateway.example.com/v1"))
require.NoError(t, ValidateGatewayURL("http://127.0.0.1:57244"))
require.NoError(t, ValidateGatewayURL("http://localhost:8080"))
require.NoError(t, ValidateGatewayURL("http://[::1]:8080"))

err := ValidateGatewayURL("http://gateway.example.com/")
require.Error(t, err)
require.Contains(t, err.Error(), "https://")

err = ValidateGatewayURL("http://10.0.0.1/")
require.Error(t, err)
require.Contains(t, err.Error(), "https://")

err = ValidateGatewayURL("http://127.0.0.1.evil.com/")
require.Error(t, err)
require.Contains(t, err.Error(), "https://")

err = ValidateGatewayURL("https://")
require.Error(t, err)
require.Contains(t, err.Error(), "missing a host")

err = ValidateGatewayURL("not-a-url")
require.Error(t, err)
require.Contains(t, err.Error(), "invalid vault gateway URL")
}
3 changes: 3 additions & 0 deletions cmd/secrets/common/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ func NewHandler(execCtx context.Context, ctx *runtime.Context, secretsFilePath,
execCtx: execCtx,
}
h.GatewayURL = gateway.ResolveVaultGatewayURL(ctx.TenantContext, ctx.EnvironmentSet)
if err := gateway.ValidateGatewayURL(h.GatewayURL); err != nil {
return nil, err
}
h.Gw = &gateway.HTTPClient{URL: h.GatewayURL, Client: &http.Client{Timeout: 90 * time.Second}}

if !IsBrowserFlow(secretsAuth) {
Expand Down
18 changes: 18 additions & 0 deletions cmd/secrets/common/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -475,4 +475,22 @@ func TestNewHandler_GatewayURL(t *testing.T) {
require.True(t, ok)
require.Equal(t, "https://env-override.example.com/", gw.URL)
})

t.Run("rejects non-https remote gateway URL", func(t *testing.T) {
t.Setenv(environments.EnvVarVaultGatewayURL, "")
ctx := *baseCtx
ctx.TenantContext = &tenantctx.EnvironmentContext{VaultGatewayURL: "http://insecure.example.com/"}
_, err := NewHandler(context.Background(), &ctx, "", SecretsAuthBrowser)
require.Error(t, err)
require.Contains(t, err.Error(), "https://")
})

t.Run("allows http loopback gateway URL", func(t *testing.T) {
t.Setenv(environments.EnvVarVaultGatewayURL, "")
ctx := *baseCtx
ctx.TenantContext = &tenantctx.EnvironmentContext{VaultGatewayURL: "http://127.0.0.1:1234"}
h, err := NewHandler(context.Background(), &ctx, "", SecretsAuthBrowser)
require.NoError(t, err)
require.Equal(t, "http://127.0.0.1:1234", h.GatewayURL)
})
}
Loading