# Guided EC2 Auto-Discovery Configuration

This guide shows you how to configure Teleport to automatically enroll EC2 instances in your cluster, with permissions configured by Teleport.

## How it works

The Teleport Discovery Service runs on an EC2 instance and queries the AWS API to list instances in your AWS account. For any new EC2 instance that you deploy, the Discovery Service uses AWS Systems Manager to install Teleport on the instance and join it to the cluster as a Teleport-protected server. `teleport` commands allow you to create IAM policies that enable the Discovery Service to enroll EC2 instances as servers in your Teleport cluster.

To manually configure IAM policies and SSM documents instead, read [Manual EC2 Auto-Discovery Configuration](https://goteleport.com/docs/enroll-resources/auto-discovery/servers/ec2-discovery/ec2-discovery-manual.md).

If you manage multiple AWS accounts in an AWS Organization, see [Organization-level EC2 Auto-Discovery Configuration](https://goteleport.com/docs/enroll-resources/auto-discovery/servers/ec2-discovery/ec2-discovery-organization.md).

## Prerequisites

- A running Teleport cluster. If you want to get started with Teleport, [sign up](https://goteleport.com/signup) for a free trial or [set up a demo environment](https://goteleport.com/docs/get-started/deploy-community.md).

- The `tctl` and `tsh` clients.

  Installing `tctl` and `tsh` clients

  1. Determine the version of your Teleport cluster. The `tctl` and `tsh` clients must be at most one major version behind your Teleport cluster version. Send a GET request to the Proxy Service at `/v1/webapi/find` and use a JSON query tool to obtain your cluster version. Replace teleport.example.com:443 with the web address of your Teleport Proxy Service:

     ```
     $ TELEPORT_DOMAIN=teleport.example.com:443
     $ TELEPORT_VERSION="$(curl -s https://$TELEPORT_DOMAIN/v1/webapi/find | jq -r '.server_version')"
     ```

  2. Follow the instructions for your platform to install `tctl` and `tsh` clients:

     **Mac**

     Download the signed macOS .pkg installer for Teleport, which includes the `tctl` and `tsh` clients:

     ```
     $ curl -O https://cdn.teleport.dev/teleport-${TELEPORT_VERSION?}.pkg
     ```

     In Finder double-click the `pkg` file to begin installation.

     ---

     DANGER

     Using Homebrew to install Teleport is not supported. The Teleport package in Homebrew is not maintained by Teleport and we can't guarantee its reliability or security.

     ---

     **Windows - Powershell**

     ```
     $ curl.exe -O https://cdn.teleport.dev/teleport-v${TELEPORT_VERSION?}-windows-amd64-bin.zip
     Unzip the archive and move the `tctl` and `tsh` clients to your %PATH%
     NOTE: Do not place the `tctl` and `tsh` clients in the System32 directory, as this can cause issues when using WinSCP.
     Use %SystemRoot% (C:\Windows) or %USERPROFILE% (C:\Users\<username>) instead.
     ```

     **Linux**

     All of the Teleport binaries in Linux installations include the `tctl` and `tsh` clients. For more options (including RPM/DEB packages and downloads for i386/ARM/ARM64) see our [installation page](https://goteleport.com/docs/installation.md).

     ```
     $ curl -O https://cdn.teleport.dev/teleport-v${TELEPORT_VERSION?}-linux-amd64-bin.tar.gz
     $ tar -xzf teleport-v${TELEPORT_VERSION?}-linux-amd64-bin.tar.gz
     $ cd teleport
     $ sudo ./install
     Teleport binaries have been copied to /usr/local/bin
     ```

* AWS account with EC2 instances and permissions to create and attach IAM policies.
* EC2 instances running Ubuntu/Debian/RHEL/Amazon Linux 2/Amazon Linux 2023 and SSM agent version 3.1 or greater if making use of the default Teleport install script. (For other Linux distributions, you can install Teleport manually.)
* To check that you can connect to your Teleport cluster, sign in with `tsh login`, then verify that you can run `tctl` commands using your current credentials. For example, run the following command, assigning teleport.example.com to the domain name of the Teleport Proxy Service in your cluster and email\@example.com to your Teleport username:
  ```
  $ tsh login --proxy=teleport.example.com --user=email@example.com
  $ tctl status
  Cluster  teleport.example.com
  Version  19.0.0-dev
  CA pin   sha256:abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678abdc1245efgh5678
  ```
  If you can connect to the cluster and run the `tctl status` command, you can use your current credentials to run subsequent `tctl` commands from your workstation. If you host your own Teleport cluster, you can also run `tctl` commands on the computer that hosts the Teleport Auth Service for full permissions.

All EC2 instances that are to be added to the Teleport cluster by the Discovery Service must include the `AmazonSSMManagedInstanceCore` IAM policy in order to receive commands from the Discovery Service. For a list of permissions included in the policy, see the [AWS documentation](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonSSMManagedInstanceCore.html).

## Step 1/6. Create an EC2 invite token

When discovering EC2 instances, Teleport makes use of IAM invite tokens for authenticating joining Nodes.

Create a file called `token.yaml`:

```
# token.yaml
kind: token
version: v2
metadata:
  # the token name is not a secret because instances must prove that they are
  # running in your AWS account to use this token
  name: aws-discovery-iam-token
spec:
  # use the minimal set of roles required (e.g. Node, App, Kube, DB, WindowsDesktop)
  roles: [Node]

  # set the join method allowed for this token
  join_method: iam

  allow:
  # specify the AWS account which Nodes may join from
  - aws_account: "123456789"

```

Assign the `aws_account` field to your AWS account number. Add the token to the Teleport cluster with:

```
$ tctl create -f token.yaml
```

## Step 2/6. Configure IAM policies

The `teleport discovery bootstrap` command will automate the process of defining and implementing IAM policies required to make auto-discovery work. It requires only a single pre-defined policy, attached to the EC2 instance running the command:

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iam:GetPolicy",
                "iam:TagPolicy",
                "iam:ListPolicyVersions",
                "iam:CreatePolicyVersion",
                "iam:CreatePolicy",
                "iam:GetRole",
                "ssm:CreateDocument",
                "iam:DeletePolicyVersion",
                "iam:AttachRolePolicy",
                "iam:PutRolePermissionsBoundary"
            ],
            "Resource": "*"
        }
    ]
}

