mirror of
https://github.com/pomerium/pomerium.git
synced 2025-07-04 18:38:12 +02:00
ssh: add envoy configuration (#5659)
## Summary Adds the envoy listener config logic for ssh. ## Related issues <!-- For example... - #159 --> ## User Explanation <!-- How would you explain this change to the user? If this change doesn't create any user-facing changes, you can leave this blank. If filled out, add the `docs` label --> ## Checklist - [ ] reference any related issues - [ ] updated unit tests - [ ] add appropriate label (`enhancement`, `bug`, `breaking`, `dependencies`, `ci`) - [ ] ready for review
This commit is contained in:
parent
6a65c52a6c
commit
ac76aeb279
10 changed files with 409 additions and 11 deletions
16
authorize/ssh_grpc.go
Normal file
16
authorize/ssh_grpc.go
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package authorize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
|
||||||
|
extensions_ssh "github.com/pomerium/envoy-custom/api/extensions/filters/network/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *Authorize) ManageStream(extensions_ssh.StreamManagement_ManageStreamServer) error {
|
||||||
|
return status.Errorf(codes.Unimplemented, "method ManageStream not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Authorize) ServeChannel(extensions_ssh.StreamManagement_ServeChannelServer) error {
|
||||||
|
return status.Errorf(codes.Unimplemented, "method ServeChannel not implemented")
|
||||||
|
}
|
|
@ -65,6 +65,16 @@ func (b *Builder) BuildListeners(
|
||||||
listeners = append(listeners, li)
|
listeners = append(listeners, li)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if shouldStartSSHListener(cfg.Options) {
|
||||||
|
li, err := buildSSHListener(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if li != nil {
|
||||||
|
listeners = append(listeners, li)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
li, err := b.buildOutboundListener(cfg)
|
li, err := b.buildOutboundListener(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
198
config/envoyconfig/listeners_ssh.go
Normal file
198
config/envoyconfig/listeners_ssh.go
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
package envoyconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
xds_core_v3 "github.com/cncf/xds/go/xds/core/v3"
|
||||||
|
xds_matcher_v3 "github.com/cncf/xds/go/xds/type/matcher/v3"
|
||||||
|
envoy_config_core_v3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
||||||
|
envoy_config_listener_v3 "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
|
||||||
|
envoy_generic_proxy_action_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/generic_proxy/action/v3"
|
||||||
|
envoy_generic_proxy_matcher_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/generic_proxy/matcher/v3"
|
||||||
|
envoy_generic_router_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/generic_proxy/router/v3"
|
||||||
|
envoy_generic_proxy_v3 "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/generic_proxy/v3"
|
||||||
|
matcherv3 "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3"
|
||||||
|
"google.golang.org/protobuf/types/known/durationpb"
|
||||||
|
|
||||||
|
extensions_ssh "github.com/pomerium/envoy-custom/api/extensions/filters/network/ssh"
|
||||||
|
"github.com/pomerium/pomerium/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func buildSSHListener(cfg *config.Config) (*envoy_config_listener_v3.Listener, error) {
|
||||||
|
if cfg.Options.SSHAddr == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
rc, err := buildRouteConfig(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if rc == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
authorizeService := &envoy_config_core_v3.GrpcService{
|
||||||
|
Timeout: durationpb.New(0),
|
||||||
|
TargetSpecifier: &envoy_config_core_v3.GrpcService_EnvoyGrpc_{
|
||||||
|
EnvoyGrpc: &envoy_config_core_v3.GrpcService_EnvoyGrpc{
|
||||||
|
ClusterName: "pomerium-authorize",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var hostKeyDataSources []*envoy_config_core_v3.DataSource
|
||||||
|
if cfg.Options.SSHHostKeyFiles != nil {
|
||||||
|
for _, filename := range *cfg.Options.SSHHostKeyFiles {
|
||||||
|
hostKeyDataSources = append(hostKeyDataSources, &envoy_config_core_v3.DataSource{
|
||||||
|
Specifier: &envoy_config_core_v3.DataSource_Filename{
|
||||||
|
Filename: filename,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cfg.Options.SSHHostKeys != nil {
|
||||||
|
for _, key := range *cfg.Options.SSHHostKeys {
|
||||||
|
hostKeyDataSources = append(hostKeyDataSources, &envoy_config_core_v3.DataSource{
|
||||||
|
Specifier: &envoy_config_core_v3.DataSource_InlineString{
|
||||||
|
InlineString: key,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var userCaKeyDataSource *envoy_config_core_v3.DataSource
|
||||||
|
if cfg.Options.SSHUserCAKeyFile != "" {
|
||||||
|
userCaKeyDataSource = &envoy_config_core_v3.DataSource{
|
||||||
|
Specifier: &envoy_config_core_v3.DataSource_Filename{
|
||||||
|
Filename: cfg.Options.SSHUserCAKeyFile,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else if cfg.Options.SSHUserCAKey != "" {
|
||||||
|
userCaKeyDataSource = &envoy_config_core_v3.DataSource{
|
||||||
|
Specifier: &envoy_config_core_v3.DataSource_InlineString{
|
||||||
|
InlineString: cfg.Options.SSHUserCAKey,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li := &envoy_config_listener_v3.Listener{
|
||||||
|
Name: "ssh",
|
||||||
|
Address: buildTCPAddress(cfg.Options.SSHAddr, 22),
|
||||||
|
FilterChains: []*envoy_config_listener_v3.FilterChain{
|
||||||
|
{
|
||||||
|
Filters: []*envoy_config_listener_v3.Filter{
|
||||||
|
{
|
||||||
|
Name: "generic_proxy",
|
||||||
|
ConfigType: &envoy_config_listener_v3.Filter_TypedConfig{
|
||||||
|
TypedConfig: marshalAny(&envoy_generic_proxy_v3.GenericProxy{
|
||||||
|
StatPrefix: "ssh",
|
||||||
|
CodecConfig: &envoy_config_core_v3.TypedExtensionConfig{
|
||||||
|
Name: "envoy.generic_proxy.codecs.ssh",
|
||||||
|
TypedConfig: marshalAny(&extensions_ssh.CodecConfig{
|
||||||
|
HostKeys: hostKeyDataSources,
|
||||||
|
UserCaKey: userCaKeyDataSource,
|
||||||
|
GrpcService: authorizeService,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Filters: []*envoy_config_core_v3.TypedExtensionConfig{
|
||||||
|
{
|
||||||
|
Name: "envoy.filters.generic.router",
|
||||||
|
TypedConfig: marshalAny(&envoy_generic_router_v3.Router{
|
||||||
|
BindUpstreamConnection: true,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RouteSpecifier: &envoy_generic_proxy_v3.GenericProxy_RouteConfig{
|
||||||
|
RouteConfig: rc,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return li, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildRouteConfig(cfg *config.Config) (*envoy_generic_proxy_v3.RouteConfiguration, error) {
|
||||||
|
var routeMatchers []*xds_matcher_v3.Matcher_MatcherList_FieldMatcher
|
||||||
|
for route := range cfg.Options.GetAllPolicies() {
|
||||||
|
if !route.IsSSH() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
from, err := url.Parse(route.From)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fromHost := from.Hostname()
|
||||||
|
if len(route.To) > 1 {
|
||||||
|
return nil, fmt.Errorf("only one 'to' entry allowed for ssh routes")
|
||||||
|
}
|
||||||
|
to := route.To[0].URL
|
||||||
|
if to.Scheme != "ssh" {
|
||||||
|
return nil, fmt.Errorf("'to' route url must have ssh scheme")
|
||||||
|
}
|
||||||
|
clusterID := getClusterID(route)
|
||||||
|
routeMatchers = append(routeMatchers, &xds_matcher_v3.Matcher_MatcherList_FieldMatcher{
|
||||||
|
Predicate: &xds_matcher_v3.Matcher_MatcherList_Predicate{
|
||||||
|
MatchType: &xds_matcher_v3.Matcher_MatcherList_Predicate_SinglePredicate_{
|
||||||
|
SinglePredicate: &xds_matcher_v3.Matcher_MatcherList_Predicate_SinglePredicate{
|
||||||
|
Input: &xds_core_v3.TypedExtensionConfig{
|
||||||
|
Name: "request",
|
||||||
|
TypedConfig: marshalAny(&envoy_generic_proxy_matcher_v3.RequestMatchInput{}),
|
||||||
|
},
|
||||||
|
Matcher: &xds_matcher_v3.Matcher_MatcherList_Predicate_SinglePredicate_CustomMatch{
|
||||||
|
CustomMatch: &xds_core_v3.TypedExtensionConfig{
|
||||||
|
Name: "request",
|
||||||
|
TypedConfig: marshalAny(&envoy_generic_proxy_matcher_v3.RequestMatcher{
|
||||||
|
Host: &matcherv3.StringMatcher{
|
||||||
|
MatchPattern: &matcherv3.StringMatcher_Exact{
|
||||||
|
Exact: fromHost,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
OnMatch: &xds_matcher_v3.Matcher_OnMatch{
|
||||||
|
OnMatch: &xds_matcher_v3.Matcher_OnMatch_Action{
|
||||||
|
Action: &xds_core_v3.TypedExtensionConfig{
|
||||||
|
Name: "route",
|
||||||
|
TypedConfig: marshalAny(&envoy_generic_proxy_action_v3.RouteAction{
|
||||||
|
Name: route.ID,
|
||||||
|
ClusterSpecifier: &envoy_generic_proxy_action_v3.RouteAction_Cluster{
|
||||||
|
Cluster: clusterID,
|
||||||
|
},
|
||||||
|
Timeout: durationpb.New(0),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if len(routeMatchers) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return &envoy_generic_proxy_v3.RouteConfiguration{
|
||||||
|
Name: "route_config",
|
||||||
|
VirtualHosts: []*envoy_generic_proxy_v3.VirtualHost{
|
||||||
|
{
|
||||||
|
Name: "ssh",
|
||||||
|
Hosts: []string{"*"},
|
||||||
|
Routes: &xds_matcher_v3.Matcher{
|
||||||
|
MatcherType: &xds_matcher_v3.Matcher_MatcherList_{
|
||||||
|
MatcherList: &xds_matcher_v3.Matcher_MatcherList{
|
||||||
|
Matchers: routeMatchers,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldStartSSHListener(options *config.Options) bool {
|
||||||
|
return config.IsAuthorize(options.Services)
|
||||||
|
}
|
148
config/envoyconfig/listeners_ssh_test.go
Normal file
148
config/envoyconfig/listeners_ssh_test.go
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
package envoyconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/pomerium/pomerium/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuildSSHListener(t *testing.T) {
|
||||||
|
t.Run("no ssh routes or address set", func(t *testing.T) {
|
||||||
|
cfg := &config.Config{
|
||||||
|
Options: config.NewDefaultOptions(),
|
||||||
|
}
|
||||||
|
l, err := buildSSHListener(cfg)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Nil(t, l)
|
||||||
|
})
|
||||||
|
t.Run("address set, but no ssh routes", func(t *testing.T) {
|
||||||
|
cfg := &config.Config{
|
||||||
|
Options: config.NewDefaultOptions(),
|
||||||
|
}
|
||||||
|
cfg.Options.Policies = []config.Policy{
|
||||||
|
{From: "https://not-ssh", To: mustParseWeightedURLs(t, "https://dest:22")},
|
||||||
|
}
|
||||||
|
cfg.Options.SSHAddr = "0.0.0.0:22"
|
||||||
|
l, err := buildSSHListener(cfg)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Nil(t, l)
|
||||||
|
})
|
||||||
|
t.Run("no address set, but routes present", func(t *testing.T) {
|
||||||
|
cfg := &config.Config{
|
||||||
|
Options: config.NewDefaultOptions(),
|
||||||
|
}
|
||||||
|
cfg.Options.Policies = []config.Policy{
|
||||||
|
{From: "ssh://host1", To: mustParseWeightedURLs(t, "ssh://to:22")},
|
||||||
|
}
|
||||||
|
l, err := buildSSHListener(cfg)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Nil(t, l)
|
||||||
|
})
|
||||||
|
t.Run("address and routes both present", func(t *testing.T) {
|
||||||
|
cfg := &config.Config{
|
||||||
|
Options: config.NewDefaultOptions(),
|
||||||
|
}
|
||||||
|
cfg.Options.SSHAddr = "0.0.0.0:22"
|
||||||
|
cfg.Options.Policies = []config.Policy{
|
||||||
|
{From: "ssh://host1", To: mustParseWeightedURLs(t, "ssh://to:22")},
|
||||||
|
}
|
||||||
|
l, err := buildSSHListener(cfg)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, l.ValidateAll())
|
||||||
|
})
|
||||||
|
t.Run("multiple routes", func(t *testing.T) {
|
||||||
|
cfg := &config.Config{
|
||||||
|
Options: config.NewDefaultOptions(),
|
||||||
|
}
|
||||||
|
cfg.Options.SSHAddr = "0.0.0.0:22"
|
||||||
|
cfg.Options.Policies = []config.Policy{
|
||||||
|
{From: "ssh://host1", To: mustParseWeightedURLs(t, "ssh://to1:22")},
|
||||||
|
{From: "ssh://host2", To: mustParseWeightedURLs(t, "ssh://to2:22")},
|
||||||
|
{From: "ssh://host3", To: mustParseWeightedURLs(t, "ssh://to3:22")},
|
||||||
|
}
|
||||||
|
l, err := buildSSHListener(cfg)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, l.ValidateAll())
|
||||||
|
})
|
||||||
|
t.Run("keys configured", func(t *testing.T) {
|
||||||
|
cfg := &config.Config{
|
||||||
|
Options: config.NewDefaultOptions(),
|
||||||
|
}
|
||||||
|
cfg.Options.SSHAddr = "0.0.0.0:22"
|
||||||
|
cfg.Options.SSHHostKeyFiles = &[]string{
|
||||||
|
"/path/to/key1",
|
||||||
|
"/path/to/key2",
|
||||||
|
}
|
||||||
|
cfg.Options.SSHHostKeys = &[]string{
|
||||||
|
"key3",
|
||||||
|
"key4",
|
||||||
|
}
|
||||||
|
cfg.Options.SSHUserCAKeyFile = "/path/to/user_ca_key"
|
||||||
|
cfg.Options.Policies = []config.Policy{
|
||||||
|
{From: "ssh://host1", To: mustParseWeightedURLs(t, "ssh://to1:22")},
|
||||||
|
{From: "ssh://host2", To: mustParseWeightedURLs(t, "ssh://to2:22")},
|
||||||
|
{From: "ssh://host3", To: mustParseWeightedURLs(t, "ssh://to3:22")},
|
||||||
|
}
|
||||||
|
l, err := buildSSHListener(cfg)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, l.ValidateAll())
|
||||||
|
})
|
||||||
|
t.Run("user ca key inline", func(t *testing.T) {
|
||||||
|
cfg := &config.Config{
|
||||||
|
Options: config.NewDefaultOptions(),
|
||||||
|
}
|
||||||
|
cfg.Options.SSHAddr = "0.0.0.0:22"
|
||||||
|
cfg.Options.SSHHostKeyFiles = &[]string{
|
||||||
|
"/path/to/key1",
|
||||||
|
"/path/to/key2",
|
||||||
|
}
|
||||||
|
cfg.Options.SSHHostKeys = &[]string{
|
||||||
|
"key3",
|
||||||
|
"key4",
|
||||||
|
}
|
||||||
|
cfg.Options.SSHUserCAKey = "key"
|
||||||
|
cfg.Options.Policies = []config.Policy{
|
||||||
|
{From: "ssh://host1", To: mustParseWeightedURLs(t, "ssh://to1:22")},
|
||||||
|
{From: "ssh://host2", To: mustParseWeightedURLs(t, "ssh://to2:22")},
|
||||||
|
{From: "ssh://host3", To: mustParseWeightedURLs(t, "ssh://to3:22")},
|
||||||
|
}
|
||||||
|
l, err := buildSSHListener(cfg)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, l.ValidateAll())
|
||||||
|
})
|
||||||
|
t.Run("invalid From url", func(t *testing.T) {
|
||||||
|
cfg := &config.Config{
|
||||||
|
Options: config.NewDefaultOptions(),
|
||||||
|
}
|
||||||
|
cfg.Options.SSHAddr = "0.0.0.0:22"
|
||||||
|
cfg.Options.Policies = []config.Policy{
|
||||||
|
{From: "ssh://\x7f", To: mustParseWeightedURLs(t, "ssh://to1:22")},
|
||||||
|
}
|
||||||
|
_, err := buildSSHListener(cfg)
|
||||||
|
assert.Error(t, err)
|
||||||
|
})
|
||||||
|
t.Run("multiple To urls", func(t *testing.T) {
|
||||||
|
cfg := &config.Config{
|
||||||
|
Options: config.NewDefaultOptions(),
|
||||||
|
}
|
||||||
|
cfg.Options.SSHAddr = "0.0.0.0:22"
|
||||||
|
cfg.Options.Policies = []config.Policy{
|
||||||
|
{From: "ssh://host1", To: mustParseWeightedURLs(t, "ssh://to1:22", "ssh://to2:22")},
|
||||||
|
}
|
||||||
|
_, err := buildSSHListener(cfg)
|
||||||
|
assert.Error(t, err)
|
||||||
|
})
|
||||||
|
t.Run("To url missing scheme", func(t *testing.T) {
|
||||||
|
cfg := &config.Config{
|
||||||
|
Options: config.NewDefaultOptions(),
|
||||||
|
}
|
||||||
|
cfg.Options.SSHAddr = "0.0.0.0:22"
|
||||||
|
cfg.Options.Policies = []config.Policy{
|
||||||
|
{From: "ssh://host1", To: mustParseWeightedURLs(t, "http://to1:22")},
|
||||||
|
}
|
||||||
|
_, err := buildSSHListener(cfg)
|
||||||
|
assert.Error(t, err)
|
||||||
|
})
|
||||||
|
}
|
|
@ -242,11 +242,22 @@ type Options struct {
|
||||||
|
|
||||||
// SSH Settings
|
// SSH Settings
|
||||||
|
|
||||||
SSHAddr string `mapstructure:"ssh_address" yaml:"ssh_address,omitempty"`
|
// Address/Port to bind to for the SSH server. If unset, SSH will be disabled.
|
||||||
SSHHostKeyFiles *[]string `mapstructure:"ssh_host_key_files" yaml:"ssh_host_key_files,omitempty"`
|
SSHAddr string `mapstructure:"ssh_address" yaml:"ssh_address,omitempty"`
|
||||||
SSHHostKeys *[]string `mapstructure:"ssh_host_keys" yaml:"ssh_host_keys,omitempty"`
|
// List of host key files for the SSH server.
|
||||||
SSHUserCAKeyFile string `mapstructure:"ssh_user_ca_key_file" yaml:"ssh_user_ca_key_file,omitempty"`
|
// Files must not be group/world-readable on disk.
|
||||||
SSHUserCAKey string `mapstructure:"ssh_user_ca_key" yaml:"ssh_user_ca_key,omitempty"`
|
// If multiple keys are given, they must each have unique algorithms.
|
||||||
|
SSHHostKeyFiles *[]string `mapstructure:"ssh_host_key_files" yaml:"ssh_host_key_files,omitempty"`
|
||||||
|
// String contents of host keys for the SSH server. If both ssh_host_keys
|
||||||
|
// and ssh_host_key_files are set, they will be combined.
|
||||||
|
SSHHostKeys *[]string `mapstructure:"ssh_host_keys" yaml:"ssh_host_keys,omitempty"`
|
||||||
|
// SSH key used to sign ephemeral certificate keys for upstream authentication.
|
||||||
|
// This key must not be group/world-readable on disk, and should not itself be
|
||||||
|
// a certificate key.
|
||||||
|
SSHUserCAKeyFile string `mapstructure:"ssh_user_ca_key_file" yaml:"ssh_user_ca_key_file,omitempty"`
|
||||||
|
// String contents of SSH key used to sign ephemeral certificate keys for
|
||||||
|
// upstream authentication. Mutually exclusive with ssh_user_ca_key_file.
|
||||||
|
SSHUserCAKey string `mapstructure:"ssh_user_ca_key" yaml:"ssh_user_ca_key,omitempty"`
|
||||||
|
|
||||||
// DataBrokerURLString is the routable destination of the databroker service's gRPC endpoint.
|
// DataBrokerURLString is the routable destination of the databroker service's gRPC endpoint.
|
||||||
DataBrokerURLString string `mapstructure:"databroker_service_url" yaml:"databroker_service_url,omitempty"`
|
DataBrokerURLString string `mapstructure:"databroker_service_url" yaml:"databroker_service_url,omitempty"`
|
||||||
|
|
|
@ -930,6 +930,11 @@ func (p *Policy) IsUDPUpstream() bool {
|
||||||
return len(p.To) > 0 && p.To[0].URL.Scheme == "udp"
|
return len(p.To) > 0 && p.To[0].URL.Scheme == "udp"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsSSH returns true if the route is for SSH.
|
||||||
|
func (p *Policy) IsSSH() bool {
|
||||||
|
return len(p.From) > 0 && strings.HasPrefix(p.From, "ssh://")
|
||||||
|
}
|
||||||
|
|
||||||
// AllAllowedDomains returns all the allowed domains.
|
// AllAllowedDomains returns all the allowed domains.
|
||||||
func (p *Policy) AllAllowedDomains() []string {
|
func (p *Policy) AllAllowedDomains() []string {
|
||||||
var ads []string
|
var ads []string
|
||||||
|
|
|
@ -460,6 +460,14 @@ func TestPolicy_IsTCPUpstream(t *testing.T) {
|
||||||
assert.False(t, p3.IsTCPUpstream())
|
assert.False(t, p3.IsTCPUpstream())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPolicy_IsSSH(t *testing.T) {
|
||||||
|
p1 := Policy{From: "https://example.com"}
|
||||||
|
assert.False(t, p1.IsSSH())
|
||||||
|
|
||||||
|
p2 := Policy{From: "ssh://example.com"}
|
||||||
|
assert.True(t, p2.IsSSH())
|
||||||
|
}
|
||||||
|
|
||||||
func mustParseWeightedURLs(t testing.TB, urls ...string) WeightedURLs {
|
func mustParseWeightedURLs(t testing.TB, urls ...string) WeightedURLs {
|
||||||
wu, err := ParseWeightedUrls(urls...)
|
wu, err := ParseWeightedUrls(urls...)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -16,6 +16,7 @@ require (
|
||||||
github.com/caddyserver/certmagic v0.23.0
|
github.com/caddyserver/certmagic v0.23.0
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0
|
github.com/cenkalti/backoff/v4 v4.3.0
|
||||||
github.com/cloudflare/circl v1.6.1
|
github.com/cloudflare/circl v1.6.1
|
||||||
|
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f
|
||||||
github.com/cockroachdb/pebble/v2 v2.0.4
|
github.com/cockroachdb/pebble/v2 v2.0.4
|
||||||
github.com/coreos/go-oidc/v3 v3.14.1
|
github.com/coreos/go-oidc/v3 v3.14.1
|
||||||
github.com/docker/docker v28.2.2+incompatible
|
github.com/docker/docker v28.2.2+incompatible
|
||||||
|
@ -54,7 +55,7 @@ require (
|
||||||
github.com/pires/go-proxyproto v0.8.1
|
github.com/pires/go-proxyproto v0.8.1
|
||||||
github.com/pomerium/csrf v1.7.0
|
github.com/pomerium/csrf v1.7.0
|
||||||
github.com/pomerium/datasource v0.18.2-0.20221108160055-c6134b5ed524
|
github.com/pomerium/datasource v0.18.2-0.20221108160055-c6134b5ed524
|
||||||
github.com/pomerium/envoy-custom v1.33.0
|
github.com/pomerium/envoy-custom v1.33.1-0.20250618175753-a0feae248696
|
||||||
github.com/pomerium/protoutil v0.0.0-20240813175624-47b7ac43ff46
|
github.com/pomerium/protoutil v0.0.0-20240813175624-47b7ac43ff46
|
||||||
github.com/pomerium/webauthn v0.0.0-20240603205124-0428df511172
|
github.com/pomerium/webauthn v0.0.0-20240603205124-0428df511172
|
||||||
github.com/prometheus/client_golang v1.22.0
|
github.com/prometheus/client_golang v1.22.0
|
||||||
|
@ -145,7 +146,6 @@ require (
|
||||||
github.com/caddyserver/zerossl v0.1.3 // indirect
|
github.com/caddyserver/zerossl v0.1.3 // indirect
|
||||||
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
|
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
|
|
||||||
github.com/cockroachdb/crlib v0.0.0-20241015224233-894974b3ad94 // indirect
|
github.com/cockroachdb/crlib v0.0.0-20241015224233-894974b3ad94 // indirect
|
||||||
github.com/cockroachdb/errors v1.11.3 // indirect
|
github.com/cockroachdb/errors v1.11.3 // indirect
|
||||||
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect
|
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -171,8 +171,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 h1:Om6kYQYDUk5wWbT0t0q6pvyM49i9XZAv9dDrkDA7gjk=
|
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f h1:C5bqEmzEPLsHm9Mv73lSE9e9bKV23aB1vxOsmZrkl3k=
|
||||||
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||||
github.com/cockroachdb/crlib v0.0.0-20241015224233-894974b3ad94 h1:bvJv505UUfjzbaIPdNS4AEkHreDqQk6yuNpsdRHpwFA=
|
github.com/cockroachdb/crlib v0.0.0-20241015224233-894974b3ad94 h1:bvJv505UUfjzbaIPdNS4AEkHreDqQk6yuNpsdRHpwFA=
|
||||||
github.com/cockroachdb/crlib v0.0.0-20241015224233-894974b3ad94/go.mod h1:Gq51ZeKaFCXk6QwuGM0w1dnaOqc/F5zKT2zA9D6Xeac=
|
github.com/cockroachdb/crlib v0.0.0-20241015224233-894974b3ad94/go.mod h1:Gq51ZeKaFCXk6QwuGM0w1dnaOqc/F5zKT2zA9D6Xeac=
|
||||||
github.com/cockroachdb/datadriven v1.0.3-0.20240530155848-7682d40af056 h1:slXychO2uDM6hYRu4c0pD0udNI8uObfeKN6UInWViS8=
|
github.com/cockroachdb/datadriven v1.0.3-0.20240530155848-7682d40af056 h1:slXychO2uDM6hYRu4c0pD0udNI8uObfeKN6UInWViS8=
|
||||||
|
@ -579,8 +579,8 @@ github.com/pomerium/csrf v1.7.0 h1:Qp4t6oyEod3svQtKfJZs589mdUTWKVf7q0PgCKYCshY=
|
||||||
github.com/pomerium/csrf v1.7.0/go.mod h1:hAPZV47mEj2T9xFs+ysbum4l7SF1IdrryYaY6PdoIqw=
|
github.com/pomerium/csrf v1.7.0/go.mod h1:hAPZV47mEj2T9xFs+ysbum4l7SF1IdrryYaY6PdoIqw=
|
||||||
github.com/pomerium/datasource v0.18.2-0.20221108160055-c6134b5ed524 h1:3YQY1sb54tEEbr0L73rjHkpLB0IB6qh3zl1+XQbMLis=
|
github.com/pomerium/datasource v0.18.2-0.20221108160055-c6134b5ed524 h1:3YQY1sb54tEEbr0L73rjHkpLB0IB6qh3zl1+XQbMLis=
|
||||||
github.com/pomerium/datasource v0.18.2-0.20221108160055-c6134b5ed524/go.mod h1:7fGbUYJnU8RcxZJvUvhukOIBv1G7LWDAHMfDxAf5+Y0=
|
github.com/pomerium/datasource v0.18.2-0.20221108160055-c6134b5ed524/go.mod h1:7fGbUYJnU8RcxZJvUvhukOIBv1G7LWDAHMfDxAf5+Y0=
|
||||||
github.com/pomerium/envoy-custom v1.33.0 h1:WK5f+mGIu6VcxYTTeZqth6If6EWHrxymfvc+Rwm5Vl8=
|
github.com/pomerium/envoy-custom v1.33.1-0.20250618175753-a0feae248696 h1:ojei2rggKHZYnDQyCbjeG2mdyqCW8E2tZpxOuiDBwxc=
|
||||||
github.com/pomerium/envoy-custom v1.33.0/go.mod h1:afbaKE6YfshVUOrYc6XWUWfZcXencWmi1jTc00ki0Oo=
|
github.com/pomerium/envoy-custom v1.33.1-0.20250618175753-a0feae248696/go.mod h1:+wpbZvum83bq/OD4cp9/8IZiMV6boBkwDhlFPLOoWoI=
|
||||||
github.com/pomerium/protoutil v0.0.0-20240813175624-47b7ac43ff46 h1:NRTg8JOXCxcIA1lAgD74iYud0rbshbWOB3Ou4+Huil8=
|
github.com/pomerium/protoutil v0.0.0-20240813175624-47b7ac43ff46 h1:NRTg8JOXCxcIA1lAgD74iYud0rbshbWOB3Ou4+Huil8=
|
||||||
github.com/pomerium/protoutil v0.0.0-20240813175624-47b7ac43ff46/go.mod h1:QqZmx6ZgPxz18va7kqoT4t/0yJtP7YFIDiT/W2n2fZ4=
|
github.com/pomerium/protoutil v0.0.0-20240813175624-47b7ac43ff46/go.mod h1:QqZmx6ZgPxz18va7kqoT4t/0yJtP7YFIDiT/W2n2fZ4=
|
||||||
github.com/pomerium/webauthn v0.0.0-20240603205124-0428df511172 h1:TqoPqRgXSHpn+tEJq6H72iCS5pv66j3rPprThUEZg0E=
|
github.com/pomerium/webauthn v0.0.0-20240603205124-0428df511172 h1:TqoPqRgXSHpn+tEJq6H72iCS5pv66j3rPprThUEZg0E=
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"go.uber.org/automaxprocs/maxprocs"
|
"go.uber.org/automaxprocs/maxprocs"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
|
extensions_ssh "github.com/pomerium/envoy-custom/api/extensions/filters/network/ssh"
|
||||||
"github.com/pomerium/pomerium/authenticate"
|
"github.com/pomerium/pomerium/authenticate"
|
||||||
"github.com/pomerium/pomerium/authorize"
|
"github.com/pomerium/pomerium/authorize"
|
||||||
"github.com/pomerium/pomerium/config"
|
"github.com/pomerium/pomerium/config"
|
||||||
|
@ -268,6 +269,7 @@ func setupAuthorize(ctx context.Context, src config.Source, controlPlane *contro
|
||||||
return nil, fmt.Errorf("error creating authorize service: %w", err)
|
return nil, fmt.Errorf("error creating authorize service: %w", err)
|
||||||
}
|
}
|
||||||
envoy_service_auth_v3.RegisterAuthorizationServer(controlPlane.GRPCServer, svc)
|
envoy_service_auth_v3.RegisterAuthorizationServer(controlPlane.GRPCServer, svc)
|
||||||
|
extensions_ssh.RegisterStreamManagementServer(controlPlane.GRPCServer, svc)
|
||||||
|
|
||||||
log.Ctx(ctx).Info().Msg("enabled authorize service")
|
log.Ctx(ctx).Info().Msg("enabled authorize service")
|
||||||
src.OnConfigChange(ctx, svc.OnConfigChange)
|
src.OnConfigChange(ctx, svc.OnConfigChange)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue