mirror of
https://github.com/gravitational/teleport
synced 2024-10-22 02:03:24 +00:00
Merge branch 'sasha/corruption' into sasha/rbac
This commit is contained in:
commit
41a4d2872c
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -19,6 +19,7 @@ build
|
|||
# Folders
|
||||
_obj
|
||||
_test
|
||||
tmp
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
|
|
2
Makefile
2
Makefile
|
@ -2,7 +2,7 @@
|
|||
# Naming convention:
|
||||
# for stable releases we use "1.0.0" format
|
||||
# for pre-releases, we use "1.0.0-beta.2" format
|
||||
VERSION=1.2.6
|
||||
VERSION=1.3.0
|
||||
|
||||
# These are standard autotools variables, don't change them please
|
||||
BUILDDIR ?= build
|
||||
|
|
90
build.assets/Dockerfile.dynamodb
Normal file
90
build.assets/Dockerfile.dynamodb
Normal file
|
@ -0,0 +1,90 @@
|
|||
# This Dockerfile makes the "build box": the container used to build
|
||||
# official releases of Teleport and its documentation
|
||||
FROM debian:jessie
|
||||
|
||||
ARG UID
|
||||
ARG GID
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
ADD build.assets/locale.gen /etc/locale.gen
|
||||
ADD build.assets/profile /etc/profile
|
||||
|
||||
RUN (apt-get clean \
|
||||
&& apt-key update \
|
||||
&& apt-get -q -y update --fix-missing \
|
||||
&& apt-get -q -y update \
|
||||
&& apt-get install -q -y apt-utils \
|
||||
&& apt-get install -q -y less \
|
||||
&& apt-get install -q -y locales) ;
|
||||
|
||||
# Set locale to en_US.UTF-8
|
||||
RUN (locale-gen \
|
||||
&& locale-gen en_US.UTF-8 \
|
||||
&& dpkg-reconfigure locales)
|
||||
|
||||
RUN apt-get -y update && apt-get -y upgrade
|
||||
RUN apt-get install -q -y \
|
||||
libsqlite3-0 \
|
||||
curl \
|
||||
make \
|
||||
git \
|
||||
libc6-dev \
|
||||
gcc \
|
||||
tar \
|
||||
gzip \
|
||||
python \
|
||||
python-pip \
|
||||
libyaml-dev \
|
||||
python-dev \
|
||||
zip
|
||||
RUN (pip install click==4.1 recommonmark mkdocs markdown-include ;\
|
||||
apt-get -y autoclean; apt-get -y clean)
|
||||
|
||||
# Install Golang:
|
||||
RUN (mkdir -p /opt && cd /opt && curl https://storage.googleapis.com/golang/go1.7.linux-amd64.tar.gz | tar xz;\
|
||||
mkdir -p /gopath/src/github.com/gravitational/teleport;\
|
||||
chmod a+w /gopath;\
|
||||
chmod a+w /var/lib)
|
||||
|
||||
ENV LANGUAGE="en_US.UTF-8" \
|
||||
LANG="en_US.UTF-8" \
|
||||
LC_ALL="en_US.UTF-8" \
|
||||
LC_CTYPE="en_US.UTF-8" \
|
||||
GOPATH="/gopath" \
|
||||
GOROOT="/opt/go" \
|
||||
PATH="$PATH:/opt/go/bin:/gopath/bin"
|
||||
|
||||
RUN go get -u github.com/aws/aws-sdk-go
|
||||
|
||||
RUN pip install awscli
|
||||
|
||||
RUN curl -sL https://deb.nodesource.com/setup_6.x |bash -
|
||||
|
||||
RUN apt-get install -y nodejs
|
||||
|
||||
ADD . /gopath/src/github.com/gravitational/teleport
|
||||
|
||||
WORKDIR /gopath/src/github.com/gravitational/teleport/web
|
||||
|
||||
RUN npm install
|
||||
|
||||
RUN npm run build
|
||||
|
||||
RUN mkdir -p /gopath/src/github.com/gravitational/teleport/build
|
||||
|
||||
RUN cd dist && zip -qr /gopath/src/github.com/gravitational/teleport/build/webassets.zip .
|
||||
|
||||
WORKDIR /gopath/src/github.com/gravitational/teleport
|
||||
|
||||
RUN go build -o build/teleport -i -tags dynamodb -ldflags '-w -s -extldflags "-static"' ./tool/teleport
|
||||
RUN go build -o build/tctl -i -tags dynamodb -ldflags '-w -s -extldflags "-static"' ./tool/tctl
|
||||
RUN go build -o build/tsh -i -tags dynamodb -ldflags '-w -s -extldflags "-static"' ./tool/tsh
|
||||
|
||||
RUN cat build/webassets.zip >> build/teleport
|
||||
|
||||
RUN zip -q -A build/teleport
|
||||
|
||||
RUN cd build && tar -czvf ../teleport.tgz teleport tctl tsh
|
||||
|
||||
CMD [ "/gopath/src/github.com/gravitational/teleport/build.assets/publisher.sh" ]
|
|
@ -9,3 +9,20 @@ It is a part of Gravitational CI/CD pipeline. To build Teleport type:
|
|||
make
|
||||
```
|
||||
|
||||
### DynamoDB static binary docker build
|
||||
|
||||
The static binary will be built along with all nodejs assets inside the container.
|
||||
From the root directory of the source checkout run:
|
||||
```
|
||||
docker build -f build.assets/Dockerfile.dynamodb -t teleportbuilder .
|
||||
```
|
||||
|
||||
Then you can upload the result to an S3 bucket for release.
|
||||
```
|
||||
docker run -it -e AWS_ACL=public-read -e S3_BUCKET=my-teleport-releases -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY teleportbuilder
|
||||
```
|
||||
|
||||
Or simply copy the binary out of the image using a volume (it will be copied to current directory/build/teleport.
|
||||
```
|
||||
docker run -v $(pwd)/build:/builds -it teleportbuilder cp /gopath/src/github.com/gravitational/teleport/teleport.tgz /builds
|
||||
```
|
||||
|
|
12
build.assets/publisher.sh
Executable file
12
build.assets/publisher.sh
Executable file
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
# required to set AWS_ACL eg. public-read
|
||||
# required to set S3_BUCKET eg. my-bucket
|
||||
|
||||
GIT_REV=$(git rev-parse --verify HEAD)
|
||||
BINARY_NAME=teleport-${GIT_REV}.tgz
|
||||
CHECKSUM_NAME=checksums-${GIT_REV}.txt
|
||||
|
||||
sha512sum teleport.tgz > $CHECKSUM_NAME
|
||||
aws s3 cp --acl $AWS_ACL teleport.tgz s3://$S3_BUCKET/$BINARY_NAME
|
||||
aws s3 cp --acl $AWS_ACL $CHECKSUM_NAME s3://$S3_BUCKET/$CHECKSUM_NAME
|
|
@ -1,23 +1,21 @@
|
|||
# This file is distributed with every binary Teleport tarball
|
||||
BINDIR=/usr/local/bin
|
||||
VARDIR=/var/lib/teleport
|
||||
WEBDIR=/usr/local/share/teleport
|
||||
|
||||
#
|
||||
# sudo make install: installs Teleport into a UNIX-like OS
|
||||
#
|
||||
.PHONY: install
|
||||
install: sudo
|
||||
mkdir -p $(VARDIR) $(WEBDIR) $(BINDIR)
|
||||
mkdir -p $(VARDIR) $(BINDIR)
|
||||
cp -f teleport tctl tsh $(BINDIR)/
|
||||
cp -fr app index.html $(WEBDIR)/
|
||||
|
||||
#
|
||||
# sudo make uninstall: removes Teleport
|
||||
#
|
||||
.PHONY: uninstall
|
||||
uninstall: sudo
|
||||
rm -rf $(VARDIR) $(WEBDIR) $(BINDIR)/tctl $(BINDIR)/teleport $(BINDIR)/tsh
|
||||
rm -rf $(VARDIR) $(BINDIR)/tctl $(BINDIR)/teleport $(BINDIR)/tsh
|
||||
|
||||
|
||||
# helper: makes sure it runs as root
|
||||
|
|
|
@ -194,7 +194,9 @@ teleport:
|
|||
|
||||
# This section configures the 'auth service':
|
||||
auth_service:
|
||||
# Turns 'auth' role on. Default is 'yes'
|
||||
enabled: yes
|
||||
|
||||
# IP and the port to bind to. Other Teleport nodes will be connecting to
|
||||
# this port (AKA "Auth API" or "Cluster API") to validate client
|
||||
# certificates
|
||||
|
@ -234,7 +236,9 @@ auth_service:
|
|||
|
||||
# This section configures the 'node service':
|
||||
ssh_service:
|
||||
# Turns 'ssh' role on. Default is 'yes'
|
||||
enabled: yes
|
||||
|
||||
# IP and the port for SSH service to bind to.
|
||||
listen_addr: 0.0.0.0:3022
|
||||
# See explanation of labels in "Labeling Nodes" section below
|
||||
|
@ -254,7 +258,9 @@ ssh_service:
|
|||
|
||||
# This section configures the 'proxy servie'
|
||||
proxy_service:
|
||||
# Turns 'proxy' role on. Default is 'yes'
|
||||
enabled: yes
|
||||
|
||||
# SSH forwarding/proxy address. Command line (CLI) clients always begin their
|
||||
# SSH sessions by connecting to this port
|
||||
listen_addr: 0.0.0.0:3023
|
||||
|
@ -766,64 +772,78 @@ your Google credentials. Teleport will keep you logged in for the next 23 hours.
|
|||
|
||||
## FIDO U2F
|
||||
|
||||
Teleport supports [FIDO U2F](https://www.yubico.com/about/background/fido/) hardware keys as a second authentication factor.
|
||||
Teleport supports [FIDO U2F](https://www.yubico.com/about/background/fido/)
|
||||
hardware keys as a second authentication factor.
|
||||
|
||||
### Enabling/Disabling U2F
|
||||
To start using U2F:
|
||||
|
||||
U2F is enabled in the demo configuration.
|
||||
To enable U2F, add the following to the auth service configuration.
|
||||
* Purchase a U2F hardware key: looks like a tiny USB drive.
|
||||
* Enable U2F in Teleport configuration.
|
||||
* Use `--u2f` CLI flag when connecting via `tsh ssh`.
|
||||
|
||||
````
|
||||
Lets look into each of these steps in detail.
|
||||
|
||||
### Getting U2F Keys
|
||||
|
||||
Visit [this page](https://www.yubico.com/about/background/fido/) to order
|
||||
a physical U2F keys for Teleport users in your organization.
|
||||
|
||||
### Enabling U2F
|
||||
|
||||
By default U2F is disabled. To enable U2F, add the following to the auth
|
||||
service configuration in `teleport.yaml`:
|
||||
|
||||
```bash
|
||||
auth_service:
|
||||
u2f:
|
||||
# Must be set to 'yes' to enable and 'no' to disable:
|
||||
enabled: yes
|
||||
|
||||
# Only matters when multiple proxy servers are used:
|
||||
app_id: https://mycorp.com/appid.js
|
||||
|
||||
# U2F facets must be set to Teleport proxy servers:
|
||||
facets:
|
||||
- https://proxy1.mycorp.com:3080
|
||||
- https://proxy2.mycorp.com:3080
|
||||
````
|
||||
|
||||
In single-server setups, `app_id` and `facets` can be omitted.
|
||||
|
||||
To disable U2F, set `enabled` to `no`.
|
||||
|
||||
`app_id` should be the App ID of your cluster. `app_id` defaults to the auth server's hostname if not set.
|
||||
|
||||
`facets` should include proxies (if any).
|
||||
If a proxy is on a port that is not standard for HTTPS (i.e. 3080), then the port must be specified in the facets list.
|
||||
`facets` defaults to having `app_id` as the only entry if not set.
|
||||
|
||||
### Using U2F
|
||||
|
||||
Once U2F is enabled, users can select U2F as their second factor during registration and log in with their U2F keys.
|
||||
|
||||
#### Web UI
|
||||
|
||||
On the signup page, a set of radio buttons should appear that allow the user to select Google Authenticator or U2F as their second factor.
|
||||
On the login page, a "Login with U2F" button should appear below the "Login" button.
|
||||
Leave the two factor token field blank when logging in with U2F.
|
||||
|
||||
#### CLI
|
||||
|
||||
You have to tell `tsh` to authenticate using U2F with the `--u2f` switch:
|
||||
|
||||
```
|
||||
tsh --proxy <proxy-addr> ssh --u2f
|
||||
```
|
||||
NOTE: You will need the [`u2f-host`](https://developers.yubico.com/libu2f-host/) binary in order to use U2F with the CLI.
|
||||
|
||||
#### Additional considerations
|
||||
If your Teleport is deployed with the same `teleport` process running as a proxy
|
||||
and as an auth server, you can omit `app_id` and `facets` settings.
|
||||
|
||||
The App ID identifies the web application to the U2F keys and should not change in the lifetime of the cluster.
|
||||
If the App ID changes, all existing U2F key registrations will become invalid and all users who use U2F as the second factor will need to re-register.
|
||||
`app_id` should be the U2F App ID of your cluster.
|
||||
`app_id` defaults to the auth server's hostname if not set.
|
||||
|
||||
For single-proxy setups, the App ID can be equal to the domain name of the proxy, but this will prevent you from adding more proxies without changing the App ID.
|
||||
For multi-proxy setups, the App ID should be an HTTPS URL pointing to a JSON file that mirrors `facets` in the auth config.
|
||||
If your Teleport deployment includes multiple Teleport proxy servers, you
|
||||
must list them all in the `facets` section. If the TCP port of a facet/proxy
|
||||
is not specified, the default Teleport proxy port (3080) will be used.
|
||||
|
||||
For single-proxy setups, the App ID can be equal to the domain name of the
|
||||
proxy, but this will prevent you from adding more proxies without changing the
|
||||
App ID. For multi-proxy setups, the App ID should be an HTTPS URL pointing to
|
||||
a JSON file that mirrors `facets` in the auth config.
|
||||
|
||||
The JSON file should be hosted on a domain you control and it should be accessible anonymously.
|
||||
See the [official U2F specification](https://fidoalliance.org/specs/fido-u2f-v1.0-ps-20141009/fido-appid-and-facets-ps-20141009.html#processing-rules-for-appid-and-facetid-assertions)
|
||||
for the exact format of the JSON file.
|
||||
|
||||
!!! warning "Warning":
|
||||
The App ID must never change in the lifetime of the cluster. If the App ID
|
||||
changes, all existing U2F key registrations will become invalid and all users
|
||||
who use U2F as the second factor will need to re-register.
|
||||
|
||||
When adding a new proxy server, make sure to add it to the list of "facets"
|
||||
in the configuration file, but also to the JSON file referenced by `app_id`
|
||||
|
||||
### Logging in with U2F
|
||||
|
||||
For logging in via the CLI, you must first install [`u2f-host`](https://developers.yubico.com/libu2f-host/)
|
||||
Then invoke `tsh ssh` to authenticate using U2F with the `--u2f` switch:
|
||||
|
||||
```
|
||||
tsh --proxy <proxy-addr> ssh --u2f <hostname>
|
||||
```
|
||||
|
||||
## High Availability and Clustering
|
||||
|
||||
Teleport can use [etcd](https://coreos.com/etcd/) as a storage backend to
|
||||
|
|
2
docs/theme/css/teleport.css
vendored
2
docs/theme/css/teleport.css
vendored
|
@ -293,7 +293,7 @@ a:visited{
|
|||
div.wy-nav-content { max-width: 1000px; }
|
||||
.rst-content table.docutils td { overflow: hidden; white-space: normal }
|
||||
|
||||
h3 { margin: 0 auto 0 auto; width: 100% }
|
||||
h3 { margin: 0 0; color: #3d73ba; width: 100% }
|
||||
|
||||
.wy-menu-vertical li ul li a { font-size: 90% }
|
||||
.wy-nav-content { padding-left: 20px; padding-top: 10px; padding-right: 20px; }
|
||||
|
|
|
@ -434,6 +434,7 @@ func (tc *TeleportClient) SSH(command []string, runLocally bool) error {
|
|||
tc.Config.HostLogin,
|
||||
false)
|
||||
if err != nil {
|
||||
tc.ExitStatus = 1
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
// proxy local ports (forward incoming connections to remote host ports)
|
||||
|
@ -764,7 +765,9 @@ func (tc *TeleportClient) ListNodes() ([]services.Server, error) {
|
|||
}
|
||||
|
||||
// runCommand executes a given bash command on a bunch of remote nodes
|
||||
func (tc *TeleportClient) runCommand(siteName string, nodeAddresses []string, proxyClient *ProxyClient, command []string) error {
|
||||
func (tc *TeleportClient) runCommand(
|
||||
siteName string, nodeAddresses []string, proxyClient *ProxyClient, command []string) error {
|
||||
|
||||
resultsC := make(chan error, len(nodeAddresses))
|
||||
for _, address := range nodeAddresses {
|
||||
go func(address string) {
|
||||
|
@ -793,9 +796,17 @@ func (tc *TeleportClient) runCommand(siteName string, nodeAddresses []string, pr
|
|||
return
|
||||
}
|
||||
if err = nodeSession.runCommand(command, tc.OnShellCreated, tc.Config.Interactive); err != nil {
|
||||
exitErr, ok := err.(*ssh.ExitError)
|
||||
originErr := trace.Unwrap(err)
|
||||
exitErr, ok := originErr.(*ssh.ExitError)
|
||||
if ok {
|
||||
tc.ExitStatus = exitErr.ExitStatus()
|
||||
} else {
|
||||
// if an error occurs, but no exit status is passed back, GoSSH returns
|
||||
// a generic error like this. in this case the error message is printed
|
||||
// to stderr by the remote process so we have to quietly return 1:
|
||||
if strings.Contains(originErr.Error(), "exited without exit status") {
|
||||
tc.ExitStatus = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}(address)
|
||||
|
|
|
@ -72,6 +72,11 @@ func FullProfilePath(pDir string) string {
|
|||
|
||||
}
|
||||
|
||||
// If there's a current profile symlink, remove it
|
||||
func UnlinkCurrentProfile() error {
|
||||
return trace.Wrap(os.Remove(path.Join(FullProfilePath(""), CurrentProfileSymlink)))
|
||||
}
|
||||
|
||||
// ProfileFromDir reads the user profile from a given directory. It works
|
||||
// by looking for a "profile" symlink in that directory pointing to the
|
||||
// profile's YAML file.
|
||||
|
|
|
@ -179,7 +179,9 @@ func ApplyFileConfig(fc *FileConfig, cfg *service.Config) error {
|
|||
a := &cfg.Auth
|
||||
a.KeysBackend.Type = dynamo.BackendType
|
||||
a.KeysBackend.Params, err = dynamo.ConfigureBackend(&fc.Storage)
|
||||
return trace.Wrap(err)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
case "":
|
||||
break // not set
|
||||
default:
|
||||
|
|
|
@ -195,9 +195,21 @@ func (a *Agent) proxyAccessPoint(ch ssh.Channel, req <-chan *ssh.Request) {
|
|||
wg.Wait()
|
||||
}
|
||||
|
||||
// proxyTransport runs as a goroutine running inside a reverse tunnel client
|
||||
// and it establishes and maintains the following remote connection:
|
||||
//
|
||||
// tsh -> proxy(also reverse-tunnel-server) -> reverse-tunnel-agent
|
||||
//
|
||||
// ch : SSH channel which received "teleport-transport" out-of-band request
|
||||
// reqC : request payload
|
||||
func (a *Agent) proxyTransport(ch ssh.Channel, reqC <-chan *ssh.Request) {
|
||||
defer ch.Close()
|
||||
|
||||
// always push space into stderr to make sure the caller can always
|
||||
// safely call read(stderr) without blocking. this stderr is only used
|
||||
// to request proxying of TCP/IP via reverse tunnel.
|
||||
fmt.Fprint(ch.Stderr(), " ")
|
||||
|
||||
var req *ssh.Request
|
||||
select {
|
||||
case <-a.broadcastClose.C:
|
||||
|
@ -218,7 +230,12 @@ func (a *Agent) proxyTransport(ch ssh.Channel, reqC <-chan *ssh.Request) {
|
|||
|
||||
conn, err := net.Dial("tcp", server)
|
||||
if err != nil {
|
||||
log.Errorf("failed to dial: %v, err: %v", server, err)
|
||||
log.Error(trace.DebugReport(err))
|
||||
// write the connection error to stderr of the caller (via SSH channel)
|
||||
// so the error will be propagated all the way back to the
|
||||
// client (most likely tsh)
|
||||
fmt.Fprint(ch.Stderr(), err.Error())
|
||||
req.Reply(false, []byte(err.Error()))
|
||||
return
|
||||
}
|
||||
req.Reply(true, []byte("connected"))
|
||||
|
|
|
@ -18,6 +18,7 @@ package reversetunnel
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
@ -514,6 +515,12 @@ func (s *tunnelSite) String() string {
|
|||
return fmt.Sprintf("remoteSite(%v)", s.domainName)
|
||||
}
|
||||
|
||||
func (s *tunnelSite) connectionCount() int {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
return len(s.connections)
|
||||
}
|
||||
|
||||
func (s *tunnelSite) nextConn() (*remoteConn, error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
@ -668,8 +675,9 @@ func (s *tunnelSite) dialAccessPoint(network, addr string) (net.Conn, error) {
|
|||
// Dial is used to connect a requesting client (say, tsh) to an SSH server
|
||||
// located in a remote connected site, the connection goes through the
|
||||
// reverse proxy tunnel.
|
||||
func (s *tunnelSite) Dial(network string, addr string) (net.Conn, error) {
|
||||
func (s *tunnelSite) Dial(network string, addr string) (conn net.Conn, err error) {
|
||||
s.log.Infof("[TUNNEL] dialing %v@%v through the tunnel", addr, s.domainName)
|
||||
stop := false
|
||||
|
||||
try := func() (net.Conn, error) {
|
||||
remoteConn, err := s.nextConn()
|
||||
|
@ -682,34 +690,44 @@ func (s *tunnelSite) Dial(network string, addr string) (net.Conn, error) {
|
|||
remoteConn.markInvalid(err)
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
// we're creating a new SSH connection inside reverse SSH connection
|
||||
// as a new SSH channel:
|
||||
stop = true
|
||||
// send a special SSH out-of-band request called "teleport-transport"
|
||||
// the agent on the other side will create a new TCP/IP connection to
|
||||
// 'addr' on its network and will start proxying that connection over
|
||||
// this SSH channel:
|
||||
var dialed bool
|
||||
dialed, err = ch.SendRequest(chanTransportDialReq, true, []byte(addr))
|
||||
if err != nil {
|
||||
remoteConn.markInvalid(err)
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
if !dialed {
|
||||
remoteConn.markInvalid(err)
|
||||
return nil, trace.ConnectionProblem(
|
||||
nil, "remote server %v is not available", addr)
|
||||
defer ch.Close()
|
||||
// pull the error message from the tunnel client (remote cluster)
|
||||
// passed to us via stderr:
|
||||
errMessage, _ := ioutil.ReadAll(ch.Stderr())
|
||||
if errMessage == nil {
|
||||
errMessage = []byte("failed connecting to " + addr)
|
||||
}
|
||||
return nil, trace.Errorf(strings.TrimSpace(string(errMessage)))
|
||||
}
|
||||
return utils.NewChConn(remoteConn.sshConn, ch), nil
|
||||
}
|
||||
|
||||
for {
|
||||
conn, err := try()
|
||||
if err != nil {
|
||||
s.log.Errorf("[TUNNEL] Dial(addr=%v) failed: %v", addr, err)
|
||||
// we interpret it as a "out of connections and will try again"
|
||||
if trace.IsNotFound(err) {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
continue
|
||||
// loop through existing TCP/IP connections (reverse tunnels) and try
|
||||
// to establish an inbound connection-over-ssh-channel to the remote
|
||||
// cluster (AKA "remotetunnel agent"):
|
||||
for i := 0; i < s.connectionCount() && !stop; i++ {
|
||||
conn, err = try()
|
||||
if err == nil {
|
||||
return conn, nil
|
||||
}
|
||||
return conn, nil
|
||||
s.log.Errorf("[TUNNEL] Dial(addr=%v) failed: %v", addr, err)
|
||||
}
|
||||
// didn't connect and no error? this means we didn't have any connected
|
||||
// tunnels to try
|
||||
if err == nil {
|
||||
err = trace.Errorf("%v is offline", s.GetName())
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (s *tunnelSite) DialServer(addr string) (net.Conn, error) {
|
||||
|
|
|
@ -451,37 +451,18 @@ func newSessionRecorder(alog events.IAuditLog, namespace string, sid rsession.ID
|
|||
|
||||
// Write takes a chunk and writes it into the audit log
|
||||
func (r *sessionRecorder) Write(data []byte) (int, error) {
|
||||
const (
|
||||
minChunkLen = 4
|
||||
maxDelay = time.Millisecond * 20
|
||||
requiredDelay = time.Millisecond * 5
|
||||
)
|
||||
// terminal recording is a tricky business. the TTY subsystem expects a certain
|
||||
// delay when it writes to a virtual console. In our case recording takes no time
|
||||
// so we have to emulate TTY delay here:
|
||||
var start time.Time
|
||||
|
||||
// the delay depends on the chunk size, but shouldn't be higher than a certain
|
||||
// ceiling (maxDelay)
|
||||
dataLen := len(data)
|
||||
if dataLen > minChunkLen {
|
||||
start = time.Now()
|
||||
defer func() {
|
||||
postingDuration := time.Now().Sub(start)
|
||||
if postingDuration < requiredDelay {
|
||||
delay := time.Millisecond * time.Duration(dataLen)
|
||||
if delay > maxDelay {
|
||||
delay = maxDelay
|
||||
}
|
||||
time.Sleep(delay)
|
||||
}
|
||||
}()
|
||||
}
|
||||
// we are copying buffer to prevent data corruption:
|
||||
// io.Copy allocates single buffer and calls multiple writes in a loop
|
||||
// our PostSessionChunk is async and sends reader wrapping buffer
|
||||
// to the channel. This can lead to cases when the buffer is re-used
|
||||
// and data is corrupted unless we copy the data buffer in the first place
|
||||
dataCopy := make([]byte, len(data))
|
||||
copy(dataCopy, data)
|
||||
// post the chunk of bytes to the audit log:
|
||||
if err := r.alog.PostSessionChunk(r.namespace, r.sid, bytes.NewReader(data)); err != nil {
|
||||
log.Error(err)
|
||||
if err := r.alog.PostSessionChunk(r.namespace, r.sid, bytes.NewReader(dataCopy)); err != nil {
|
||||
log.Error(trace.DebugReport(err))
|
||||
}
|
||||
return dataLen, nil
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
// Close() does nothing for session recorder (audit log cannot be closed)
|
||||
|
|
|
@ -621,7 +621,7 @@ func (s *Server) handleDirectTCPIPRequest(sconn *ssh.ServerConn, ch ssh.Channel,
|
|||
ctx.Infof("direct-tcpip channel: %#v to --> %v", req, addr)
|
||||
conn, err := net.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
ctx.Infof("failed to connect to: %v, err: %v", addr, err)
|
||||
ctx.Infof("failed connecting to: %v, err: %v", addr, err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
@ -832,7 +832,7 @@ func (s *Server) handleSubsystem(ch ssh.Channel, req *ssh.Request, ctx *ctx) err
|
|||
// starting subsystem is blocking to the client,
|
||||
// while collecting its result and waiting is not blocking
|
||||
if err := sb.start(ctx.conn, ch, req, ctx); err != nil {
|
||||
ctx.Warnf("[SSH] failed to execute request, err: %v", err)
|
||||
ctx.Warnf("[SSH] failed executing request: %v", err)
|
||||
ctx.sendSubsystemResult(trace.Wrap(err))
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
|
|
@ -49,17 +49,15 @@ func ObeyTimeouts(conn net.Conn, timeout time.Duration, name string) net.Conn {
|
|||
}
|
||||
|
||||
func (tc *TimeoutConn) Read(p []byte) (n int, err error) {
|
||||
err = tc.Conn.SetReadDeadline(time.Now().Add(tc.TimeoutDuration))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// note: checking for errors here does not buy anything: some net.Conn interface
|
||||
// implementations (sshConn, pipe) simply return "not supported" error
|
||||
tc.Conn.SetReadDeadline(time.Now().Add(tc.TimeoutDuration))
|
||||
return tc.Conn.Read(p)
|
||||
}
|
||||
|
||||
func (tc *TimeoutConn) Write(p []byte) (n int, err error) {
|
||||
err = tc.Conn.SetWriteDeadline(time.Now().Add(tc.TimeoutDuration))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// note: checking for errors here does not buy anything: some net.Conn interface
|
||||
// implementations (sshConn, pipe) simply return "not supported" error
|
||||
tc.Conn.SetWriteDeadline(time.Now().Add(tc.TimeoutDuration))
|
||||
return tc.Conn.Write(p)
|
||||
}
|
||||
|
|
|
@ -241,7 +241,7 @@ func SSHAgentU2FLogin(proxyAddr, user, password string, pubKey []byte, ttl time.
|
|||
|
||||
// The origin URL is passed back base64-encoded and the keyHandle is passed back as is.
|
||||
// A very long proxy hostname or keyHandle can overflow a fixed-size buffer.
|
||||
signResponseLen := 500 + len(u2fSignRequest.Bytes()) + len(proxyAddr) * 4 / 3
|
||||
signResponseLen := 500 + len(u2fSignRequest.Bytes()) + len(proxyAddr)*4/3
|
||||
signResponseBuf := make([]byte, signResponseLen)
|
||||
signResponseLen, err = io.ReadFull(stdout, signResponseBuf)
|
||||
// unexpected EOF means we have read the data completely.
|
||||
|
@ -288,7 +288,11 @@ func SSHAgentU2FLogin(proxyAddr, user, password string, pubKey []byte, ttl time.
|
|||
return out, nil
|
||||
}
|
||||
|
||||
// initClient creates and initializes HTTPS client for talking to teleport proxy HTTPS
|
||||
// endpoint.
|
||||
func initClient(proxyAddr string, insecure bool, pool *x509.CertPool) (*webClient, *url.URL, error) {
|
||||
log.Debugf("HTTPS client init(insecure=%v)", insecure)
|
||||
|
||||
// validate proxyAddr:
|
||||
host, port, err := net.SplitHostPort(proxyAddr)
|
||||
if err != nil || host == "" || port == "" {
|
||||
|
@ -305,13 +309,13 @@ func initClient(proxyAddr string, insecure bool, pool *x509.CertPool) (*webClien
|
|||
|
||||
var opts []roundtrip.ClientParam
|
||||
|
||||
if pool != nil {
|
||||
// use custom set of trusted CAs
|
||||
opts = append(opts, roundtrip.HTTPClient(newClientWithPool(pool)))
|
||||
} else if insecure {
|
||||
if insecure {
|
||||
// skip https cert verification, oh no!
|
||||
fmt.Printf("WARNING: You are using insecure connection to SSH proxy %v\n", proxyAddr)
|
||||
opts = append(opts, roundtrip.HTTPClient(newInsecureClient()))
|
||||
} else if pool != nil {
|
||||
// use custom set of trusted CAs
|
||||
opts = append(opts, roundtrip.HTTPClient(newClientWithPool(pool)))
|
||||
}
|
||||
|
||||
clt, err := newWebClient(proxyAddr, opts...)
|
||||
|
|
|
@ -199,6 +199,8 @@ func onLogin(cf *CLIConf) {
|
|||
if err := tc.Login(); err != nil {
|
||||
utils.FatalError(err)
|
||||
}
|
||||
tc.SaveProfile("")
|
||||
|
||||
if tc.SiteName != "" {
|
||||
fmt.Printf("\nYou are now logged into %s as %s\n", tc.SiteName, tc.Username)
|
||||
} else {
|
||||
|
@ -208,6 +210,7 @@ func onLogin(cf *CLIConf) {
|
|||
|
||||
// onLogout deletes a "session certificate" from ~/.tsh for a given proxy
|
||||
func onLogout(cf *CLIConf) {
|
||||
client.UnlinkCurrentProfile()
|
||||
tc, err := makeClient(cf, true)
|
||||
if err != nil {
|
||||
utils.FatalError(err)
|
||||
|
@ -301,9 +304,6 @@ func onSSH(cf *CLIConf) {
|
|||
} else {
|
||||
utils.FatalError(err)
|
||||
}
|
||||
} else {
|
||||
// successful session? update the profile then:
|
||||
tc.SaveProfile("")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,9 +319,6 @@ func onJoin(cf *CLIConf) {
|
|||
}
|
||||
if err = tc.Join(cf.Namespace, *sid, nil); err != nil {
|
||||
utils.FatalError(err)
|
||||
} else {
|
||||
// successful session? update the profile then:
|
||||
tc.SaveProfile("")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,9 +335,6 @@ func onSCP(cf *CLIConf) {
|
|||
} else {
|
||||
utils.FatalError(err)
|
||||
}
|
||||
} else {
|
||||
// successful session? update the profile then:
|
||||
tc.SaveProfile("")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
5
vendor/github.com/gravitational/trace/errors.go
generated
vendored
5
vendor/github.com/gravitational/trace/errors.go
generated
vendored
|
@ -268,7 +268,10 @@ type ConnectionProblemError struct {
|
|||
|
||||
// Error is debug - friendly error message
|
||||
func (c *ConnectionProblemError) Error() string {
|
||||
return fmt.Sprintf("%v: %v", c.Message, c.Err)
|
||||
if c.Err == nil {
|
||||
return c.Message
|
||||
}
|
||||
return c.Err.Error()
|
||||
}
|
||||
|
||||
// IsConnectionProblemError indicates that this error is of ConnectionProblemError type
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
package teleport
|
||||
|
||||
const (
|
||||
Version = "1.2.6"
|
||||
Version = "1.3.0"
|
||||
)
|
||||
|
||||
var Gitref string
|
||||
|
|
Loading…
Reference in a new issue