```

Create this policy and apply it to the Node (EC2 instance) that will run the Discovery Service.

## Step 3/6. Install Teleport on the Discovery Node

---

TIP

If you plan on running the Discovery Service on the same Node already running another Teleport service (Auth or Proxy, for example), you can skip this step.

---

Install Teleport on the EC2 instance that will run the Discovery Service:

To install a Teleport Agent on your Linux server:

The recommended installation method is the cluster install script. It will select the correct version, edition, and installation mode for your cluster.

1. Assign teleport.example.com:443 to your Teleport cluster hostname and port, but not the scheme (https\://).

2. Run your cluster's install script:

   ```
   $ curl "https://teleport.example.com:443/scripts/install.sh" | sudo bash
   ```

## Step 4/6. Configure Teleport to discover EC2 instances

If you are running the Discovery Service on its own host, the service requires a valid invite token to connect to the cluster. Generate one by running the following command against your Teleport Auth Service:

```
$ tctl tokens add --type=discovery
```

Save the generated token in `/tmp/token` on the Node (EC2 instance) that will run the Discovery Service.

---

WARNING

Discovery Service exposes a configuration parameter - `discovery_service.discovery_group` - that allows you to group discovered resources into different sets. This parameter is used to prevent Discovery Agents watching different sets of cloud resources from colliding against each other and deleting resources created by another services.

When running multiple Discovery Services, you must ensure that each service is configured with the same `discovery_group` value if they are watching the same cloud resources or a different value if they are watching different cloud resources.

It is possible to run a mix of configurations in the same Teleport cluster meaning that some Discovery Services can be configured to watch the same cloud resources while others watch different resources. As an example, a 4-agent high availability configuration analyzing data from two different cloud accounts would run with the following configuration.

- 2 Discovery Services configured with `discovery_group: "prod"` polling data from Production account.
- 2 Discovery Services configured with `discovery_group: "staging"` polling data from Staging account.

---

Assign teleport.example.com:443 to the host and port of the Teleport Proxy Service in your cluster, and aws-prod to a name that identifies a group of resources that you will enroll:

```
# teleport.yaml
version: v3
teleport:
  join_params:
    token_name: "/tmp/token"
    method: token
  proxy_server: "teleport.example.com:443"
