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
2 changes: 2 additions & 0 deletions api/types/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,8 @@ const (
DiscoveryAppRewriteLabel = TeleportNamespace + "/app-rewrite"
// DiscoveryAppNameLabel specifies explicitly name of an app created from Kubernetes service.
DiscoveryAppNameLabel = TeleportNamespace + "/name"
// DiscoveryPathLabel optionally specifies a context path for apps created from Kubernetes services.
DiscoveryPathLabel = TeleportNamespace + "/path"
// DiscoveryAppInsecureSkipVerify specifies the TLS verification enforcement for a discovered app created from Kubernetes service.
DiscoveryAppInsecureSkipVerify = TeleportNamespace + "/insecure-skip-verify"
// DiscoveryAppIgnore specifies if a Kubernetes service should be ignored by discovery service.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,13 @@ Controls the public address for the Teleport app we create if needed.
annotations:
teleport.dev/public-addr: "custom.teleport.dev"
```

### `teleport.dev/path`

The path is appended to the URI generated for the Teleport app for cases where
an application is served on a sub-path of an HTTP service.

```yaml
annotations:
teleport.dev/path: "foo/bar"
```
4 changes: 4 additions & 0 deletions lib/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2015,6 +2015,8 @@ func (process *TeleportProcess) initAuthService() error {
}
process.backend = b

// TODO(zmb3) maybe check here

var emitter apievents.Emitter
var streamer events.Streamer
var uploadHandler events.MultipartHandler
Expand Down Expand Up @@ -6316,6 +6318,8 @@ func (process *TeleportProcess) initAuthStorage() (backend.Backend, error) {
return nil, trace.Wrap(err)
}

// TODO(zmb3): bk (if firestore or dynamo) should not use same table as recordings

reporter, err := backend.NewReporter(backend.ReporterConfig{
Component: teleport.ComponentBackend,
Backend: backend.NewSanitizer(bk),
Expand Down
5 changes: 3 additions & 2 deletions lib/services/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func UnmarshalAppServer(data []byte, opts ...MarshalOption) (types.AppServer, er
// It transforms service fields and annotations into appropriate Teleport app fields.
// Service labels are copied to app labels.
func NewApplicationFromKubeService(service corev1.Service, clusterName, protocol string, port corev1.ServicePort) (types.Application, error) {
appURI := buildAppURI(protocol, GetServiceFQDN(service), port.Port)
appURI := buildAppURI(protocol, GetServiceFQDN(service), service.GetAnnotations()[types.DiscoveryPathLabel], port.Port)

rewriteConfig, err := getAppRewriteConfig(service.GetAnnotations())
if err != nil {
Expand Down Expand Up @@ -210,10 +210,11 @@ func GetServiceFQDN(service corev1.Service) string {
return fmt.Sprintf("%s.%s.svc.%s", service.GetName(), service.GetNamespace(), clusterDomainResolver())
}

func buildAppURI(protocol, serviceFQDN string, port int32) string {
func buildAppURI(protocol, serviceFQDN, path string, port int32) string {
return (&url.URL{
Scheme: protocol,
Host: fmt.Sprintf("%s:%d", serviceFQDN, port),
Path: path,
}).String()
}

Expand Down
31 changes: 30 additions & 1 deletion lib/services/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ func TestBuildAppURI(t *testing.T) {
tests := []struct {
serviceFQDN string
port int32
path string
protocol string
expected string
}{
Expand All @@ -220,6 +221,34 @@ func TestBuildAppURI(t *testing.T) {
protocol: "http",
expected: "http://service.example:8080",
},
{
serviceFQDN: "service.example",
port: 8080,
protocol: "http",
path: "foo",
expected: "http://service.example:8080/foo",
},
{
serviceFQDN: "service.example",
port: 8080,
protocol: "http",
path: "/foo",
expected: "http://service.example:8080/foo",
},
{
serviceFQDN: "service.example",
port: 8080,
protocol: "http",
path: "foo/bar",
expected: "http://service.example:8080/foo/bar",
},
{
serviceFQDN: "service.example",
port: 8080,
protocol: "http",
path: "foo bar",
expected: "http://service.example:8080/foo%20bar",
},
{
serviceFQDN: "service.example",
port: 443,
Expand All @@ -235,7 +264,7 @@ func TestBuildAppURI(t *testing.T) {
}

for _, tt := range tests {
require.Equal(t, tt.expected, buildAppURI(tt.protocol, tt.serviceFQDN, tt.port))
require.Equal(t, tt.expected, buildAppURI(tt.protocol, tt.serviceFQDN, tt.path, tt.port))
}
}

Expand Down
24 changes: 19 additions & 5 deletions lib/srv/discovery/discovery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ import (
"errors"
"fmt"
"io"
"net/url"
"os"
"regexp"
"slices"
"strings"
"sync"
"testing"
"time"
Expand Down Expand Up @@ -1197,12 +1199,17 @@ func TestDiscoveryKubeServices(t *testing.T) {

appProtocolHTTP := "http"
mockKubeServices := []*corev1.Service{
newMockKubeService("service1", "ns1", "", map[string]string{"test-label": "testval"}, map[string]string{types.DiscoveryPublicAddr: "custom.example.com"},
newMockKubeService("service1", "ns1", "",
map[string]string{"test-label": "testval"},
map[string]string{types.DiscoveryPublicAddr: "custom.example.com", types.DiscoveryPathLabel: "foo/bar baz"},
[]corev1.ServicePort{{Port: 42, Name: "http", Protocol: corev1.ProtocolTCP}}),
newMockKubeService("service2", "ns2", "", map[string]string{
"test-label": "testval",
"test-label2": "testval2",
}, nil, []corev1.ServicePort{{Port: 42, Name: "custom", AppProtocol: &appProtocolHTTP, Protocol: corev1.ProtocolTCP}}),
newMockKubeService("service2", "ns2", "",
map[string]string{
"test-label": "testval",
"test-label2": "testval2",
},
nil,
[]corev1.ServicePort{{Port: 42, Name: "custom", AppProtocol: &appProtocolHTTP, Protocol: corev1.ProtocolTCP}}),
}

app1 := mustConvertKubeServiceToApp(t, mainDiscoveryGroup, "http", mockKubeServices[0], mockKubeServices[0].Spec.Ports[0])
Expand Down Expand Up @@ -2047,6 +2054,13 @@ func mustConvertKubeServiceToApp(t *testing.T, discoveryGroup, protocol string,
app, err := services.NewApplicationFromKubeService(*kubeService, discoveryGroup, protocol, port)
require.NoError(t, err)
require.Equal(t, kubeService.Annotations[types.DiscoveryPublicAddr], app.GetPublicAddr())
if p, ok := kubeService.Annotations[types.DiscoveryPathLabel]; ok {
components := strings.Split(p, "/")
for i := range components {
components[i] = url.PathEscape(components[i])
}
require.True(t, strings.HasSuffix(app.GetURI(), "/"+strings.Join(components, "/")), "uri: %v", app.GetURI())
}

app.GetStaticLabels()[types.TeleportInternalDiscoveryGroupName] = discoveryGroup
app.GetStaticLabels()[types.OriginLabel] = types.OriginDiscoveryKubernetes
Expand Down