Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ Configurations can be set via flags or environment variables. To view available
| Configuration | Flag | Environment Variable | Default Value | Description |
| --- | --- | --- | --- | --- |
| Allowed hostnames | `--allowed-hostnames` | `ALLOWED_HOSTNAMES` | `"localhost"` | Comma delimited list of hostnames that are allowed to connect to the websocket |
| Authentication | `--authentication` | `AUTHENTICATION` | `""` | If set, require this *username*:*password* using HTTP Basic Authorization |
| Arguments | `--arguments` | `ARGUMENTS` | `"-l"` | Comma delimited list of arguments that should be passed to the target binary |
| Command | `--command` | `COMMAND` | `"/bin/bash"` | Absolute path to the binary to run |
| Connection error limit | `--connection-error-limit` | `CONNECTION_ERROR_LIMIT` | `10` | Number of times a connection should be re-attempted by the server to the XTerm.js frontend before the connection is considered dead and shut down |
Expand Down
5 changes: 5 additions & 0 deletions cmd/cloudshell/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ var conf = config.Map{
Usage: "comma-delimited list of hostnames that are allowed to connect to the websocket",
Shorthand: "H",
},
"authentication": &config.String{
Default: "",
Usage: "require this username:password using HTTP Basic Authorization",
Shorthand: "A",
},
"arguments": &config.StringSlice{
Default: []string{},
Usage: "comma-delimited list of arguments that should be passed to the terminal command",
Expand Down
9 changes: 8 additions & 1 deletion cmd/cloudshell/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func runE(_ *cobra.Command, _ []string) error {
connectionErrorLimit := conf.GetInt("connection-error-limit")
arguments := conf.GetStringSlice("arguments")
allowedHostnames := conf.GetStringSlice("allowed-hostnames")
authentication := conf.GetString("authentication")
keepalivePingTimeout := time.Duration(conf.GetInt("keepalive-ping-timeout")) * time.Second
maxBufferSizeBytes := conf.GetInt("max-buffer-size-bytes")
pathLiveness := conf.GetString("path-liveness")
Expand Down Expand Up @@ -131,11 +132,17 @@ func runE(_ *cobra.Command, _ []string) error {
}
}(time.NewTicker(time.Second * 30))

var handler http.Handler = router
handler = addIncomingRequestLogging(handler)
if authentication != "" {
handler = addAuthentication(handler, authentication)
}

// listen
listenOnAddress := fmt.Sprintf("%s:%v", serverAddress, serverPort)
server := http.Server{
Addr: listenOnAddress,
Handler: addIncomingRequestLogging(router),
Handler: handler,
}

log.Infof("starting server on interface:port '%s'...", listenOnAddress)
Expand Down
14 changes: 14 additions & 0 deletions cmd/cloudshell/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,17 @@ func addIncomingRequestLogging(next http.Handler) http.Handler {
createRequestLog(r).Infof("request completed in %vms", float64(duration.Nanoseconds())/1000000)
})
}

func addAuthentication(next http.Handler, authentication string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)

username, password, ok := r.BasicAuth()
if !ok || username + ":" + password != authentication {
http.Error(w, "Unauthorized", 401)
return
}

next.ServeHTTP(w, r)
})
}
2 changes: 1 addition & 1 deletion pkg/xtermjs/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func getConnectionUpgrader(
return true
}
}
logger.Warnf("failed to find '%s' in the list of allowed hostnames ('%s')", requesterHostname)
logger.Warnf("failed to find '%s' in the list of allowed hostnames ('%s')", requesterHostname, allowedHostnames)
return false
},
HandshakeTimeout: 0,
Expand Down