Forward ssh2 ports into docker
This commit is contained in:
parent
45f63935cd
commit
5bceaa0d47
24 changed files with 745 additions and 117 deletions
110
internal/dis/component/ssh2/server_auth.go
Normal file
110
internal/dis/component/ssh2/server_auth.go
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
package ssh2
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gliderlabs/ssh"
|
||||
)
|
||||
|
||||
func (ssh2 *SSH2) setupAuth(server *ssh.Server) {
|
||||
server.PublicKeyHandler = ssh2.handleAuth
|
||||
}
|
||||
|
||||
// ssh2Key is a type of context keys for this package
|
||||
type ssh2Key int
|
||||
|
||||
const (
|
||||
// permissions represents the permissions for the given session
|
||||
permission ssh2Key = iota
|
||||
)
|
||||
|
||||
func setPermissions(context ssh.Context, permissions map[string]bool) {
|
||||
context.SetValue(permission, permissions)
|
||||
}
|
||||
|
||||
// hasPermission checks if the given context permits access to the given slug.
|
||||
// The empty slug checks for global access.
|
||||
func hasPermission(context ssh.Context, slug string) bool {
|
||||
value, ok := context.Value(permission).(map[string]bool)
|
||||
return ok && value[slug]
|
||||
}
|
||||
|
||||
// getAnyPermission gets some instance the user has access to.
|
||||
// If the user does not have access to anything, returns "", false.
|
||||
// If the user has superuser access, but there are no instances, returns "", true.
|
||||
func getAnyPermission(context ssh.Context) (string, bool) {
|
||||
value, ok := context.Value(permission).(map[string]bool)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
|
||||
for slug, ok := range value {
|
||||
if ok && slug != "" {
|
||||
return slug, true
|
||||
}
|
||||
}
|
||||
|
||||
return "", (false || value[""])
|
||||
}
|
||||
|
||||
const authDelay = time.Second / 10
|
||||
|
||||
func (ssh2 *SSH2) handleAuth(ctx ssh.Context, key ssh.PublicKey) bool {
|
||||
return slowdown(func() (ok bool) {
|
||||
permissions := make(map[string]bool)
|
||||
|
||||
// grab the global permissions
|
||||
{
|
||||
globalKeys, err := ssh2.GlobalKeys()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
permissions[""] = isKey(globalKeys, key)
|
||||
ok = permissions[""]
|
||||
}
|
||||
|
||||
// grab permissions for each instance
|
||||
{
|
||||
instances, err := ssh2.Instances.All()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, instance := range instances {
|
||||
ikeys, err := instance.SSH().Keys()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
access := isKey(ikeys, key)
|
||||
|
||||
permissions[instance.Slug] = access || permissions[""]
|
||||
ok = ok || access
|
||||
}
|
||||
}
|
||||
|
||||
setPermissions(ctx, permissions)
|
||||
return
|
||||
}, authDelay)
|
||||
}
|
||||
|
||||
// slowdown invokes f immediatly, but only returns the result to the caller after at least duration.
|
||||
// It can be used to prevent timing attacks
|
||||
func slowdown[T any](f func() T, duration time.Duration) T {
|
||||
result := make(chan T, 1)
|
||||
go func() {
|
||||
result <- f()
|
||||
}()
|
||||
time.Sleep(duration)
|
||||
return <-result
|
||||
}
|
||||
|
||||
// isKey checks if keys contains key in O(len(keys))
|
||||
func isKey(keys []ssh.PublicKey, key ssh.PublicKey) bool {
|
||||
var res bool
|
||||
for _, ak := range keys {
|
||||
if ssh.KeysEqual(ak, key) {
|
||||
res = true
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue