[Fleet] Prevent agents from enrolling in a managed policy (#90458)

## Summary
Add guard to `/agents/enroll` API preventing agents from enrolling in managed policies

closes #90435
- [x] No Agents can be enrolled into this policy by the user.
- [x] The install & enroll commands should print an error to the console if the enroll command fails (due to being a managed policy or any other reason)



#### So how do you associate an agent with a managed policy?
Enroll in an unmanaged policy then set that policy to managed. 

We don't restrict the agent policy, only what other things (agents, integrations) can do if they're associated with a managed policy.

A _force flag_ has been mentioned for some other actions. It might work here as well, but I'd like to handle discussion & implementation of those later.

### Manual testing
<details><summary>Prevent enroll for managed policies</summary>

1. Created a managed agent policy
    ```
    curl --user elastic:changeme -X POST localhost:5601/api/fleet/agent_policies -H 'Content-Type: application/json' -d'{ "name": "User created MANAGED", "namespace": "default", "is_managed": true}' -H 'kbn-xsrf: true'
    {"item":{"id":"3bd07db0-67d0-11eb-b656-21ad68ebfa8a","name":"User created MANAGED","namespace":"default","is_managed":true,"revision":1,"updated_at":"2021-02-05T16:36:01.931Z","updated_by":"elastic"}}
    ```
2. Try `install` command show in the UI
    ```
    sudo ./elastic-agent install -f --kibana-url=http://localhost:5601 --enrollment-token=WmcwTWMzY0IzWlBUUWJJUjZqRDA6UGRZelVlaS1STml1cVdjSUVwSkJRQQ== --insecure
    Password:
    The Elastic Agent is currently in BETA and should not be used in production

    Error: fail to enroll: fail to execute request to Kibana: Status code: 400, Kibana returned an error: Bad Request, message: Cannot enroll in managed policy 3bd07db0-67d0-11eb-b656-21ad68ebfa8a
    Error: enroll command failed with exit code: 1
    ```
3. Observe `Cannot enroll in managed policy 3bd07db0-67d0-11eb-b656-21ad68ebfa8a` error
4. Try `enroll` instead:
    ```
    sudo ./elastic-agent enroll http://localhost:5601 WmcwTWMzY0IzWlBUUWJJUjZqRDA6UGRZelVlaS1STml1cVdjSUVwSkJRQQ== --insecure
    The Elastic Agent is currently in BETA and should not be used in production

    This will replace your current settings. Do you want to continue? [Y/n]:
    Error: fail to enroll: fail to execute request to Kibana: Status code: 400, Kibana returned an error: Bad Request, message: Cannot enroll in managed policy 3bd07db0-67d0-11eb-b656-21ad68ebfa8a
    ```
5. Observe same `Cannot enroll in managed policy 3bd07db0-67d0-11eb-b656-21ad68ebfa8a` error

</details>

<details><summary>Enroll in unmanaged policy, then update it to managed</summary>

Agent policies are `is_managed: false` by default, or we can update the policy to `is_managed: false`, like:

```
curl --user elastic:changeme -X PUT localhost:5601/api/fleet/agent_policies/3bd07db0-67d0-11eb-b656-21ad68ebfa8a -H 'Content-Type: application/json' -d'{ "is_managed": false, "name": "xyz", "namespace": "default" }' -H 'kbn-xsrf: true'
{"item":{"id":"3bd07db0-67d0-11eb-b656-21ad68ebfa8a","name":"xyz","namespace":"default","is_managed":false,"revision":4,"updated_at":"2021-02-05T17:42:05.610Z","updated_by":"elastic","package_policies":[]}}
```

then enroll

```
 sudo ./elastic-agent install -f --kibana-url=http://localhost:5601 --enrollment-token=WmcwTWMzY0IzWlBUUWJJUjZqRDA6UGRZelVlaS1STml1cVdjSUVwSkJRQQ== --insecure
The Elastic Agent is currently in BETA and should not be used in production

Successfully enrolled the Elastic Agent.
Installation was successful and Elastic Agent is running.
```

and set the policy back to managed

```
curl --user elastic:changeme -X PUT localhost:5601/api/fleet/agent_policies/3bd07db0-67d0-11eb-b656-21ad68ebfa8a -H 'Content-Type: application/json' -d'{ "is_managed": true, "name": "xyz", "namespace": "default" }' -H 'kbn-xsrf: true'
{"item":{"id":"3bd07db0-67d0-11eb-b656-21ad68ebfa8a","name":"xyz","namespace":"default","is_managed":true,"revision":5,"updated_at":"2021-02-05T17:44:18.757Z","updated_by":"elastic","package_policies":[]}}
```

with all the restrictions that entails (cannot unenroll, reassign, etc)

```
curl --user elastic:changeme -X PUT 'http://localhost:5601/api/fleet/agents/8169f0a0-67d9-11eb-80f2-73dd45e7318e/reassign'   -X 'PUT'  -H 'kbn-xsrf: abc'  -H 'Content-Type: application/json'   --data-raw '{"policy_id":"729f8440-67cf-11eb-b656-21ad68ebfa8a"}'   
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Cannot reassign an agent from managed agent policy 3bd07db0-67d0-11eb-b656-21ad68ebfa8a"
}
```

</details>

### Checklist
- [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
John Schulz 2021-02-09 08:54:51 -05:00 committed by GitHub
parent 731e333078
commit 810e4ab8e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 3 deletions

View file

@ -11,11 +11,13 @@ import semverParse from 'semver/functions/parse';
import semverDiff from 'semver/functions/diff';
import semverLte from 'semver/functions/lte';
import { SavedObjectsClientContract } from 'src/core/server';
import { AgentType, Agent, AgentSOAttributes, FleetServerAgent } from '../../types';
import type { SavedObjectsClientContract } from 'src/core/server';
import type { AgentType, Agent, AgentSOAttributes, FleetServerAgent } from '../../types';
import { savedObjectToAgent } from './saved_objects';
import { AGENT_SAVED_OBJECT_TYPE, AGENTS_INDEX } from '../../constants';
import { IngestManagerError } from '../../errors';
import * as APIKeyService from '../api_keys';
import { agentPolicyService } from '../../services';
import { appContextService } from '../app_context';
export async function enroll(
@ -27,6 +29,11 @@ export async function enroll(
const agentVersion = metadata?.local?.elastic?.agent?.version;
validateAgentVersion(agentVersion);
const agentPolicy = await agentPolicyService.get(soClient, agentPolicyId, false);
if (agentPolicy?.is_managed) {
throw new IngestManagerError(`Cannot enroll in managed policy ${agentPolicyId}`);
}
if (appContextService.getConfig()?.agents?.fleetServerEnabled) {
const esClient = appContextService.getInternalUserESClient();

View file

@ -18,8 +18,9 @@ export default function (providerContext: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const esClient = getService('es');
const kibanaServer = getService('kibanaServer');
const supertestWithAuth = getService('supertest');
const supertest = getSupertestWithoutAuth(providerContext);
let apiKey: { id: string; api_key: string };
let kibanaVersion: string;
@ -58,6 +59,51 @@ export default function (providerContext: FtrProviderContext) {
await esArchiver.unload('fleet/agents');
});
it('should not allow enrolling in a managed policy', async () => {
// update existing policy to managed
await supertestWithAuth
.put(`/api/fleet/agent_policies/policy1`)
.set('kbn-xsrf', 'xxxx')
.send({
name: 'Test policy',
namespace: 'default',
is_managed: true,
})
.expect(200);
// try to enroll in managed policy
const { body } = await supertest
.post(`/api/fleet/agents/enroll`)
.set('kbn-xsrf', 'xxx')
.set(
'Authorization',
`ApiKey ${Buffer.from(`${apiKey.id}:${apiKey.api_key}`).toString('base64')}`
)
.send({
type: 'PERMANENT',
metadata: {
local: {
elastic: { agent: { version: kibanaVersion } },
},
user_provided: {},
},
})
.expect(400);
expect(body.message).to.contain('Cannot enroll in managed policy');
// restore to original (unmanaged)
await supertestWithAuth
.put(`/api/fleet/agent_policies/policy1`)
.set('kbn-xsrf', 'xxxx')
.send({
name: 'Test policy',
namespace: 'default',
is_managed: false,
})
.expect(200);
});
it('should not allow to enroll an agent with a invalid enrollment', async () => {
await supertest
.post(`/api/fleet/agents/enroll`)