Update backend authz for software installers feature (#18513)

This commit is contained in:
Sarah Gillespie 2024-04-24 13:37:35 -05:00 committed by GitHub
parent 7e4bcae7c3
commit 845984e3e8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 139 additions and 2 deletions

View file

@ -643,6 +643,36 @@ allow {
action == read
}
# Global admins, maintainers, observers, and observer_plus can read any software installer.
allow {
object.type == "software_installer"
subject.global_role == [admin, maintainer, observer, observer_plus][_]
action == read
}
# Global admins, maintainers, and gitops can write any software installer.
allow {
object.type == "software_installer"
subject.global_role == [admin, maintainer, gitops][_]
action == write
}
# Team admins, maintainers, observers, and observer_plus can read any software installer in their teams.
allow {
not is_null(object.team_id)
object.type == "software_installer"
team_role(subject, object.team_id) == [admin, maintainer, observer, observer_plus][_]
action == read
}
# Team admins, maintainers, and gitops can write any software installer in their teams.
allow {
not is_null(object.team_id)
object.type == "software_installer"
team_role(subject, object.team_id) == [admin, maintainer, gitops][_]
action == write
}
##
# Apple and Windows MDM
##

View file

@ -500,6 +500,101 @@ func TestAuthorizeSoftwareInventory(t *testing.T) {
})
}
func TestAuthorizeSoftwareInstaller(t *testing.T) {
t.Parallel()
noTeamInstaller := &fleet.SoftwareInstaller{}
team1Installer := &fleet.SoftwareInstaller{TeamID: ptr.Uint(1)}
team2Installer := &fleet.SoftwareInstaller{TeamID: ptr.Uint(2)}
runTestCases(t, []authTestCase{
{user: nil, object: noTeamInstaller, action: read, allow: false},
{user: nil, object: noTeamInstaller, action: write, allow: false},
{user: nil, object: team1Installer, action: read, allow: false},
{user: nil, object: team1Installer, action: write, allow: false},
{user: nil, object: team2Installer, action: read, allow: false},
{user: nil, object: team2Installer, action: write, allow: false},
{user: test.UserNoRoles, object: noTeamInstaller, action: read, allow: false},
{user: test.UserNoRoles, object: noTeamInstaller, action: write, allow: false},
{user: test.UserNoRoles, object: team1Installer, action: read, allow: false},
{user: test.UserNoRoles, object: team1Installer, action: write, allow: false},
{user: test.UserNoRoles, object: team2Installer, action: read, allow: false},
{user: test.UserNoRoles, object: team2Installer, action: write, allow: false},
{user: test.UserAdmin, object: noTeamInstaller, action: read, allow: true},
{user: test.UserAdmin, object: noTeamInstaller, action: write, allow: true},
{user: test.UserAdmin, object: team1Installer, action: read, allow: true},
{user: test.UserAdmin, object: team1Installer, action: write, allow: true},
{user: test.UserAdmin, object: team2Installer, action: read, allow: true},
{user: test.UserAdmin, object: team2Installer, action: write, allow: true},
{user: test.UserMaintainer, object: noTeamInstaller, action: read, allow: true},
{user: test.UserMaintainer, object: noTeamInstaller, action: write, allow: true},
{user: test.UserMaintainer, object: team1Installer, action: read, allow: true},
{user: test.UserMaintainer, object: team1Installer, action: write, allow: true},
{user: test.UserMaintainer, object: team2Installer, action: read, allow: true},
{user: test.UserMaintainer, object: team2Installer, action: write, allow: true},
{user: test.UserObserver, object: noTeamInstaller, action: read, allow: true},
{user: test.UserObserver, object: noTeamInstaller, action: write, allow: false},
{user: test.UserObserver, object: team1Installer, action: read, allow: true},
{user: test.UserObserver, object: team1Installer, action: write, allow: false},
{user: test.UserObserver, object: team2Installer, action: read, allow: true},
{user: test.UserObserver, object: team2Installer, action: write, allow: false},
{user: test.UserObserverPlus, object: noTeamInstaller, action: read, allow: true},
{user: test.UserObserverPlus, object: noTeamInstaller, action: write, allow: false},
{user: test.UserObserverPlus, object: team1Installer, action: read, allow: true},
{user: test.UserObserverPlus, object: team1Installer, action: write, allow: false},
{user: test.UserObserverPlus, object: team2Installer, action: read, allow: true},
{user: test.UserObserverPlus, object: team2Installer, action: write, allow: false},
// TODO: confirm gitops permissions
{user: test.UserGitOps, object: noTeamInstaller, action: read, allow: false},
{user: test.UserGitOps, object: noTeamInstaller, action: write, allow: true},
{user: test.UserGitOps, object: team1Installer, action: read, allow: false},
{user: test.UserGitOps, object: team1Installer, action: write, allow: true},
{user: test.UserGitOps, object: team2Installer, action: read, allow: false},
{user: test.UserGitOps, object: team2Installer, action: write, allow: true},
// TODO: confirm gitops permissions
{user: test.UserTeamGitOpsTeam1, object: noTeamInstaller, action: read, allow: false},
{user: test.UserTeamGitOpsTeam1, object: noTeamInstaller, action: write, allow: false},
{user: test.UserTeamGitOpsTeam1, object: team1Installer, action: read, allow: false},
{user: test.UserTeamGitOpsTeam1, object: team1Installer, action: write, allow: true},
{user: test.UserTeamGitOpsTeam1, object: team2Installer, action: read, allow: false},
{user: test.UserTeamGitOpsTeam1, object: team2Installer, action: write, allow: false},
{user: test.UserTeamAdminTeam1, object: noTeamInstaller, action: read, allow: false},
{user: test.UserTeamAdminTeam1, object: noTeamInstaller, action: write, allow: false},
{user: test.UserTeamAdminTeam1, object: team1Installer, action: read, allow: true},
{user: test.UserTeamAdminTeam1, object: team1Installer, action: write, allow: true},
{user: test.UserTeamAdminTeam1, object: team2Installer, action: read, allow: false},
{user: test.UserTeamAdminTeam1, object: team2Installer, action: write, allow: false},
{user: test.UserTeamMaintainerTeam1, object: noTeamInstaller, action: read, allow: false},
{user: test.UserTeamMaintainerTeam1, object: noTeamInstaller, action: write, allow: false},
{user: test.UserTeamMaintainerTeam1, object: team1Installer, action: read, allow: true},
{user: test.UserTeamMaintainerTeam1, object: team1Installer, action: write, allow: true},
{user: test.UserTeamMaintainerTeam1, object: team2Installer, action: read, allow: false},
{user: test.UserTeamMaintainerTeam1, object: team2Installer, action: write, allow: false},
{user: test.UserTeamObserverTeam1, object: noTeamInstaller, action: read, allow: false},
{user: test.UserTeamObserverTeam1, object: noTeamInstaller, action: write, allow: false},
{user: test.UserTeamObserverTeam1, object: team1Installer, action: read, allow: true},
{user: test.UserTeamObserverTeam1, object: team1Installer, action: write, allow: false},
{user: test.UserTeamObserverTeam1, object: team2Installer, action: read, allow: false},
{user: test.UserTeamObserverTeam1, object: team2Installer, action: write, allow: false},
{user: test.UserTeamObserverPlusTeam1, object: noTeamInstaller, action: read, allow: false},
{user: test.UserTeamObserverPlusTeam1, object: noTeamInstaller, action: write, allow: false},
{user: test.UserTeamObserverPlusTeam1, object: team1Installer, action: read, allow: true},
{user: test.UserTeamObserverPlusTeam1, object: team1Installer, action: write, allow: false},
{user: test.UserTeamObserverPlusTeam1, object: team2Installer, action: read, allow: false},
{user: test.UserTeamObserverPlusTeam1, object: team2Installer, action: write, allow: false},
})
}
func TestAuthorizeHost(t *testing.T) {
t.Parallel()

View file

@ -18,8 +18,7 @@ type SoftwareInstallerStore interface {
// FailingSoftwareInstallerStore is an implementation of SoftwareInstallerStore
// that fails all operations. It is used when S3 is not configured and the
// local filesystem store could not be setup.
type FailingSoftwareInstallerStore struct {
}
type FailingSoftwareInstallerStore struct{}
func (FailingSoftwareInstallerStore) Get(ctx context.Context, installerID string) (io.ReadCloser, int64, error) {
return nil, 0, errors.New("software installer store not properly configured")
@ -32,3 +31,16 @@ func (FailingSoftwareInstallerStore) Put(ctx context.Context, installerID string
func (FailingSoftwareInstallerStore) Exists(ctx context.Context, installerID string) (bool, error) {
return false, errors.New("software installer store not properly configured")
}
// SoftwareInstaller represents a software installer package that can be used to install software on
// hosts in Fleet.
type SoftwareInstaller struct {
// TeamID is the ID of the team. A value of nil means it is scoped to hosts that are assigned to
// no team.
TeamID *uint `json:"team_id"`
}
// AuthzType implements authz.AuthzTyper.
func (s *SoftwareInstaller) AuthzType() string {
return "software_installer"
}