diff --git a/changes/fix-manual-enrollment-profile-permissions b/changes/fix-manual-enrollment-profile-permissions new file mode 100644 index 0000000000..fa790ab146 --- /dev/null +++ b/changes/fix-manual-enrollment-profile-permissions @@ -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. diff --git a/server/authz/policy.rego b/server/authz/policy.rego index c8b8e6e11c..0c3d4bd0a7 100644 --- a/server/authz/policy.rego +++ b/server/authz/policy.rego @@ -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 } diff --git a/server/authz/policy_test.go b/server/authz/policy_test.go index f48c5a5f79..72505b3ba6 100644 --- a/server/authz/policy_test.go +++ b/server/authz/policy_test.go @@ -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() diff --git a/server/service/apple_mdm_test.go b/server/service/apple_mdm_test.go index 58f6a02d09..50397464d1 100644 --- a/server/service/apple_mdm_test.go +++ b/server/service/apple_mdm_test.go @@ -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)