# Dioad Connect

Dioad Connect provides  agent and server commands that together
will setup a SNI based reverse connection.

The agent can also be used with the online service hosted at https://connect.lab.dioad.net which allows hosts to expose
services to the internet without requiring needing to configure port forwarding, and can work behind a proxy.

This is obviously a little bit dangerous, particuarly when using the `file`, `httpreverseproxy` or `tcp` tunnels as they could be used to 
expose artbitrary local data or services to the internet

For the `file` tunnel type it attempts to be secure by default by randomising the path prefix, whenever the agent
connects (if the agent disconnects, the next connection will get a different prefix). It also supports enabling basic 
authentication (recommended).

Some special features:
* The real client-ip is available in the agent logs for all connections coming from the internet.
* Support for mutual TLS and other authentication mechanisms in front of tunnel endpoints
* Support for wrapping non-TLS local services in TLS (including ACME/Let's Encrypt)
* Support for custom domains
* All client traffic is encrypted end to end, the server component cannot inspect the traffic passing through it (with 
  the exception of the SNI header that is used for routing)
* Support for Let's Encrypt/ACME for publicly 'trusted' certificates for tunnel endpoints.

> Note: when using Let's Encrypt, the certificate SANs are published to a certificate transparency log, and the endpoints will be probed.


# Quick Start

## Docker

The `dioad/connect` image comes with support for both `linux/amd64` and `linux/arm64` architectures, so can also be used directly on Raspberry Pi's

The default image runs the `hello` module which just shows a templated page that mentions the github user who authenticated.

```shell
$ VERSION=0.38.3
$ docker volume create dioad-connect-persist
$ docker run -v dioad-connect-persist:/persist dioad/connect:${VERSION} auth --headless
$ docker run -v dioad-connect-persist:/persist dioad/connect:${VERSION}
```

There is also another `file` image available which can be retrieved via the `dioad/connect:${VERSION}-file`.

```shell
$ VERSION=0.38.3
$ docker volume create dioad-connect-persist
$ docker run -v dioad-connect-persist:/persist dioad/connect:${VERSION}-file auth --headless
$ docker run -v dioad-connect-persist:/persist dioad/connect:${VERSION}-file
```

and to share a directory
```shell
$ docker run -v dioad-connect-persist:/persist -v /my/path/to/share:/data dioad/connect:${VERSION}-file
```

## Install

### MacOS
```shell
$ brew install dioad/tap/connect
```

### RHEL/CentOS
> Signing of artifacts not yet available
```shell
$ VERSION=0.38.3
$ ARCH=amd64
$ yum install -y https://releases.lab.dioad.net/data/connect/${VERSION}/dioad-connect_${VERSION}_linux_${ARCH}.rpm
```

### Debian/Ubuntu
> Signing of artifacts not yet available
```shell
$ VERSION=0.38.3
$ ARCH=amd64
$ wget https://releases.lab.dioad.net/data/connect/${VERSION}/
dioad-connect_${VERSION}_linux_${ARCH}.apk
$ dpkg -i dioad-connect_${VERSION}_linux_${ARCH}.deb
```

### Alpine
> Signing of artifacts not yet available
```shell
$ VERSION=0.33.8
$ ARCH=amd64
$ wget https://releases.lab.dioad.net/data/connect/${VERSION}/
dioad-connect_${VERSION}_linux_${ARCH}.apk
$ apk add --allow-untrusted dioad-connect_${VERSION}_linux_${ARCH}.apk
```

## Configure
`--headless` can be ignored on MacOS to open a browser automatically.

```shell
$ mkdir -p ~/.config/dioad/connect
$ cat > ~/.config/dioad/connect/config.yaml <<EOF
credentials:
  github:
    access-token-file: ~/.config/dioad/connect/auth.yaml

traffic:
  tunnels:
    - type: hello
      name: hello
      endpoint: https://connect.lab.dioad.net/connect
      tls-server-config:
        auto-cert-config:
          cache-directory: .autocert
      config:
        custom-message: "Hello from {{ .TunnelPrincipal }}"
EOF
$ connect agent auth --headless
```

## Run
```shell
$ connect agent
```

## Test
```shell
$ curl https://hello.${GITHUB_USER}.traffic.lab.dioad.net
```


# Configuration

## Agent Configuration

`agent.yaml`

```yaml
tls-client-config:
  root-ca-file: .local-dev/TestServerCertificateCA.pem
  cert: .local-dev/TestClientCertificate.pem
  key: .local-dev/TestClientCertificate.key
```

## Examples

### Generate basic auth creds

Enter password with on command line

```shell
htpasswd -bnB -C 10 <username> <password>
```

Enter password with verification on command line

```shell
htpasswd -nB -C 10 <username>
```

Create htpasswd file

```shell
htpasswd -B -C 10 <passwordfile> <user>
```

### Agent Authentication

#### HMAC Shared Token

#### Github

`agent.yaml`

##### External Credentials
```yaml
auth:
  github:
    access-token-file: ~/.config/dioad/connect/auth.yaml
```

###### File format
Alternatively use the `connect agent auth` command.

```yaml
token: e82b1ebeafe7ce6ca2661183c0624333f5cd7bd5
type: bearer
```

#### HTTP Basic Auth

### Tunnel Types
#### Echo service

Example service that will echo HTTP requests back to the client.

`agent.yaml`

```yaml
traffic:
  tunnels:
  - type: echo
    name: echo
    endpoint: https://connect.lab.dioad.net/connect
    tls-server-config:
      auto-cert-config:
        cache-directory: /path/to/.autocert
        email: someone@example.com
    config:
      enable-prometheus-metrics: true
      debug: true
```

#### Hello Service
Example service to show connectivity

`agent.yaml`

```yaml
traffic:
  tunnels:
  - type: hello
    name: hello
    endpoint: https://connect.lab.dioad.net/connect
    tls-server-config:
      auto-cert-config:
        cache-directory: /path/to/.autocert
        email: someone@example.com
    config:
      custom-message: "your message here"
```

#### File Service

Can be used to share files from the local machine with the world wide web.

Tries to be 'secure' by default, using a random path prefix, this can be
disabled if desired

`agent.yaml`

```yaml
traffic:
  tunnels:
  - type: file
    name: file
    endpoint: https://connect.lab.dioad.net/connect
    tls-server-config:
      auto-cert-config:
        cache-directory: /path/to/.autocert
        email: someone@example.com
    config:
      enable-dynamic-prefix: true
      enable-prometheus-metrics: true
      debug: true
      root-directory: .
      prefix: /something-custom
      disable-dynamic-prefix: false
      authentication:
        basic:
          file: /path/to/htpasswd
```

#### HTTP Reverse Proxy Service
`agent.yaml`

```yaml
traffic:
  tunnels:
    - name: nginx
      type: httpreverseproxy
      tls-server-config:
        cert: /path/to/TestServerCertificate.pem
        key: /path/to/TestServerCertificate.key
      config:
        target-url: http://127.0.0.1:8080
```


#### TCP Service
`agent.yaml`

Note: For HTTP backends please use the HTTP Reverse Proxy service.

`agent.yaml`
```yaml
traffic:
  tunnels:
  - name: ssh
    type: tcp
    tls-server-config:
      cert: /path/to/TestServerCertificate.pem
      key: /path/to/TestServerCertificate.key
    config:
      target-address: 127.0.0.1:22
```


## Server Configuration

### Example
```yaml
log-level: trace

control-listen-address: 0.0.0.0:8119
traffic-listen-address: 0.0.0.0:8443

management:
  listen-address: 0.0.0.0:5555
  enable-prometheus-metrics: true
  enable-debug: true

default-agent-domain: local.lab.dioad.net

tls-server-config:
  cert: .local-dev/TestServerCertificate.pem
  key: .local-dev/TestServerCertificate.key
  client-ca-file: .local-dev/TestClientCertificateCA.pem

auth:
  github:
    client-id: abcdefghijk1234567890
    client-secret: aabbccddeeffgghhiijjkkllmmnnooppqqrrsstt

# agent-event-callback-url: https://127.0.0.1:8120


```

### Auth Support
Uses configuration definitions from `github.com/dioad/net/auth`

Provides support for authenticating agents

#### No Auth
If no `auth` block is present in the `server.yaml` file no authentication is required.

#### Basic Auth

##### Inline Specification
`server.yaml`

```yaml
auth:
  basic:
    users:
      - dummy:$2y$10$Xi5ZxfWOyXpCanRc/20Nzuc2jivfTd82dif/RliZ9WOPKyQPJRSbu
```

##### External Specification
You can specify external users using a `htpasswd` file.

This file can be managed using the `htpasswd` command that usually ships with https://httpd.apache.org and MacOS

`server.yaml`

```yaml
auth:
  basic:
    htpasswd-file: .local-dev/htpasswd
```
#### HMAC Auth
`server.yaml`

##### Inline Specification
`server.yaml`
```yaml
auth:
  hmac:
    shared-key: "f91457f8-deadBeaf-11ea-8d00-93f9cfa8cc35"
    http-header: "X-Agent-ID"
```

##### External Specification
Requires implementation 
```yaml
auth:
  hmac:
    shared-key-path: "/etc/dioad/connect/auth.yaml"
    http-header: "X-Agent-ID"
```
### Other
```yaml
auth:
  hmac:
    allow-insecure-http: true
```
`allow-insecure-http` is a setting to enable if the auth procedure should still proceed even if the request is not using
TLS. 

The intention for this is to be used in the case that TLS is either being terminated by an NLB or other ingress router 
and not directly by the server service.

#### GitHub Auth
`server.yaml`

Authenticates agent using github device authentication.

##### Inline Specification
```yaml
auth:
  github:
    client-id: "abcdefghijk1234567890"
    client-secret: "aabbccddeeffgghhiijjkkllmmnnooppqqrrsstt"
```

##### External Specification
```yaml
auth:
  github:
    config-file: /etc/dioad/connect/auth.yaml
```

##### User Access Control Lists
###### User Allow List
To only allow named Github users to authenticate
`server.yaml`

```yaml
auth:
  github:
    ...
    user-allow-list:
      - joeblogs
      - johndoe
```

###### User Deny List
To allow everyone except the named Github accounts

`server.yaml`

```yaml
auth:
  github:
    ...
    user-deny-list:
      - joeblogs
      - johndoe
```

### TLS Support
Uses configuration definitions from `github.com/dioad/net/tls`

Provides support for TLS for HTTP connections to the server.
#### Certificates on Disk

`server.yaml`

```yaml
tls-server-config:
  cert: .local-dev/TestServerCertificate.pem
  key: .local-dev/TestServerCertificate.key
  client-ca-file: .local-dev/TestClientCertificateCA.pem
```

#### ACME/Let's Encrypt Support

`server.yaml`

For github based authentication the `email` property will be set
automatically to the primary email address associated with the
github account and can be left out.


```yaml
tls-server-config:
  auto-cert-config:
    cache-directory: /etc/dioad/autocert
    email: someone@example.com
```


### Network ACLs
All types of tunnel can specify a separate ACL.

```yaml
traffic:
  tunnels:
   - name: nacl
     type: tcp
     ...
     network-acl:
       allow:
         - 192.168.0.0/16
         - 127.0.0.1
       deny:
         - 8.8.0.0/16
       allow-by-default: true # defaults to false
     
```



## Cookbook
### SSH through reverse tunnel

If you have a reverse tunnel set up to forward to ssh, you can use `socat` or `stunnel` to route ssh connections over 
the tunnel. You can also use mutual TLS to secure these connections to the agent before sending SSH traffic over the
tunnel.

This doesn't currently work with ACME let's encrypt certificates as mentioned above, without a bit of a hack - which is 
to use either `echo` or `hello` type of tunnel to fetch the certificate to the cache directory first, and then changing 
it back to `type: tcp`.

`agent.yaml`

```yaml
traffic:
  tunnels:
  - name: ssh
    type: tcp
    tls-server-config:
      cert: /path/to/TestServerCertificate.pem
      key: /path/to/TestServerCertificate.key
    config:
      target-address: 127.0.0.1:22
```

`~/.ssh/config`

```
Host ssh.tradition-unwanted.local.lab.dioad.net
  ProxyCommand socat - OPENSSL:ssh.%h:9443,verify=0
```
