diff --git a/x-pack/legacy/plugins/fleet/public/hooks/use_input.tsx b/x-pack/legacy/plugins/fleet/public/hooks/use_input.tsx
new file mode 100644
index 0000000000000..4aa0ad7155d2f
--- /dev/null
+++ b/x-pack/legacy/plugins/fleet/public/hooks/use_input.tsx
@@ -0,0 +1,24 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+
+export function useInput(defaultValue = '') {
+  const [value, setValue] = React.useState<string>(defaultValue);
+
+  return {
+    value,
+    props: {
+      onChange: (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
+        setValue(e.target.value);
+      },
+      value,
+    },
+    clear: () => {
+      setValue('');
+    },
+  };
+}
diff --git a/x-pack/legacy/plugins/fleet/public/hooks/use_pagination.tsx b/x-pack/legacy/plugins/fleet/public/hooks/use_pagination.tsx
index 16c9262934478..b478c039dad64 100644
--- a/x-pack/legacy/plugins/fleet/public/hooks/use_pagination.tsx
+++ b/x-pack/legacy/plugins/fleet/public/hooks/use_pagination.tsx
@@ -7,11 +7,13 @@
 import { useState } from 'react';
 import { DEFAULT_AGENTS_PAGE_SIZE, AGENTS_PAGE_SIZE_OPTIONS } from '../../common/constants';
 
