Skip to content

Commit

Permalink
refact watch conf
Browse files Browse the repository at this point in the history
  • Loading branch information
akhenakh committed Sep 17, 2024
1 parent bbeef07 commit 3bda1c0
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 110 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Deploy the app.
kubectl apply -f deployment/sshjump-deployment.yaml
```

Finally you need to open a TCP port to SSHJump (This example use the Gateway API and Envoy):
Finally, you need to open a TCP port to SSHJump (This example use the Gateway API and Envoy):

```sh
kubectl apply -f deployment/sshjump-tcp.yaml
Expand Down Expand Up @@ -167,7 +167,7 @@ There is a `Dockerfile` to be used with Docker & Podman too.
- [X] logs
- [X] user tunnel connection metric
- [ ] allow/deny metrics
- [ ] reload config on changes
- [X] reload config on changes
- [ ] config map example
- [X] kubernetes example
- [ ] helm example
Expand Down
65 changes: 15 additions & 50 deletions cmd/sshjump/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type EnvConfig struct {
ConfigPath string `env:"CONFIG_PATH" envDefault:"sshjump.yaml"`
Host string `env:"HOST" envDefault:"0.0.0.0"`
Port int `env:"PORT" envDefault:"2222"`
PrivateKeyPath string `env:"PRIVATE_KEY_PATH" envDefault:"ssh_host_rsa_key"`
PrivateKeyPath string `env:"PRIVATE_KEY_PATH"`
HealthPort int `env:"HEALTH_PORT" envDefault:"6666"`
HTTPMetricsPort int `env:"METRICS_PORT" envDefault:"8888"`
KubeConfigPath string `env:"KUBE_CONFIG_PATH"` // Set the path of a kubeconfig file when running outside a cluster
Expand All @@ -47,46 +47,6 @@ var (
httpMetricsServer *http.Server
)

// readKeys reads all the keys from the config file
// it does not break if some keys are invalid because
// the same function is used to reload to file it changes
// and the system needs to keep running.
func readKeys(logger *slog.Logger, cfg SSHJumpConfig) map[string]Permission {
m := make(map[string]Permission)
for i, perm := range cfg.Permissions {
if perm.Username == "" {
logger.Warn("invalid config no username", "index", i)

continue
}

// testing for username duplicates
if _, exist := m[perm.Username]; exist {
logger.Warn("duplicate username entry",
"username", perm.Username,
"index", i)

continue
}

key, _, _, _, err := ssh.ParseAuthorizedKey([]byte(perm.AuthorizedKey))
if err != nil {
logger.Warn("invalid key",
"error", err,
"username", perm.Username,
"key", perm.AuthorizedKey,
"index", i)

continue
}

perm.Key = key
m[perm.Username] = perm
}

return m
}

func main() {
var envCfg EnvConfig
if err := env.Parse(&envCfg); err != nil {
Expand All @@ -97,7 +57,7 @@ func main() {

keys, err := readPermission(logger, envCfg.ConfigPath)
if err != nil {
logger.Error("can't read permissions, aborting", "path", envCfg.ConfigPath)
logger.Error("can't read permissions, aborting", "path", envCfg.ConfigPath, "error", err)
os.Exit(1)
}

Expand Down Expand Up @@ -141,7 +101,7 @@ func main() {
return grpcHealthServer.Serve(hln)
})

signer, err := createSigner(envCfg, logger)
signer, err := createSigner(logger, envCfg)
if err != nil {
logger.Error("can't get valid host key", "error", err)
os.Exit(1)
Expand Down Expand Up @@ -232,19 +192,19 @@ func main() {
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer shutdownCancel()

s.StopWatchConf()

if httpMetricsServer != nil {
_ = httpMetricsServer.Shutdown(shutdownCtx)
}

if sshServer != nil {
sshServer.Shutdown(ctx) //nolint:errcheck
}

if grpcHealthServer != nil {
grpcHealthServer.GracefulStop()
}

if sshServer != nil {
sshServer.Shutdown(ctx) //nolint:errcheck
}
s.StopWatchConf()

err = g.Wait()
if err != nil {
Expand All @@ -268,7 +228,7 @@ func readPermission(logger *slog.Logger, path string) (map[string]Permission, er
return readKeys(logger, cfg), nil
}

func createSigner(envCfg EnvConfig, logger *slog.Logger) (gossh.Signer, error) {
func createSigner(logger *slog.Logger, envCfg EnvConfig) (gossh.Signer, error) {
// no key provided generate one
if envCfg.PrivateKeyPath == "" {
k, err := keygen.New("id_ed25519", keygen.WithKeyType(keygen.Ed25519), keygen.WithWrite())
Expand All @@ -281,6 +241,8 @@ func createSigner(envCfg EnvConfig, logger *slog.Logger) (gossh.Signer, error) {
return nil, fmt.Errorf("can't parse generated private key: %w", err)
}

logger.Warn("no host private key provided, generating ephemeral key")

return gens, nil
}
// reading private key
Expand Down Expand Up @@ -328,7 +290,10 @@ func createKubeClient(envCfg EnvConfig, logger *slog.Logger) (*kubernetes.Client

func createLogger(envCfg EnvConfig) *slog.Logger {
programLevel := new(slog.LevelVar)
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: programLevel}))
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
AddSource: true,
Level: programLevel,
}))
slog.SetDefault(logger)

switch strings.ToUpper(envCfg.LogLevel) {
Expand Down
40 changes: 40 additions & 0 deletions cmd/sshjump/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,3 +346,43 @@ func (srv *Server) StopWatchConf() {
_ = srv.configWatcher.Close()
}
}

// readKeys reads all the keys from the config file
// it does not break if some keys are invalid because
// the same function is used to reload to file it changes
// and the system needs to keep running.
func readKeys(logger *slog.Logger, cfg SSHJumpConfig) map[string]Permission {
m := make(map[string]Permission)
for i, perm := range cfg.Permissions {
if perm.Username == "" {
logger.Warn("invalid config no username", "index", i)

continue
}

// testing for username duplicates
if _, exist := m[perm.Username]; exist {
logger.Warn("duplicate username entry",
"username", perm.Username,
"index", i)

continue
}

key, _, _, _, err := ssh.ParseAuthorizedKey([]byte(perm.AuthorizedKey))
if err != nil {
logger.Warn("invalid key",
"error", err,
"username", perm.Username,
"key", perm.AuthorizedKey,
"index", i)

continue
}

perm.Key = key
m[perm.Username] = perm
}

return m
}
19 changes: 0 additions & 19 deletions cmd/testconn/main.go

This file was deleted.

39 changes: 0 additions & 39 deletions cmd/testfwd/main.go

This file was deleted.

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/charmbracelet/log v0.4.0
github.com/charmbracelet/ssh v0.0.0-20240725163421-eb71b85b27aa
github.com/charmbracelet/wish v1.4.3
github.com/fsnotify/fsnotify v1.7.0
github.com/gliderlabs/ssh v0.3.7
github.com/prometheus/client_golang v1.20.3
golang.org/x/crypto v0.26.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/gaissmai/bart v0.11.1 h1:5Uv5XwsaFBRo4E5VBcb9TzY8B7zxFf+U7isDxqOrRfc=
Expand Down

0 comments on commit 3bda1c0

Please sign in to comment.