Skip to content

Commit

Permalink
Auto-merge for PR #18 via VersionBot
Browse files Browse the repository at this point in the history
Misc Fixes
  • Loading branch information
resin-io-versionbot[bot] authored Jun 7, 2017
2 parents a9b17ff + 7d53d02 commit ceed9a6
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 61 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
This project adheres to [Semantic Versioning](http://semver.org/).

## v1.2.0 - 2017-06-07

* Update README [Will Boyce]
* Update Makefile and add circleci config [Will Boyce]
* Lint fixes [Will Boyce]
* Do not pass env vars from client to shell by default [Will Boyce]

## v1.1.2 - 2017-05-18

* Also use ecdsa and dsa host keys [Will Boyce]
Expand Down
92 changes: 54 additions & 38 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,48 +1,64 @@
PKG := resin
VERSION := $(shell git describe --abbrev=0 --tags --dirty)
EXECUTABLE := sshproxy
USERNAME ?= resin-io
PROJECT ?= sshproxy
PACKAGE ?= resin
EXECUTABLE ?= sshproxy
VERSION := $(shell git describe --abbrev=0 --tags)
BUILD_PLATFORMS ?= darwin/amd64 freebsd/amd64 linux/arm linux/arm64 linux/amd64 openbsd/amd64 netbsd/amd64
SHASUM ?= sha256sum

all: bin/$(EXECUTABLE)

bin/$(EXECUTABLE):
go build -o "$@" ./$(PKG)
dep:
go get -v ./...
go get github.com/mitchellh/gox

release: release/$(EXECUTABLE)-$(VERSION)_linux_arm5.tar.bz2 \
release/$(EXECUTABLE)-$(VERSION)_linux_arm7.tar.bz2 \
release/$(EXECUTABLE)-$(VERSION)_darwin_386.tar.bz2 \
release/$(EXECUTABLE)-$(VERSION)_linux_386.tar.bz2 \
release/$(EXECUTABLE)-$(VERSION)_darwin_amd64.tar.bz2 \
release/$(EXECUTABLE)-$(VERSION)_freebsd_amd64.tar.bz2 \
release/$(EXECUTABLE)-$(VERSION)_linux_amd64.tar.bz2
lint-dep: dep
go get github.com/golang/lint/golint
go get golang.org/x/tools/cmd/goimports

release-sign: release
for f in release/*.tar.bz2; do gpg --armor --detach-sign $$f; done
lint: lint-dep
goimports -d .
gofmt -e -l -s .
golint -set_exit_status ./...
go tool vet .

test-dep: dep
go test -i -v ./...

test: test-dep
go test -v ./...

release: $(addsuffix .tar.gz,$(addprefix build/$(EXECUTABLE)-$(VERSION)_,$(subst /,_,$(BUILD_PLATFORMS))))
release: $(addsuffix .tar.gz.sha256,$(addprefix build/$(EXECUTABLE)-$(VERSION)_,$(subst /,_,$(BUILD_PLATFORMS))))

upload-dep:
go get github.com/aktau/github-release

upload: lint test upload-dep
ifndef GITHUB_TOKEN
$(error GITHUB_TOKEN is undefined)
endif
git describe --exact-match --tags >/dev/null

git log --format='* %s' --grep=$(VERSION) --invert-grep --no-merges $(shell git describe --tag --abbrev=0 $(VERSION)^)...$(VERSION)
$(foreach FILE, $(addsuffix .tar.gz,$(addprefix build/$(EXECUTABLE)-$(VERSION)_,$(subst /,_,$(BUILD_PLATFORMS)))), \
echo github-release upload -u $(USERNAME) -r $(EXECUTABLE) -t $(VERSION) -n $(notdir $(FILE)) -f $(FILE) && \
echo github-release upload -u $(USERNAME) -r $(EXECUTABLE) -t $(VERSION) -n $(notdir $(addsuffix .sha256,$(FILE))) -f $(addsuffix .sha256,$(FILE)) ;)

clean:
rm -vrf bin/* build/* release/*

# arm
build/linux_arm5/$(EXECUTABLE):
GOARM=5 GOARCH=arm GOOS=linux go build -o "$@" ./$(PKG)
build/linux_arm7/$(EXECUTABLE):
GOARM=7 GOARCH=arm GOOS=linux go build -o "$@" ./$(PKG)

# 386
build/darwin_386/$(EXECUTABLE):
GOARCH=386 GOOS=darwin go build -o "$@" ./$(PKG)
build/linux_386/$(EXECUTABLE):
GOARCH=386 GOOS=linux go build -o "$@" ./$(PKG)

# amd64
build/darwin_amd64/$(EXECUTABLE):
GOARCH=amd64 GOOS=darwin go build -o "$@" ./$(PKG)
build/freebsd_amd64/$(EXECUTABLE):
GOARCH=amd64 GOOS=freebsd go build -o "$@" ./$(PKG)
build/linux_amd64/$(EXECUTABLE):
GOARCH=amd64 GOOS=linux go build -o "$@" ./$(PKG)
rm -vrf bin/* build/*

# binary
bin/$(EXECUTABLE): dep
go build -o "$@" -v ./$(PACKAGE)
# release binaries
build/%/$(EXECUTABLE): dep
gox -parallel=1 -osarch=$(subst _,/,$(subst build/,,$(@:/$(EXECUTABLE)=))) -output="build/{{.OS}}_{{.Arch}}/$(EXECUTABLE)" ./$(PACKAGE)
# compressed artifacts
release/$(EXECUTABLE)-$(VERSION)_%.tar.bz2: build/%/$(EXECUTABLE)
tar -jcvf "$@" -C "`dirname $<`" $(EXECUTABLE)
build/$(EXECUTABLE)-$(VERSION)_%.tar.gz: build/%/$(EXECUTABLE)
tar -zcf "$@" -C "$(dir $<)" $(EXECUTABLE)
# signed artifacts
%.sha256: %
cd $(dir $<) && $(SHASUM) $(notdir $<) > $(addsuffix .sha256,$(notdir $<))

.PHONY: clean release-sign
.PHONY: dep lint-dep lint test-dep test release upload-dep upload clean
24 changes: 24 additions & 0 deletions circle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
version: 2
jobs:
build:
working_directory: /go/src/github.com/resin-io/sshproxy
docker:
- image: golang:1.8.3-stretch
steps:
- checkout
- run:
name: Install Dependencies
command: make dep
- run:
name: Lint Code
command: make lint
- run:
name: Run Tests
command: make test
- run:
name: Build Releases
command: make -j release
- deploy:
name: Upload Releases
command: if git describe --exact-match --tags 2>/dev/null; then make upload; fi
15 changes: 12 additions & 3 deletions resin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ work dir. The following config file formats are supported:
* [HCL](https://github.com/hashicorp/hcl) (`sshproxy.hcl`)
* [Java .properties](https://en.wikipedia.org/wiki/.properties) (`sshproxy.properties`)

There are a total of 8 configuration options. With the exception of `dir`
There are a total of 9 configuration options. With the exception of `dir`
they can all be set via commandline, environment or config file.

| Name | Commandline | Environment | Config |
Expand All @@ -27,9 +27,11 @@ they can all be set via commandline, environment or config file.
| Shell | `--shell` `-s` | `SSHPROXY_SHELL` | `shell` |
| Auth Failed Banner | `--auth-failed-banner` `-b` | `SSHPROXY_AUTH_FAILED_BANNER` | `auth-failed-banner` |
| Max Auth Tries | `--max-auth-tries` `-m` | `SSHPROXY_MAX_AUTH_TRIES` | `max-auth-tries` |
| Allow Env | `--allow-env` `-E` | `SSHPROXY_ALLOW_ENV` | `allow-env` |

```
Usage of sshproxy:
-E, --allow-env Pass environment from client to shell (default: false) (warning: security implications)
-H, --apihost string Resin API Host (default "api.resin.io")
-K, --apikey string Resin API Key (required)
-P, --apiport string Resin API Port (default "443")
Expand All @@ -40,9 +42,9 @@ Usage of sshproxy:
-s, --shell string Path to shell to execute post-authentication (default "shell.sh")
```

## Unauth Template
## Auth Failed Banner/Template

The 'unauth template' is a template rendered and displayed to the user after failed authentication. It should be a
The 'auth failed banner' is a template rendered and displayed to the user after failed authentication. It should be a
[Go template](https://golang.org/pkg/text/template/) has two available properties; `.user` and `.fingerprints`.

## Example Usage
Expand All @@ -67,3 +69,10 @@ SSH_ORIGINAL_COMMAND=some command
LC_CTYPE=en_GB.UTF-8
_=/usr/bin/env
```

### Building

The `Makefile` in the project root contains all necessary rules for linting, testing and building sshproxy packages.
Building via a Docker image can be achieved with, for example:
`docker run --rm -v $PWD:/go/src/github.com/resin-io/sshproxy golang make -C /go/src/github.com/resin-io/sshproxy lint test release`.

13 changes: 7 additions & 6 deletions resin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,8 @@ func (a *authHandler) keyboardInteractiveCallback(meta ssh.ConnMetadata, client
delete(a.rejectedSessions, sessionKey)
}
return nil, errors.New("Unauthorised")
} else {
a.rejectedSessions[sessionKey] = 1
}
a.rejectedSessions[sessionKey] = 1

// fetch user's keys...
keys, err := a.getUserKeys(meta.User())
Expand Down Expand Up @@ -151,6 +150,7 @@ func init() {
pflag.CommandLine.StringP("shell", "s", "shell.sh", "Path to shell to execute post-authentication")
pflag.CommandLine.StringP("auth-failed-banner", "b", "", "Path to template displayed after failed authentication")
pflag.CommandLine.IntP("max-auth-tries", "m", 0, "Maximum number of authentication attempts per connection (default 0; unlimited)")
pflag.CommandLine.BoolP("allow-env", "E", false, "Pass environment from client to shell (default: false) (warning: security implications)")

viper.BindPFlags(pflag.CommandLine)
viper.SetConfigName("sshproxy")
Expand All @@ -163,6 +163,7 @@ func init() {
viper.BindEnv("shell")
viper.BindEnv("auth-failed-banner", "SSHPROXY_AUTH_FAILED_BANNER")
viper.BindEnv("max-auth-tries", "SSHPROXY_MAX_AUTH_TRIES")
viper.BindEnv("allow-env", "SSHPROXY_ALLOW_ENV")
}

func main() {
Expand All @@ -186,7 +187,7 @@ func main() {
}

// if paths are relative, prepend with dir and verify files exist
fix_path_check_exists := func(key string) {
fixPathCheckExists := func(key string) {
if viper.GetString(key)[0] != '/' {
viper.Set(key, path.Join(viper.GetString("dir"), viper.GetString(key)))
}
Expand All @@ -195,9 +196,9 @@ func main() {
os.Exit(2)
}
}
fix_path_check_exists("shell")
fixPathCheckExists("shell")
if viper.GetString("auth-failed-banner") != "" {
fix_path_check_exists("auth-failed-banner")
fixPathCheckExists("auth-failed-banner")
}

apiURL := fmt.Sprintf("https://%s:%d", viper.GetString("apihost"), viper.GetInt("apiport"))
Expand All @@ -216,5 +217,5 @@ func main() {
sshConfig.KeyboardInteractiveCallback = auth.keyboardInteractiveCallback
}

sshproxy.New(viper.GetString("dir"), viper.GetString("shell"), sshConfig).Listen(viper.GetString("port"))
sshproxy.New(viper.GetString("dir"), viper.GetString("shell"), viper.GetBool("allow-env"), sshConfig).Listen(viper.GetString("port"))
}
32 changes: 18 additions & 14 deletions sshproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,22 @@ import (

// Server holds server specific configuration data.
type Server struct {
keyDir string
config *ssh.ServerConfig
shell string
keyDir string
config *ssh.ServerConfig
shell string
passEnv bool
}

// New takes a directory to generate/store server keys, a path to the shell
// and an ssh.ServerConfig. If no ServerConfig is provided, then
// ServerConfig.NoClientAuth is set to true. ed25519, rsa, ecdsa and dsa
// keys are loaded, and generated if they do not exist. Returns a new Server.
func New(keyDir, shell string, sshConfig *ssh.ServerConfig) *Server {
func New(keyDir, shell string, passEnv bool, sshConfig *ssh.ServerConfig) *Server {
s := &Server{
keyDir: keyDir,
config: sshConfig,
shell: shell,
keyDir: keyDir,
config: sshConfig,
shell: shell,
passEnv: passEnv,
}
if s.config == nil {
s.config = &ssh.ServerConfig{
Expand Down Expand Up @@ -160,13 +162,15 @@ func (s *Server) handleRequests(reqs <-chan *ssh.Request, channel ssh.Channel, c
log.Printf("New SSH request '%s' from %s", req.Type, conn.RemoteAddr())
switch req.Type {
case "env":
// append client env to the command environment
keyLen := req.Payload[3]
valLen := req.Payload[keyLen+7]
key := string(req.Payload[4 : keyLen+4])
val := string(req.Payload[keyLen+8 : keyLen+valLen+8])
env = append(env, fmt.Sprintf("%s=%s", key, val))
req.Reply(true, nil)
if s.passEnv {
// append client env to the command environment
keyLen := req.Payload[3]
valLen := req.Payload[keyLen+7]
key := string(req.Payload[4 : keyLen+4])
val := string(req.Payload[keyLen+8 : keyLen+valLen+8])
env = append(env, fmt.Sprintf("%s=%s", key, val))
}
req.Reply(s.passEnv, nil)
case "pty-req":
// client has requested a PTY
wantsPty = true
Expand Down

0 comments on commit ceed9a6

Please sign in to comment.