auth_service:
  enabled: false
proxy_service:
  enabled: false
ssh_service:
  enabled: false
discovery_service:
  enabled: true
  discovery_group: aws-prod

```

Create a matcher for the resources you want to enroll.

---

TIP

Dynamic configuration uses Discovery Configs which can be managed using Terraform. See the [Terraform `discovery_config` reference](https://goteleport.com/docs/reference/infrastructure-as-code/terraform-provider/resources/discovery_config.md) for more information.

Static configuration while simpler at first, has less flexibility because enrollment changes require edits to `teleport.yaml` and the restart of the Discovery Service.

---

**Dynamic configuration (recommended)**

Create a Discovery Config resource, that has the same discovery group you configured earlier, to enable EC2 instance discovery.

Create a file named `discovery-aws-prod.yaml` with the following content:

```
kind: discovery_config
version: v1
metadata:
  name: example-discovery-config
spec:
  discovery_group: aws-prod
  aws:
  - types: ["ec2"]
    regions: ["us-east-1", "us-west-1"]
    tags:
      "env": "prod" # Match EC2 instances where tag:env=prod
    ssm:
      document_name: "AWS-RunShellScript"
    install:
      enroll_mode: 1
      install_teleport: true
      join_method: iam
      join_token: aws-discovery-iam-token

```

Adjust the keys under `spec.aws` to match your EC2 environment, specifically the regions and tags you want to associate with the Discovery Service.

Create the Discovery Config by running the following command:

```
$ tctl create -f discovery-aws-prod.yaml
```

Matching instances will be added to the Teleport cluster automatically.

You can update the Discovery Config at any time, and the service will automatically re-apply the changes.

**Static configuration**

In order to enable EC2 instance discovery the `discovery_service.aws` section of `teleport.yaml` must include at least one entry:

```
# teleport.yaml
# ...
discovery_service:
  enabled: true
  discovery_group: aws-prod
  aws:
  - types: ["ec2"]
    regions: ["us-east-1", "us-west-1"]
    tags:
      "env": "prod" # Match EC2 instances where tag:env=prod
    ssm:
      document_name: "AWS-RunShellScript"
    install:
      enroll_mode: script
      install_teleport: true
      join_params:
        token_name: aws-discovery-iam-token
        method: iam

