Skip to content

Commit

Permalink
[Fleet] Use a scopped SO client in agent policies handler to avoid sp…
Browse files Browse the repository at this point in the history
…aces divulgation (#211506)
  • Loading branch information
nchaulet authored Feb 19, 2025
1 parent 5908bf4 commit 0ae316f
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import { AgentPolicyNotFoundError, FleetUnauthorizedError, FleetError } from '..
import { createAgentPolicyWithPackages } from '../../services/agent_policy_create';
import { updateAgentPolicySpaces } from '../../services/spaces/agent_policy';
import { packagePolicyToSimplifiedPackagePolicy } from '../../../common/services/simplified_package_policy_helper';
import { FLEET_API_PRIVILEGES } from '../../constants/api_privileges';
import { getAutoUpgradeAgentsStatus } from '../../services/agents';

export async function populateAssignedAgentsCount(
Expand Down Expand Up @@ -133,16 +134,25 @@ export const getAgentPoliciesHandler: FleetRequestHandler<
TypeOf<typeof GetAgentPoliciesRequestSchema.query>
> = async (context, request, response) => {
const [coreContext, fleetContext] = await Promise.all([context.core, context.fleet]);
const soClient = fleetContext.internalSoClient;

const authzFleetReadAgentPolicies =
request.authzResult?.[FLEET_API_PRIVILEGES.AGENT_POLICIES.READ] === true;
const authzFleetAgentRead = request.authzResult?.[FLEET_API_PRIVILEGES.AGENTS.READ] === true;

const soClient =
authzFleetReadAgentPolicies || authzFleetAgentRead
? coreContext.savedObjects.client
: fleetContext.internalSoClient;
const esClient = coreContext.elasticsearch.client.asInternalUser;

const {
full: withPackagePolicies = false,
noAgentCount,
withAgentCount,
format,
...restOfQuery
} = request.query;
if (!fleetContext.authz.fleet.readAgentPolicies && withPackagePolicies) {
if (!authzFleetReadAgentPolicies && withPackagePolicies) {
throw new FleetUnauthorizedError(
'full query parameter require agent policies read permissions'
);
Expand All @@ -155,11 +165,11 @@ export const getAgentPoliciesHandler: FleetRequestHandler<
let { items } = agentPoliciesResponse;
const { total, page, perPage } = agentPoliciesResponse;

if (fleetContext.authz.fleet.readAgents && (noAgentCount === false || withAgentCount)) {
if (authzFleetAgentRead && (noAgentCount === false || withAgentCount)) {
await populateAssignedAgentsCount(fleetContext.agentClient.asCurrentUser, items);
}

if (!fleetContext.authz.fleet.readAgentPolicies) {
if (!authzFleetReadAgentPolicies) {
items = items.map(sanitizeItemForReadAgentOnly);
} else if (withPackagePolicies && format === inputsFormat.Simplified) {
items.map((item) => {
Expand Down Expand Up @@ -190,10 +200,18 @@ export const bulkGetAgentPoliciesHandler: FleetRequestHandler<
TypeOf<typeof BulkGetAgentPoliciesRequestSchema.body>
> = async (context, request, response) => {
try {
const fleetContext = await context.fleet;
const soClient = fleetContext.internalSoClient;
const [coreContext, fleetContext] = await Promise.all([context.core, context.fleet]);
const authzFleetReadAgentPolicies =
request.authzResult?.[FLEET_API_PRIVILEGES.AGENT_POLICIES.READ] === true;
const authzFleetAgentRead = request.authzResult?.[FLEET_API_PRIVILEGES.AGENTS.READ] === true;

const soClient =
authzFleetReadAgentPolicies || authzFleetAgentRead
? coreContext.savedObjects.client
: fleetContext.internalSoClient;

const { full: withPackagePolicies = false, ignoreMissing = false, ids } = request.body;
if (!fleetContext.authz.fleet.readAgentPolicies && withPackagePolicies) {
if (!authzFleetReadAgentPolicies && withPackagePolicies) {
throw new FleetUnauthorizedError(
'full query parameter require agent policies read permissions'
);
Expand All @@ -202,7 +220,7 @@ export const bulkGetAgentPoliciesHandler: FleetRequestHandler<
withPackagePolicies,
ignoreMissing,
});
if (!fleetContext.authz.fleet.readAgentPolicies) {
if (!authzFleetReadAgentPolicies) {
items = items.map(sanitizeItemForReadAgentOnly);
} else if (withPackagePolicies && request.query.format === inputsFormat.Simplified) {
items.map((item) => {
Expand All @@ -221,7 +239,7 @@ export const bulkGetAgentPoliciesHandler: FleetRequestHandler<
const body: BulkGetAgentPoliciesResponse = {
items,
};
if (fleetContext.authz.fleet.readAgents) {
if (authzFleetAgentRead) {
await populateAssignedAgentsCount(fleetContext.agentClient.asCurrentUser, items);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export default function (providerContext: FtrProviderContext) {
let defaultSpacePolicy1: CreateAgentPolicyResponse;
let spaceTest1Policy1: CreateAgentPolicyResponse;
let spaceTest1Policy2: CreateAgentPolicyResponse;
let defaultAndTestSpacePolicy: CreateAgentPolicyResponse;

before(async () => {
await setupTestUsers(getService('security'), true);
Expand All @@ -51,16 +52,24 @@ export default function (providerContext: FtrProviderContext) {

await apiClient.postEnableSpaceAwareness();

const [_defaultSpacePolicy1, _spaceTest1Policy1, _spaceTest1Policy2] = await Promise.all([
await spaces.createTestSpace(TEST_SPACE_1);
const [
_defaultSpacePolicy1,
_spaceTest1Policy1,
_spaceTest1Policy2,
_defaultAndTestSpacePolicy,
] = await Promise.all([
apiClient.createAgentPolicy(),
apiClient.createAgentPolicy(TEST_SPACE_1),
apiClient.createAgentPolicy(TEST_SPACE_1),
apiClient.createAgentPolicy(undefined, {
space_ids: ['default', TEST_SPACE_1],
}),
]);
defaultSpacePolicy1 = _defaultSpacePolicy1;
spaceTest1Policy1 = _spaceTest1Policy1;
spaceTest1Policy2 = _spaceTest1Policy2;

await spaces.createTestSpace(TEST_SPACE_1);
defaultAndTestSpacePolicy = _defaultAndTestSpacePolicy;
});

after(async () => {
Expand All @@ -74,20 +83,31 @@ export default function (providerContext: FtrProviderContext) {
describe('GET /agent_policies', () => {
it('should return policies in a specific space', async () => {
const agentPolicies = await apiClient.getAgentPolicies(TEST_SPACE_1);
expect(agentPolicies.total).to.eql(2);
expect(agentPolicies.total).to.eql(3);
const policyIds = agentPolicies.items?.map((item) => item.id);
expect(policyIds).to.contain(spaceTest1Policy1.item.id);
expect(policyIds).to.contain(spaceTest1Policy2.item.id);
expect(policyIds).to.contain(defaultAndTestSpacePolicy.item.id);
expect(policyIds).not.to.contain(defaultSpacePolicy1.item.id);
});

it('should return policies in default space', async () => {
const agentPolicies = await apiClient.getAgentPolicies();
expect(agentPolicies.total).to.eql(1);
expect(agentPolicies.total).to.eql(2);
const policyIds = agentPolicies.items?.map((item) => item.id);
expect(policyIds).not.to.contain(spaceTest1Policy1.item.id);
expect(policyIds).not.contain(spaceTest1Policy2.item.id);
expect(policyIds).to.contain(defaultSpacePolicy1.item.id);
expect(policyIds).to.contain(defaultAndTestSpacePolicy.item.id);
});

it('should return only spaces user can access', async () => {
const agentPolicies = await apiClientDefaultSpaceOnly.getAgentPolicies();

expect(
agentPolicies.items.find((item) => item.id === defaultAndTestSpacePolicy.item.id)
?.space_ids
).to.eql(['default', '?']);
});
});

Expand All @@ -104,6 +124,14 @@ export default function (providerContext: FtrProviderContext) {
apiClient.getAgentPolicy(defaultSpacePolicy1.item.id, TEST_SPACE_1)
);
});

it('should return only spaces user can access', async () => {
const policyRes = await apiClientDefaultSpaceOnly.getAgentPolicy(
defaultAndTestSpacePolicy.item.id
);

expect(policyRes.item.space_ids).to.eql(['default', '?']);
});
});

describe('POST /agent_policies', () => {
Expand Down

0 comments on commit 0ae316f

Please sign in to comment.