Skip to content

Commit

Permalink
Merge pull request #7 from uselagoon/ssh-portal
Browse files Browse the repository at this point in the history
Implement SSH portal service
  • Loading branch information
smlx authored Jan 28, 2022
2 parents 5519324 + 1df571d commit a6f0ea8
Show file tree
Hide file tree
Showing 19 changed files with 820 additions and 127 deletions.
36 changes: 29 additions & 7 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,45 @@ jobs:
with:
version: latest
args: build --snapshot --rm-dist
- name: Upload binaries
uses: actions/upload-artifact@v2
with:
name: dist
path: dist
buildimage:
strategy:
matrix:
binary:
- service-api
- ssh-portal
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Download binaries
uses: actions/download-artifact@v2
with:
name: dist
path: dist
- name: Login to GHCR
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker metadata
id: service_api_meta
# this id is namespaced per matrix run
id: docker_metadata
uses: docker/metadata-action@v3
with:
images: ghcr.io/uselagoon/lagoon-ssh-portal/service-api
- name: Build and push service-api container image
images: ghcr.io/uselagoon/lagoon-ssh-portal/${{ matrix.binary }}
- name: Build and push ${{ matrix.binary }} container image
id: docker_build
uses: docker/build-push-action@v2
with:
push: true
tags: ${{ steps.service_api_meta.outputs.tags }}
labels: ${{ steps.service_api_meta.outputs.labels }}
file: deploy/service-api/Dockerfile
context: dist/lagoon-ssh-portal_linux_amd64
tags: ${{ steps.docker_metadata.outputs.tags }}
labels: ${{ steps.docker_metadata.outputs.labels }}
file: deploy/${{ matrix.binary }}/Dockerfile
context: dist/${{ matrix.binary }}_linux_amd64
36 changes: 29 additions & 7 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,48 @@ jobs:
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload binaries
uses: actions/upload-artifact@v2
with:
name: dist
path: dist
releaseimage:
strategy:
matrix:
binary:
- service-api
- ssh-portal
needs: release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Download binaries
uses: actions/download-artifact@v2
with:
name: dist
path: dist
- name: Login to GHCR
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker metadata
id: service_api_meta
# this id is namespaced per matrix run
id: docker_metadata
uses: docker/metadata-action@v3
with:
images: ghcr.io/uselagoon/lagoon-ssh-portal/service-api
images: ghcr.io/uselagoon/lagoon-ssh-portal/${{ matrix.binary }}
tags: |
${{ needs.tag.outputs.new-tag-version }}
latest
- name: Build and push service-api container image
- name: Build and push ${{ matrix.binary }} container image
id: docker_build
uses: docker/build-push-action@v2
with:
push: true
tags: ${{ steps.service_api_meta.outputs.tags }}
labels: ${{ steps.service_api_meta.outputs.labels }}
file: deploy/service-api/Dockerfile
context: dist/lagoon-ssh-portal_linux_amd64
tags: ${{ steps.docker_metadata.outputs.tags }}
labels: ${{ steps.docker_metadata.outputs.labels }}
file: deploy/${{ matrix.binary }}/Dockerfile
context: dist/${{ matrix.binary }}_linux_amd64
18 changes: 17 additions & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
builds:
- dir: cmd/service-api
- id: service-api
dir: cmd/service-api
binary: service-api
ldflags:
- >
-s -w -X main.date={{.Date}} -X "main.goVersion={{.Env.GOVERSION}}"
-X main.shortCommit={{.ShortCommit}} -X main.version={{.Version}}
env:
- CGO_ENABLED=0
goarch:
- amd64
- arm64
- id: ssh-portal
dir: cmd/ssh-portal
binary: ssh-portal
ldflags:
- >
-s -w -X main.date={{.Date}} -X "main.goVersion={{.Env.GOVERSION}}"
-X main.shortCommit={{.ShortCommit}} -X main.version={{.Version}}
env:
- CGO_ENABLED=0
goarch:
- amd64
- arm64
7 changes: 0 additions & 7 deletions cmd/service-api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@ import (
"go.uber.org/zap"
)

var (
date string
goVersion string
shortCommit string
version string
)

// CLI represents the command-line interface.
type CLI struct {
Debug bool `kong:"env='DEBUG',help='Enable debug logging'"`
Expand Down
28 changes: 4 additions & 24 deletions cmd/service-api/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ package main
import (
"context"
"fmt"
"os"
"os/signal"

"github.com/go-sql-driver/mysql"
"github.com/uselagoon/ssh-portal/internal/keycloak"
"github.com/uselagoon/ssh-portal/internal/lagoondb"
"github.com/uselagoon/ssh-portal/internal/metrics"
"github.com/uselagoon/ssh-portal/internal/server"
"github.com/uselagoon/ssh-portal/internal/serviceapi"
"github.com/uselagoon/ssh-portal/internal/signalctx"
"go.uber.org/zap"
)

Expand All @@ -26,25 +25,6 @@ type ServeCmd struct {
NATSServer string `kong:"required,env='NATS_URL',help='NATS server URL (nats://... or tls://...)'"`
}

// getContext starts a goroutine to handle ^C gracefully, and returns a context
// with a "cancel" function which cleans up the signal handling and ensures the
// goroutine exits. This "cancel" function should be deferred in Run().
func getContext() (context.Context, func()) {
ctx, cancel := context.WithCancel(context.Background())
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt)
go func() {
select {
case <-signalChan:
cancel()
case <-ctx.Done():
}
<-signalChan
os.Exit(130) // https://tldp.org/LDP/abs/html/exitcodes.html
}()
return ctx, func() { signal.Stop(signalChan); cancel() }
}

