mirror of
https://github.com/jsiebens/ionscale.git
synced 2026-03-31 15:07:49 +01:00
feat: ssh recording
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/jsiebens/ionscale/pkg/client/ionscale"
|
||||
"net/netip"
|
||||
"strings"
|
||||
@@ -48,6 +49,24 @@ func (a ACLPolicy) IsValidPeer(src *Machine, dest *Machine) bool {
|
||||
}
|
||||
}
|
||||
|
||||
for _, ssh := range a.SSH {
|
||||
selfIps, otherIps := a.translateDestinationAliasesToMachineIPs(ssh.Recorder, dest)
|
||||
if len(selfIps) != 0 {
|
||||
for _, alias := range ssh.Destination {
|
||||
if len(a.translateSourceAliasToMachineIPs(alias, src, &dest.User)) != 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(otherIps) != 0 {
|
||||
for _, alias := range ssh.Destination {
|
||||
if len(a.translateSourceAliasToMachineIPs(alias, src, nil)) != 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -100,9 +119,36 @@ func (a ACLPolicy) BuildFilterRules(peers []Machine, dst *Machine) []tailcfg.Fil
|
||||
rules = matchSourceAndAppendRule(rules, acl.Source, other, nil)
|
||||
}
|
||||
|
||||
for _, acl := range a.SSH {
|
||||
ssh := a.prepareFilterRulesFromSSH(dst, acl)
|
||||
rules = matchSourceAndAppendRule(rules, acl.Destination, ssh, nil)
|
||||
}
|
||||
|
||||
return rules
|
||||
}
|
||||
|
||||
func normalizeSSHRecordersToDestinationAliases(recorders []string) []string {
|
||||
recorderAliases := make([]string, 0)
|
||||
for _, alias := range recorders {
|
||||
if strings.HasPrefix(alias, "tag:") {
|
||||
recorderAliases = append(recorderAliases, fmt.Sprintf("%s:80", alias))
|
||||
}
|
||||
}
|
||||
return recorderAliases
|
||||
}
|
||||
|
||||
func (a ACLPolicy) prepareFilterRulesFromSSH(candidate *Machine, entry ionscale.ACLSSH) []tailcfg.FilterRule {
|
||||
_, otherDstPorts := a.translateDestinationAliasesToMachineNetPortRanges(normalizeSSHRecordersToDestinationAliases(entry.Recorder), candidate)
|
||||
|
||||
var otherFilterRules []tailcfg.FilterRule
|
||||
|
||||
if len(otherDstPorts) != 0 {
|
||||
otherFilterRules = append(otherFilterRules, tailcfg.FilterRule{IPProto: []int{protocolTCP}, DstPorts: otherDstPorts})
|
||||
}
|
||||
|
||||
return otherFilterRules
|
||||
}
|
||||
|
||||
func (a ACLPolicy) prepareFilterRulesFromACL(candidate *Machine, acl ionscale.ACLEntry) ([]tailcfg.FilterRule, []tailcfg.FilterRule) {
|
||||
proto := parseProtocol(acl.Protocol)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package domain
|
||||
|
||||
import (
|
||||
"github.com/jsiebens/ionscale/pkg/client/ionscale"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"tailscale.com/tailcfg"
|
||||
)
|
||||
@@ -29,6 +30,20 @@ func (a ACLPolicy) BuildSSHPolicy(srcs []Machine, dst *Machine) *tailcfg.SSHPoli
|
||||
return result
|
||||
}
|
||||
|
||||
expandRecorderAliases := func(aliases []string) []netip.AddrPort {
|
||||
result := make([]netip.AddrPort, 0)
|
||||
|
||||
for _, alias := range aliases {
|
||||
for _, src := range append(srcs, *dst) {
|
||||
if src.HasTag(alias) {
|
||||
result = append(result, netip.AddrPortFrom(*src.IPv4.Addr, 80))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
for _, rule := range a.SSH {
|
||||
if rule.Action != "accept" && rule.Action != "check" {
|
||||
continue
|
||||
@@ -46,6 +61,17 @@ func (a ACLPolicy) BuildSSHPolicy(srcs []Machine, dst *Machine) *tailcfg.SSHPoli
|
||||
}
|
||||
}
|
||||
|
||||
if len(rule.Recorder) != 0 {
|
||||
action.Recorders = expandRecorderAliases(rule.Recorder)
|
||||
action.Message = "# This session is being recorded.\n"
|
||||
if rule.EnforceRecorder {
|
||||
action.OnRecordingFailure = &tailcfg.SSHRecorderFailureAction{
|
||||
RejectSessionWithMessage: "# Session rejected: failed to start session recording.",
|
||||
TerminateSessionWithMessage: "# Session terminated: failed to record session.",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selfUsers, otherUsers := a.expandSSHDstToSSHUsers(dst, rule)
|
||||
|
||||
if len(selfUsers) != 0 {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/jsiebens/ionscale/pkg/client/ionscale"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"tailscale.com/tailcfg"
|
||||
@@ -385,14 +383,6 @@ func TestACLPolicy_BuildSSHPolicy_WithTagsAndActionCheck(t *testing.T) {
|
||||
assert.Nil(t, actualRules.Rules)
|
||||
}
|
||||
|
||||
func printRules(rules []*tailcfg.SSHRule) {
|
||||
indent, err := json.MarshalIndent(rules, "", " ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(string(indent))
|
||||
}
|
||||
|
||||
func sshPrincipalsFromMachines(machines ...Machine) []*tailcfg.SSHPrincipal {
|
||||
x := StringSet{}
|
||||
for _, m := range machines {
|
||||
|
||||
Reference in New Issue
Block a user