```

Adjust the keys under `discovery_service.aws` to match your EC2 environment, specifically the regions and tags you want to associate with the Discovery Service.

## Step 5/6. Bootstrap the Discovery Service AWS configuration

On the same Node as above, run `teleport discovery bootstrap`. This command will generate and display the additional IAM policies and AWS Systems Manager (SSM) documents required to enable the Discovery Service:

```
$ sudo teleport discovery bootstrap
Reading configuration at "/etc/teleport.yaml"...
...
```

This will add the following additional permissions to the Discovery Service's role:

- `account:ListRegions`
- `ec2:DescribeInstances`
- `ssm:DescribeInstanceInformation`
- `ssm:GetCommandInvocation`
- `ssm:ListCommandInvocations`
- `ssm:SendCommand`

Review the policies and confirm:

```
...
Confirm? [y/N]: y
✅[AWS] Create IAM Policy "TeleportEC2Discovery"... done.
✅[AWS] Create IAM Policy "TeleportEC2DiscoveryBoundary"... done.
✅[AWS] Create IAM SSM Document "AWS-RunShellScript"... done.
✅[AWS] Attach IAM policies to "alex-discovery-role"... done.
```

## Step 6/6. Start Teleport

Grant the Discovery Service access to credentials that it can use to authenticate to AWS.

- If you are running the Discovery Service on an EC2 instance, you may use the EC2 Instance Metadata Service method
- If you are running the Discovery Service in Kubernetes, you can use IAM Roles for Service Accounts (IRSA)
- Otherwise, you must use environment variables

**Instance Metadata Service**

Teleport will detect when it is running on an EC2 instance and use the Instance Metadata Service to fetch credentials.

The EC2 instance should be configured to use an EC2 instance profile. For more information, see: [Using Instance Profiles](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html).

**Kubernetes IRSA**

Refer to [IAM Roles for Service Accounts (IRSA)](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) to set up an OIDC provider in AWS and configure an AWS IAM role that allows the pod's service account to assume the role.

**Environment Variables**

Teleport's built-in AWS client reads credentials from the following environment variables:

- `AWS_ACCESS_KEY_ID`
- `AWS_SECRET_ACCESS_KEY`
- `AWS_DEFAULT_REGION`

When you start the Discovery Service, the service reads environment variables from a file at the path `/etc/default/teleport`. Obtain these credentials from your organization. Ensure that `/etc/default/teleport` has the following content, replacing the values of each variable:

```
AWS_ACCESS_KEY_ID=00000000000000000000
AWS_SECRET_ACCESS_KEY=0000000000000000000000000000000000000000
AWS_DEFAULT_REGION=<YOUR_REGION>

```

Have multiple sources of AWS credentials?

Teleport's AWS client loads credentials from different sources in the following order:

- Environment Variables
- Shared credentials file
- Shared configuration file (Teleport always enables shared configuration)
- EC2 Instance Metadata (credentials only)

While you can provide AWS credentials via a shared credentials file or shared configuration file, you will need to run the Discovery Service with the `AWS_PROFILE` environment variable assigned to the name of your profile of choice.

If you have a specific use case that the instructions above do not account for, consult the documentation for the [AWS SDK for Go](https://docs.aws.amazon.com/sdk-for-go/api/aws/session/) for a detailed description of credential loading behavior.

Configure the Discovery Service to start automatically when the host boots up by creating a systemd service for it. The instructions depend on how you installed the Discovery Service.

**Package Manager**

On the host where you will run the Discovery Service, enable and start Teleport:

```
$ sudo systemctl enable teleport
$ sudo systemctl start teleport
```

**TAR Archive**

On the host where you will run the Discovery Service, create a systemd service configuration for Teleport, enable the Teleport service, and start Teleport:

```
$ sudo teleport install systemd -o /etc/systemd/system/teleport.service
$ sudo systemctl enable teleport
$ sudo systemctl start teleport
```

You can check the status of the Discovery Service with `systemctl status teleport` and view its logs with `journalctl -fu teleport`.

Once you have started the Discovery Service, EC2 instances matching the tags you specified earlier will begin to be added to the Teleport cluster automatically.

## Discovering instances in multiple AWS accounts

To discover EC2 instances in AWS accounts other than the account your Teleport Discovery Service is running in, Teleport must have permission to assume an IAM role in each of those accounts. This guide assumes you have finished the main EC2 discovery guide above and should be repeated for each AWS account you want to discover instances from.

### Step 1/5. Update EC2 invite token

Add a new entry to `spec.allow` in `token.yaml` and set `aws_account` to the account number of the new account, including the destination AWS account ID:

```
# token.yaml
kind: token
version: v2
metadata:
  name: aws-discovery-iam-token
spec:
  roles: [Node]
  join_method: iam
  allow:
  - aws_account: "123456789012"
    # Existing entry...
+ - aws_account: "destination AWS account ID"

