Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor GenerateUserCerts to create App Sessions #39970

Merged
merged 22 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
af1aa02
Add CreateAppSessionFromReq.
Joerger Mar 22, 2024
725c089
Deprecate passing route_to_app.session_id in cert requests.
Joerger Mar 27, 2024
11132ed
Automatically create app sessions for app cert requests.
Joerger Mar 27, 2024
de78ab7
Deprecate client use of CreateAppSession for app cert requests.
Joerger Mar 28, 2024
0bf630e
Fix affected tests.
Joerger Mar 29, 2024
834a32e
Use traits and roles from existing user certificate for app sessions.
Joerger Apr 2, 2024
0506010
Merge branch 'master' into joerger/generate-app-certs-and-session
Joerger Apr 16, 2024
688e0c9
Merge branch 'master' into joerger/generate-app-certs-and-session
Joerger Apr 18, 2024
8a8a89e
Fix app access integration tests.
Joerger Apr 19, 2024
9216974
Merge branch 'master' into joerger/generate-app-certs-and-session
Joerger Apr 19, 2024
f7b6d86
Merge branch 'master' into joerger/generate-app-certs-and-session
Joerger Apr 22, 2024
cc6caa2
go mod tidy.
Joerger Apr 22, 2024
ee3ed91
Fix TestTCP.
Joerger Apr 22, 2024
d6ff75e
Fix TestALPNSNIProxyAppAccess.
Joerger Apr 22, 2024
b0aba70
Merge branch 'master' into joerger/generate-app-certs-and-session
Joerger Apr 22, 2024
688c2da
Merge branch 'master' into joerger/generate-app-certs-and-session
Joerger Apr 22, 2024
9591190
Merge branch 'master' into joerger/generate-app-certs-and-session
Joerger Apr 23, 2024
733e87f
Merge branch 'master' into joerger/generate-app-certs-and-session
Joerger Apr 23, 2024
8ac5669
Revert "go mod tidy."
Joerger Apr 23, 2024
2867af7
Merge branch 'master' into joerger/generate-app-certs-and-session
Joerger Apr 24, 2024
45e15ef
Merge branch 'master' into joerger/generate-app-certs-and-session
Joerger Apr 25, 2024
55103b4
Merge branch 'master' into joerger/generate-app-certs-and-session
Joerger Apr 25, 2024
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
1,761 changes: 882 additions & 879 deletions api/client/proto/authservice.pb.go

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion api/proto/teleport/legacy/client/proto/authservice.proto
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,12 @@ message RouteToApp {
// Name is the application name certificate is being requested for.
string Name = 1 [(gogoproto.jsontag) = "name"];
// SessionID is the ID of the application session.
string SessionID = 2 [(gogoproto.jsontag) = "session_id"];
// DEPRECATED: Automatically generated by server.
// TODO (Joerger): DELETE IN v17.0.0
string SessionID = 2 [
(gogoproto.jsontag) = "session_id",
deprecated = true
];
// PublicAddr is the application public address.
string PublicAddr = 3 [(gogoproto.jsontag) = "public_addr"];
// ClusterName is the cluster where the application resides.
Expand Down
86 changes: 28 additions & 58 deletions integration/appaccess/appaccess_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import (
"github.com/stretchr/testify/require"

"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/client/proto"
"github.com/gravitational/teleport/api/types"
apievents "github.com/gravitational/teleport/api/types/events"
"github.com/gravitational/teleport/integration/helpers"
Expand Down Expand Up @@ -77,8 +76,8 @@ func TestAppAccess(t *testing.T) {
// testForward tests that requests get forwarded to the target application
// within a single cluster and trusted cluster.
func testForward(p *Pack, t *testing.T) {
rootCookies := helpers.ParseCookies(t, p.CreateAppSession(t, p.rootAppPublicAddr, p.rootAppClusterName))
leafCookies := helpers.ParseCookies(t, p.CreateAppSession(t, p.leafAppPublicAddr, p.leafAppClusterName))
rootCookies := helpers.ParseCookies(t, p.CreateAppSessionCookies(t, p.rootAppPublicAddr, p.rootAppClusterName))
leafCookies := helpers.ParseCookies(t, p.CreateAppSessionCookies(t, p.leafAppPublicAddr, p.leafAppClusterName))
tests := []struct {
desc string
inCookies []*http.Cookie
Expand Down Expand Up @@ -157,27 +156,27 @@ func testWebsockets(p *Pack, t *testing.T) {
}{
{
desc: "root cluster, valid application session cookie, successful websocket (ws://) request",
inCookies: p.CreateAppSession(t, p.rootWSPublicAddr, p.rootAppClusterName),
inCookies: p.CreateAppSessionCookies(t, p.rootWSPublicAddr, p.rootAppClusterName),
outMessage: p.rootWSMessage,
},
{
desc: "root cluster, valid application session cookie, successful secure websocket (wss://) request",
inCookies: p.CreateAppSession(t, p.rootWSSPublicAddr, p.rootAppClusterName),
inCookies: p.CreateAppSessionCookies(t, p.rootWSSPublicAddr, p.rootAppClusterName),
outMessage: p.rootWSSMessage,
},
{
desc: "leaf cluster, valid application session cookie, successful websocket (ws://) request",
inCookies: p.CreateAppSession(t, p.leafWSPublicAddr, p.leafAppClusterName),
inCookies: p.CreateAppSessionCookies(t, p.leafWSPublicAddr, p.leafAppClusterName),
outMessage: p.leafWSMessage,
},
{
desc: "leaf cluster, valid application session cookie, successful secure websocket (wss://) request",
inCookies: p.CreateAppSession(t, p.leafWSSPublicAddr, p.leafAppClusterName),
inCookies: p.CreateAppSessionCookies(t, p.leafWSSPublicAddr, p.leafAppClusterName),
outMessage: p.leafWSSMessage,
},
{
desc: "valid application session cookie, invalid subject session cookie, websocket request fails to dial",
inCookies: helpers.ParseCookies(t, p.CreateAppSession(t, p.rootWSPublicAddr, p.rootAppClusterName)).WithSubjectCookie(
inCookies: helpers.ParseCookies(t, p.CreateAppSessionCookies(t, p.rootWSPublicAddr, p.rootAppClusterName)).WithSubjectCookie(
&http.Cookie{
Name: app.SubjectCookieName,
Value: "foobarbaz",
Expand Down Expand Up @@ -237,13 +236,13 @@ func testForwardModes(p *Pack, t *testing.T) {
}{
{
desc: "root cluster, valid application session cookie, success",
inCookies: p.CreateAppSession(t, p.rootAppPublicAddr, p.rootAppClusterName),
inCookies: p.CreateAppSessionCookies(t, p.rootAppPublicAddr, p.rootAppClusterName),
outStatusCode: http.StatusOK,
outMessage: p.rootMessage,
},
{
desc: "leaf cluster, valid application session cookie, success",
inCookies: p.CreateAppSession(t, p.leafAppPublicAddr, p.leafAppClusterName),
inCookies: p.CreateAppSessionCookies(t, p.leafAppPublicAddr, p.leafAppClusterName),
outStatusCode: http.StatusOK,
outMessage: p.leafMessage,
},
Expand All @@ -270,19 +269,8 @@ func testClientCert(p *Pack, t *testing.T) {
},
})
evilUser, _ := p.CreateUser(t)
rootWs, err := p.tc.CreateAppSession(context.Background(), &proto.CreateAppSessionRequest{
Username: p.user.GetName(),
PublicAddr: p.rootAppPublicAddr,
ClusterName: p.rootAppClusterName,
})
require.NoError(t, err)

leafWs, err := p.tc.CreateAppSession(context.Background(), &proto.CreateAppSessionRequest{
Username: p.user.GetName(),
PublicAddr: p.leafAppPublicAddr,
ClusterName: p.leafAppClusterName,
})
require.NoError(t, err)
rootWs := p.CreateAppSession(t, p.username, p.rootAppClusterName, p.rootAppPublicAddr)
leafWs := p.CreateAppSession(t, p.username, p.leafAppClusterName, p.leafAppPublicAddr)

tests := []struct {
desc string
Expand Down Expand Up @@ -355,7 +343,7 @@ func testFlush(p *Pack, t *testing.T) {
req, err := http.NewRequest("GET", p.assembleRootProxyURL("/"), nil)
require.NoError(t, err)

cookies := p.CreateAppSession(t, p.flushAppPublicAddr, p.flushAppClusterName)
cookies := p.CreateAppSessionCookies(t, p.flushAppPublicAddr, p.flushAppClusterName)
for _, c := range cookies {
req.AddCookie(c)
}
Expand Down Expand Up @@ -389,7 +377,7 @@ func testFlush(p *Pack, t *testing.T) {
// rewrite configuration are correctly passed to proxied applications in root.
func testRewriteHeadersRoot(p *Pack, t *testing.T) {
// Create an application session for dumper app in root cluster.
appCookies := p.CreateAppSession(t, "dumper-root.example.com", "example.com")
appCookies := p.CreateAppSessionCookies(t, "dumper-root.example.com", "example.com")

// Get headers response and make sure headers were passed.
status, resp, err := p.MakeRequest(appCookies, http.MethodGet, "/", servicecfg.Header{
Expand Down Expand Up @@ -425,7 +413,7 @@ func testRewriteHeadersRoot(p *Pack, t *testing.T) {
// rewrite configuration are correctly passed to proxied applications in leaf.
func testRewriteHeadersLeaf(p *Pack, t *testing.T) {
// Create an application session for dumper app in leaf cluster.
appCookie := p.CreateAppSession(t, "dumper-leaf.example.com", "leaf.example.com")
appCookie := p.CreateAppSessionCookies(t, "dumper-leaf.example.com", "leaf.example.com")

// Get headers response and make sure headers were passed.
status, resp, err := p.MakeRequest(appCookie, http.MethodGet, "/", servicecfg.Header{
Expand Down Expand Up @@ -456,7 +444,7 @@ func testRewriteHeadersLeaf(p *Pack, t *testing.T) {
// testLogout verifies the session is removed from the backend when the user logs out.
func testLogout(p *Pack, t *testing.T) {
// Create an application session.
appCookies := p.CreateAppSession(t, p.rootAppPublicAddr, p.rootAppClusterName)
appCookies := p.CreateAppSessionCookies(t, p.rootAppPublicAddr, p.rootAppClusterName)

// Log user out of session.
status, _, err := p.MakeRequest(appCookies, http.MethodGet, "/teleport-logout")
Expand All @@ -473,7 +461,7 @@ func testLogout(p *Pack, t *testing.T) {
// be validated.
func testJWT(p *Pack, t *testing.T) {
// Create an application session.
appCookies := p.CreateAppSession(t, p.jwtAppPublicAddr, p.jwtAppClusterName)
appCookies := p.CreateAppSessionCookies(t, p.jwtAppPublicAddr, p.jwtAppClusterName)

// Get JWT.
status, token, err := p.MakeRequest(appCookies, http.MethodGet, "/")
Expand All @@ -484,7 +472,7 @@ func testJWT(p *Pack, t *testing.T) {
verifyJWT(t, p, token, p.jwtAppURI)

// Connect to websocket application that dumps the upgrade request.
wsCookies := p.CreateAppSession(t, p.wsHeaderAppPublicAddr, p.wsHeaderAppClusterName)
wsCookies := p.CreateAppSessionCookies(t, p.wsHeaderAppPublicAddr, p.wsHeaderAppClusterName)
body, err := p.makeWebsocketRequest(wsCookies, "/")
require.NoError(t, err)

Expand All @@ -502,7 +490,7 @@ func testJWT(p *Pack, t *testing.T) {
// by values passed in by the user.
func testNoHeaderOverrides(p *Pack, t *testing.T) {
// Create an application session.
appCookies := p.CreateAppSession(t, p.headerAppPublicAddr, p.headerAppClusterName)
appCookies := p.CreateAppSessionCookies(t, p.headerAppPublicAddr, p.headerAppClusterName)

// Get HTTP headers forwarded to the application.
status, origHeaderResp, err := p.MakeRequest(appCookies, http.MethodGet, "/")
Expand Down Expand Up @@ -535,7 +523,7 @@ func testNoHeaderOverrides(p *Pack, t *testing.T) {
}

func testAuditEvents(p *Pack, t *testing.T) {
inCookies := p.CreateAppSession(t, p.rootAppPublicAddr, p.rootAppClusterName)
inCookies := p.CreateAppSessionCookies(t, p.rootAppPublicAddr, p.rootAppClusterName)

status, body, err := p.MakeRequest(inCookies, http.MethodGet, "/")
require.NoError(t, err)
Expand Down Expand Up @@ -593,7 +581,7 @@ func TestInvalidateAppSessionsOnLogout(t *testing.T) {
p := Setup(t)

// Create an application session.
appCookies := p.CreateAppSession(t, p.rootAppPublicAddr, p.rootAppClusterName)
appCookies := p.CreateAppSessionCookies(t, p.rootAppPublicAddr, p.rootAppClusterName)
sessID := helpers.ParseCookies(t, appCookies).SessionCookie.Value

// Issue a request to the application to guarantee everything is working correctly.
Expand Down Expand Up @@ -640,18 +628,8 @@ func TestTCP(t *testing.T) {
pack := Setup(t)
evilUser, _ := pack.CreateUser(t)

rootWs, err := pack.tc.CreateAppSession(context.Background(), &proto.CreateAppSessionRequest{
Username: pack.tc.Username,
PublicAddr: pack.rootTCPPublicAddr,
ClusterName: pack.rootAppClusterName,
})
require.NoError(t, err)
leafWs, err := pack.tc.CreateAppSession(context.Background(), &proto.CreateAppSessionRequest{
Username: pack.tc.Username,
PublicAddr: pack.leafTCPPublicAddr,
ClusterName: pack.leafAppClusterName,
})
require.NoError(t, err)
rootWs := pack.CreateAppSession(t, pack.tc.Username, pack.rootAppClusterName, pack.rootTCPPublicAddr)
leafWs := pack.CreateAppSession(t, pack.tc.Username, pack.rootAppClusterName, pack.leafTCPPublicAddr)

tests := []struct {
description string
Expand Down Expand Up @@ -719,17 +697,13 @@ func TestTCPLock(t *testing.T) {
msg := []byte(uuid.New().String())

// Start the proxy to the two way communication app.
rootWs, err := pack.tc.CreateAppSession(context.Background(), &proto.CreateAppSessionRequest{
Username: pack.tc.Username,
PublicAddr: pack.rootTCPTwoWayPublicAddr,
ClusterName: pack.rootAppClusterName,
})
require.NoError(t, err)
rootWs := pack.CreateAppSession(t, pack.tc.Username, pack.rootAppClusterName, pack.rootTCPTwoWayPublicAddr)
tlsConfig := pack.makeTLSConfig(t, rootWs.GetName(), rootWs.GetUser(), pack.rootTCPTwoWayPublicAddr, pack.rootAppClusterName, "")

address := pack.startLocalProxy(t, tlsConfig)

var conn net.Conn
var err error
var n int
buf := make([]byte, 1024)

Expand Down Expand Up @@ -797,17 +771,13 @@ func TestTCPCertExpiration(t *testing.T) {
msg := []byte(uuid.New().String())

// Start the proxy to the two way communication app.
rootWs, err := pack.tc.CreateAppSession(context.Background(), &proto.CreateAppSessionRequest{
Username: pack.tc.Username,
PublicAddr: pack.rootTCPTwoWayPublicAddr,
ClusterName: pack.rootAppClusterName,
})
require.NoError(t, err)
rootWs := pack.CreateAppSession(t, pack.tc.Username, pack.rootAppClusterName, pack.rootTCPTwoWayPublicAddr)
tlsConfig := pack.makeTLSConfig(t, rootWs.GetName(), rootWs.GetUser(), pack.rootTCPTwoWayPublicAddr, pack.rootAppClusterName, "")

address := pack.startLocalProxy(t, tlsConfig)

var conn net.Conn
var err error
var n int
buf := make([]byte, 1024)

Expand Down Expand Up @@ -947,8 +917,8 @@ func testServersHA(p *Pack, t *testing.T) {
t.Run(name, func(t *testing.T) {
t.Parallel()
info := test.packInfo(p)
httpCookies := p.CreateAppSession(t, info.publicHTTPAddr, info.clusterName)
wsCookies := p.CreateAppSession(t, info.publicWSAddr, info.clusterName)
httpCookies := p.CreateAppSessionCookies(t, info.publicHTTPAddr, info.clusterName)
wsCookies := p.CreateAppSessionCookies(t, info.publicWSAddr, info.clusterName)

makeRequests(t, p, httpCookies, wsCookies, responseWithoutError)

Expand Down
43 changes: 33 additions & 10 deletions integration/appaccess/pack.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ import (

"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/breaker"
"github.com/gravitational/teleport/api/client/proto"
apidefaults "github.com/gravitational/teleport/api/defaults"
"github.com/gravitational/teleport/api/types"
apievents "github.com/gravitational/teleport/api/types/events"
"github.com/gravitational/teleport/integration/helpers"
"github.com/gravitational/teleport/lib/auth"
"github.com/gravitational/teleport/lib/auth/native"
"github.com/gravitational/teleport/lib/client"
"github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/events"
"github.com/gravitational/teleport/lib/httplib/csrf"
"github.com/gravitational/teleport/lib/httplib/reverseproxy"
Expand Down Expand Up @@ -303,9 +303,10 @@ func (p *Pack) GenerateAndSetupUserCreds(t *testing.T, tc *client.TeleportClient
require.NoError(t, err)
}

// CreateAppSession creates an application session with the root cluster. The
// application that the user connects to may be running in a leaf cluster.
func (p *Pack) CreateAppSession(t *testing.T, publicAddr, clusterName string) []*http.Cookie {
// CreateAppSessionCookies creates an application session with the root cluster through the web
// API and returns the app session cookies. The application that the user connects to may be
// running in a leaf cluster.
func (p *Pack) CreateAppSessionCookies(t *testing.T, publicAddr, clusterName string) []*http.Cookie {
require.NotEmpty(t, p.webCookie)
require.NotEmpty(t, p.webToken)

Expand Down Expand Up @@ -341,16 +342,38 @@ func (p *Pack) CreateAppSession(t *testing.T, publicAddr, clusterName string) []
// cluster and returns the client cert that can be used for an application
// request.
func (p *Pack) CreateAppSessionWithClientCert(t *testing.T) []tls.Certificate {
session, err := p.tc.CreateAppSession(context.Background(), &proto.CreateAppSessionRequest{
Username: p.username,
PublicAddr: p.rootAppPublicAddr,
ClusterName: p.rootAppClusterName,
})
require.NoError(t, err)
session := p.CreateAppSession(t, p.username, p.rootAppPublicAddr, p.rootAppClusterName)
config := p.makeTLSConfig(t, session.GetName(), session.GetUser(), p.rootAppPublicAddr, p.rootAppClusterName, "")
return config.Certificates
}

func (p *Pack) CreateAppSession(t *testing.T, username, clusterName, appPublicAddr string) types.WebSession {
privateKey, publicKey, err := native.GenerateKeyPair()
require.NoError(t, err)

certificate, err := p.rootCluster.Process.GetAuthServer().GenerateUserAppTestCert(
auth.AppTestCertRequest{
PublicKey: publicKey,
Username: username,
TTL: time.Hour,
PublicAddr: appPublicAddr,
ClusterName: clusterName,
})
require.NoError(t, err)

token, err := utils.CryptoRandomHex(defaults.SessionTokenBytes)
require.NoError(t, err)

ws, err := types.NewWebSession(token, types.KindAppSession, types.WebSessionSpecV2{
Priv: privateKey,
Pub: publicKey,
TLSCert: certificate,
})
require.NoError(t, err)

return ws
}

// LockUser will lock the configured user for this pack.
func (p *Pack) LockUser(t *testing.T) {
err := p.rootCluster.Process.GetAuthServer().UpsertLock(context.Background(), &types.LockV2{
Expand Down
4 changes: 2 additions & 2 deletions integration/proxy/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1238,14 +1238,14 @@ func TestALPNSNIProxyAppAccess(t *testing.T) {
})

t.Run("root cluster", func(t *testing.T) {
cookies := pack.CreateAppSession(t, pack.RootAppPublicAddr(), pack.RootAppClusterName())
cookies := pack.CreateAppSessionCookies(t, pack.RootAppPublicAddr(), pack.RootAppClusterName())
status, _, err := pack.MakeRequest(cookies, http.MethodGet, "/")
require.NoError(t, err)
require.Equal(t, http.StatusOK, status)
})

t.Run("leaf cluster", func(t *testing.T) {
cookies := pack.CreateAppSession(t, pack.LeafAppPublicAddr(), pack.LeafAppClusterName())
cookies := pack.CreateAppSessionCookies(t, pack.LeafAppPublicAddr(), pack.LeafAppClusterName())
status, _, err := pack.MakeRequest(cookies, http.MethodGet, "/")
require.NoError(t, err)
require.Equal(t, http.StatusOK, status)
Expand Down
Loading
Loading