+export interface Pagination {
+  currentPage: number;
+  pageSize: number;
+}
+
 export function usePagination() {
-  const [pagination, setPagination] = useState<{
-    currentPage: number;
-    pageSize: number;
-  }>({
+  const [pagination, setPagination] = useState<Pagination>({
     currentPage: 1,
     pageSize: DEFAULT_AGENTS_PAGE_SIZE,
   });
diff --git a/x-pack/legacy/plugins/fleet/public/lib/compose/kibana.ts b/x-pack/legacy/plugins/fleet/public/lib/compose/kibana.ts
index bf5d456e528ca..84f5e36cce478 100644
--- a/x-pack/legacy/plugins/fleet/public/lib/compose/kibana.ts
+++ b/x-pack/legacy/plugins/fleet/public/lib/compose/kibana.ts
@@ -25,6 +25,7 @@ import { FrontendLibs } from '../types';
 import { PLUGIN } from '../../../common/constants/plugin';
 import { FrameworkLib } from '../framework';
 import { INDEX_NAMES } from '../../../common/constants';
+import { EnrollmentApiKeyLib } from '../enrollment_api_key';
 
 // A super early spot in kibana loading that we can use to hook before most other things
 const onKibanaReady = chrome.dangerouslyGetActiveInjector;
@@ -35,6 +36,7 @@ export function compose(): FrontendLibs {
   const elasticsearchLib = new ElasticsearchLib(esAdapter);
   const agents = new AgentsLib(new RestAgentAdapter(api));
   const policies = new PoliciesLib(new RestPolicyAdapter(api));
+  const enrollmentApiKeys = new EnrollmentApiKeyLib(api);
 
   const framework = new FrameworkLib(
     new KibanaFrameworkAdapter(
@@ -54,6 +56,7 @@ export function compose(): FrontendLibs {
     elasticsearch: elasticsearchLib,
     agents,
     policies,
+    enrollmentApiKeys,
   };
   return libs;
 }
diff --git a/x-pack/legacy/plugins/fleet/public/lib/compose/memory.ts b/x-pack/legacy/plugins/fleet/public/lib/compose/memory.ts
deleted file mode 100644
index 60f7ffd689759..0000000000000
--- a/x-pack/legacy/plugins/fleet/public/lib/compose/memory.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import 'ui/autoload/all';
-// @ts-ignore: path dynamic for kibana
-import { management } from 'ui/management';
-// @ts-ignore: path dynamic for kibana
-import { toastNotifications } from 'ui/notify';
-// @ts-ignore: path dynamic for kibana
-import { uiModules } from 'ui/modules';
-// @ts-ignore: path dynamic for kibana
-import routes from 'ui/routes';
-// @ts-ignore: path dynamic for kibana
-import { MemoryAgentAdapter } from '../adapters/agent/memory_agent_adapter';
-import { PolicyAdapter } from '../adapters/policy/memory_policy_adapter';
-import { KibanaFrameworkAdapter } from '../adapters/framework/kibana_framework_adapter';
-import { AgentsLib } from '../agent';
-import { PoliciesLib } from '../policy';
-import { FrameworkLib } from '../framework';
-import { FrontendLibs } from '../types';
-import { MemoryElasticsearchAdapter } from '../adapters/elasticsearch/memory';
-import { AutocompleteSuggestion } from '../../../../../../../src/plugins/data/public';
-import { ElasticsearchLib } from '../elasticsearch';
-
-const onKibanaReady = uiModules.get('kibana').run;
-
-export function compose(
-  mockIsKueryValid: (kuery: string) => boolean,
-  mockKueryToEsQuery: (kuery: string) => string,
-  suggestions: AutocompleteSuggestion[]
-): FrontendLibs {
-  const esAdapter = new MemoryElasticsearchAdapter(
-    mockIsKueryValid,
-    mockKueryToEsQuery,
-    suggestions
-  );
-  const elasticsearchLib = new ElasticsearchLib(esAdapter);
-
-  const agents = new AgentsLib(new MemoryAgentAdapter([]));
-  const policies = new PoliciesLib(new PolicyAdapter([]));
-
-  const pluginUIModule = uiModules.get('app/fleet');
-
-  const framework = new FrameworkLib(
-    new KibanaFrameworkAdapter(
-      pluginUIModule,
-      management,
-      routes,
-      () => '',
-      onKibanaReady,
-      null,
-      '7.0.0',
-      toastNotifications
-    )
-  );
-  const libs: FrontendLibs = {
-    framework,
-    elasticsearch: elasticsearchLib,
-    agents,
-    policies,
-  };
-  return libs;
-}
diff --git a/x-pack/legacy/plugins/fleet/public/lib/compose/scripts.ts b/x-pack/legacy/plugins/fleet/public/lib/compose/scripts.ts
deleted file mode 100644
index f6a0b3bc9fbab..0000000000000
--- a/x-pack/legacy/plugins/fleet/public/lib/compose/scripts.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { RestAgentAdapter } from '../adapters/agent/rest_agent_adapter';
-import { RestPolicyAdapter } from '../adapters/policy/rest_policy_adapter';
-import { MemoryElasticsearchAdapter } from '../adapters/elasticsearch/memory';
-import { TestingFrameworkAdapter } from '../adapters/framework/testing_framework_adapter';
-import { NodeAxiosAPIAdapter } from '../adapters/rest_api/node_axios_api_adapter';
-import { AgentsLib } from '../agent';
-import { PoliciesLib } from '../policy';
-import { ElasticsearchLib } from '../elasticsearch';
-import { FrameworkLib } from '../framework';
-import { FrontendLibs } from '../types';
-
-export function compose(basePath: string): FrontendLibs {
-  const api = new NodeAxiosAPIAdapter('elastic', 'changeme', basePath);
-  const esAdapter = new MemoryElasticsearchAdapter(
-    () => true,
-    () => '',
-    []
-  );
-  const elasticsearchLib = new ElasticsearchLib(esAdapter);
-
-  const agents = new AgentsLib(new RestAgentAdapter(api));
-  const policies = new PoliciesLib(new RestPolicyAdapter(api));
-
-  const framework = new FrameworkLib(
-    new TestingFrameworkAdapter(
-      {
-        basePath,
-        license: {
-          type: 'gold',
-          expired: false,
-          expiry_date_in_millis: 34353453452345,
-        },
-        security: {
-          enabled: true,
-          available: true,
-        },
-        settings: {},
-      },
-      {
-        username: 'joeuser',
-        roles: ['fleet_admin'],
-        enabled: true,
-        full_name: null,
-        email: null,
-      },
-      '6.7.0'
-    )
-  );
-
-  const libs: FrontendLibs = {
-    framework,
-    elasticsearch: elasticsearchLib,
-    agents,
-    policies,
-  };
-  return libs;
-}
diff --git a/x-pack/legacy/plugins/fleet/public/lib/enrollment_api_key.ts b/x-pack/legacy/plugins/fleet/public/lib/enrollment_api_key.ts
new file mode 100644
index 0000000000000..512ed367bc65b
--- /dev/null
+++ b/x-pack/legacy/plugins/fleet/public/lib/enrollment_api_key.ts
@@ -0,0 +1,46 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import {
+  ReturnTypeList,
+  ReturnTypeGet,
+  ReturnTypeCreate,
+  ReturnTypeDelete,
+} from '../../common/return_types';
+import { RestAPIAdapter } from './adapters/rest_api/adapter_types';
+import { Pagination } from '../hooks/use_pagination';
+import { EnrollmentApiKey } from '../../common/types/domain_data';
+
+export class EnrollmentApiKeyLib {
+  constructor(private readonly rest: RestAPIAdapter) {}
+
+  public async listKeys(pagination: Pagination) {
+    return await this.rest.get<ReturnTypeList<EnrollmentApiKey>>('/api/fleet/enrollment-api-keys', {
+      page: pagination.currentPage,
+      perPage: pagination.pageSize,
+    });
+  }
+
+  public async get(keyId: string) {
+    return await this.rest.get<ReturnTypeGet<EnrollmentApiKey>>(
+      `/api/fleet/enrollment-api-keys/${keyId}`
+    );
+  }
+
+  public async delete(keyId: string) {
+    return await this.rest.delete<ReturnTypeDelete>(`/api/fleet/enrollment-api-keys/${keyId}`);
+  }
+
+  public async create(data: { name: string; policyId: string }) {
+    return await this.rest.post<ReturnTypeCreate<EnrollmentApiKey>>(
+      `/api/fleet/enrollment-api-keys`,
+      {
+        name: data.name,
+        policy_id: data.policyId,
+      }
+    );
+  }
+}
diff --git a/x-pack/legacy/plugins/fleet/public/lib/types.ts b/x-pack/legacy/plugins/fleet/public/lib/types.ts
index c7b33e1b8a2ea..eebb2a806407c 100644
--- a/x-pack/legacy/plugins/fleet/public/lib/types.ts
+++ b/x-pack/legacy/plugins/fleet/public/lib/types.ts
@@ -10,12 +10,14 @@ import { AgentsLib } from './agent';
 import { PoliciesLib } from './policy';
 import { ElasticsearchLib } from './elasticsearch';
 import { FrameworkLib } from './framework';
+import { EnrollmentApiKeyLib } from './enrollment_api_key';
 
 export interface FrontendLibs {
   elasticsearch: ElasticsearchLib;
   framework: FrameworkLib;
   agents: AgentsLib;
   policies: PoliciesLib;
+  enrollmentApiKeys: EnrollmentApiKeyLib;
 }
 
 export type FramworkAdapterConstructable = new (uiModule: IModule) => FrameworkAdapter;
diff --git a/x-pack/legacy/plugins/fleet/public/pages/agent_details/components/metadata_form.tsx b/x-pack/legacy/plugins/fleet/public/pages/agent_details/components/metadata_form.tsx
index 6df53cd0ec1d7..45b62a0823497 100644
--- a/x-pack/legacy/plugins/fleet/public/pages/agent_details/components/metadata_form.tsx
+++ b/x-pack/legacy/plugins/fleet/public/pages/agent_details/components/metadata_form.tsx
@@ -21,20 +21,7 @@ import { AxiosError } from 'axios';
 import { Agent } from '../../../../common/types/domain_data';
 import { useLibs } from '../../../hooks/use_libs';
 import { useAgentRefresh } from '../hooks/use_agent';
-
-function useInput() {
-  const [value, setValue] = useState<string>('');
-
-  return {
-    value,
-    onChange: (e: React.ChangeEvent<HTMLInputElement>) => {
-      setValue(e.target.value);
-    },
-    clear: () => {
-      setValue('');
-    },
-  };
-}
+import { useInput } from '../../../hooks/use_input';
 
 function useAddMetadataForm(agent: Agent, done: () => void) {
   const libs = useLibs();
@@ -132,11 +119,7 @@ export const MetadataForm: SFC<{ agent: Agent }> = ({ agent }) => {
                     defaultMessage: 'Key',
                   })}
                 >
-                  <EuiFieldText
-                    required={true}
-                    onChange={keyInput.onChange}
-                    value={keyInput.value}
-                  />
+                  <EuiFieldText required={true} {...keyInput.props} />
                 </EuiFormRow>
               </EuiFlexItem>
               <EuiFlexItem>
@@ -145,11 +128,7 @@ export const MetadataForm: SFC<{ agent: Agent }> = ({ agent }) => {
                     defaultMessage: 'Value',
                   })}
                 >
-                  <EuiFieldText
-                    required={true}
-                    onChange={valueInput.onChange}
-                    value={valueInput.value}
-                  />
+                  <EuiFieldText required={true} {...valueInput.props} />
                 </EuiFormRow>
               </EuiFlexItem>
               <EuiFlexItem grow={false}>
diff --git a/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/agent_enrollment.tsx b/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/agent_enrollment.tsx
index 18914f957a887..98a1ce4a612e9 100644
--- a/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/agent_enrollment.tsx
+++ b/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/agent_enrollment.tsx
@@ -19,6 +19,8 @@ import {
   EuiText,
   EuiFilterGroup,
   EuiFilterButton,
+  EuiSelect,
+  EuiHorizontalRule,
 } from '@elastic/eui';
 import {
   ShellEnrollmentInstructions,
@@ -26,6 +28,8 @@ import {
   ToolsEnrollmentInstructions,
 } from './enrollment_instructions';
 import { useLibs } from '../../../hooks/use_libs';
+import { useEnrollmentApiKeys, useEnrollmentApiKey } from './enrollment_api_keys/hooks';
+import { EnrollmentApiKeysTable } from './enrollment_api_keys';
 
 interface RouterProps {
   onClose: () => void;
@@ -36,8 +40,21 @@ export const AgentEnrollmentFlyout: React.SFC<RouterProps> = ({ onClose }) => {
   const [quickInstallType, setQuickInstallType] = useState<'shell' | 'container' | 'tools'>(
     'shell'
   );
+  // api keys
+  const enrollmentApiKeys = useEnrollmentApiKeys({
+    currentPage: 1,
+    pageSize: 1000,
+  });
+  const [selectedApiKeyId, setSelectedApiKeyId] = useState<string | null>(null);
+  React.useEffect(() => {
+    if (!selectedApiKeyId && enrollmentApiKeys.data && enrollmentApiKeys.data.list.length > 0) {
+      setSelectedApiKeyId(enrollmentApiKeys.data.list[0].id);
+    }
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, [enrollmentApiKeys.data]);
+  const apiKey = useEnrollmentApiKey(selectedApiKeyId);
 
-  const renderHeader = () => (
+  const header = (
     <EuiFlyoutHeader hasBorder aria-labelledby="FleetAgentEnrollmentFlyoutTitle">
       <EuiTitle size="m">
         <h2 id="FleetAgentEnrollmentFlyoutTitle">
@@ -59,7 +76,63 @@ export const AgentEnrollmentFlyout: React.SFC<RouterProps> = ({ onClose }) => {
     </EuiFlyoutHeader>
   );
 
-  const renderInstructions = () => (
+  const policyOptions = enrollmentApiKeys.data
+    ? enrollmentApiKeys.data.list.map(key => ({
+        value: key.id,
+        text: key.name,
+      }))
+    : [];
+
+  const [apiKeyListVisible, setApiKeyListVisble] = useState(false);
+  const renderedPolicySelect = (
+    <>
+      <EuiText>
+        <h5>
+          <FormattedMessage
+            id="xpack.fleet.agentEnrollment.selectPolicyTitle"
+            defaultMessage="Select Policy"
+          />
+        </h5>
+      </EuiText>
+      <EuiSpacer size="s" />
+      <EuiSelect
+        options={policyOptions}
+        value={selectedApiKeyId || undefined}
+        onChange={e => setSelectedApiKeyId(e.target.value)}
+      />
+      <EuiSpacer size="m" />
+      <EuiButtonEmpty
+        color="text"
+        onClick={() => {
+          setApiKeyListVisble(!apiKeyListVisible);
+        }}
+        iconType={apiKeyListVisible ? 'arrowUp' : 'arrowDown'}
+        iconSide="right"
+        size="xs"
+        flush="left"
+      >
+        {apiKeyListVisible ? (
+          <FormattedMessage
+            id="xpack.fleet.agentEnrollment.hideKeysButton"
+            defaultMessage="Hide ApiKeys"
+          />
+        ) : (
+          <FormattedMessage
+            id="xpack.fleet.agentEnrollment.viewKeysButton"
+            defaultMessage="View ApiKeys"
+          />
+        )}
+      </EuiButtonEmpty>
+      {apiKeyListVisible && (
+        <>
+          <EuiSpacer size="m" />
+          <EnrollmentApiKeysTable />
+        </>
+      )}
+    </>
+  );
+
+  const renderedInstructions = apiKey.data && (
     <Fragment>
       <EuiText>
         <h5>
@@ -102,6 +175,7 @@ export const AgentEnrollmentFlyout: React.SFC<RouterProps> = ({ onClose }) => {
       <EuiSpacer size="m" />
       {quickInstallType === 'shell' ? (
         <ShellEnrollmentInstructions
+          apiKey={apiKey.data.item}
           kibanaUrl={`${window.location.origin}${libs.framework.info.basePath}`}
         />
       ) : null}
@@ -110,9 +184,16 @@ export const AgentEnrollmentFlyout: React.SFC<RouterProps> = ({ onClose }) => {
     </Fragment>
   );
 
-  const renderBody = () => <EuiFlyoutBody>{renderInstructions()}</EuiFlyoutBody>;
+  const body = (
+    <EuiFlyoutBody>
+      {renderedPolicySelect}
+      <EuiHorizontalRule />
+      <EuiSpacer size="l" />
+      {renderedInstructions}
+    </EuiFlyoutBody>
+  );
 
-  const renderFooter = () => (
+  const footer = (
     <EuiFlyoutFooter>
       <EuiFlexGroup justifyContent="spaceBetween">
         <EuiFlexItem grow={false}>
@@ -130,10 +211,10 @@ export const AgentEnrollmentFlyout: React.SFC<RouterProps> = ({ onClose }) => {
   );
 
   return (
-    <EuiFlyout onClose={onClose} size="m" maxWidth={650}>
-      {renderHeader()}
-      {renderBody()}
-      {renderFooter()}
+    <EuiFlyout onClose={onClose} size="l" maxWidth={950}>
+      {header}
+      {body}
+      {footer}
     </EuiFlyout>
   );
 };
diff --git a/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/enrollment_api_keys/confirm_delete_modal.tsx b/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/enrollment_api_keys/confirm_delete_modal.tsx
new file mode 100644
index 0000000000000..0d24f1fe28e9e
--- /dev/null
+++ b/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/enrollment_api_keys/confirm_delete_modal.tsx
@@ -0,0 +1,46 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import { EuiOverlayMask, EuiConfirmModal } from '@elastic/eui';
+import { FormattedMessage } from '@kbn/i18n/react';
+
+export const ConfirmDeleteModal: React.SFC<{
+  onConfirm: () => void;
+  onCancel: () => void;
+  apiKeyId: string;
+}> = ({ onConfirm, onCancel, apiKeyId }) => {
+  return (
+    <EuiOverlayMask>
+      <EuiConfirmModal
+        title={
+          <FormattedMessage
+            id="xpack.fleet.deleteApiKeys.confirmModal.title"
+            defaultMessage="Delete api key: {apiKeyId}"
+            values={{
+              apiKeyId,
+            }}
+          />
+        }
+        onCancel={onCancel}
+        onConfirm={onConfirm}
+        cancelButtonText={
+          <FormattedMessage
+            id="xpack.fleet.deleteApiKeys.confirmModal.cancelButtonLabel"
+            defaultMessage="Cancel"
+          />
+        }
+        confirmButtonText={
+          <FormattedMessage
+            id="xpack.fleet.deleteApiKeys.confirmModal.confirmButtonLabel"
+            defaultMessage="Delete"
+          />
+        }
+        buttonColor="danger"
+      />
+    </EuiOverlayMask>
+  );
+};
diff --git a/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/enrollment_api_keys/create_api_key_form.tsx b/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/enrollment_api_keys/create_api_key_form.tsx
new file mode 100644
index 0000000000000..2451ec2fe01c9
--- /dev/null
+++ b/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/enrollment_api_keys/create_api_key_form.tsx
@@ -0,0 +1,86 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import React from 'react';
+import {
+  EuiFlexGroup,
+  EuiFlexItem,
+  EuiFormRow,
+  EuiFieldText,
+  EuiButton,
+  EuiSelect,
+} from '@elastic/eui';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { useInput } from '../../../../hooks/use_input';
+import { useLibs } from '../../../../hooks/use_libs';
+import { usePolicies } from './hooks';
+
+export const CreateApiKeyForm: React.SFC<{ onChange: () => void }> = ({ onChange }) => {
+  const { data: policies } = usePolicies();
+  const { inputs, onSubmit, submitted } = useCreateApiKey(() => onChange());
+
+  return (
+    <EuiFlexGroup style={{ maxWidth: 600 }}>
+      <EuiFlexItem>
+        <EuiFormRow
+          label={i18n.translate('xpack.fleet.apiKeysForm.nameLabel', {
+            defaultMessage: 'Key Name',
+          })}
+        >
+          <EuiFieldText autoComplete={'false'} {...inputs.nameInput.props} />
+        </EuiFormRow>
+      </EuiFlexItem>
+      <EuiFlexItem>
+        <EuiFormRow
+          label={i18n.translate('xpack.fleet.apiKeysForm.policyLabel', {
+            defaultMessage: 'Policy',
+          })}
+        >
+          <EuiSelect
+            {...inputs.policyIdInput.props}
+            options={policies.map(policy => ({
+              value: policy.id,
+              text: policy.name,
+            }))}
+          />
+        </EuiFormRow>
+      </EuiFlexItem>
+      <EuiFlexItem grow={false}>
+        <EuiFormRow hasEmptyLabelSpace>
+          <EuiButton disabled={submitted} onClick={() => onSubmit()}>
+            <FormattedMessage id="xpack.fleet.apiKeysForm.saveButton" defaultMessage="Save" />
+          </EuiButton>
+        </EuiFormRow>
+      </EuiFlexItem>
+    </EuiFlexGroup>
+  );
+};
+
+function useCreateApiKey(onSuccess: () => void) {
+  const { enrollmentApiKeys } = useLibs();
+  const [submitted, setSubmitted] = React.useState(false);
+  const inputs = {
+    nameInput: useInput(),
+    policyIdInput: useInput('default'),
+  };
+
+  const onSubmit = async () => {
+    setSubmitted(true);
+    await enrollmentApiKeys.create({
+      name: inputs.nameInput.value,
+      policyId: inputs.policyIdInput.value,
+    });
+    setSubmitted(false);
+    onSuccess();
+  };
+
+  return {
+    inputs,
+    onSubmit,
+    submitted,
+  };
+}
diff --git a/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/enrollment_api_keys/hooks.tsx b/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/enrollment_api_keys/hooks.tsx
new file mode 100644
index 0000000000000..c65b7012979b4
--- /dev/null
+++ b/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/enrollment_api_keys/hooks.tsx
@@ -0,0 +1,121 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { useEffect, useState } from 'react';
+import { useLibs } from '../../../../hooks/use_libs';
+import { Pagination } from '../../../../hooks/use_pagination';
+import { ReturnTypeList, ReturnTypeGet } from '../../../../../common/return_types';
+import { EnrollmentApiKey } from '../../../../../common/types/domain_data';
+import { Policy } from '../../../../../scripts/mock_spec/types';
+
+export function useEnrollmentApiKeys(pagination: Pagination) {
+  const { enrollmentApiKeys } = useLibs();
+  const [state, setState] = useState<{
+    data: ReturnTypeList<EnrollmentApiKey> | null;
+    isLoading: boolean;
+  }>({
+    isLoading: true,
+    data: null,
+  });
+  async function fetchApiKeys() {
+    try {
+      const data = await enrollmentApiKeys.listKeys(pagination);
+      setState({
+        isLoading: false,
+        data,
+      });
+    } catch (error) {
+      setState({
+        isLoading: false,
+        data: null,
+      });
+    }
+  }
+  useEffect(() => {
+    fetchApiKeys();
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, []);
+
+  return {
+    ...state,
+    refresh: () => fetchApiKeys(),
+  };
+}
+
+export function usePolicies() {
+  const { policies } = useLibs();
+  const [state, setState] = useState<{
+    data: Policy[];
+    isLoading: boolean;
+  }>({
+    isLoading: true,
+    data: [],
+  });
+
+  async function fetchPolicies() {
+    try {
+      const data = await policies.getAll();
+      setState({
+        data,
+        isLoading: false,
+      });
+    } catch (err) {
+      setState({
+        data: [],
+        isLoading: false,
+      });
+    }
+  }
+
+  useEffect(() => {
+    fetchPolicies();
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, []);
+
+  return {
+    ...state,
+  };
+}
+
+export function useEnrollmentApiKey(apiKeyId: string | null) {
+  const { enrollmentApiKeys } = useLibs();
+  const [state, setState] = useState<{
+    data: ReturnTypeGet<EnrollmentApiKey> | null;
+    isLoading: boolean;
+  }>({
+    isLoading: true,
+    data: null,
+  });
+  useEffect(() => {
+    async function fetchApiKey() {
+      if (!apiKeyId) {
+        setState({
+          isLoading: false,
+          data: null,
+        });
+        return;
+      }
+      try {
+        const data = await enrollmentApiKeys.get(apiKeyId);
+        setState({
+          isLoading: false,
+          data,
+        });
+      } catch (error) {
+        setState({
+          isLoading: false,
+          data: null,
+        });
+      }
+    }
+    fetchApiKey();
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, [apiKeyId]);
+
+  return {
+    ...state,
+  };
+}
diff --git a/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/enrollment_api_keys/index.tsx b/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/enrollment_api_keys/index.tsx
new file mode 100644
index 0000000000000..55c1272766612
--- /dev/null
+++ b/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/enrollment_api_keys/index.tsx
@@ -0,0 +1,143 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+import React, { useState } from 'react';
+import { EuiBasicTable, EuiButtonEmpty, EuiSpacer, EuiPopover } from '@elastic/eui';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { i18n } from '@kbn/i18n';
+import { useEnrollmentApiKeys, useEnrollmentApiKey } from './hooks';
+import { EnrollmentApiKey } from '../../../../../common/types/domain_data';
+import { useLibs } from '../../../../hooks/use_libs';
+import { usePagination } from '../../../../hooks/use_pagination';
+import { ConfirmDeleteModal } from './confirm_delete_modal';
+import { CreateApiKeyForm } from './create_api_key_form';
+
+export const EnrollmentApiKeysTable: React.SFC = () => {
+  const { enrollmentApiKeys } = useLibs();
+  const [confirmDeleteApiKeyId, setConfirmDeleteApiKeyId] = useState<string | null>(null);
+  const { pagination } = usePagination();
+  const { data, isLoading, refresh } = useEnrollmentApiKeys(pagination);
+
+  const columns: any[] = [
+    {
+      field: 'name',
+      name: i18n.translate('xpack.fleet.apiKeysList.nameColumnTitle', {
+        defaultMessage: 'Name',
+      }),
+      width: '300px',
+    },
+    {
+      field: 'policy_id',
+      name: i18n.translate('xpack.fleet.agentList.policyColumnTitle', {
+        defaultMessage: 'Policy',
+      }),
+      width: '100px',
+    },
+    {
+      field: null,
+      name: i18n.translate('xpack.fleet.agentList.apiKeyColumnTitle', {
+        defaultMessage: 'Api Key',
+      }),
+      render: (key: EnrollmentApiKey) => <ApiKeyField apiKeyId={key.id} />,
+    },
+    {
+      field: null,
+      width: '50px',
+      render: (key: EnrollmentApiKey) => {
+        return (
+          <EuiButtonEmpty onClick={() => setConfirmDeleteApiKeyId(key.id)} iconType={'trash'} />
+        );
+      },
+    },
+  ];
+
+  return (
+    <>
+      {confirmDeleteApiKeyId && (
+        <ConfirmDeleteModal
+          apiKeyId={confirmDeleteApiKeyId}
+          onCancel={() => setConfirmDeleteApiKeyId(null)}
+          onConfirm={async () => {
+            await enrollmentApiKeys.delete(confirmDeleteApiKeyId);
+            setConfirmDeleteApiKeyId(null);
+            refresh();
+          }}
+        />
+      )}
+      <EuiBasicTable
+        compressed={true}
+        loading={isLoading}
+        noItemsMessage={
+          <FormattedMessage
+            id="xpack.fleet.agentList.emptyEnrollmentKeysMessage"
+            defaultMessage="No api keys"
+          />
+        }
+        items={data ? data.list : []}
+        itemId="id"
+        columns={columns}
+      />
+      <EuiSpacer size={'s'} />
+      <CreateApiKeyButton onChange={() => refresh()} />
+    </>
+  );
+};
+
+const CreateApiKeyButton: React.SFC<{ onChange: () => void }> = ({ onChange }) => {
+  const [isOpen, setIsOpen] = React.useState(false);
+
+  return (
+    <EuiPopover
+      ownFocus
+      button={
+        <EuiButtonEmpty
+          onClick={() => setIsOpen(true)}
+          color="text"
+          iconType={'plusInCircle'}
+          size="xs"
+        >
+          <FormattedMessage
+            id="xpack.fleet.enrollmentApiKeyList.createNewButton"
+            defaultMessage="Create a new key"
+          />
+        </EuiButtonEmpty>
+      }
+      isOpen={isOpen}
+      closePopover={() => setIsOpen(false)}
+    >
+      <CreateApiKeyForm
+        onChange={() => {
+          setIsOpen(false);
+          onChange();
+        }}
+      />
+    </EuiPopover>
+  );
+  return <></>;
+};
+
+const ApiKeyField: React.SFC<{ apiKeyId: string }> = ({ apiKeyId }) => {
+  const [visible, setVisible] = useState(false);
+  const { data } = useEnrollmentApiKey(apiKeyId);
+
+  return (
+    <>
+      {visible && data ? data.item.api_key : '••••••••••••••••••••••••••••'}
+      <EuiButtonEmpty size="xs" color={'text'} onClick={() => setVisible(!visible)}>
+        {visible ? (
+          <FormattedMessage
+            id="xpack.fleet.enrollmentApiKeyList.hideTableButton"
+            defaultMessage="Hide"
+          />
+        ) : (
+          <FormattedMessage
+            id="xpack.fleet.enrollmentApiKeyList.viewTableButton"
+            defaultMessage="View"
+          />
+        )}
+      </EuiButtonEmpty>{' '}
+    </>
+  );
+};
diff --git a/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/enrollment_instructions/shell/index.tsx b/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/enrollment_instructions/shell/index.tsx
index a518a75ccdb9a..6955f4f69ffa3 100644
--- a/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/enrollment_instructions/shell/index.tsx
+++ b/x-pack/legacy/plugins/fleet/public/pages/agent_list/components/enrollment_instructions/shell/index.tsx
@@ -17,6 +17,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
 import { i18n } from '@kbn/i18n';
 import { ManualEnrollmentInstructions, ManualEnrollmentSteps } from '../';
 import * as MAC_COMMANDS from './mac_commands';
+import { EnrollmentApiKey } from '../../../../../../common/types/domain_data';
 
 // No need for i18n as these are platform names
 const PLATFORMS = {
@@ -56,16 +57,17 @@ const PLATFORM_INSTRUCTIONS: {
 
 interface Props {
   kibanaUrl: string;
+  apiKey: EnrollmentApiKey;
 }
 
-export const ShellEnrollmentInstructions: React.SFC<Props> = ({ kibanaUrl }) => {
+export const ShellEnrollmentInstructions: React.SFC<Props> = ({ kibanaUrl, apiKey }) => {
   // Platform state
   const [currentPlatform, setCurrentPlatform] = useState<keyof typeof PLATFORMS>('macos');
   const [isPlatformOptionsOpen, setIsPlatformOptionsOpen] = useState<boolean>(false);
   const [isManualInstallationOpen, setIsManualInstallationOpen] = useState<boolean>(false);
 
   // Build quick installation command
-  const quickInstallInstructions = `curl ${kibanaUrl}/api/fleet/install/${currentPlatform} | bash`;
+  const quickInstallInstructions = `API_KEY=${apiKey.api_key} curl ${kibanaUrl}/api/fleet/install/${currentPlatform} | bash`;
 
   return (
     <Fragment>
diff --git a/x-pack/legacy/plugins/fleet/server/libs/api_keys.ts b/x-pack/legacy/plugins/fleet/server/libs/api_keys.ts
index 3135f6d3d48f1..7d261f6601eaf 100644
--- a/x-pack/legacy/plugins/fleet/server/libs/api_keys.ts
+++ b/x-pack/legacy/plugins/fleet/server/libs/api_keys.ts
@@ -208,13 +208,11 @@ export class ApiKeyLib {
   }
 
   private _getEnrollmentApiKeyName(id: string, name?: string, policyId?: string): string {
-    const generatedName = `Fleet:EnrollmentApiKey:${id}${policyId ? `:${policyId}` : ''}`;
-
-    return name ? `${name} (${generatedName})` : generatedName;
+    return name ? `${name} (${id})` : id;
   }
 
   private _getAccesstApiKeyName(agentId: string): string {
-    return `Fleet:AccessApiKey:${agentId}`;
+    return agentId;
   }
 
   public async addEnrollmentRule(