```

### Step 2/5. Configure IAM permissions

In the destination account, create a new role and note its ARN. Create the following IAM policy and attach it to the new role:

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iam:GetPolicy",
                "iam:TagPolicy",
                "iam:ListPolicyVersions",
                "iam:CreatePolicyVersion",
                "iam:CreatePolicy",
                "iam:GetRole",
                "ssm:CreateDocument",
                "iam:DeletePolicyVersion",
                "iam:AttachRolePolicy",
                "iam:PutRolePermissionsBoundary"
            ],
            "Resource": "*"
        }
    ]
}

```

Edit the trust policy of the new role to allow the Discovery Service to assume it, adding the Discovery Service role's ARN:

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "Discovery Service role's ARN"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

```

Create the following policy in the Discovery Service's account and attach it to the Discovery Service's role, adding the new role ARN:

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "new role ARN"
        }
    ]
}

```

### Step 3/5. Update Teleport configuration

**Dynamic configuration (recommended)**

Edit the Discovery Config created previously to add an entry to the `spec.aws` section, assigning role ARN to the ARN of the IAM role to assume and optional external ID to an optional external ID:

```
kind: discovery_config
# ...
spec:
  aws:
  - types: ["ec2"]
    ssm:
      document_name: "AWS-RunShellScript"
    # Add new entry after existing entries
  - types: ["ec2"]
    regions: ["us-east-1", "us-west-1"]
    tags:
      "env": "prod" # Match EC2 instances where tag:env=prod
    install:
      enroll_mode: 1
      install_teleport: true
      join_method: iam
      join_token: aws-discovery-iam-token
    ssm:
      document_name: "AWS-RunShellScript"
    assume_role:
      role_arn: "role ARN"
      external_id: "optional external ID"
  - types: ["ec2"]
    ssm:
      document_name: "AWS-RunShellScript"
    # Add a new entry for each account.
    # ...

```

**Static configuration**

Add an entry to the `discovery_service.aws` section of your `teleport.yaml` file, assigning role ARN to the ARN of the IAM role to assume and optional external ID to an optional external ID:

```
# teleport.yaml
# ...
discovery_service:
  enabled: true
  discovery_group: "aws-prod"
  aws:
  - types: ["ec2"]
    ssm:
      document_name: "AWS-RunShellScript"
    # Add new entry after existing entries
  - types: ["ec2"]
    regions: ["us-east-1", "us-west-1"]
    tags:
      "env": "prod" # Match EC2 instances where tag:env=prod
    install:
      enroll_mode: script
      install_teleport: true
      join_method: iam
      join_token: aws-discovery-iam-token
    ssm:
      document_name: "AWS-RunShellScript"
    assume_role_arn: "role ARN"
    external_id: "optional external ID"
  - types: ["ec2"]
    ssm:
      document_name: "AWS-RunShellScript"
    # Add a new entry for each account.
    # ...

```

### Step 4/5. Bootstrap the Discovery Service AWS configuration

When all of your accounts are ready, run `teleport discovery bootstrap` again to generate the remaining IAM policies and SSM documents. For each distinct `assume_role_arn`/`external_id`, Teleport will assume that role and attach the new policies to it (unless overridden by `--attach-to-user` or `--attach-to-role`).

```
$ sudo teleport discovery bootstrap
```

### Step 5/5. Restart Teleport

Restart the Teleport service to start discovering new instances:

```
$ sudo systemctl restart teleport
```

You can check the status of the Discovery Service with `systemctl status teleport` and view its logs with `journalctl -fu teleport`.

## Auto-discovery labels

