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:
Joe Kralicky 2025-06-30 15:15:05 -04:00 committed by GitHub
parent 6a65c52a6c
commit ac76aeb279
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 409 additions and 11 deletions

16
authorize/ssh_grpc.go Normal file
View 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")
}

View file

@ -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

View 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)
}

View 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)
})
}

View file

@ -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"`

View file

@ -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

View file

@ -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
View file

@ -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
View file

@ -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=

View file

@ -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)