mirror of
https://github.com/gravitational/teleport
synced 2024-10-20 17:23:22 +00:00
working hangouts
This commit is contained in:
parent
f35f74cb46
commit
66dd4436e9
|
@ -67,3 +67,5 @@ proxy:
|
|||
- period: 1s
|
||||
average: 500
|
||||
burst: 300
|
||||
hangouts_enabled: true
|
||||
hangouts_listen_addr: tcp://localhost:33009
|
|
@ -191,7 +191,7 @@ func (s *AuthServer) CreateToken() (string, error) {
|
|||
return "", err
|
||||
}
|
||||
|
||||
return string(p.SID)
|
||||
return string(p.SID), nil
|
||||
}
|
||||
|
||||
func (s *AuthServer) GenerateToken(domainName, role string, ttl time.Duration) (string, error) {
|
||||
|
|
|
@ -36,6 +36,7 @@ func NewStandardPermissions() PermissionChecker {
|
|||
ActionSignIn: true,
|
||||
ActionGenerateUserCert: true,
|
||||
ActionGetTrustedCertificates: true,
|
||||
ActionGetRemoteCertificates: true,
|
||||
}
|
||||
|
||||
sp.permissions[RoleProvisionToken] = map[string]bool{
|
||||
|
@ -73,6 +74,53 @@ func NewStandardPermissions() PermissionChecker {
|
|||
return &sp
|
||||
}
|
||||
|
||||
func NewHangoutPermissions() PermissionChecker {
|
||||
sp := standardPermissions{}
|
||||
sp.permissions = make(map[string](map[string]bool))
|
||||
|
||||
sp.permissions[RoleUser] = map[string]bool{
|
||||
ActionSignIn: true,
|
||||
ActionGenerateUserCert: true,
|
||||
ActionGetTrustedCertificates: true,
|
||||
ActionGetRemoteCertificates: true,
|
||||
}
|
||||
|
||||
sp.permissions[RoleProvisionToken] = map[string]bool{
|
||||
ActionRegisterUsingToken: true,
|
||||
ActionRegisterNewAuthServer: true,
|
||||
ActionGenerateUserCert: true,
|
||||
}
|
||||
|
||||
sp.permissions[RoleNode] = map[string]bool{
|
||||
ActionUpsertServer: true,
|
||||
ActionGetUserCertificateAuthority: true,
|
||||
ActionGetRemoteCertificates: true,
|
||||
ActionGetTrustedCertificates: true,
|
||||
ActionGetCertificateID: true,
|
||||
ActionGetAllUserMappings: true,
|
||||
ActionUserMappingExists: true,
|
||||
ActionGetUserKeys: true,
|
||||
ActionGetServers: true,
|
||||
ActionGetAuthServers: true,
|
||||
ActionGetHostCertificateAuthority: true,
|
||||
ActionUpsertParty: true,
|
||||
ActionLogEntry: true,
|
||||
ActionGetChunkWriter: true,
|
||||
}
|
||||
|
||||
sp.permissions[RoleWeb] = map[string]bool{
|
||||
ActionGetWebSession: true,
|
||||
ActionDeleteWebSession: true,
|
||||
}
|
||||
|
||||
sp.permissions[RoleSignup] = map[string]bool{
|
||||
ActionGetSignupTokenData: true,
|
||||
ActionCreateUserWithToken: true,
|
||||
}
|
||||
|
||||
return &sp
|
||||
}
|
||||
|
||||
func (sp *standardPermissions) HasPermission(role, action string) error {
|
||||
if role == RoleAdmin {
|
||||
return nil
|
||||
|
@ -114,6 +162,7 @@ var StandardRoles = []string{
|
|||
var HangoutRoles = []string{
|
||||
RoleAdmin,
|
||||
RoleHangoutUser,
|
||||
RoleProvisionToken,
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
|
@ -530,6 +530,30 @@ func (t *TunDialer) Dial(network, address string) (net.Conn, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func NewClientFromSSHClient(sshClient *ssh.Client) (*Client, error) {
|
||||
tr := &http.Transport{
|
||||
Dial: sshClient.Dial,
|
||||
/*Dial: func(network, addr string) (net.Conn, error) {
|
||||
ch, _, err := conn.OpenChannel(ReqDirectTCPIP, nil)
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return nil, err
|
||||
}
|
||||
return utils.NewChConn(conn, ch), nil
|
||||
},*/
|
||||
}
|
||||
clt, err := NewClient(
|
||||
"http://stub:0",
|
||||
roundtrip.HTTPClient(&http.Client{
|
||||
Transport: tr,
|
||||
}))
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return clt, nil
|
||||
}
|
||||
|
||||
const (
|
||||
ReqWebSessionAgent = "web-session-agent@teleport"
|
||||
ReqProvision = "provision@teleport"
|
||||
|
|
|
@ -247,6 +247,88 @@ func (proxy *ProxyClient) ConnectToNode(nodeAddress string, authMethods []ssh.Au
|
|||
return nil, e
|
||||
}
|
||||
|
||||
// ConnectToNode connects to the ssh server via Proxy.
|
||||
// It returns connected and authenticated NodeClient
|
||||
//DialHangout
|
||||
func (proxy *ProxyClient) ConnectToHangout(nodeAddress string, authMethods []ssh.AuthMethod,
|
||||
hostKeyCallback utils.HostKeyCallback, user string) (*NodeClient, error) {
|
||||
if len(authMethods) == 0 {
|
||||
return nil, trace.Errorf("no authMethods were provided")
|
||||
}
|
||||
|
||||
proxy.Lock()
|
||||
defer proxy.Unlock()
|
||||
|
||||
e := trace.Errorf("unknown Error")
|
||||
|
||||
for _, authMethod := range authMethods {
|
||||
|
||||
proxySession, err := proxy.Client.NewSession()
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
proxyWriter, err := proxySession.StdinPipe()
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
proxyReader, err := proxySession.StdoutPipe()
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = proxySession.RequestSubsystem(fmt.Sprintf("hangout:%v", nodeAddress))
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
localAddr, err := utils.ParseAddr("tcp://" + proxy.proxyAddress)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
remoteAddr, err := utils.ParseAddr("tcp://" + nodeAddress)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
pipeNetConn := utils.NewPipeNetConn(
|
||||
proxyReader,
|
||||
proxyWriter,
|
||||
proxySession,
|
||||
localAddr,
|
||||
remoteAddr,
|
||||
)
|
||||
|
||||
sshConfig := &ssh.ClientConfig{
|
||||
User: user,
|
||||
Auth: []ssh.AuthMethod{authMethod},
|
||||
HostKeyCallback: hostKeyCallback,
|
||||
}
|
||||
|
||||
conn, chans, reqs, err := ssh.NewClientConn(pipeNetConn,
|
||||
nodeAddress, sshConfig)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "handshake failed") ||
|
||||
strings.Contains(err.Error(), "CheckHostSigners") {
|
||||
e = trace.Wrap(err)
|
||||
proxySession.Close()
|
||||
continue
|
||||
}
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
client := ssh.NewClient(conn, chans, reqs)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return &NodeClient{Client: client}, nil
|
||||
}
|
||||
return nil, e
|
||||
}
|
||||
|
||||
func (proxy *ProxyClient) Close() error {
|
||||
return proxy.Client.Close()
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/gravitational/teleport/lib/auth/native"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
"github.com/gravitational/teleport/lib/web"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
|
@ -60,6 +61,7 @@ func NewWebAuth(ag agent.Agent,
|
|||
callbackFunc := func() (signers []ssh.Signer, err error) {
|
||||
err = Login(ag, webProxyAddress, user, certificateTTL, passwordCallback)
|
||||
if err != nil {
|
||||
fmt.Printf("Can't login to the server: %v\n", err)
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
|
@ -71,6 +73,7 @@ func NewWebAuth(ag agent.Agent,
|
|||
if err != nil {
|
||||
err = Login(ag, webProxyAddress, user, certificateTTL, passwordCallback)
|
||||
if err != nil {
|
||||
fmt.Printf("Can't login to the server: %v\n", err)
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
return CheckHostSignerFromCache(hostname, remote, key)
|
||||
|
|
|
@ -22,37 +22,44 @@ import (
|
|||
"os/user"
|
||||
//"path/filepath"
|
||||
//"strings"
|
||||
//"time"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/gravitational/teleport/lib/auth"
|
||||
authority "github.com/gravitational/teleport/lib/auth/native"
|
||||
//"github.com/gravitational/teleport/lib/backend/boltbk"
|
||||
//"github.com/gravitational/teleport/lib/backend/encryptedbk"
|
||||
//"github.com/gravitational/teleport/lib/backend/encryptedbk/encryptor"
|
||||
"github.com/gravitational/teleport/lib/backend"
|
||||
"github.com/gravitational/teleport/lib/backend/boltbk"
|
||||
"github.com/gravitational/teleport/lib/backend/encryptedbk"
|
||||
"github.com/gravitational/teleport/lib/backend/encryptedbk/encryptor"
|
||||
"github.com/gravitational/teleport/lib/backend/etcdbk"
|
||||
"github.com/gravitational/teleport/lib/events"
|
||||
//"github.com/gravitational/teleport/lib/events/boltlog"
|
||||
"github.com/gravitational/teleport/lib/events/boltlog"
|
||||
"github.com/gravitational/teleport/lib/limiter"
|
||||
"github.com/gravitational/teleport/lib/recorder"
|
||||
//"github.com/gravitational/teleport/lib/recorder/boltrec"
|
||||
"github.com/gravitational/teleport/lib/recorder/boltrec"
|
||||
"github.com/gravitational/teleport/lib/reversetunnel"
|
||||
"github.com/gravitational/teleport/lib/service"
|
||||
//"github.com/gravitational/teleport/lib/services"
|
||||
//sess "github.com/gravitational/teleport/lib/session"
|
||||
"github.com/gravitational/teleport/lib/services"
|
||||
"github.com/gravitational/teleport/lib/session"
|
||||
"github.com/gravitational/teleport/lib/srv"
|
||||
//"github.com/gravitational/teleport/lib/sshutils"
|
||||
"github.com/gravitational/teleport/lib/utils"
|
||||
|
||||
"github.com/gravitational/session"
|
||||
//"github.com/gravitational/session"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
//"github.com/gravitational/log"
|
||||
"github.com/gravitational/trace"
|
||||
//"github.com/gokyle/hotp"
|
||||
//"github.com/mailgun/lemma/secret"
|
||||
"github.com/codahale/lunk"
|
||||
"golang.org/x/crypto/ssh"
|
||||
//"golang.org/x/crypto/ssh/agent"
|
||||
"golang.org/x/crypto/ssh/agent"
|
||||
)
|
||||
|
||||
type Hangout struct {
|
||||
auth auth.AuthServer
|
||||
auth *auth.AuthServer
|
||||
tunClt reversetunnel.Agent
|
||||
elog events.Log
|
||||
rec recorder.Recorder
|
||||
|
@ -62,45 +69,53 @@ type Hangout struct {
|
|||
authPort string
|
||||
ClientAuthMethod ssh.AuthMethod
|
||||
HostKeyCallback utils.HostKeyCallback
|
||||
client *auth.TunClient
|
||||
passwordToken string
|
||||
HangoutInfo HangoutInfo
|
||||
Token string
|
||||
}
|
||||
|
||||
func New(proxyTunnelAddress, nodeListeningAddress, authListeningAddress string,
|
||||
readOnly bool, authMethods []ssh.AuthMethod,
|
||||
hostKeyCallback utils.HostKeyCallback) (*Hangout, error) {
|
||||
|
||||
//log.SetOutput(os.Stderr)
|
||||
//log.SetLevel(log.InfoLevel)
|
||||
//log.Initialize("console", "INFO")
|
||||
|
||||
cfg := service.Config{}
|
||||
service.SetDefaults(&cfg)
|
||||
cfg.DataDir = "/tmp/teleporthangout"
|
||||
cfg.DataDir = HangoutDataDir
|
||||
cfg.Hostname = "localhost"
|
||||
|
||||
cfg.Auth.HostAuthorityDomain = "localhost"
|
||||
cfg.Auth.KeysBackend.Type = "bolt"
|
||||
cfg.Auth.KeysBackend.Params = `{"path": "` + DataDir + `/teleport.auth.db"}`
|
||||
cfg.Auth.KeysBackend.Params = `{"path": "` + cfg.DataDir + `/teleport.auth.db"}`
|
||||
cfg.Auth.EventsBackend.Type = "bolt"
|
||||
cfg.Auth.EventsBackend.Params = `{"path": "` + DataDir + `/teleport.event.db"}`
|
||||
cfg.Auth.EventsBackend.Params = `{"path": "` + cfg.DataDir + `/teleport.event.db"}`
|
||||
cfg.Auth.RecordsBackend.Type = "bolt"
|
||||
cfg.Auth.RecordsBackend.Params = `{"path": "` + DataDir + `/teleport.records.db"}`
|
||||
authAddress, err := utils.ParseAddr(authListeningAddress)
|
||||
cfg.Auth.RecordsBackend.Params = `{"path": "` + cfg.DataDir + `/teleport.records.db"}`
|
||||
authAddress, err := utils.ParseAddr("tcp://" + authListeningAddress)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
cfg.Auth.SSHAddr = authAddress
|
||||
cfg.Auth.SSHAddr = *authAddress
|
||||
cfg.AuthServers = []utils.NetAddr{cfg.Auth.SSHAddr}
|
||||
|
||||
nodeAddress, err := utils.ParseAddr(nodeListeningAddress)
|
||||
nodeAddress, err := utils.ParseAddr("tcp://" + nodeListeningAddress)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
cfg.SSH.Addr = nodeAddress
|
||||
cfg.SSH.Addr = *nodeAddress
|
||||
|
||||
tunnelAddress, err := utils.ParseAddr(proxyTunnelAddress)
|
||||
tunnelAddress, err := utils.ParseAddr("tcp://" + proxyTunnelAddress)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
cfg.ReverseTunnel.DialAddr = tunnelAddress
|
||||
cfg.ReverseTunnel.DialAddr = *tunnelAddress
|
||||
|
||||
_, err := os.Stat(cfg.DataDir)
|
||||
_, err = os.Stat(cfg.DataDir)
|
||||
if os.IsNotExist(err) {
|
||||
err := os.MkdirAll(cfg.DataDir, os.ModeDir|0777)
|
||||
if err != nil {
|
||||
|
@ -113,19 +128,31 @@ func New(proxyTunnelAddress, nodeListeningAddress, authListeningAddress string,
|
|||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
h.hangoutID, err = h.auth.CreateToken()
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
thisSrv := services.Server{
|
||||
ID: cfg.Auth.SSHAddr.Addr,
|
||||
Addr: cfg.Auth.SSHAddr.Addr,
|
||||
Hostname: h.hangoutID,
|
||||
}
|
||||
err = h.auth.UpsertServer(thisSrv, 0)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
log.Infof("***************** init SSH")
|
||||
|
||||
if err := h.initSSHEndpoint(cfg); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
log.Infof("***************** init Tun Agent")
|
||||
if err := h.initTunAgent(cfg, authMethods, hostKeyCallback); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
log.Infof("***************** create User")
|
||||
if err := h.createUser(); err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
@ -139,12 +166,25 @@ func New(proxyTunnelAddress, nodeListeningAddress, authListeningAddress string,
|
|||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
h.ClientAuthMethod, h.HostKeyCallback, err = Authorize(auth, h.userPassword)
|
||||
h.ClientAuthMethod, h.HostKeyCallback, err = Authorize(h.client, h.userPassword)
|
||||
|
||||
h.HangoutInfo.AuthPort = h.authPort
|
||||
h.HangoutInfo.NodePort = h.nodePort
|
||||
h.HangoutInfo.HangoutID = h.hangoutID
|
||||
h.HangoutInfo.HangoutPassword = h.passwordToken
|
||||
|
||||
h.Token, err = MarshalHangoutInfo(&h.HangoutInfo)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (h *Hangout) createUser() error {
|
||||
var err error
|
||||
h.userPassword, err = h.auth.GenerateToken(HangoutUser, services.TokenRoleHangout, 0)
|
||||
h.passwordToken, err = h.auth.GenerateToken(HangoutUser, services.TokenRoleHangout, 0)
|
||||
h.userPassword = h.passwordToken[0:100]
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
@ -154,18 +194,24 @@ func (h *Hangout) createUser() error {
|
|||
return trace.Wrap(err)
|
||||
}
|
||||
osUser := u.Username
|
||||
h.HangoutInfo.OSUser = osUser
|
||||
|
||||
_, _, err := s.a.UpsertPassword(HangoutUser, h.userPassword)
|
||||
_, _, err = h.auth.UpsertPassword(HangoutUser, []byte(h.userPassword))
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
err = h.auth.UpsertUserMapping("local", HangoutUser, osUser, 0)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Authorize(auth auth.Client, userPassword string) (ssh.AuthMethod, utils.HostKeyCallback, error) {
|
||||
func Authorize(auth auth.ClientI, userPassword string) (ssh.AuthMethod, utils.HostKeyCallback, error) {
|
||||
|
||||
priv, pub, err := native.New().GenerateKeyPair("")
|
||||
priv, pub, err := authority.New().GenerateKeyPair("")
|
||||
if err != nil {
|
||||
return nil, nil, trace.Wrap(err)
|
||||
}
|
||||
|
@ -174,7 +220,7 @@ func Authorize(auth auth.Client, userPassword string) (ssh.AuthMethod, utils.Hos
|
|||
return nil, nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
pcert, _, _, _, err := ssh.ParseAuthorizedKey(login.Cert)
|
||||
pcert, _, _, _, err := ssh.ParseAuthorizedKey(cert)
|
||||
if err != nil {
|
||||
return nil, nil, trace.Wrap(err)
|
||||
}
|
||||
|
@ -244,8 +290,9 @@ func (h *Hangout) initAuth(cfg service.Config, readOnlyHangout bool) error {
|
|||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
apisrv := auth.NewAPIWithRoles(asrv, elog, session.New(b), rec,
|
||||
auth.NewStandardPermissions(), auth.HangoutRoles,
|
||||
h.auth = asrv
|
||||
apisrv := auth.NewAPIWithRoles(asrv, h.elog, session.New(b), h.rec,
|
||||
auth.NewHangoutPermissions(), auth.HangoutRoles,
|
||||
)
|
||||
go apisrv.Serve()
|
||||
|
||||
|
@ -270,16 +317,10 @@ func (h *Hangout) initAuth(cfg service.Config, readOnlyHangout bool) error {
|
|||
}
|
||||
}()
|
||||
|
||||
thisSrv := services.Server{
|
||||
ID: cfg.Auth.SSHAddr.Addr(),
|
||||
Addr: cfg.Auth.SSHAddr.Addr(),
|
||||
Hostname: h.HangoutID,
|
||||
}
|
||||
err := asrv.UpsertServer(thisSrv, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Hangout) initTunAgent(cfg Config, authMethods []ssh.AuthMethod, hostKeyCallback utils.HostKeyCallback) error {
|
||||
func (h *Hangout) initTunAgent(cfg service.Config, authMethods []ssh.AuthMethod, hostKeyCallback utils.HostKeyCallback) error {
|
||||
signer, err := auth.ReadKeys(cfg.Hostname, cfg.DataDir)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
|
@ -293,6 +334,8 @@ func (h *Hangout) initTunAgent(cfg Config, authMethods []ssh.AuthMethod, hostKey
|
|||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
h.client = client
|
||||
|
||||
elog := &service.FanOutEventLogger{
|
||||
Loggers: []lunk.EventLogger{
|
||||
lunk.NewTextEventLogger(log.StandardLogger().Writer()),
|
||||
|
@ -311,10 +354,11 @@ func (h *Hangout) initTunAgent(cfg Config, authMethods []ssh.AuthMethod, hostKey
|
|||
}
|
||||
|
||||
log.Infof("[REVERSE TUNNEL] teleport tunnel agent starting")
|
||||
if err := a.Start(); err != nil {
|
||||
log.Fatalf("failed to start: %v", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := a.Start(); err != nil {
|
||||
log.Fatalf("failed to start: %v", err)
|
||||
}
|
||||
if err := a.Wait(); err != nil {
|
||||
log.Fatalf("failed to start: %v", err)
|
||||
}
|
||||
|
@ -322,7 +366,7 @@ func (h *Hangout) initTunAgent(cfg Config, authMethods []ssh.AuthMethod, hostKey
|
|||
return nil
|
||||
}
|
||||
|
||||
func (h *Hangout) initSSHEndpoint(cfg Config) error {
|
||||
func (h *Hangout) initSSHEndpoint(cfg service.Config) error {
|
||||
signer, err := auth.ReadKeys(cfg.Hostname, cfg.DataDir)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
|
@ -349,7 +393,7 @@ func (h *Hangout) initSSHEndpoint(cfg Config) error {
|
|||
}
|
||||
|
||||
s, err := srv.New(cfg.SSH.Addr,
|
||||
cfg.Hostname,
|
||||
h.hangoutID,
|
||||
[]ssh.Signer{signer},
|
||||
client,
|
||||
limiter,
|
||||
|
@ -367,18 +411,86 @@ func (h *Hangout) initSSHEndpoint(cfg Config) error {
|
|||
log.Infof("[SSH] server is starting on %v", cfg.SSH.Addr)
|
||||
go func() {
|
||||
if err := s.Start(); err != nil {
|
||||
log.Errorf(err)
|
||||
}
|
||||
if err := s.Wait(); err != nil {
|
||||
log.Errorf(err)
|
||||
log.Errorf(err.Error())
|
||||
}
|
||||
s.Wait()
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func initBackend(dataDir, domainName string, peers service.NetAddrSlice, cfg service.AuthConfig) (*encryptedbk.ReplicatedBackend, error) {
|
||||
var bk backend.Backend
|
||||
var err error
|
||||
|
||||
switch cfg.KeysBackend.Type {
|
||||
case "etcd":
|
||||
bk, err = etcdbk.FromJSON(cfg.KeysBackend.Params)
|
||||
case "bolt":
|
||||
bk, err = boltbk.FromJSON(cfg.KeysBackend.Params)
|
||||
default:
|
||||
return nil, trace.Errorf("unsupported backend type: %v", cfg.KeysBackend.Type)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
keyStorage := path.Join(dataDir, "backend_keys")
|
||||
encryptionKeys := []encryptor.Key{}
|
||||
for _, strKey := range cfg.KeysBackend.EncryptionKeys {
|
||||
encKey, err := encryptedbk.KeyFromString(strKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encryptionKeys = append(encryptionKeys, encKey)
|
||||
}
|
||||
|
||||
encryptedBk, err := encryptedbk.NewReplicatedBackend(bk,
|
||||
keyStorage, encryptionKeys, encryptor.GenerateGPGKey)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
log.Infof("Initializing backend as follower node")
|
||||
myKey, err := encryptor.GenerateGPGKey(domainName + " key")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
masterKey, err := auth.RegisterNewAuth(
|
||||
domainName, cfg.Token, myKey.Public(), peers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Infof(" ", myKey, masterKey)
|
||||
encryptedBk, err = encryptedbk.NewReplicatedBackend(bk,
|
||||
keyStorage, []encryptor.Key{myKey, masterKey},
|
||||
encryptor.GenerateGPGKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return encryptedBk, nil
|
||||
}
|
||||
|
||||
func initEventBackend(btype string, params string) (events.Log, error) {
|
||||
switch btype {
|
||||
case "bolt":
|
||||
return boltlog.FromJSON(params)
|
||||
}
|
||||
return nil, trace.Errorf("unsupported backend type: %v", btype)
|
||||
}
|
||||
|
||||
func initRecordBackend(btype string, params string) (recorder.Recorder, error) {
|
||||
switch btype {
|
||||
case "bolt":
|
||||
return boltrec.FromJSON(params)
|
||||
}
|
||||
return nil, trace.Errorf("unsupported backend type: %v", btype)
|
||||
}
|
||||
|
||||
func (h *Hangout) GetJoinCommand() string {
|
||||
nodeAddress := h.hangoutID + ":" + h.nodePort
|
||||
authAddress := h.hangoutID + ":" + h.authPort
|
||||
//nodeAddress := h.hangoutID + ":" + h.nodePort
|
||||
//authAddress := h.hangoutID + ":" + h.authPort
|
||||
return ""
|
||||
}
|
||||
|
||||
const HangoutUser = "hangoutUser"
|
||||
const HangoutDataDir = "/tmp/teleport_hangouts"
|
||||
|
|
53
lib/hangout/token.go
Normal file
53
lib/hangout/token.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Copyright 2015 Gravitational, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package hangout
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
)
|
||||
|
||||
type HangoutInfo struct {
|
||||
AuthPort string
|
||||
NodePort string
|
||||
HangoutID string
|
||||
HangoutPassword string
|
||||
OSUser string
|
||||
}
|
||||
|
||||
func MarshalHangoutInfo(h *HangoutInfo) (string, error) {
|
||||
jsonString, err := json.Marshal(h)
|
||||
if err != nil {
|
||||
return "", trace.Wrap(err)
|
||||
}
|
||||
b64str := base64.StdEncoding.EncodeToString(jsonString)
|
||||
return string(b64str), nil
|
||||
}
|
||||
|
||||
func UnmarshalHangoutInfo(id string) (*HangoutInfo, error) {
|
||||
jsonString, err := base64.StdEncoding.DecodeString(id)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
var h HangoutInfo
|
||||
err = json.Unmarshal(jsonString, &h)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
return &h, nil
|
||||
}
|
|
@ -180,9 +180,6 @@ func (a *Agent) connect() error {
|
|||
Auth: []ssh.AuthMethod{authMethod},
|
||||
HostKeyCallback: a.hostKeyCallback,
|
||||
})
|
||||
if err != nil {
|
||||
log.Warningf(err.Error())
|
||||
}
|
||||
if c != nil {
|
||||
break
|
||||
}
|
||||
|
|
|
@ -91,6 +91,30 @@ func NewServer(addr utils.NetAddr, hostSigners []ssh.Signer,
|
|||
return srv, nil
|
||||
}
|
||||
|
||||
// New returns an unstarted server
|
||||
func NewHangoutServer(addr utils.NetAddr, hostSigners []ssh.Signer,
|
||||
ap auth.AccessPoint, limiter *limiter.Limiter) (Server, error) {
|
||||
srv := &server{
|
||||
sites: []*remoteSite{},
|
||||
ap: ap,
|
||||
}
|
||||
s, err := sshutils.NewServer(
|
||||
addr,
|
||||
srv,
|
||||
hostSigners,
|
||||
sshutils.AuthMethods{
|
||||
PublicKey: srv.hangoutKeyAuth,
|
||||
},
|
||||
limiter,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
srv.certChecker = ssh.CertChecker{IsAuthority: srv.isHangoutAuthority}
|
||||
srv.srv = s
|
||||
return srv, nil
|
||||
}
|
||||
|
||||
func (s *server) Wait() {
|
||||
s.srv.Wait()
|
||||
}
|
||||
|
@ -144,6 +168,20 @@ func (s *server) isAuthority(auth ssh.PublicKey) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// isAuthority is called during checking the client key, to see if the signing
|
||||
// key is the real CA authority key.
|
||||
func (s *server) isHangoutAuthority(auth ssh.PublicKey) bool {
|
||||
_, found, err := s.ap.GetCertificateID(services.UserCert, auth)
|
||||
if err != nil {
|
||||
log.Errorf("failed to retrieve trused keys, err: %v", err)
|
||||
return false
|
||||
}
|
||||
if found {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *server) getTrustedCAKeys() ([]ssh.PublicKey, error) {
|
||||
out := []ssh.PublicKey{}
|
||||
authKeys := [][]byte{}
|
||||
|
@ -155,6 +193,7 @@ func (s *server) getTrustedCAKeys() ([]ssh.PublicKey, error) {
|
|||
|
||||
certs, err := s.ap.GetRemoteCertificates(services.HostCert, "")
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
return nil, err
|
||||
}
|
||||
for _, c := range certs {
|
||||
|
@ -201,6 +240,44 @@ func (s *server) keyAuth(
|
|||
return perms, nil
|
||||
}
|
||||
|
||||
func (s *server) hangoutKeyAuth(
|
||||
conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
|
||||
cid := fmt.Sprintf(
|
||||
"reversetunnelconn(%v->%v, user=%v)", conn.RemoteAddr(),
|
||||
conn.LocalAddr(), conn.User())
|
||||
|
||||
log.Infof("%v auth attempt with key %v", cid, key.Type())
|
||||
|
||||
_, ok := key.(*ssh.Certificate)
|
||||
if !ok {
|
||||
log.Warningf("conn(%v->%v, user=%v) ERROR: Server doesn't support provided key type",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), conn.User())
|
||||
return nil, trace.Errorf("ERROR: Server doesn't support provided key type")
|
||||
}
|
||||
//teleportUser := cert.Permissions.Extensions[utils.CertExtensionUser]
|
||||
|
||||
_, err := s.certChecker.Authenticate(conn, key)
|
||||
if err != nil {
|
||||
log.Warningf("conn(%v->%v, user=%v) ERROR: Failed to authorize user %v, err: %v",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), conn.User(), conn.User(), err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := s.certChecker.CheckCert(conn.User(), key.(*ssh.Certificate)); err != nil {
|
||||
log.Warningf("conn(%v->%v, user=%v) ERROR: Failed to authorize user %v, err: %v",
|
||||
conn.RemoteAddr(), conn.LocalAddr(), conn.User(), conn.User(), err)
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
perms := &ssh.Permissions{
|
||||
Extensions: map[string]string{
|
||||
ExtHost: conn.User(),
|
||||
},
|
||||
}
|
||||
|
||||
return perms, nil
|
||||
}
|
||||
|
||||
func (s *server) upsertSite(c ssh.Conn) (*remoteSite, error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
@ -316,7 +393,7 @@ func (s *remoteSite) init(c ssh.Conn) error {
|
|||
log.Errorf("remoteSite:authProxy %v", err)
|
||||
return nil, err
|
||||
}
|
||||
return newChConn(s.conn, ch), nil
|
||||
return utils.NewChConn(s.conn, ch), nil
|
||||
},
|
||||
}
|
||||
clt, err := auth.NewClient(
|
||||
|
@ -374,7 +451,7 @@ func (s *remoteSite) ConnectToServer(server, user string, auth []ssh.AuthMethod)
|
|||
if !dialed {
|
||||
return nil, trace.Errorf("remote server %v is not available", server)
|
||||
}
|
||||
transportConn := newChConn(s.conn, ch)
|
||||
transportConn := utils.NewChConn(s.conn, ch)
|
||||
conn, chans, reqs, err := ssh.NewClientConn(
|
||||
transportConn, server,
|
||||
&ssh.ClientConfig{
|
||||
|
@ -419,7 +496,7 @@ func (s *remoteSite) DialServer(server string) (net.Conn, error) {
|
|||
if !dialed {
|
||||
return nil, trace.Errorf("remote server %v is not available", server)
|
||||
}
|
||||
return newChConn(s.conn, ch), nil
|
||||
return utils.NewChConn(s.conn, ch), nil
|
||||
}
|
||||
|
||||
func (s *remoteSite) GetServers() ([]services.Server, error) {
|
||||
|
@ -434,7 +511,7 @@ func (s *remoteSite) handleAuthProxy(w http.ResponseWriter, r *http.Request) {
|
|||
log.Errorf("remoteSite:authProxy %v", err)
|
||||
return nil, err
|
||||
}
|
||||
return newChConn(s.conn, ch), nil
|
||||
return utils.NewChConn(s.conn, ch), nil
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -449,36 +526,4 @@ func (s *remoteSite) handleAuthProxy(w http.ResponseWriter, r *http.Request) {
|
|||
fwd.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func newChConn(conn ssh.Conn, ch ssh.Channel) *chConn {
|
||||
c := &chConn{}
|
||||
c.Channel = ch
|
||||
c.conn = conn
|
||||
return c
|
||||
}
|
||||
|
||||
type chConn struct {
|
||||
ssh.Channel
|
||||
conn ssh.Conn
|
||||
}
|
||||
|
||||
func (c *chConn) LocalAddr() net.Addr {
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (c *chConn) RemoteAddr() net.Addr {
|
||||
return c.conn.RemoteAddr()
|
||||
}
|
||||
|
||||
func (c *chConn) SetDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *chConn) SetReadDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *chConn) SetWriteDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
const ExtHost = "host@teleport"
|
||||
|
|
|
@ -90,6 +90,11 @@ type ProxyConfig struct {
|
|||
// ReverseTunnelListenAddr is address where reverse tunnel dialers connect to
|
||||
ReverseTunnelListenAddr utils.NetAddr `yaml:"reverse_tunnel_listen_addr" env:"TELEPORT_PROXY_REVERSE_TUNNEL_LISTEN_ADDR"`
|
||||
|
||||
HangoutsEnabled bool `yaml:"hangouts_enabled" env:"TELEPORT_PROXY_HANGOUTS_ENABLED`
|
||||
|
||||
// HangoutListenAddr is address where hangout reverse tunnel dialers connect to
|
||||
HangoutsListenAddr utils.NetAddr `yaml:"hangouts_listen_addr" env:"TELEPORT_PROXY_HANGOUTS_LISTEN_ADDR"`
|
||||
|
||||
// WebAddr is address for web portal of the proxy
|
||||
WebAddr utils.NetAddr `yaml:"web_addr" env:"TELEPORT_PROXY_WEB_ADDR"`
|
||||
|
||||
|
|
|
@ -405,13 +405,32 @@ func initProxyEndpoint(supervisor Supervisor, cfg Config) error {
|
|||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
var hsrv reversetunnel.Server
|
||||
if cfg.Proxy.HangoutsEnabled {
|
||||
hsrv, err = reversetunnel.NewHangoutServer(
|
||||
cfg.Proxy.HangoutsListenAddr,
|
||||
[]ssh.Signer{signer},
|
||||
client,
|
||||
reverseTunnelLimiter,
|
||||
)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
options := []srv.ServerOption{srv.SetProxyMode(tsrv)}
|
||||
if cfg.Proxy.HangoutsEnabled {
|
||||
options = append(options, srv.EnableHangouts(hsrv))
|
||||
}
|
||||
|
||||
SSHProxy, err := srv.New(cfg.Proxy.SSHAddr,
|
||||
cfg.Hostname,
|
||||
[]ssh.Signer{signer},
|
||||
client,
|
||||
proxyLimiter,
|
||||
cfg.DataDir,
|
||||
srv.SetProxyMode(tsrv),
|
||||
options...,
|
||||
)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
|
@ -429,6 +448,20 @@ func initProxyEndpoint(supervisor Supervisor, cfg Config) error {
|
|||
return nil
|
||||
})
|
||||
|
||||
if cfg.Proxy.HangoutsEnabled {
|
||||
// register SSH reverse tunnel server that accepts connections
|
||||
// from remote teleport nodes
|
||||
supervisor.RegisterFunc(func() error {
|
||||
log.Infof("[PROXY] hangouts listening server starting on %v",
|
||||
cfg.Proxy.HangoutsListenAddr)
|
||||
if err := hsrv.Start(); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
hsrv.Wait()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Register web proxy server
|
||||
supervisor.RegisterFunc(func() error {
|
||||
log.Infof("[PROXY] teleport web proxy server starting on %v",
|
||||
|
|
102
lib/srv/hangouts.go
Normal file
102
lib/srv/hangouts.go
Normal file
|
@ -0,0 +1,102 @@
|
|||
package srv
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/gravitational/teleport/lib/services"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/gravitational/trace"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// hangoutsSubsys is an SSH subsystem for easy proxyneling through proxy server
|
||||
// This subsystem creates a new TCP connection and connects ssh channel
|
||||
// with this connection
|
||||
type hangoutsSubsys struct {
|
||||
srv *Server
|
||||
host string
|
||||
port string
|
||||
}
|
||||
|
||||
func parseHangoutsSubsys(name string, srv *Server) (*hangoutsSubsys, error) {
|
||||
out := strings.Split(name, ":")
|
||||
if len(out) != 3 {
|
||||
return nil, trace.Errorf("invalid format for proxy request: '%v', expected 'proxy:host:port'", name)
|
||||
}
|
||||
return &hangoutsSubsys{
|
||||
srv: srv,
|
||||
host: out[1],
|
||||
port: out[2],
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *hangoutsSubsys) String() string {
|
||||
return fmt.Sprintf("hangoutsSubsys(host=%v, port=%v)", t.host, t.port)
|
||||
}
|
||||
|
||||
func (t *hangoutsSubsys) execute(sconn *ssh.ServerConn, ch ssh.Channel, req *ssh.Request, ctx *ctx) error {
|
||||
remoteSrv, err := t.srv.hangoutsTun.GetSite(t.host)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
// find matching server in the list of servers for this site
|
||||
servers, err := remoteSrv.GetServers()
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
serverAddr := fmt.Sprintf("%v:%v", t.host, t.port)
|
||||
var server *services.Server
|
||||
for i := range servers {
|
||||
log.Infof("%v %v", servers[i].Addr, servers[i].Hostname)
|
||||
ip, port, err := net.SplitHostPort(servers[i].Addr)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
// match either by hostname of ip, based on the match
|
||||
if (t.host == ip || t.host == servers[i].Hostname) && port == t.port {
|
||||
server = &servers[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
if server == nil {
|
||||
return trace.Errorf("server %v not found", serverAddr)
|
||||
}
|
||||
|
||||
// we must dial by server IP address because hostname
|
||||
// may not be actually DNS resolvable
|
||||
conn, err := remoteSrv.DialServer(server.Addr)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(2)
|
||||
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
_, err := io.Copy(ch, conn)
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
}
|
||||
ch.Close()
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
_, err := io.Copy(conn, ch)
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
}
|
||||
conn.Close()
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return nil
|
||||
}
|
|
@ -39,8 +39,8 @@ import (
|
|||
"github.com/gravitational/teleport/lib/utils"
|
||||
|
||||
"code.google.com/p/go-uuid/uuid"
|
||||
"github.com/codahale/lunk"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/codahale/lunk"
|
||||
"github.com/gravitational/trace"
|
||||
"golang.org/x/crypto/ssh"
|
||||
// Server implements SSH server that uses configuration backend and certificate-based authentication:
|
||||
|
@ -68,8 +68,9 @@ type Server struct {
|
|||
|
||||
certificatesCache *services.CAService
|
||||
|
||||
proxyMode bool
|
||||
proxyTun reversetunnel.Server
|
||||
proxyMode bool
|
||||
proxyTun reversetunnel.Server
|
||||
hangoutsTun reversetunnel.Server
|
||||
}
|
||||
|
||||
type ServerOption func(s *Server) error
|
||||
|
@ -110,6 +111,13 @@ func SetProxyMode(tsrv reversetunnel.Server) ServerOption {
|
|||
}
|
||||
}
|
||||
|
||||
func EnableHangouts(hangoutsTun reversetunnel.Server) ServerOption {
|
||||
return func(s *Server) error {
|
||||
s.hangoutsTun = hangoutsTun
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func SetLabels(labels map[string]string,
|
||||
cmdLabels services.CommandLabels) ServerOption {
|
||||
return func(s *Server) error {
|
||||
|
@ -147,6 +155,11 @@ func New(addr utils.NetAddr, hostname string, signers []ssh.Signer,
|
|||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if (s.hangoutsTun != nil) && (!s.proxyMode) {
|
||||
return nil, trace.Errorf("Hangout available only in proxy mode")
|
||||
}
|
||||
|
||||
if s.elog == nil {
|
||||
s.elog = utils.NullEventLogger
|
||||
}
|
||||
|
@ -417,7 +430,6 @@ func (s *Server) HandleRequest(r *ssh.Request) {
|
|||
|
||||
func (s *Server) HandleNewChan(sconn *ssh.ServerConn, nch ssh.NewChannel) {
|
||||
channelType := nch.ChannelType()
|
||||
|
||||
if s.proxyMode {
|
||||
if channelType == "session" { // interactive sessions
|
||||
ch, requests, err := nch.Accept()
|
||||
|
|
|
@ -50,6 +50,9 @@ func parseSubsystemRequest(srv *Server, req *ssh.Request) (subsystem, error) {
|
|||
if srv.proxyMode && strings.HasPrefix(s.Name, "proxy:") {
|
||||
return parseProxySubsys(s.Name, srv)
|
||||
}
|
||||
if srv.proxyMode && srv.hangoutsTun != nil && strings.HasPrefix(s.Name, "hangout:") {
|
||||
return parseHangoutsSubsys(s.Name, srv)
|
||||
}
|
||||
if srv.proxyMode && strings.HasPrefix(s.Name, "proxysites") {
|
||||
return parseProxySitesSubsys(s.Name, srv)
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ import (
|
|||
"io"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// PipeNetConn implemetns net.Conn from io.Reader,io.Writer and io.Closer
|
||||
|
@ -81,3 +83,35 @@ func SplitReaders(r1 io.Reader, r2 io.Reader) io.Reader {
|
|||
go io.Copy(writer, r2)
|
||||
return reader
|
||||
}
|
||||
|
||||
func NewChConn(conn ssh.Conn, ch ssh.Channel) *chConn {
|
||||
c := &chConn{}
|
||||
c.Channel = ch
|
||||
c.conn = conn
|
||||
return c
|
||||
}
|
||||
|
||||
type chConn struct {
|
||||
ssh.Channel
|
||||
conn ssh.Conn
|
||||
}
|
||||
|
||||
func (c *chConn) LocalAddr() net.Addr {
|
||||
return c.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (c *chConn) RemoteAddr() net.Addr {
|
||||
return c.conn.RemoteAddr()
|
||||
}
|
||||
|
||||
func (c *chConn) SetDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *chConn) SetReadDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *chConn) SetWriteDeadline(t time.Time) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -20,10 +20,12 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type HostKeyCallback func(hostname string, remote net.Addr, key ssh.PublicKey) error
|
||||
|
|
|
@ -51,6 +51,9 @@ func RunTSH(app *kingpin.Application) error {
|
|||
scpIsDir := scp.Flag("recursively", "Source path is a directory").Short('r').Bool()
|
||||
scpPort := scp.Flag("port", "Remote server port").Short('P').String()
|
||||
|
||||
share := app.Command("share", "share")
|
||||
join := app.Command("join", "join")
|
||||
|
||||
selectedCommand := kingpin.MustParse(app.Parse(os.Args[1:]))
|
||||
|
||||
if (selectedCommand == getServers.FullCommand()) && (len(*proxy) == 0) {
|
||||
|
@ -93,6 +96,10 @@ func RunTSH(app *kingpin.Application) error {
|
|||
case scp.FullCommand():
|
||||
err = SCP(*proxy, *scpSource, *scpDest, *scpIsDir, *scpPort,
|
||||
authMethods, hostKeyCallback)
|
||||
case share.FullCommand():
|
||||
err = Share("localhost:33009", "localhost:33010", "localhost:33011", authMethods, hostKeyCallback)
|
||||
case join.FullCommand():
|
||||
err = Join(*proxy, "", authMethods, hostKeyCallback)
|
||||
}
|
||||
|
||||
return err
|
||||
|
|
|
@ -21,11 +21,13 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"os/user"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/gravitational/teleport/lib/auth"
|
||||
"github.com/gravitational/teleport/lib/client"
|
||||
"github.com/gravitational/teleport/lib/hangout"
|
||||
"github.com/gravitational/teleport/lib/services"
|
||||
|
@ -34,7 +36,6 @@ import (
|
|||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/gravitational/trace"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/crypto/ssh/agent"
|
||||
)
|
||||
|
||||
func SSH(target, proxyAddress, command, port string, authMethods []ssh.AuthMethod, hostKeyCallback utils.HostKeyCallback) error {
|
||||
|
@ -79,6 +80,11 @@ func SSH(target, proxyAddress, command, port string, authMethods []ssh.AuthMetho
|
|||
return trace.Wrap(err)
|
||||
}
|
||||
}
|
||||
return shell(c, address)
|
||||
}
|
||||
|
||||
func shell(c *client.NodeClient, address string) error {
|
||||
|
||||
defer c.Close()
|
||||
|
||||
// disable input buffering
|
||||
|
@ -272,14 +278,65 @@ func SCP(proxyAddress, source, dest string, isDir bool, port string, authMethods
|
|||
return nil
|
||||
}
|
||||
|
||||
func Share(proxyAddress, nodeListeningAddress, authListeningAddress,
|
||||
authMethods []ssh.AuthMethod, hostKeyCallback utils.HostKeyCallback) {
|
||||
hangoutServer := hangout.New(proxyAddress, nodeListeningAddress,
|
||||
authListeningAddress, authMethods, hostKeyCallback)
|
||||
func Share(hangoutProxyAddress, nodeListeningAddress, authListeningAddress string,
|
||||
authMethods []ssh.AuthMethod, hostKeyCallback utils.HostKeyCallback) error {
|
||||
hangoutServer, err := hangout.New(hangoutProxyAddress, nodeListeningAddress,
|
||||
authListeningAddress, false, authMethods, hostKeyCallback)
|
||||
|
||||
return SSH(nodeListeningAddress, "", "", "", []ssh.AuthMethod{h.AuthMethod}, h.HostKeyCallback)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
return SSH(u.Username+"@"+nodeListeningAddress, "", "", "", []ssh.AuthMethod{hangoutServer.ClientAuthMethod}, hangoutServer.HostKeyCallback)
|
||||
}
|
||||
|
||||
func Join(proxyAddress, nodeAddress, authAddress, userPassword string) {
|
||||
func Join(proxyAddress, hangoutToken string, authMethods []ssh.AuthMethod, hostKeyCallback utils.HostKeyCallback) error {
|
||||
hangoutServer, err := hangout.New("localhost:33009", "localhost:33010",
|
||||
"localhost:33011", false, authMethods, hostKeyCallback)
|
||||
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
time.Sleep(time.Second * 1)
|
||||
|
||||
hangoutToken = hangoutServer.Token
|
||||
hInfo, err := hangout.UnmarshalHangoutInfo(hangoutToken)
|
||||
|
||||
proxy, err := client.ConnectToProxy(proxyAddress, authMethods, hostKeyCallback, "123")
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
hangoutAuthMethod, err := auth.NewTokenAuth(hangout.HangoutUser, hInfo.HangoutPassword)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
authConn, err := proxy.ConnectToHangout(hInfo.HangoutID+":"+hInfo.AuthPort, hangoutAuthMethod, nil, hangout.HangoutUser)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
authClient, err := auth.NewClientFromSSHClient(authConn.Client)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
nodeAuthMethod, nodeHostKeyCallback, err := hangout.Authorize(authClient, hInfo.HangoutPassword[0:100])
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
nodeConn, err := proxy.ConnectToHangout(hInfo.HangoutID+":"+hInfo.NodePort, []ssh.AuthMethod{nodeAuthMethod}, nodeHostKeyCallback, hInfo.OSUser)
|
||||
if err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
return shell(nodeConn, hInfo.HangoutID)
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import (
|
|||
"github.com/gravitational/teleport/lib/backend/boltbk"
|
||||
"github.com/gravitational/teleport/lib/backend/encryptedbk"
|
||||
"github.com/gravitational/teleport/lib/backend/encryptedbk/encryptor"
|
||||
"github.com/gravitational/teleport/lib/client"
|
||||
"github.com/gravitational/teleport/lib/events/boltlog"
|
||||
"github.com/gravitational/teleport/lib/limiter"
|
||||
"github.com/gravitational/teleport/lib/recorder/boltrec"
|
||||
|
|
Loading…
Reference in a new issue