{"id":152,"date":"2023-02-04T11:39:29","date_gmt":"2023-02-04T11:39:29","guid":{"rendered":"https:\/\/mrzebra.co.uk\/code\/?p=152"},"modified":"2023-02-04T11:39:29","modified_gmt":"2023-02-04T11:39:29","slug":"how-to-automate-installation-of-fleet","status":"publish","type":"post","link":"https:\/\/zebra-north.com\/code\/2023\/02\/04\/how-to-automate-installation-of-fleet\/","title":{"rendered":"How to Automate Installation of Fleet"},"content":{"rendered":"\n<p>Fleet is part of the Elastic Stack, and allows you to manage all your Elastic Agents.  Installing it in a fully automated manner is difficult because it requires configuration in Kibana.  Here&#8217;s how to do it.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Configuring Kibana<\/h2>\n\n\n\n<p>Kibana&#8217;s REST API can be used to set up all the necessary configuration options for the Fleet server.<\/p>\n\n\n\n<p>A note about SSL: This tutorial includes SSL configuration and supports using certificates signed by your own Certificate Authority (CA), as recommended by the Elasticsearch installation guide.  If you are not using SSL then you can remove the <code>--cacert<\/code> options and change <code>https<\/code> to <code>http<\/code>.<\/p>\n\n\n\n<p>First, we&#8217;ll set up some variables.  Modify these values to suit your environment:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\"># The location of the Certificate Authority file.\n# This is generated by Elasticsearch in the setup container and mounted into the container.\nCA=\/certs\/ca\/ca.crt\n\n# The host and port of the Elasticsearch server.\nELASTIC_HOST=es01:9200\n\n# The username this script uses to connect to Elasticsearch.\nELASTIC_USER=elastic\n\n# The password this script uses to connect to Elasticsearch.\nELASTIC_PASS=elastic\n\n# The URL to the Kibana server, without a trailing slash.\nKIBANA_URL=http:\/\/kibana:5601\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Service Account Token<\/h3>\n\n\n\n<p>The Service Account Token is used by Fleet to authorize itself with Elasticsearch.  We will create a token with a random name so that it does not collide with any existing tokens.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">createServiceAccountToken()\n{\n    echo -n &#039;Creating service account token... &#039;\n\n    # Create a random name for the token so it does not collied with any existing tokens.\n    tokenName=`cat \/proc\/sys\/kernel\/random\/uuid`\n\n    # Create the token.\n    response=`curl \\\n        -u $ELASTIC_USER:$ELASTIC_PASS \\\n        --silent \\\n        --cacert $CA \\\n        -X POST &quot;https:\/\/$ELASTIC_HOST\/_security\/service\/elastic\/fleet-server\/credential\/token\/$tokenName?pretty&quot;`\n\n    # Check that the response was successful.\n    if ! echo &quot;$response&quot; | grep --silent &#039;&quot;created&quot; : true&#039;; then\n        echo &#039;failed&#039;\n        echo &quot;$response&quot;\n        exit 1\n    fi\n\n    # Parse the token out of the response.\n    token=`echo &quot;$response&quot; | awk &#039;\/value\/ { print $3 }&#039; | sed &#039;s\/&quot;\/\/g&#039;`\n\n    echo &quot;success: $token&quot;\n}<\/code><\/pre>\n\n\n\n<p>This will store the token in the variable <code>$token<\/code> for use later.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Agent Policy<\/h3>\n\n\n\n<p>The Agent Policy configures which integrations (plugins) are associated with the agent.  This will create an empty policy, to which we will later add the Fleet Server integration.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">createAgentPolicy()\n{\n    echo -n &#039;Creating Fleet server policy... &#039;\n\n    response=`curl \\\n        -u $ELASTIC_USER:$ELASTIC_PASS \\\n        --silent \\\n        --request POST \\\n        --url $KIBANA_URL\/api\/fleet\/agent_policies?sys_monitoring=true \\\n        --header &#039;content-type: application\/json&#039; \\\n        --header &#039;kbn-xsrf: true&#039; \\\n        --data &#039;{&quot;id&quot;: &quot;docker-fleet-server-policy&quot;,&quot;name&quot;:&quot;Docker Fleet Server Policy&quot;,&quot;namespace&quot;:&quot;default&quot;,&quot;monitoring_enabled&quot;:[&quot;logs&quot;,&quot;metrics&quot;],&quot;is_default_fleet_server&quot;: true}&#039;`\n\n    if echo &quot;$response&quot; | grep --silent &#039;document already exists&#039;; then\n        green &#039;already exists&#039;\n        return 0\n    fi\n\n    green &#039;success&#039;\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Server Integration<\/h3>\n\n\n\n<p>The Agent Policy needs the &#8220;Fleet Server&#8221; integration added to it:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">addServerIntegration()\n{\n    echo -n &#039;Adding Fleet server integration to policy... &#039;\n\n    response=`curl \\\n        -u $ELASTIC_USER:$ELASTIC_PASS \\\n        --silent \\\n        --request POST \\\n        --url $KIBANA_URL\/api\/fleet\/package_policies \\\n        --header &#039;content-type: application\/json&#039; \\\n        --header &#039;kbn-xsrf: true&#039; \\\n        --data &#039;\n        {\n            &quot;policy_id&quot;: &quot;fleet-server-policy&quot;,\n            &quot;package&quot;: {\n                &quot;name&quot;: &quot;fleet_server&quot;,\n                &quot;version&quot;: &quot;1.2.0&quot;\n            },\n            &quot;name&quot;: &quot;fleet_server&quot;,\n            &quot;description&quot;: &quot;&quot;,\n            &quot;namespace&quot;: &quot;default&quot;,\n            &quot;inputs&quot;: {\n                &quot;fleet_server-fleet-server&quot;: {\n                &quot;enabled&quot;: true,\n                &quot;vars&quot;: {\n                    &quot;host&quot;: &quot;fleet&quot;,\n                    &quot;port&quot;: [\n                    8220\n                    ],\n                    &quot;custom&quot;: &quot;&quot;\n                },\n                &quot;streams&quot;: {}\n                }\n            }\n        }&#039;`\n\n    if echo $response | grep --silent &#039;already exists&#039;; then\n        echo &#039;already exists&#039;;\n        return 0\n    fi\n\n    if echo $response | grep --silent &#039;error&#039;; then\n        echo &#039;failed&#039;\n        echo &quot;$response&quot;\n        exit 1\n    fi\n\n    echo &#039;success&#039;\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Server Host<\/h3>\n\n\n\n<p>The Fleet Server Host setting tells the Elastic Agents the hostname and port on which they can contact the Fleet server.  Make sure to update the URL to match your environment.  The default port for a Fleet server is 8220.<\/p>\n\n\n\n<p>Note: There is a <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/elastic\/kibana\/issues\/149933\" target=\"_blank\">bug<\/a> in Kibana that will clear the <code>is_default<\/code> option if you try to overwrite an ID that already exists.  If there is a chance that the setting may already exist, you must check first.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">addServerHost()\n{\n    echo -n &#039;Checking if Fleet server host exists... &#039;\n\n    response=`curl \\\n        -u elastic:elastic \\\n        --silent \\\n        --request GET \\\n        --cacert \/usr\/share\/kibana\/config\/certs\/ca\/ca.crt \\\n        --url http:\/\/kibana:5601\/api\/fleet\/fleet_server_hosts\/fleet-server \\\n        --header &#039;content-type: application\/json&#039; \\\n        --header &#039;kbn-xsrf: true&#039;`\n\n    if ! echo $response | grep --silent &#039;Not Found&#039;; then\n        echo &#039;already exists&#039;\n        return 0\n    else\n        echo &#039;does not exist&#039;\n    fi\n\n    echo -n &#039;Adding Fleet server host... &#039;\n\n    response=`curl \\\n        -u $ELASTIC_USER:$ELASTIC_PASS \\\n        --silent \\\n        --request POST \\\n        --url $KIBANA_URL\/api\/fleet\/fleet_server_hosts \\\n        --header &#039;content-type: application\/json&#039; \\\n        --header &#039;kbn-xsrf: true&#039; \\\n        --data &#039;\n        {\n            &quot;id&quot;: &quot;fleet-server&quot;,\n            &quot;name&quot;: &quot;Fleet Server&quot;,\n            &quot;is_default&quot;: true,\n            &quot;host_urls&quot;: [\n                &quot;https:\/\/fleet:8220&quot;\n            ]\n        }&#039;`\n\n    if echo $response | grep --silent &#039;error&#039;; then\n        echo &#039;failed&#039;\n        echo &quot;$response&quot;\n        exit 1\n    fi\n\n    echo &#039;success&#039;\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Output<\/h3>\n\n\n\n<p>The Output setting defines where Fleet should send its data to.  In this case, it&#8217;s being sent to Elasticsearch.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">setOutput()\n{\n    echo -n &#039;Setting agent output location... &#039;\n\n    response=`curl \\\n        -u $ELASTIC_USER:$ELASTIC_PASS \\\n        --silent \\\n        --request PUT \\\n        --url $KIBANA_URL\/api\/fleet\/outputs\/fleet-default-output \\\n        --header &#039;content-type: application\/json&#039; \\\n        --header &#039;kbn-xsrf: true&#039; \\\n        --data &quot;\n        {\n            \\&quot;name\\&quot;: \\&quot;default\\&quot;,\n            \\&quot;type\\&quot;: \\&quot;elasticsearch\\&quot;,\n            \\&quot;is_default\\&quot;: true,\n            \\&quot;is_default_monitoring\\&quot;: true,\n            \\&quot;hosts\\&quot;: [\n                \\&quot;https:\/\/$ELASTIC_HOST\\&quot;\n            ],\n            \\&quot;config_yaml\\&quot;: \\&quot;ssl.certificate_authorities: [&#039;\/certs\/ca\/ca.crt&#039;]\\&quot;\n        }&quot;`\n\n    if echo &quot;$response&quot; | grep --silent &#039;document already exists&#039;; then\n        echo &#039;already exists&#039;\n        return 0\n    fi\n\n    if echo $response | grep --silent &#039;error&#039;; then\n        echo &#039;failed&#039;\n        echo &quot;$response&quot;\n        exit 1\n    fi\n\n    echo &#039;success&#039;\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Installing Fleet<\/h2>\n\n\n\n<p>Now that Kibana has been configured, Fleet can be installed.  Be sure to edit the <code>--url=<\/code> parameter to the hostname of your fleet server.<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">installFleet()\n{\n    apt update\n    apt install -y curl\n    curl -L -O https:\/\/artifacts.elastic.co\/downloads\/beats\/elastic-agent\/elastic-agent-8.6.0-linux-x86_64.tar.gz\n    tar xzvf elastic-agent-8.6.0-linux-x86_64.tar.gz\n    cd elastic-agent-8.6.0-linux-x86_64\n\n    .\/elastic-agent install \\\n        --non-interactive \\\n        --fleet-server-es=https:\/\/$ELASTIC_HOST \\\n        --fleet-server-service-token=$token  \\\n        --fleet-server-policy=docker-fleet-server-policy \\\n        --fleet-server-es-ca=\/certs\/ca\/ca.crt \\\n        --fleet-server-cert=\/certs\/fleet\/fleet.crt \\\n        --fleet-server-cert-key=\/certs\/fleet\/fleet.key \\\n        --certificate-authorities=\/certs\/ca\/ca.crt \\\n        --url=https:\/\/fleet:8220\n}<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Fleet is part of the Elastic Stack, and allows you to manage all your Elastic Agents. Installing it in a fully automated manner is difficult because it requires configuration in Kibana. Here&#8217;s how to do it.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[20],"tags":[21],"class_list":["post-152","post","type-post","status-publish","format-standard","hentry","category-elastic-stack","tag-fleet"],"_links":{"self":[{"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/posts\/152","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/comments?post=152"}],"version-history":[{"count":1,"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/posts\/152\/revisions"}],"predecessor-version":[{"id":153,"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/posts\/152\/revisions\/153"}],"wp:attachment":[{"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/media?parent=152"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/categories?post=152"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zebra-north.com\/code\/wp-json\/wp\/v2\/tags?post=152"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}