// Run the serve command to service API requests.
func (cmd *ServeCmd) Run(log *zap.Logger) error {
// instrumentation requires a separate context because deferred Shutdown()
Expand All @@ -54,7 +34,7 @@ func (cmd *ServeCmd) Run(log *zap.Logger) error {
m := metrics.NewServer(log)
defer m.Shutdown(ictx) //nolint:errcheck
// get main process context
ctx, cancel := getContext()
ctx, cancel := signalctx.GetContext()
defer cancel()
// init lagoon DB client
dbConf := mysql.NewConfig()
Expand All @@ -74,5 +54,5 @@ func (cmd *ServeCmd) Run(log *zap.Logger) error {
return fmt.Errorf("couldn't init keycloak Client: %v", err)
}
// start serving NATS requests
return server.ServeNATS(ctx, log, l, k, cmd.NATSServer)
return serviceapi.ServeNATS(ctx, log, l, k, cmd.NATSServer)
}
7 changes: 7 additions & 0 deletions cmd/service-api/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ package main

import "fmt"

var (
date string
goVersion string
shortCommit string
version string
)

// VersionCmd represents the version command.
type VersionCmd struct{}

Expand Down
35 changes: 35 additions & 0 deletions cmd/ssh-portal/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

import (
"github.com/alecthomas/kong"
"go.uber.org/zap"
)

// CLI represents the command-line interface.
type CLI struct {
Debug bool `kong:"env='DEBUG',help='Enable debug logging'"`
Serve ServeCmd `kong:"cmd,default=1,help='(default) Serve service-api requests'"`
Version VersionCmd `kong:"cmd,help='Print version information'"`
}

func main() {
// parse CLI config
cli := CLI{}
kctx := kong.Parse(&cli,
kong.UsageOnError(),
)
// init logger
var log *zap.Logger
var err error
if cli.Debug {
log, err = zap.NewDevelopment(zap.AddStacktrace(zap.ErrorLevel))
} else {
log, err = zap.NewProduction()
}
if err != nil {
panic(err)
}
defer log.Sync() //nolint:errcheck
// execute CLI
kctx.FatalIfErrorf(kctx.Run(log))
}
50 changes: 50 additions & 0 deletions cmd/ssh-portal/serve.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package main

import (
"context"
"fmt"
"net"

"github.com/nats-io/nats.go"
"github.com/uselagoon/ssh-portal/internal/k8s"
"github.com/uselagoon/ssh-portal/internal/metrics"
"github.com/uselagoon/ssh-portal/internal/signalctx"
"github.com/uselagoon/ssh-portal/internal/sshportal"
"go.uber.org/zap"
)

// ServeCmd represents the serve command.
type ServeCmd struct {
NATSServer string `kong:"required,env='NATS_URL',help='NATS server URL (nats://... or tls://...)'"`
SSHServerPort uint `kong:"default='2222',env='SSH_SERVER_PORT',help='Port the SSH server will listen on for SSH client connections'"`
}

// Run the serve command to service API requests.
func (cmd *ServeCmd) Run(log *zap.Logger) error {
// instrumentation requires a separate context because deferred Shutdown()
// will exit immediately if the context is already done.
ictx := context.Background()
// init metrics
m := metrics.NewServer(log)
defer m.Shutdown(ictx) //nolint:errcheck
// get main process context
ctx, cancel := signalctx.GetContext()
defer cancel()
// get nats server connection
nc, err := nats.Connect(cmd.NATSServer)
if err != nil {
return fmt.Errorf("couldn't connect to NATS server: %v", err)
}
// start listening on TCP port
l, err := net.Listen("tcp", fmt.Sprintf(":%d", cmd.SSHServerPort))
if err != nil {
return fmt.Errorf("couldn't listen on port %d: %v", cmd.SSHServerPort, err)
}
// get kubernetes client
c, err := k8s.NewClient()
if err != nil {
return fmt.Errorf("couldn't create k8s client: %v", err)
}
// start serving SSH connection requests
return sshportal.Serve(ctx, log, nc, l, c)
}
20 changes: 20 additions & 0 deletions cmd/ssh-portal/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package main

import "fmt"

var (
date string
goVersion string
shortCommit string
version string
)

// VersionCmd represents the version command.
type VersionCmd struct{}

// Run the version command to print version information.
func (cmd *VersionCmd) Run() error {
fmt.Printf("Lagoon service-api %v (%v) compiled with %v on %v\n", version,
shortCommit, goVersion, date)
return nil
}
34 changes: 30 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,39 @@ go 1.17

require (
github.com/alecthomas/kong v0.2.18
github.com/gliderlabs/ssh v0.3.3
github.com/go-sql-driver/mysql v1.6.0
github.com/google/uuid v1.3.0
github.com/jmoiron/sqlx v1.3.4
github.com/nats-io/nats.go v1.13.1-0.20211018182449-f2416a8b1483
github.com/prometheus/client_golang v1.11.0
go.opentelemetry.io/otel v1.3.0
go.uber.org/zap v1.19.1
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
gopkg.in/square/go-jose.v2 v2.6.0
k8s.io/api v0.23.3
k8s.io/apimachinery v0.23.3
k8s.io/client-go v0.23.3
)

require (
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v1.2.1 // indirect
github.com/go-logr/stdr v1.2.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.6 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/nats-io/nats-server/v2 v2.6.4 // indirect
github.com/nats-io/nkeys v0.3.0 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
Expand All @@ -32,9 +47,20 @@ require (
go.opentelemetry.io/otel/trace v1.3.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
google.golang.org/appengine v1.6.6 // indirect
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e // indirect
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/klog/v2 v2.30.0 // indirect
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect
)
Loading

0 comments on commit a6f0ea8

Please sign in to comment.