# Registering Agentless OpenSSH Servers with IaC

In this guide, you will see how to register in Teleport your OpenSSH nodes through infrastructure as code (IaC). Teleport supports three ways to dynamically create resources from code:

- The Teleport Kubernetes Operator, which allows you to manage Teleport resources from Kubernetes
- The Teleport Terraform Provider, which allows you to manage Teleport resources via Terraform
- The `tctl` CLI, which allows you to manage Teleport resources from your local computer or your CI environment

## How it works

Teleport can route SSH connections through the Teleport Proxy Service to SSH nodes. Once you have configured your SSH nodes to trust the Teleport certificate authority for OpenSSH (see the [Agentless OpenSSH guide](https://goteleport.com/docs/enroll-resources/server-access/openssh/openssh-agentless.md), the Proxy Service can present a Teleport-signed certificate to the node and establish a connection. For this to work, the Teleport Proxy Service must be able to dial the node.

Agentless SSH servers are registered with the Teleport Auth Service as resources stored on the Auth Service backend. The Teleport Auth Service exposes a gRPC API that enables clients to create, delete, or modify backend resources, including agentless SSH servers. The Teleport Kubernetes Operator and Terraform provider, along with the `tctl` command-line tool, can manage agentless SSH services by authenticating to the Teleport Auth Service and interacting with its gRPC API.

To follow this guide, you must have:

**tctl**

- 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
     ```

**Kubernetes Operator**

A running operator by following either:

- [the guide to enable the operator in the `teleport-cluster` Helm chart](https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/teleport-operator/teleport-operator-helm.md).
- [the guide to setup a standalone operator](https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/teleport-operator/teleport-operator-standalone.md).

You must also set the namespace in which you deployed the operator as this is the namespace where you will deploy the CustomResources:

```
for operators deployed with the `teleport-cluster` Helm chart
$ export OPERATOR_NAMESPACE="teleport-cluster"

for standalone operators
$ export OPERATOR_NAMESPACE="teleport-iac"
```

**Terraform**

A functional Teleport Terraform provider by following [the Terraform provider guide](https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/terraform-provider.md).

- a server running OpenSSH you will add to the Teleport cluster. This server must be reachable from the proxy (public IP address and firewall allowing traffic on port 22).

---

TIP

If you want to add a private SSH server (e.g. behind a NAT, in a private network, protected by a firewall blocking inbound traffic, ...) you can [install a Teleport Agent](https://goteleport.com/docs/enroll-resources/server-access/getting-started.md). The Teleport Agent opens a tunnel to the Teleport Proxy Service, allowing any user to connect to it by going through the Proxy Service.

---

## Step 1/5 - Gather the required information

To register an OpenSSH server in Teleport you will need the following information:

- The server hostname: ssh-server-hostname
- The public server IP address with SSH port: 198.51.100.1:22

You must also choose a set of labels for the server. Those labels can be used to describe the server and control which users can access the server. They can be dynamically changed later, without having to reconfigure openSSH.

See the [Access Controls for Servers](https://goteleport.com/docs/enroll-resources/server-access/rbac.md) page for more details about labels and how to control access to your servers.

In the rest of this guide, the labels will be:

```
env: test
team: engineering

```

## Step 2/5 - Write the server manifest

In this step, we'll write text files describing the OpenSSH server resource we want to register in Teleport. Those files are called manifests and their syntax will vary based on the IaC tooling you'll use.

Those manifests are typically versioned in a shared revision system like git. This allows you to keep track of all changes, follow standard code review procedures before changing resources in Teleport, and quickly redeploy your Teleport instance if needed.

**tctl**

You must pick a server ID, or Teleport will pick one for you. This ID is used for two things:

- if you want to update the server information (e.g. change the labels) later, you will need to specify its ID in the manifest. Else Teleport will create a new server resource instead of editing the existing one.
- if you have multiple servers with identical hostnames, the unique ID allows you to pick a specific server.

To generate a new UUID:

**Linux**

Use `uuidgen`. This executable is installed by default on most machines. If it's not installed, it is available via the `uuid-runtime` package for DEB-based distros, and `util-linux` for RPM-based distros.

```
$ uuidgen

a100fdd0-52db-4eca-a7ab-c3afa7a1564a
```

**macOS**

Use `uuidgen` and `tr` packages that are installed by default:

```
$ uuidgen | tr '[:upper:]' '[:lower:]'

a100fdd0-52db-4eca-a7ab-c3afa7a1564a
```

**Windows**

Use the `NewGuid` powershell cmdlet:

```
$ New-guid
Guid
----
a100fdd0-52db-4eca-a7ab-c3afa7a1564a
```

Create the following `openssh-node-resource.yaml` file:

```
kind: node
version: v2
sub_kind: openssh
metadata:
  name: a100fdd0-52db-4eca-a7ab-c3afa7a1564a  # this is the UUID previously generated
  labels:
    env: test
    team: engineering
spec:
  addr: 198.51.100.1:22
  hostname: ssh-server-hostname

```

**Kubernetes Operator**

To generate a new UUID:

**Linux**

Use `uuidgen`. This executable is installed by default on most machines. If it's not installed, it is available via the `uuid-runtime` package for DEB-based distros, and `util-linux` for RPM-based distros.

```
$ uuidgen

a100fdd0-52db-4eca-a7ab-c3afa7a1564a
```

**macOS**

Use `uuidgen` and `tr` packages that are installed by default:

```
$ uuidgen | tr '[:upper:]' '[:lower:]'

a100fdd0-52db-4eca-a7ab-c3afa7a1564a
```

**Windows**

Use the `NewGuid` powershell cmdlet:

```
$ New-guid
Guid
----
a100fdd0-52db-4eca-a7ab-c3afa7a1564a
```

Create the following `openssh-node-resource.yaml` file:

```
apiVersion: resources.teleport.dev/v1
kind: TeleportOpenSSHServerV2
metadata:
  name: a100fdd0-52db-4eca-a7ab-c3afa7a1564a  # this is the UUID previously generated
  # kubernetes CR labels are propagated to the Teleport resource
  labels:
    env: test
    team: engineering
spec:
  addr: 198.51.100.1:22
  hostname: ssh-server-hostname

```

**Terraform**

Create the following `openssh-node-resource.tf` file:

```
resource "teleport_server" "openssh_agentless" {
  version = "v2"
  sub_kind = "openssh"
  // Name is not required for servers, this is a special case.
  // When a name is not set, an UUID will be generated by Teleport and
  // imported back into Terraform.
  spec = {
    addr = "198.51.100.1:22"
    hostname = "ssh-server-hostname"
  }
}

output "openssh_node_id" {
  value = teleport_server.openssh_agentless.metadata.name
}

```

## Step 3/5. Apply all manifests

**tctl**

Declare the server with the following command:

```
$ tctl create -f openssh-node-resource.yaml
node "a100fdd0-52db-4eca-a7ab-c3afa7a1564a" has been created
```

**Kubernetes Operator**

Apply the Kubernetes manifest with the following command:

```
$ kubectl apply -n "$OPERATOR_NAMESPACE" -f openssh-node-resource.yaml
teleportopensshserverv2.resources.teleport.dev/a100fdd0-52db-4eca-a7ab-c3afa7a1564a created
```

Then list the `TeleportOpenSSHServerV2` Kubernetes custom resources:

```
$ kubectl get teleportopensshserverv2 -n "$OPERATOR_NAMESPACE"
NAME                                   AGE
a100fdd0-52db-4eca-a7ab-c3afa7a1564a   10m
```

**Terraform**

Test the Terraform connectivity and review the changes:

```
$ terraform plan
Terraform will perform the following actions:

  # teleport_server.openssh_agentless will be created
  + resource "teleport_server" "openssh_agentless" {
      + id       = (known after apply)
      + kind     = (known after apply)
      + metadata = (known after apply)
      + spec     = {
          + addr     = "198.51.100.1:22"
          + hostname = "ssh-server-hostname"
        }
      + sub_kind = "openssh"
      + version  = "v2"
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + openssh_node_id = (known after apply)
```

Apply the plan and recover the node UUID:

```
$ terraform apply
[...]
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

teleport_server.openssh_agentless: Creating...
teleport_server.openssh_agentless: Creation complete after 3s [id=a100fdd0-52db-4eca-a7ab-c3afa7a1564a]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

openssh_node_id = "a100fdd0-52db-4eca-a7ab-c3afa7a1564a"
```

## Step 4/5. Validate the server created in Teleport

Now that the IaC tooling has run, we'll validate that Teleport is now aware of the OpenSSH server:

```
List nodes with a given hostname or IP address
$ tsh ls --search="ssh-server-hostname"
Node Name                                           Address        Labels
--------------------- ------------ --------------- --------------------------
ssh-server-hostname 198.51.100.1:22 env=test,team=engineering

Get the node details by hostname
$ tctl get "node/ssh-server-hostname"

Get the node details by ID
$ tctl get node/a100fdd0-52db-4eca-a7ab-c3afa7a1564a
```

## Step 5/5. Trust the Teleport CA and issue host certificates

At this point, Teleport is aware that there's an OpenSSH server and knows how to contact it and which user should have access. However, neither Teleport nor the server trust each other.

You need to configure the server to trust connections coming from Teleport (trust the Teleport SSH Certificate Authority), and you need to give the server an SSH Host certificate issued by Teleport.

Those steps can be automated, but the automation will depend on your custom infrastructure and tooling (you can configure the SSH CA in the VM image, use custom startup scripts, provision servers with Ansible, ...).

A step-by-step manual setup is described in [the OpenSSH manual installation guide](https://goteleport.com/docs/enroll-resources/server-access/openssh/openssh-manual-install.md) starting with the Step 2.

## Next steps

- [Setup RBAC](https://goteleport.com/docs/enroll-resources/server-access/rbac.md) to control which user can SSH on which server.
