mirror of
https://github.com/gravitational/teleport
synced 2024-10-20 01:03:40 +00:00
205 lines
11 KiB
Markdown
205 lines
11 KiB
Markdown
|
---
|
|||
|
authors: Trent Clarke (trent@goteleport.com)
|
|||
|
state: draft
|
|||
|
---
|
|||
|
|
|||
|
# RFD 22 - SSH key agent forwarding
|
|||
|
|
|||
|
## What
|
|||
|
|
|||
|
Issue [#1517](https://github.com/gravitational/teleport/issues/1517) draws
|
|||
|
attention to the behaviour of `tsh ssh` differing from the behaviour of the
|
|||
|
stock OpenSSH `ssh` client when forwarding a Key Agent to the remote machine.
|
|||
|
|
|||
|
This is a proposal to change `tsh ssh`'s agent-forwarding behaviour to match
|
|||
|
that of the OpenSSH client, while also allowing the legacy `tsh` behaviour if
|
|||
|
necessary.
|
|||
|
|
|||
|
## Why
|
|||
|
|
|||
|
### Background: What is Key Agent Forwarding?
|
|||
|
|
|||
|
An SSH Key Agent is a service that brokers access to keys, used by an SSH client
|
|||
|
when authenticating against a remote machine.
|
|||
|
|
|||
|
The OpenSSH remote login client allows a user to _forward_ their key agent to
|
|||
|
the remote server via a secondary channel in the ssh protocol. This makes the Key
|
|||
|
Agent on the user's local machine available on the remote server, and allowing the
|
|||
|
user to connect to a _third_ machine from the remote server and authenticate
|
|||
|
with keys stored on the user's local machine.
|
|||
|
|
|||
|
```
|
|||
|
Overly Simplified Authentication Flow with Forwarded Key Agent
|
|||
|
|
|||
|
┌─────────┐ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐
|
|||
|
│Key Agent│ │Local Machine│ │Remote Machine│ │Third Machine│
|
|||
|
└────┬────┘ └──────┬──────┘ └──────┬───────┘ └──────┬──────┘
|
|||
|
│ │ SSH Connect │ │
|
|||
|
│ │───────────────────────>│ │
|
|||
|
│ │ Auth challenge │ │
|
|||
|
│ │<───────────────────────│ │
|
|||
|
│ Auth Challenge │ │ │
|
|||
|
│<─────────────────────│ │ │
|
|||
|
│ Signed Response │ │ │
|
|||
|
│─────────────────────>│ │ │
|
|||
|
│ │ Signed Response │ │
|
|||
|
│ │───────────────────────>│ │
|
|||
|
│ ╔═══════╧════════════════════════╧════════╗ │
|
|||
|
│ ║ Authentication established ║ │
|
|||
|
│ ╚═══════╤════════════════════════╤════════╝ │
|
|||
|
│ │ ╔════════╧═════════╗ │
|
|||
|
│ │ ║ User connects to ║ │
|
|||
|
│ │ ║ "Third Machine" ║ │
|
|||
|
│ │ ╚════════╤═════════╝ │
|
|||
|
│ │ │ SSH Connect │
|
|||
|
│ │ │ ───────────────────────>│
|
|||
|
│ │ │ Auth challenge │
|
|||
|
│ │ │ <───────────────────────│
|
|||
|
│ Auth Challenge (via forwarded connection) │ │
|
|||
|
│<──────────────────────────────────────────────│ │
|
|||
|
│ Signed Response (via forwarded connection) │ │
|
|||
|
│──────────────────────────────────────────────>│ │
|
|||
|
│ │ │ Signed Response │
|
|||
|
│ │ │ ───────────────────────>│
|
|||
|
│ │ ╔═══════╧═════════════════════════╧═══════╗
|
|||
|
│ │ ║ Authentication established ║
|
|||
|
| | ╚═════════════════════════════════════════╝
|
|||
|
┌────┴────┐ ┌──────┴──────┐ ┌──────┴───────┐ ┌──────┴──────┐
|
|||
|
│Key Agent│ │Local Machine│ │Remote Machine│ │Third Machine│
|
|||
|
└─────────┘ └─────────────┘ └──────────────┘ └─────────────┘
|
|||
|
```
|
|||
|
|
|||
|
The above diagram leaves out a _lot_ of detail, but the overall process should be clear
|
|||
|
enough for this discussion.
|
|||
|
|
|||
|
### What's the issue?
|
|||
|
|
|||
|
An OpenSSH user can forward their Key Agent to the remote machine using the `-A` flag on
|
|||
|
the `ssh` command line. This allows the user to use arbitrary keys stored on their _local_
|
|||
|
machine to authenticate against a "Third Machine" from inside their session on the Remote
|
|||
|
Machine.
|
|||
|
|
|||
|
When running `tsh ssh`, a user may have _two_ independent key agents running: their own
|
|||
|
(which we will call the _System Key Agent_), and an ephemeral one inside the `tsh` process
|
|||
|
itself (the _Teleport Key Agent_). The Teleport Key Agent is populated with the contents
|
|||
|
of the user's `.tsh` directory.
|
|||
|
|
|||
|
The `tsh ssh` client _also_ offers a `-A` option to forward a Key Agent to the Remote
|
|||
|
Machine, but it will only ever forward the Teleport Key Agent, not the System Key Agent.
|
|||
|
This is surprising behaviour to a user accustomed to OpenSSH. The user finds that keys
|
|||
|
they expected to be available to them in the session on the Remote Machine are not
|
|||
|
available.
|
|||
|
|
|||
|
The tricky part is that _both_ of these behaviours are sensible, depending on the user's
|
|||
|
expectations. Any solution will have to accommodate both behaviours.
|
|||
|
|
|||
|
## Details
|
|||
|
|
|||
|
### Proposed Solution
|
|||
|
|
|||
|
**NB:** This proposal is strictly about how a Key Agent is forwarded to a remote
|
|||
|
machine by `tsh ssh`. It does _not_ change how `tsh` authenticates against a `teleport`
|
|||
|
auth service.
|
|||
|
|
|||
|
Behind the scenes, both the OpenSSH client & `tsh ssh` treat the `-A` flag as shorthand
|
|||
|
for setting the SSH config value `ForwardAgent` to `yes`.
|
|||
|
|
|||
|
Looking at the `man` page for `ssh_config(5)`, we can see the definitive list of values
|
|||
|
that `ForwardAgent` can take, and their meaning:
|
|||
|
|
|||
|
> **ForwardAgent**
|
|||
|
>
|
|||
|
> Specifies whether the connection to the authentication agent (if any) will be forwarded
|
|||
|
> to the remote machine. The argument may be `yes`, `no` (the default), an explicit path
|
|||
|
> to an agent socket or the name of an environment variable (beginning with ‘$’) in which
|
|||
|
> to find the path.
|
|||
|
|
|||
|
The `tsh ssh` client already supports the `yes` and `no` options, where `yes` means
|
|||
|
forwarding the Teleport Key Agent. To allow the user to forward their own Key Agent, _and_
|
|||
|
to bring `tsh ssh`'s behaviour more in line with the OpenSSH client, I propose the following
|
|||
|
values be allowed for the `ForwardAgent`option:
|
|||
|
|
|||
|
|
|||
|
| Value | Interpretation |
|
|||
|
|----------------|----------------------------------------------------------|
|
|||
|
| `no` (default) | `tsh ssh` will not forward _any_ Key Agent |
|
|||
|
| `yes` | `tsh ssh` will forward the System Key Agent (if present) |
|
|||
|
| `local` | `tsh ssh` will forward the Teleport Key Agent |
|
|||
|
|
|||
|
|
|||
|
* The value `yes` is redefined to refer to the System Key Agent instead of
|
|||
|
the Teleport Key Agent.
|
|||
|
|
|||
|
* The value `local` is a `tsh`-specific extension that will activate the
|
|||
|
backwards-compatible behaviour.
|
|||
|
|
|||
|
The effect of this change is that the `tsh ssh` option `-A` will automatically acquire
|
|||
|
semantics in line with the OpenSSH client, while the backwards compatible behaviour can be
|
|||
|
activated with something like:
|
|||
|
|
|||
|
```bash
|
|||
|
$ tsh ssh -o "ForwardAgent local" root@example.com
|
|||
|
```
|
|||
|
|
|||
|
### Backwards compatibility breakage
|
|||
|
|
|||
|
This change introduces a backwards compatibility breakage, albeit a very small one. It _does_
|
|||
|
provide an escape hatch back to legacy behaviour, but using the legacy behaviour requires
|
|||
|
action from the user.
|
|||
|
|
|||
|
### Precedence
|
|||
|
|
|||
|
If both `-A` and `-o "ForwardAgent $VALUE"` are specified together on the same command line, `-A`
|
|||
|
will take precedence. This is consistent with the existing behaviour of `tsh ssh`, where a
|
|||
|
command line like...
|
|||
|
```bash
|
|||
|
$ tsh ssh -A -o "ForwardAgent no" root@example.com
|
|||
|
```
|
|||
|
...would result in the Key Agent being forwarded.
|
|||
|
|
|||
|
|
|||
|
### No System Key Agent
|
|||
|
|
|||
|
If no System Key Agent is running and the user specifies `-A` and/or `-o "ForwardAgent yes"`,
|
|||
|
then `tsh ssh` will NOT forward an Key Agent to the remote machine, consistent with the
|
|||
|
behaviour of OpenSSH.
|
|||
|
|
|||
|
## Out of scope
|
|||
|
|
|||
|
Adding support for indicating an arbitrary Key Agent to forward (by passing the path to a unix
|
|||
|
domain socket, or an environment variable containing the same) as per `man ssh_config(5)` is
|
|||
|
not being considered here. My only concern in that direction has been to avoid making it harder
|
|||
|
to implement later, if it's ever required.
|
|||
|
|
|||
|
## Appendices
|
|||
|
|
|||
|
### PlantUML source
|
|||
|
|
|||
|
```PlantUML
|
|||
|
@startuml
|
|||
|
|
|||
|
title "Overly Simplified Authentication Flow"
|
|||
|
|
|||
|
participant "Key Agent"
|
|||
|
participant "Local Machine"
|
|||
|
participant "Remote Machine"
|
|||
|
participant "Third Machine"
|
|||
|
|
|||
|
"Local Machine" -> "Remote Machine" : SSH Connect
|
|||
|
"Remote Machine" -> "Local Machine" : Auth challenge
|
|||
|
"Local Machine" -> "Key Agent" : Sign Challenge
|
|||
|
"Key Agent" -> "Local Machine": Signed Response
|
|||
|
"Local Machine" -> "Remote Machine" : Signed Response
|
|||
|
|
|||
|
note over "Local Machine", "Remote Machine": Authentication established
|
|||
|
|
|||
|
note over "Remote Machine": User connects to\n"Third Machine"
|
|||
|
"Remote Machine" -> "Third Machine" : SSH Connect
|
|||
|
"Third Machine" -> "Remote Machine" : Auth challenge
|
|||
|
"Remote Machine" -> "Key Agent" : Sign Challenge (via forwarded connection)
|
|||
|
"Key Agent" -> "Remote Machine": Signed Response (via forwarded connection)
|
|||
|
"Remote Machine" -> "Third Machine" : Signed Response
|
|||
|
|
|||
|
note over "Remote Machine", "Third Machine": Authentication established
|
|||
|
@enduml
|
|||
|
```
|