> ## Documentation Index
> Fetch the complete documentation index at: https://docs.formal.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# SSH/AWS SSM

> How to connect to an SSH Resource using the Formal Connector

The Formal Connector supports connecting to upstream resources via both SSH and AWS SSM.

## Requirements for SSH

When creating an SSH resource, set the resource hostname to the hostname of the target instance.

You can create native users that use either password authentication, SSH key authentication, or SSH certificate authentication:

* **Password authentication**: The secret should be the password of the user.
* **SSH key authentication**: The secret should be the SSH private key of the user in PEM format.
* **SSH certificate authentication**: The secret should be a JSON object with the following fields:

  * `key`: The SSH private key of the user in PEM format.
  * `cert`: The SSH certificate of the user signed by the CA that the resource trusts.

  ```json theme={null}
  {
    "key": "-----BEGIN OPENSSH PRIVATE KEY-----...",
    "cert": "ssh-ed25519-cert-v01@openssh.com ..."
  }
  ```

## Requirements for AWS SSM

Formal streamlines user access to instances using the AWS SSM protocol (AWS EC2 and ECS Fargate instances) through the Connector.

* **For AWS EC2 instances**:
  To utilize AWS SSM with EC2 instances, ensure the following:

  * SSM Agent Installation: The AWS Systems Manager Agent (SSM Agent) must be installed and running on the instance. While the SSM Agent comes pre-installed on certain Amazon Machine Images (AMIs), it may need to be manually installed or updated on others. For detailed guidance on verifying installation and performing manual installations, refer to [the SSM Agent documentation](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent.html).
  * IAM Role Configuration: The EC2 instance must be associated with an IAM Role that includes the `AmazonSSMManagedInstanceCore` policy. This policy grants the necessary permissions to enable AWS Systems Manager service core functionality.

  For a list of AMIs with the SSM Agent pre-installed and additional setup information, visit [the official documentation](https://docs.aws.amazon.com/systems-manager/latest/userguide/ami-preinstalled-agent.html).

* **For ECS Fargate instances**:
  For applications running on ECS Fargate, AWS SSM access requires enabling the ECS Exec feature. This feature allows you to interact with your containers in real-time for tasks such as executing commands within a container or obtaining container logs.

  * ECS Exec Enablement: To use AWS SSM with ECS Fargate, the ECS Exec feature must be enabled for your services and standalone tasks. This setup allows secure and interactive access to your Fargate containers.

  For comprehensive steps on activating and using ECS Exec, consult [the ECS Exec documentation.](https://docs.aws.amazon.com/AmazonECS/latest/userguide/ecs-exec.html).

### Permissions

In order to discover and connect to the EC2 and ECS instances, the Formal Connector requires some permissions. You can give those permissions in two ways:

#### Ambient IAM role

You can configure an IAM role for the Formal Connector with the necessary permissions; the Connector loads credentials automatically from the AWS context. When using this option, no native user should be created.

#### IAM Role as a Native User

You can configure an IAM role to be assumed by the Formal Connector when connecting to the EC2 or ECS instances. This is useful if you want to use a specific IAM role for the Formal Connector rather than the default role, e.g. for connecting to resources in a different account.

To do so, see [Native User IAM Authentication](/docs/guides/core-concepts/resources/native_users#iam-authentication). The username of the IAM role can be set to any string.

#### Required IAM permissions

The IAM role requires the following permissions:

```
- ssm:StartSession
- ssm:DescribeInstanceInformation
- ecs:ExecuteCommand
- ecs:DescribeClusters
- ecs:ListTasks
- ecs:DescribeTasks
- ecs:ListResourceTags
- ec2:DescribeRegions
- ec2:DescribeInstances
- sts:GetCallerIdentity
```

## Connect to the Connector

<Tip>
  The [desktop app](/docs/guides/client-apps/desktop-app) helps configure your `~/.ssh/config` file automatically for SSH resources.
</Tip>

Once you have created an SSH resource, you can connect to it by making an SSH connection to the connector using a remote command to tell the connector which resource to connect to.

<Tabs>
  <Tab title="SSH">
    ```bash theme={null}
    ssh -t -p [CONNECTOR_LISTENER_PORT] \
      'idp:formal:human:john@joinformal.com'@[CONNECTOR_HOSTNAME] \
      formal connect ssh --instance-name [RESOURCE_NAME]
    ```
  </Tab>

  <Tab title="EC2">
    ```bash theme={null}
    ssh -t -p [CONNECTOR_LISTENER_PORT] \
      'idp:formal:human:john@joinformal.com'@[CONNECTOR_HOSTNAME] \
      formal connect ec2 --instance-arn arn:aws:ec2:us-east-1:123456789012:instance/i-01234567890abcdef0
    ```

    Note for EC2, either an instance ARN or an instance ID and region must be provided (i.e., `--instance-id <INSTANCE_ID> --region <REGION>`).

    The connector can optionally assume a role from the command line argument `--assume-role <IAM_ROLE_ARN>` before making the connection.
  </Tab>

  <Tab title="ECS">
    ```bash theme={null}
    ssh -t -p [CONNECTOR_LISTENER_PORT] \
      'idp:formal:human:john@joinformal.com'@[CONNECTOR_HOSTNAME] \
      formal connect ecs \
        --cluster-arn arn:aws:ecs:us-east-1:123456789012:cluster/my-cluster \
        --task-id 0761dca1661d4776b3fba04fe985cbcf \
        --container-name my-container
    ```

    Note that for ECS, you can pass a service ARN rather than a task ID and container name, in which case the connector will automatically find the first task in the service's first container.

    The connector can optionally assume a role from the command line argument `--assume-role <IAM_ROLE_ARN>` before making the connection.
  </Tab>
</Tabs>

As with other resources, the Formal user password to the connector is the Formal access token available from the Control Plane. Additionally, with the desktop app installed, a local private key identity automatically populated at `~/.formal/id_rsa` can be used as well.

## Policy Evaluation

Formal supports the following policy evaluation stages for SSH:

* **Session**: Evaluate and enforce policies at connection time

## Policies

You can apply access restrictions to SSH Resources, similar to any other Resource. For EC2 resources, you can apply restrictions based on the instance ARN and tags. For ECS resources, you can apply restrictions based on the cluster ARN, service ARN, task ID, task tags, and container name.

## Recordings

The Formal Connector records every session and makes recordings available in the [Sessions application](/docs/guides/observability/sessions).

## Applications

### VSCode Remote SSH

The Formal Connector supports the VSCode Remote SSH extension for SSH and SSM remotes. To do so, we recommend adding configuration in the `~/.ssh/config` file, which VSCode will read to render a menu of hosts to connect to.

For hosts that you would like to use VSCode Remote SSH with, we recommend configuring your SSH client to:

* Refrain from requesting a TTY (`RequestTTY no`)
* Use the `formal` command to request a remote host to connect to from the connector (see Direct Connections above)
* For ECS Fargate remotes, use `--shell /bin/bash` to avoid breaking VSCode Remote SSH's setup script.

Additionally,

* For SSH remotes, ensure the `AllowTcpForwarding` directive is set to `yes` in your SSH server configuration.
* For EC2 remotes, set the SSM agent to `exec /bin/bash` at startup in the AWS Session Manager console's Preferences section.

In the VSCode Remote SSH extension, you should also configure

* Remote.SSH: Enable Dynamic Forwarding (enabled)
* Remote.SSH: Use Local Server (enabled)
* Remote.SSH: Enable Remote Command (enabled)
* Remote.SSH: Permit Pty Allocation (disabled)
* Remote.SSH: Use Curl And Wget Configuration Files (enabled)
* Remote.SSH: Use Exec Server (enabled for ECS Fargate remotes, disabled for EC2 remotes)

Note that you'll need to configure additional IAM permissions for the Formal Connector to work with VSCode Remote SSH with SSM remotes. You'll need to allow the following permissions:

* `ssm:StartSession` on `AWS-StartPortForwardingSession`
* `ssm:TerminateSession`

For ECS Fargate remotes, AWS requires a "runtime ID" of the specific container to start a port forwarding session with. The Formal Connector will automatically fill this parameter if the `ENABLE_ECS_AUTO_DISCOVERY` is set to `true`; otherwise, you'll need to manually fill it yourself, e.g. with

```
ssh ... formal connect ecs ... --runtime-id $(aws ecs describe-tasks --cluster [CLUSTER_NAME] --tasks [TASK_ID] | jq .tasks[].containers[].runtimeId)
```

#### Cursor Remote SSH

As a VS Code fork, Cursor's Remote SSH extension works similarly to that of VS Code. However, the way it sets up the remote server binary is a bit different and requires additional configuration against ECS Fargate remotes.

First, create an `.ssh_inputrc` file in the home directory of the remote native user with the following content:

```
set enable-bracketed-paste off
set completion-query-items 0
set page-completions off
```

Then, in your Formal connection string, use `--shell "/bin/bash -c 'exec env INPUTRC=/path/to/.ssh_inputrc /bin/bash'"` to ensure that the `~/.ssh_inputrc` file is used when connecting to the remote host.

### SCP/SFTP

The Formal Connector supports SCP using the SFTP protocol for SSH resources only.

For SSH remotes, note that the `scp` command will not work with the `RemoteCommand` SSH directive, which is used by the Formal Connector to determine which remote host to connect to. Instead, you can include the resource name in the user identity string, such as `idp:human:example@example.com+resource-name` (i.e., the resource name is the last part of the identity string after the `+` character).

To transfer a file, you can format the SCP command as

```bash theme={null}
scp -i ~/.formal/id_rsa \
  -o User='idp:formal:human:john@joinformal.com+ssh-demo-resource' \
  /path/to/src \
  demo-connector.formal.connectors.joinformal.com:/path/to/dest
```

or, you can format `~/.ssh/config` as

```
Host scp-demo-connector
	Port 22
	User idp:formal:human:john@joinformal.com+ssh-demo-resource
	HostName demo-connector.formal.connectors.joinformal.com
	RequestTTY yes
	IdentityFile ~/.formal/id_rsa
```

<Tip>
  The desktop app above version 0.3.4 will automatically configure `~/.ssh/config` in this way.
</Tip>

### Rsync

The Formal Connector supports rsync over SSH for SSH and SSM remotes.

For SSH remotes, `rsync` encounters a similar `RemoteCommand` limitation as `scp`. You will need to configure `~/.ssh/config` similar to the example above, but also set `RequestTTY` to `no` for rsync compatibility.

For SSM remotes, the Formal Connector does not support `rsync` using the normal SSH channel due to [AWS limitations](https://github.com/aws/containers-roadmap/issues/1536). Instead, you can run `rsync` as a daemon on the remote host and then use `rsync://` to connect to it. Note that the rsync daemon needs to run on a port greater than 1000 (e.g., 8873) for permissions reasons. For EC2 remotes, ensure that the receiving directory is writable by the `ssm-user` user and for ECS Fargate remotes, ensure that the receiving directory is writable by the container user. For example, you can configure `/etc/rsyncd.conf` on the remote host as follows:

```
port = 8873

# EC2
[ec2-upload]
path = /home/ssm-user/upload
uid = ssm-user

# ECS Fargate
[ecs-upload]
path = /root/upload
uid = root
```

Then, port-forward the rsync daemon to your local machine:

```
ssh -L 8873:localhost:8873 -i ~/.formal/id_rsa -p 2022 'idp:human:example@example.com' formal connect ec2 --instance-id i-01234567890abcdef0
```

Then, you can use the following command to copy files to the remote host:

```
rsync -r target-dir rsync://localhost:8873/ec2-upload/
```
