Tweak manual enroll profile permissions (#50688)

<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.

- [x] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements), JS
inline code is prevented especially for url redirects, and untrusted
data interpolated into shell scripts/commands is validated against shell
metacharacters.
- [x] Timeouts are implemented and retries are limited to avoid infinite
loops
- [x] If paths of existing endpoints are modified without backwards
compatibility, checked the frontend/CLI for any necessary changes

## Testing

- [x] Added/updated automated tests
- [x] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)

- [x] QA'd all new/changed functionality manually

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Restricted access to manual MDM enrollment profiles to global or team
administrators and maintainers.
* Prevented unauthenticated, roleless, observer, and GitOps users from
viewing enrollment profile data.
* Updated authorization documentation to reflect the required
permissions.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Jordan Montgomery
2026-08-06 14:00:49 -04:00
committed by GitHub
parent dd0c275974
commit 133e4a3832
4 changed files with 52 additions and 9 deletions
@@ -0,0 +1 @@
- Restricted the manual MDM enrollment profile endpoint (`GET /api/v1/fleet/enrollment_profiles/manual`) to global and fleet-scoped admins and maintainers.
+12 -2
View File
@@ -1192,10 +1192,20 @@ allow {
action == write
}
# Any logged in user can read the manual enrollment profile data.
# The manual enrollment profile embeds the SCEP challenge, so it is restricted
# to the same roles as enroll secrets.
# Global admins and maintainers can read the manual enrollment profile data.
allow {
object.type == "mdm_apple_manual_enrollment_profile"
not is_null(subject)
subject.global_role == [admin, maintainer][_]
action == read
}
# Team admins and maintainers can read the manual enrollment profile data.
allow {
object.type == "mdm_apple_manual_enrollment_profile"
team_role(subject, subject.teams[_].id) == [admin, maintainer][_]
action == read
}
+24
View File
@@ -2611,6 +2611,30 @@ func TestAuthorizeMDMAppleSetupAssistant(t *testing.T) {
})
}
func TestAuthorizeMDMAppleManualEnrollmentProfile(t *testing.T) {
t.Parallel()
profile := &fleet.MDMAppleManualEnrollmentProfile{}
runTestCases(t, []authTestCase{
{user: nil, object: profile, action: read, allow: false},
{user: test.UserNoRoles, object: profile, action: read, allow: false},
{user: test.UserAdmin, object: profile, action: read, allow: true},
{user: test.UserMaintainer, object: profile, action: read, allow: true},
{user: test.UserObserver, object: profile, action: read, allow: false},
{user: test.UserObserverPlus, object: profile, action: read, allow: false},
{user: test.UserTechnician, object: profile, action: read, allow: false},
{user: test.UserGitOps, object: profile, action: read, allow: false},
{user: test.UserTeamAdminTeam1, object: profile, action: read, allow: true},
{user: test.UserTeamMaintainerTeam1, object: profile, action: read, allow: true},
{user: test.UserTeamObserverTeam1, object: profile, action: read, allow: false},
{user: test.UserTeamObserverPlusTeam1, object: profile, action: read, allow: false},
{user: test.UserTeamTechnicianTeam1, object: profile, action: read, allow: false},
{user: test.UserTeamGitOpsTeam1, object: profile, action: read, allow: false},
})
}
func TestAuthorizeMDMAppleBootstrapPackage(t *testing.T) {
t.Parallel()
+15 -7
View File
@@ -356,23 +356,31 @@ func TestAppleMDMAuthorization(t *testing.T) {
_, err = svc.NewMDMAppleDEPKeyPair(ctx)
require.NoError(t, err)
// Should work for all user types
// The manual enrollment profile embeds the SCEP challenge, so only global
// and team admins and maintainers can read it (same roles as enroll secrets).
for _, user := range []*fleet.User{
test.UserAdmin,
test.UserMaintainer,
test.UserObserver,
test.UserObserverPlus,
test.UserTeamAdminTeam1,
test.UserTeamGitOpsTeam1,
test.UserGitOps,
test.UserTeamMaintainerTeam1,
test.UserTeamObserverTeam1,
test.UserTeamObserverPlusTeam1,
} {
usrctx := test.UserContext(ctx, user)
_, err = svc.GetMDMManualEnrollmentProfile(usrctx, false)
require.NoError(t, err)
}
for _, user := range []*fleet.User{
test.UserNoRoles,
test.UserObserver,
test.UserObserverPlus,
test.UserGitOps,
test.UserTeamObserverTeam1,
test.UserTeamObserverPlusTeam1,
test.UserTeamGitOpsTeam1,
} {
usrctx := test.UserContext(ctx, user)
_, err = svc.GetMDMManualEnrollmentProfile(usrctx, false)
checkAuthErr(t, err, true)
}
// Must be device-authenticated, should fail
_, err = svc.GetDeviceMDMAppleEnrollmentProfile(ctx)