mirror of
https://github.com/gravitational/teleport.git
synced 2026-09-19 01:58:44 +08:00
Prevent users from creating apps for the beam app service (#66937)
Beams runs an app_service, configured to look for apps with the "teleport.internal/beams/app-type" label. Users should not be able to create apps with this label - we expect these apps are only created via static beams config or via the `tsh beams publish` command. It's safe to block these requests at the RPC layer because beam apps are written directly to storage and don't go through these auth RPCs.
This commit is contained in:
@@ -1355,20 +1355,23 @@ const (
|
||||
// AppSubKindLabel is the label that has the same value of "app.sub_kind".
|
||||
AppSubKindLabel = TeleportInternalLabelPrefix + "app-sub-kind"
|
||||
|
||||
// BeamsInternalLabelPrefix is the prefix used by internal beams labels.
|
||||
BeamsInternalLabelPrefix = TeleportInternalLabelPrefix + "beams/"
|
||||
|
||||
// BeamIDLabel is the label used to track which Beam a resource belongs to.
|
||||
BeamIDLabel = TeleportInternalLabelPrefix + "beams/id"
|
||||
BeamIDLabel = BeamsInternalLabelPrefix + "id"
|
||||
|
||||
// BeamOwnerLabel is the label used to track which user's Beam a resource
|
||||
// belongs to.
|
||||
BeamOwnerLabel = TeleportInternalLabelPrefix + "beams/owner"
|
||||
BeamOwnerLabel = BeamsInternalLabelPrefix + "owner"
|
||||
|
||||
// BeamAliasLabel is the label used to track the alias of the Beam a
|
||||
// resource belongs to.
|
||||
BeamAliasLabel = TeleportInternalLabelPrefix + "beams/alias"
|
||||
BeamAliasLabel = BeamsInternalLabelPrefix + "alias"
|
||||
|
||||
// BeamAppTypeLabel is the label used to denote the type of app created for
|
||||
// Beams. Valid values: "ingress" and "llm".
|
||||
BeamAppTypeLabel = TeleportInternalLabelPrefix + "beams/app-type"
|
||||
BeamAppTypeLabel = BeamsInternalLabelPrefix + "app-type"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -6957,6 +6957,15 @@ func sessionTypeFromStartEvent(sessionStart apievents.AuditEvent) types.SessionK
|
||||
}
|
||||
}
|
||||
|
||||
func hasInternalBeamsLabel(labels map[string]string) bool {
|
||||
for key := range maps.Keys(labels) {
|
||||
if strings.HasPrefix(key, types.BeamsInternalLabelPrefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// CreateApp creates a new application resource.
|
||||
func (a *ServerWithRoles) CreateApp(ctx context.Context, app types.Application) error {
|
||||
if err := a.authorizeAction(types.KindApp, types.VerbCreate); err != nil {
|
||||
@@ -6973,6 +6982,13 @@ func (a *ServerWithRoles) CreateApp(ctx context.Context, app types.Application)
|
||||
if err := a.checkAccessToApp(app); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
// Users are not allowed to create apps that would be picked up
|
||||
// by the beams app_service.
|
||||
if hasInternalBeamsLabel(app.GetAllLabels()) {
|
||||
return trace.AccessDenied("access denied")
|
||||
}
|
||||
|
||||
return trace.Wrap(a.authServer.CreateApp(ctx, app))
|
||||
}
|
||||
|
||||
@@ -6998,6 +7014,13 @@ func (a *ServerWithRoles) UpdateApp(ctx context.Context, app types.Application)
|
||||
if err := a.checkAccessToApp(app); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
// Users are not allowed to create apps that would be picked up
|
||||
// by the beams app_service.
|
||||
if hasInternalBeamsLabel(app.GetAllLabels()) {
|
||||
return trace.AccessDenied("access denied")
|
||||
}
|
||||
|
||||
return trace.Wrap(a.authServer.UpdateApp(ctx, app))
|
||||
}
|
||||
|
||||
|
||||
@@ -4085,7 +4085,7 @@ func TestListSAMLIdPServiceProviderAndListResources(t *testing.T) {
|
||||
// TestApps verifies RBAC is applied to app resources.
|
||||
func TestApps(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
ctx := t.Context()
|
||||
srv := newTestTLSServer(t)
|
||||
|
||||
// Setup a couple of users:
|
||||
@@ -4093,19 +4093,25 @@ func TestApps(t *testing.T) {
|
||||
// - "admin" has access to all apps
|
||||
dev, devRole, err := authtest.CreateUserAndRole(srv.Auth(), "dev", nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
devRole.SetAppLabels(types.Allow, types.Labels{"env": {"dev"}})
|
||||
_, err = srv.Auth().UpsertRole(ctx, devRole)
|
||||
require.NoError(t, err)
|
||||
|
||||
devClt, err := srv.NewClient(authtest.TestUser(dev.GetName()))
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { devClt.Close() })
|
||||
|
||||
admin, adminRole, err := authtest.CreateUserAndRole(srv.Auth(), "admin", nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
adminRole.SetAppLabels(types.Allow, types.Labels{types.Wildcard: {types.Wildcard}})
|
||||
_, err = srv.Auth().UpsertRole(ctx, adminRole)
|
||||
require.NoError(t, err)
|
||||
|
||||
adminClt, err := srv.NewClient(authtest.TestUser(admin.GetName()))
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { adminClt.Close() })
|
||||
|
||||
// Prepare a couple of app resources.
|
||||
devApp, err := types.NewAppV3(types.Metadata{
|
||||
@@ -4115,6 +4121,7 @@ func TestApps(t *testing.T) {
|
||||
URI: "localhost1",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
adminApp, err := types.NewAppV3(types.Metadata{
|
||||
Name: "admin",
|
||||
Labels: map[string]string{"env": "prod", types.OriginLabel: types.OriginDynamic},
|
||||
@@ -4172,6 +4179,17 @@ func TestApps(t *testing.T) {
|
||||
cmpopts.IgnoreFields(types.Metadata{}, "Revision"),
|
||||
))
|
||||
|
||||
// Clients can't create/update apps for the beams service.
|
||||
adminApp.GetMetadata().Labels["teleport.internal/beams/app-type"] = "llm"
|
||||
err = adminClt.UpdateApp(ctx, adminApp)
|
||||
require.True(t, trace.IsAccessDenied(err))
|
||||
delete(adminApp.GetMetadata().Labels, "teleport.internal/beams/app-type")
|
||||
|
||||
beamApp := devApp.Copy()
|
||||
beamApp.GetMetadata().Labels["teleport.internal/beams/app-type"] = "llm"
|
||||
err = devClt.CreateApp(ctx, beamApp)
|
||||
require.True(t, trace.IsAccessDenied(err))
|
||||
|
||||
// When listing apps, dev should only see one.
|
||||
apps, err := devClt.GetApps(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
Reference in New Issue
Block a user