# Joining Services via AWS EC2 Identity Document

This guide explains how to use the **EC2 join method** to configure Teleport processes to join your Teleport cluster without sharing any secrets when they are running in AWS.

The EC2 join method is only available in self-hosted Teleport deployments. There are two other AWS join methods available depending on your use case:

1. The **IAM join method** is available to any Teleport process running anywhere with access to IAM credentials, such as an EC2 instance with an attached IAM role (see [documentation](https://goteleport.com/docs/enroll-resources/agents/aws-iam.md)). No specific permissions or IAM policy is required: an IAM role with no attached policies is sufficient. No IAM credentials are required on the Teleport Auth Service.
2. **Tokens not signed by AWS:** You can configure Teleport processes running on AWS to join a cluster via [Teleport join tokens](https://goteleport.com/docs/enroll-resources/agents/join-token.md) or, for Teleport processes running on Kubernetes, [signed ServiceAccount tokens](https://goteleport.com/docs/enroll-resources/agents/kubernetes.md). These approaches allow you to join a Teleport process to a cluster when you don't want to rely on AWS-specific APIs, e.g., when adopting a cloud-agnostic approach.

## How it works

The EC2 join method is available to any Teleport process running on an EC2 instance. Only one Teleport process per EC2 instance may use the EC2 join method. The process presents an [EC2 instance identity document](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html) to the Teleport Auth Service.

Meanwhile, the Teleport Auth Service has AWS IAM credentials with `ec2:DescribeInstances` permissions in order to check that the identity document belongs to a legitimate EC2 instance. No IAM credentials are required on the Teleport processes joining the cluster.

## Prerequisites

- A running self-hosted 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
     ```

* One of the following client tools for managing Teleport resources:

  - The `tctl` CLI, which you can install along with Teleport on your workstation ([documentation](https://goteleport.com/docs/installation.md)) on your workstation.
  - [Teleport Terraform provider](https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/terraform-provider.md)
  - [Teleport Kubernetes operator](https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/terraform-provider.md)

* An AWS EC2 instance to host a Teleport process, with the Teleport binary installed. The host should not have an existing data dir (`/var/lib/teleport` by default). Remove the data directory if this instance has previously joined a Teleport cluster.

## Step 1/5. Set up AWS IAM credentials

The Teleport Auth Service needs permission to call `ec2:DescribeInstances` in order to check that the EC2 instances attempting to join your cluster are legitimate and currently running.

### Create the IAM policy

Create the following AWS IAM policy named `teleport-DescribeInstances-policy` in your account:

```
{
   "Version": "2012-10-17",
   "Statement": [
	   {
		   "Effect": "Allow",
		   "Action": "ec2:DescribeInstances",
		   "Resource": "*"
	   }
   ]
}

```

### Attach the IAM policy

If your Teleport Auth Service is running on an EC2 instance and already has an attached "IAM role for Amazon EC2", add the above `teleport-DescribeInstances-policy` to the existing role. If the instance does not already have an attached role, create an IAM role with the above policy and attach it to your EC2 instance running the Teleport Auth Service.

If you are running your Teleport Auth Service outside of AWS you can attach the `teleport-DescribeInstances-policy` directly to an IAM user which Teleport will use to authenticate.

You can provide the IAM credentials to Teleport through a shared configuration file or environment variables. See [Specifying Credentials](https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/configure-gosdk.html#specifying-credentials) for details.

## Step 2/5. Create the AWS joining token

Configure your Teleport Auth Service with a special dynamic token which will allow services from your AWS account to join your Teleport cluster.

Under the hood, services will prove that they are running in your AWS account by sending a signed EC2 Instance Identity Document which matches an allow rule configured in your AWS joining token.

You can create the token with `tctl` as well as the Teleport Terraform provider or Kubernetes operator:

**tctl**

Create the following `token.yaml` with an `allow` rule specifying your AWS account and the AWS regions in which your EC2 instances will run.

```
# 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: ec2-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: ec2

  # aws_iid_ttl is the amount of time after the EC2 instance is launched during
  # which it should be allowed to join the cluster. Use a short TTL to decrease
  # the risk of stolen EC2 Instance Identity Documents being used to join your
  # cluster.
  #
  # When launching your first Teleport process using the EC2 join method, you may need to
  # temporarily configure a higher `aws_iid_ttl` value so that you have time
  # to get Teleport set up and configured. This feature works best once Teleport
  # is configured in an EC2 AMI to start automatically on launch.
  aws_iid_ttl: 5m

  allow:
  - aws_account: "111111111111" # your AWS account ID
    aws_regions: # use the minimal set of AWS regions required
    - us-west-1
    - us-west-2

```

Run `tctl create token.yaml` to create the token.

**Terraform**

Add the following resource to your Terraform configuration, replacing values as indicated:

```
resource "teleport_provision_token" "ec2-token" {
  version = "v2"
  metadata = {
    name = "ec2-token"
  }

  labels = {
    // This label is added on the Teleport side by default
    "teleport.dev/origin" = "dynamic"
  }

  spec = {
    // use the minimal set of roles required (e.g. Node, Proxy, App, Kube, DB, WindowsDesktop)
    roles       = ["Node"]
    join_method = "ec2"
    // aws_iid_ttl is the amount of time after the EC2 instance is launched during
    // which it should be allowed to join the cluster. Use a short TTL to decrease
    // the risk of stolen EC2 Instance Identity Documents being used to join your
    // cluster.
    //
    // When launching your first Teleport process using the EC2 join method, you may need to
    // temporarily configure a higher `aws_iid_ttl` value so that you have time
    // to get Teleport set up and configured. This feature works best once Teleport
    // is configured in an EC2 AMI to start automatically on launch.
    aws_iid_ttl = "5m"

    allow = [
      {
        aws_account = "111111111111"             # your AWS account ID
        aws_regions = ["us-west-1", "us-west-2"] # use the minimal set of AWS regions required
      },
    ]
  }
}

```

**Kubernetes**

Add the following Kubernetes resource manifest, replacing values as indicated:

```
apiVersion: "resources.teleport.dev/v2"
kind: TeleportProvisionToken
metadata:
  name: "ec2-token"
  labels:
    # This label is added on the Teleport side by default
    "teleport.dev/origin": "dynamic"
spec:
  # use the minimal set of roles required (e.g. Node, Proxy, App, Kube, DB, WindowsDesktop)
  roles: [Node]
  # set the join method allowed for this token
  join_method: ec2

  # aws_iid_ttl is the amount of time after the EC2 instance is launched during
  # which it should be allowed to join the cluster. Use a short TTL to decrease
  # the risk of stolen EC2 Instance Identity Documents being used to join your
  # cluster.
  #
  # When launching your first Teleport process using the EC2 join method, you may need to
  # temporarily configure a higher `aws_iid_ttl` value so that you have time
  # to get Teleport set up and configured. This feature works best once Teleport
  # is configured in an EC2 AMI to start automatically on launch.
  aws_iid_ttl: 5m

  allow:
  - aws_account: "111111111111" # your AWS account ID
    aws_regions: # use the minimal set of AWS regions required
    - us-west-1
    - us-west-2

```

## Step 3/5 Install Teleport

Install Teleport on your AWS EC2 Instance.

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/5. Configure your services

The EC2 join method can be used for Teleport processes running the SSH, Proxy, Kubernetes, Application, Database, or Windows Desktop Services. The Teleport process should be run directly on an AWS EC2 instance and must have network access to the AWS EC2 IMDSv2 (enabled by default for most EC2 instances).

Configure your Teleport process with a custom `teleport.yaml` file. Use the `join_params` section with `token_name` matching your token created in Step 2 and `method: ec2` as shown in the following example config:

```
# /etc/teleport.yaml
version: v3
teleport:
  join_params:
    token_name: ec2-token
    method: ec2
  proxy_server: https://teleport.example.com:443
ssh_service:
  enabled: true
auth_service:
  enabled: false
proxy_service:
  enabled: false

```

## Step 5/5. Launch your Teleport process

---

IMPORTANT

The data directory (`/var/lib/teleport` by default) must be empty prior to launching the Teleport process. If this Teleport process had previously joined by another method (e.g. token or IAM) the host UUID will not match the expected name (`<AWS Account number>-<instance id>`) and will not be allowed to join.

---

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

**Package Manager**

On the host where you will run your Teleport instance, enable and start Teleport:

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

**TAR Archive**

On the host where you will run your Teleport instance, 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 your Teleport instance with `systemctl status teleport` and view its logs with `journalctl -fu teleport`.

Start Teleport on the host and confirm that it is able to connect to and join your cluster. You're all set!

## Configuring the EC2 join method for Multiple AWS accounts

In order for Teleport processes to join from EC2 instances in AWS accounts other than the account in which your Teleport Auth Service is running, Teleport must have permissions to assume an IAM role in each of those accounts and call `ec2:DescribeInstances` in the foreign account.

In each AWS account where your EC2 instances will be running:

1. Create the `teleport-DescribeInstances-policy` from [Step 1.1](#create-the-iam-policy).

2. Create an IAM role `teleport-DescribeInstances-role` that can be assumed from the account where your Teleport Auth Service is running.

   Go to the AWS IAM Console, select Create Role, and for "Select type of trusted entity", select "Another AWS account" and enter the AWS Account ID of the account where your Teleport Auth Service is running.

3. Attach the `teleport-DescribeInstances-policy` to the role.

In the AWS account where your Teleport Auth Service is running:

1. Create an IAM policy named `teleport-AssumeRole-policy` with an `AssumeRole` statement for each foreign account:

```
{
   "Version": "2012-10-17",
   "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::222222222222:role/teleport-DescribeInstances-role"
        },
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::333333333333:role/teleport-DescribeInstances-role"
        }
   ]
}

```

1. Attach this `teleport-AssumeRole-policy` to the IAM role your Teleport Auth Service has credentials for, see [Step 1.2](#attach-the-iam-policy).

When creating the AWS joining token, include an allow rule for each foreign account and specify the AWS ARN for the foreign `teleport-DescribeInstances-role`.

```
# token.yaml
kind: token
version: v2
metadata:
  name: ec2-multiaccount-token
spec:
  roles: [Node]
  aws_iid_ttl: 5m
  allow:
  - aws_account: "222222222222"
    aws_regions:
    - us-west-1
    - us-west-2
    aws_role: "arn:aws:iam::222222222222:role/teleport-DescribeInstances-role"
  - aws_account: "333333333333"
    aws_regions:
    - us-west-1
    - us-west-2
    aws_role: "arn:aws:iam::333333333333:role/teleport-DescribeInstances-role"

```