Teleport applies a set of default labels to resources on AWS, Azure, and Google Cloud that join a cluster via auto-discovery. See the auto-discovery labels [reference](https://goteleport.com/docs/enroll-resources/auto-discovery/reference/labels.md)

## Advanced configuration

This section covers configuration options for discovering and enrolling servers.

### Install multiple Teleport agents on the same instance

When using blue-green deployments or other multiple clusters setups, you might want to access your instances from different clusters.

Teleport supports installing and running multiple agents on the same instance, using a suffixed installation which allows you to isolate each installation.

**Dynamic configuration (recommended)**

To configure the Discovery Service to use a suffixed installation, edit the Discovery Config and set the `spec.aws.install.suffix` key:

```
kind: discovery_config
# ...
spec:
  aws:
   - install:
       suffix: "blue-cluster"

```

**Static configuration**

To configure the Discovery Service to use a suffixed installation, specify the `install.suffix` key in your Discovery Service configuration:

```
# teleport.yaml
version: v3
# ...
discovery_service:
  enabled: true
  aws:
   - install:
       suffix: "blue-cluster"

```

Requires [agent managed updates](https://goteleport.com/docs/upgrading/agent-managed-updates.md) to be enabled.

### Define the group for Managed Updates

If you are using Teleport [Agent managed updates](https://goteleport.com/docs/upgrading/agent-managed-updates.md), you can configure the update group so that you can control which instances get updated together.

**Dynamic configuration (recommended)**

To set the update group, edit the Discovery Config and set the `spec.aws.install.update_group` key:

```
kind: discovery_config
# ...
spec:
  aws:
   - install:
       update_group: "update-group-1"

```

**Static configuration**

To set the update group, specify the `install.update_group` key in your Discovery Service configuration:

```
# teleport.yaml
version: v3
# ...
discovery_service:
  enabled: true
  aws:
   - install:
       update_group: "update-group-1"

```

### Configure HTTP Proxy during installation

For instances which require a proxy to access the installation files, you can configure HTTP Proxy settings in the Discovery Service.

**Dynamic configuration (recommended)**

To set the HTTP proxy settings, edit the Discovery Config and set the `spec.aws.install.http_proxy_settings` key:

```
kind: discovery_config
# ...
spec:
  aws:
   - install:
       http_proxy_settings:
         https_proxy: http://172.31.5.130:3128
         http_proxy: http://172.31.5.130:3128
         no_proxy: my-local-domain

```

**Static configuration**

You must set the `install.http_proxy_settings` key in your configuration:

```
# teleport.yaml
version: v3
# ...
discovery_service:
  enabled: true
  aws:
   - install:
       http_proxy_settings:
         https_proxy: http://172.31.5.130:3128
         http_proxy: http://172.31.5.130:3128
         no_proxy: my-local-domain

```

### Use a custom installation script

To customize an installer, your user must have a role that allows `list`, `create`, `read` and `update` verbs on the `installer` resource.

Create a file called `installer-manager.yaml` with the following content:

```
kind: role
version: v5
metadata:
  name: installer-manager
spec:
  allow:
    rules:
      - resources: [installer]
        verbs: [list, create, read, update]

```

Create the role:

```
$ tctl create -f installer-manager.yaml
role 'installer-manager' has been created
```

---

TIP

You can also create and edit roles using the Web UI. Go to **Access -> Roles** and click **Create New Role** or pick an existing role to edit.

---

The preset `editor` role has the required permissions by default.

To customize the default installer script, execute the following command on your workstation:

```
$ tctl edit installer/default-installer
```

After making the desired changes to the default installer, save and close the file in your text editor.

Multiple `installer` resources can exist and be specified in the `aws.install.script_name` section:

**Dynamic configuration (recommended)**

Edit the Discovery Config to specify a custom installer script:

```
kind: discovery_config
# ...
spec:
  aws:
    - types: ["ec2"]
      tags:
       - "env": "prod"
      regions: ["us-west1", "us-east1"]
      install:
        enroll_mode: 1
        install_teleport: true
        script_name: "default-installer"
      ssm:
        document_name: "AWS-RunShellScript"
    - types: ["ec2"]
      tags:
       - "env": "devel"
      regions: ["us-west1", "us-east1"]
      install:
        enroll_mode: 1
        install_teleport: true
        script_name: "devel-installer"
      ssm:
        document_name: "AWS-RunShellScript"


```

**Static configuration**

Edit the `teleport.yaml` configuration to specify a custom installer script:

```
discovery_service:
  # ...
  aws:
    - types: ["ec2"]
      tags:
       - "env": "prod"
      regions: ["us-west1", "us-east1"]
      install:
        enroll_mode: script
        install_teleport: true
        script_name: "default-installer"
      ssm:
        document_name: "AWS-RunShellScript"
    - types: ["ec2"]
      tags:
       - "env": "devel"
      regions: ["us-west1", "us-east1"]
      install:
        enroll_mode: script
        install_teleport: true
        script_name: "devel-installer"
      ssm:
        document_name: "AWS-RunShellScript"

```

---

The `installer` resource has the following templating options:

- `{{ .MajorVersion }}`: the major version of Teleport to use when installing from the repository.
- `{{ .PublicProxyAddr }}`: the public address of the Teleport Proxy Service to connect to.
- `{{ .RepoChannel }}`: Optional package repository (apt/yum) channel name. Has format `<channel>/<version>` e.g. stable/v19. See [installation](https://goteleport.com/docs/installation/linux.md) for more details.
- `{{ .AutomaticUpgrades }}`: indicates whether Automatic Updates are enabled or disabled. Its value is either `true` or `false`. See [Automatic Agent Updates](https://goteleport.com/docs/upgrading/agent-managed-updates.md) for more information.
- `{{ .TeleportPackage }}`: the Teleport package to use. Its value is either `teleport-ent` or `teleport` depending on whether the cluster is enterprise or not.

These can be used as follows:

```
kind: installer
metadata:
  name: default-installer
spec:
  script: |
    echo {{ .PublicProxyAddr }}
    echo Teleport-{{ .MajorVersion }}
    echo Repository Channel: {{ .RepoChannel }}
version: v1

```

Which, when retrieved for installation, will evaluate to a script with the following contents:

```
echo teleport.example.com
echo Teleport-19.0.0-dev
echo Repository Channel: stable/v19.0.0-dev

```

The default installer will take the following actions:

- Add an official Teleport repository to supported Linux distributions.
- Install Teleport via `apt` or `yum`.
- Generate the Teleport config file and write it to `/etc/teleport.yaml`.
- Enable and start the Teleport service.

### Use a custom SSM Document

When executing the installation script on discovered EC2 instances, the Discovery Service uses an SSM document.

The default `AWS-RunShellScript` SSM document works in most cases and is always available in AWS.

However, if you need to customize the installation process for your environment, you can create a custom SSM Document and configure the Discovery Service to use it during installation.

The custom document's parameters must include `env`, `scriptName` and `token`.

The recommended approach is to use the following document and customize it as needed:

```
schemaVersion: '2.2'
description: aws:runShellScript
parameters:
  token:
    type: String
    description: "(Required) The Teleport invite token to use when joining the cluster."
  scriptName:
    type: String
    description: "(Required) The Teleport installer script to use when joining the cluster."
  env:
    type: String
    description: "Environment variables exported to the script. Format 'ENV=var FOO=bar'"
    default: "X=$X"
mainSteps:
- action: aws:downloadContent
  name: downloadContent
  inputs:
    sourceType: "HTTP"
    destinationPath: "/tmp/installTeleport.sh"
    sourceInfo:
      url: "https://teleport.example.com:443/webapi/scripts/installer/{{ scriptName }}"
- action: aws:runShellScript
  name: runShellScript
  inputs:
    timeoutSeconds: '300'
    runCommand:
      - export {{ env }}; /bin/sh /tmp/installTeleport.sh "{{ token }}"

```

Create this document using AWS Systems Manager in each region where you plan to discover instances.

Edit your Discovery Service configuration to use the custom SSM Document, by setting the `ssm.document_name` key:

```
# teleport.yaml
version: v3
# ...
discovery_service:
  enabled: true
  aws:
   - ssm:
       document_name: "TeleportDiscoveryInstaller"

```

### Discover instances in all active regions

The Discovery Service can be configured to scan all active AWS regions for EC2 instances.

Edit the AWS matcher and set the `regions` key to wildcard (`*`):

```
# teleport.yaml
version: v3
# ...
discovery_service:
  enabled: true
  aws:
   - regions: ["*"]
     # other fields

```

Add the necessary IAM permissions to allow the Discovery Service to list regions:

```
{
    "Effect": "Allow",
    "Action": [
        // existing permissions
        "account:ListRegions"
    ],
    "Resource": "*"
}

```

## Troubleshooting

If Installs are showing failed or instances are failing to appear check the Command history in AWS Systems Manager -> Node Management -> Run Command. Select the instance-id of the Target to review Errors.

### Installation script exit codes

When enrolling an instance into Teleport, the installation script returns a specific exit code when facing well-known issues:

- 100: `bash` binary is missing
- 101: `sudo` binary is missing
- 102: `curl` binary is missing
- 103: `/opt` or `/` do not have the required minimum space to install Teleport, at least 1250MB is required
- 104: host is unable to connect to the Teleport Proxy Services's HTTPS endpoint

You can customize the installation script - as describe in the **Use a custom installation script** section above - and implement other checks with specific exit codes.

Whether the installation exits with a pre-flight check or with your own custom installation script, the exit code appears in `ssm.run` Teleport audit events, in the `exit_code` field. It also appears in AWS Systems Manager -> Node Management -> Run Command -> Command history.

Example of the `ssm.run` event with an exit code:

```
{
  "code": "TDS00W",
  "event": "ssm.run",
  "instance_id": "i-0000",
  "region": "<region>",
  "invocation_url": "https://<region>.console.aws.amazon.com/systems-manager/run-command/<uuid>/i-0000",
  "platform_name": "Ubuntu",
  "platform_type": "Linux",
  "platform_version": "24.04",
  "status": "curl is not installed in the instance. Please install all required tools (bash, sudo, curl) and try again.",
  "stderr": "failed to run commands: exit status 102",
  "stdout": "curl is missing\n",
  "exit_code": 102
}

```

### `cannot unmarshal object into Go struct field`

If you encounter an error similar to the following:

```
invalid format in plugin properties map[destinationPath:/tmp/installTeleport.sh sourceInfo:map[url:[https://example.teleport.sh:443/webapi/scripts/installer/preprod-installer](https://example.teleport.sh/webapi/scripts/installer/preprod-installer)] sourceType:HTTP];
error json: cannot unmarshal object into Go struct field DownloadContentPlugin.sourceInfo of type string

```

It is likely that you're running an older SSM agent version. Upgrade to SSM agent version 3.1 or greater to resolve.

### `InvalidInstanceId: Instances [[i-123]] not in a valid state for account 456`

The following problems can cause this error:

- The Discovery Service doesn't have permission to access the managed node.
- AWS Systems Manager Agent (SSM Agent) isn't running. Verify that SSM Agent is running.
- SSM Agent isn't registered with the SSM endpoint. Try reinstalling SSM Agent.
- The discovered instance does not have permission to receive SSM commands, verify the instance includes the AmazonSSMManagedInstanceCore IAM policy.

See SSM RunCommand error codes and troubleshooting information in AWS documentation for more details:

- <https://docs.aws.amazon.com/systems-manager/latest/userguide/troubleshooting-managed-instances.html>
- [https://docs.aws.amazon.com/systems-manager/latest/APIReference/API\_SendCommand.html#API\_SendCommand\_Errors](https://docs.aws.amazon.com/systems-manager/latest/apireference/api_sendcommand.html#api_sendcommand_errors)

## Next steps

- Read [Joining Nodes via AWS IAM Role](https://goteleport.com/docs/enroll-resources/agents/aws-iam.md) for more information on IAM Invite Tokens.
- Information on IAM best practices on EC2 instances managed by Systems Manager can be found in the [AWS Cloud Operations & Migrations Blog ](https://aws.amazon.com/blogs/mt/applying-managed-instance-policy-best-practices/).
- Full documentation on EC2 discovery configuration can be found through the [config file reference documentation](https://goteleport.com/docs/reference/deployment/config.md).
