mirror of
https://github.com/zrepl/zrepl.git
synced 2024-12-22 23:20:51 +01:00
docs: transport: document ssh+stdinserver
This commit is contained in:
parent
3f394a8960
commit
b4d8c93fae
@ -3,22 +3,91 @@ title = "Transports"
|
||||
weight = 30
|
||||
+++
|
||||
|
||||
{{% alert theme="warning" %}}Under Construction{{% /alert %}}
|
||||
A transport provides an authenticated [`io.ReadWriteCloser`](https://golang.org/pkg/io/#ReadWriteCloser) to the RPC layer.
|
||||
(An `io.ReadWriteCloser` is essentially a bidirectional reliable communication channel.)
|
||||
|
||||
## Stdinserver
|
||||
Currently, only the `ssh+stdinserver` transport is supported.
|
||||
|
||||
## `ssh+stdinserver`
|
||||
|
||||
The SSH transport connects to the remote server using the SSH binary in
|
||||
`$PATH` and the parameters specified in the `zrepl` config file.
|
||||
The way the `ssh+stdinserver` transport works is inspired by [git shell](https://git-scm.com/docs/git-shell) and [Borg Backup](https://borgbackup.readthedocs.io/en/stable/deployment.html).
|
||||
It is implemented in the Go package `github.com/zrepl/zrepl/sshbytestream`.
|
||||
The config excerpts are taken from the [tutorial]({{< relref "tutorial/_index.md" >}}) which you should complete before reading further.
|
||||
|
||||
However, instead of a traditional interactive SSH session, `zrepl` expects
|
||||
another instance of `zrepl` on the other side of the connection; You may be
|
||||
familiar with this concept from [git shell](https://git-scm.com/docs/git-shell)
|
||||
or [Borg Backup](https://borgbackup.readthedocs.io/en/stable/deployment.html).
|
||||
### `serve`
|
||||
|
||||
Check the examples for instructions on how to set this up on your machines!
|
||||
```yaml
|
||||
jobs:
|
||||
- name: pull_backup
|
||||
type: source
|
||||
serve:
|
||||
type: stdinserver
|
||||
client_identity: backup-srv.example.com
|
||||
...
|
||||
```
|
||||
|
||||
{{% panel %}}
|
||||
The environment variables of the underlying SSH process are cleared. `$SSH_AUTH_SOCK` will not be available. We suggest creating a separate, unencrypted SSH key.
|
||||
{{% / panel %}}
|
||||
The serving job opens a UNIX socket named after `client_identity` in the runtime directory, e.g. `/var/run/zrepl/stdinserver/backup-srv.example.com`.
|
||||
|
||||
On the same machine, the `zrepl stdinserver $client_identity` command connects to that socket.
|
||||
For example, `zrepl stdinserver backup-srv.example.com` connects to the UNIX socket `/var/run/zrepl/stdinserver/backup-srv.example.com`.
|
||||
|
||||
It then passes its stdin and stdout file descriptors to the zrepl daemon via *cmsg(3)*.
|
||||
zrepl daemon in turn combines them into an `io.ReadWriteCloser`:
|
||||
a `Write()` turns into a write to stdout, a `Read()` turns into a read from stdin.
|
||||
|
||||
Interactive use of the `stdinserver` subcommand does not make much sense.
|
||||
However, we can force its execution when a user with a particular SSH pubkey connects via SSH.
|
||||
This can be achieved with an entry in the `authorized_keys` file of the serving zrepl daemon.
|
||||
|
||||
```
|
||||
# for OpenSSH >= 7.2
|
||||
command="zrepl stdinserver CLIENT_IDENTITY",restrict CLIENT_SSH_KEY
|
||||
# for older OpenSSH versions
|
||||
command="zrepl stdinserver CLIENT_IDENTITY",no-port-forwarding,no-X11-forwarding,no-pty,no-agent-forwarding,no-user-rc CLIENT_SSH_KEY
|
||||
```
|
||||
|
||||
* CLIENT_IDENTITY is substituted with `backup-srv.example.com`
|
||||
* CLIENT_SSH_KEY is substituted with the public part of the SSH keypair specified in the `connect` directive on the connecting host.
|
||||
|
||||
To recap, this is of how client authentication works with the `ssh+stdinserver` transport:
|
||||
|
||||
* Connections to the `client_identity` UNIX socket are blindly trusted by zrepl daemon.
|
||||
* Thus, the runtime directory must be private to the zrepl user (checked by zrepl daemon)
|
||||
* The admin of the host with the serving zrepl daemon controls the `authorized_keys` file.
|
||||
* Thus, the administrator controls the mapping `PUBKEY -> CLIENT_IDENTITY`.
|
||||
|
||||
### `connect`
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
- name: pull_app-srv
|
||||
type: pull
|
||||
connect:
|
||||
type: ssh+stdinserver
|
||||
host: app-srv.example.com
|
||||
user: root
|
||||
port: 22
|
||||
identity_file: /etc/zrepl/ssh/identity
|
||||
options: # optional
|
||||
- "Compression=on"
|
||||
```
|
||||
|
||||
The connecting zrepl daemon
|
||||
|
||||
1. Creates a pipe
|
||||
1. Forks
|
||||
1. In the forked process
|
||||
1. Replaces forked stdin and stdout with the corresponding pipe ends
|
||||
1. Executes the `ssh` binary found in `$PATH`.
|
||||
1. The identity file (`-i`) is set to `$identity_file`.
|
||||
1. The remote user, host and port correspond to those configured.
|
||||
1. Further options can be specified using the `options` field, which appends each entry in the list to the command line using `-o $entry`.
|
||||
1. Wraps the pipe ends in an `io.ReadWriteCloser` and uses it for RPC.
|
||||
|
||||
As discussed in the section above, the connecting zrepl daemon expects that `zrepl stdinserver $client_identity` is executed automatically via an `authorized_keys` file entry.
|
||||
|
||||
{{% notice info %}}
|
||||
The environment variables of the underlying SSH process are cleared. `$SSH_AUTH_SOCK` will not be available.<br />
|
||||
It is suggested to create a separate, unencrypted SSH key solely for that purpose.
|
||||
{{% / notice %}}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user