mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-01 14:05:39 +00:00
ssh/tailssh: work around lack of scontext in SELinux
Trying to SSH when SELinux is enforced results in errors like: ``` ➜ ~ ssh ec2-user@<ip> Last login: Thu Jun 1 22:51:44 from <ip2> ec2-user: no shell: Permission denied Connection to <ip> closed. ``` while the `/var/log/audit/audit.log` has ``` type=AVC msg=audit(1685661291.067:465): avc: denied { transition } for pid=5296 comm="login" path="/usr/bin/bash" dev="nvme0n1p1" ino=2564 scontext=system_u:system_r:unconfined_service_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0 tclass=process permissive=0 ``` The right fix here would be to somehow install the appropriate context when tailscale is installed on host, but until we figure out a way to do that stop using the `login` cmd in these situations. Updates #4908 Signed-off-by: Maisem Ali <maisem@tailscale.com>
This commit is contained in:
parent
0ed088b47b
commit
2ae670eb71
@ -7,8 +7,10 @@
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
@ -434,3 +436,12 @@ func etcAptSourceFileIsDisabled(r io.Reader) bool {
|
|||||||
}
|
}
|
||||||
return disabled
|
return disabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsSELinuxEnforcing reports whether SELinux is in "Enforcing" mode.
|
||||||
|
func IsSELinuxEnforcing() bool {
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
out, _ := exec.Command("getenforce").Output()
|
||||||
|
return string(bytes.TrimSpace(out)) == "Enforcing"
|
||||||
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
package ipnlocal
|
package ipnlocal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -18,7 +17,6 @@
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"os/user"
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -2583,7 +2581,7 @@ func (b *LocalBackend) checkSSHPrefsLocked(p *ipn.Prefs) error {
|
|||||||
if distro.Get() == distro.QNAP && !envknob.UseWIPCode() {
|
if distro.Get() == distro.QNAP && !envknob.UseWIPCode() {
|
||||||
return errors.New("The Tailscale SSH server does not run on QNAP.")
|
return errors.New("The Tailscale SSH server does not run on QNAP.")
|
||||||
}
|
}
|
||||||
checkSELinux()
|
b.updateSELinuxHealthWarning()
|
||||||
// otherwise okay
|
// otherwise okay
|
||||||
case "darwin":
|
case "darwin":
|
||||||
// okay only in tailscaled mode for now.
|
// okay only in tailscaled mode for now.
|
||||||
@ -4705,12 +4703,8 @@ func (b *LocalBackend) sshServerOrInit() (_ SSHServer, err error) {
|
|||||||
|
|
||||||
var warnSSHSELinux = health.NewWarnable()
|
var warnSSHSELinux = health.NewWarnable()
|
||||||
|
|
||||||
func checkSELinux() {
|
func (b *LocalBackend) updateSELinuxHealthWarning() {
|
||||||
if runtime.GOOS != "linux" {
|
if hostinfo.IsSELinuxEnforcing() {
|
||||||
return
|
|
||||||
}
|
|
||||||
out, _ := exec.Command("getenforce").Output()
|
|
||||||
if string(bytes.TrimSpace(out)) == "Enforcing" {
|
|
||||||
warnSSHSELinux.Set(errors.New("SELinux is enabled; Tailscale SSH may not work. See https://tailscale.com/s/ssh-selinux"))
|
warnSSHSELinux.Set(errors.New("SELinux is enabled; Tailscale SSH may not work. See https://tailscale.com/s/ssh-selinux"))
|
||||||
} else {
|
} else {
|
||||||
warnSSHSELinux.Set(nil)
|
warnSSHSELinux.Set(nil)
|
||||||
@ -4722,7 +4716,7 @@ func (b *LocalBackend) handleSSHConn(c net.Conn) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
checkSELinux()
|
b.updateSELinuxHealthWarning()
|
||||||
return s.HandleSSHConn(c)
|
return s.HandleSSHConn(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
"tailscale.com/cmd/tailscaled/childproc"
|
"tailscale.com/cmd/tailscaled/childproc"
|
||||||
|
"tailscale.com/hostinfo"
|
||||||
"tailscale.com/tempfork/gliderlabs/ssh"
|
"tailscale.com/tempfork/gliderlabs/ssh"
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
"tailscale.com/version/distro"
|
"tailscale.com/version/distro"
|
||||||
@ -120,10 +121,18 @@ func (ss *sshSession) newIncubatorCommand() (cmd *exec.Cmd) {
|
|||||||
if isShell {
|
if isShell {
|
||||||
incubatorArgs = append(incubatorArgs, "--shell")
|
incubatorArgs = append(incubatorArgs, "--shell")
|
||||||
}
|
}
|
||||||
if isShell || runtime.GOOS == "darwin" {
|
// Only the macOS version of the login command supports executing a
|
||||||
// Only the macOS version of the login command supports executing a
|
// command, all other versions only support launching a shell
|
||||||
// command, all other versions only support launching a shell
|
// without taking any arguments.
|
||||||
// without taking any arguments.
|
shouldUseLoginCmd := isShell || runtime.GOOS == "darwin"
|
||||||
|
if hostinfo.IsSELinuxEnforcing() {
|
||||||
|
// If we're running on a SELinux-enabled system, the login
|
||||||
|
// command will be unable to set the correct context for the
|
||||||
|
// shell. Fall back to using the incubator to launch the shell.
|
||||||
|
// See http://github.com/tailscale/tailscale/issues/4908.
|
||||||
|
shouldUseLoginCmd = false
|
||||||
|
}
|
||||||
|
if shouldUseLoginCmd {
|
||||||
if lp, err := exec.LookPath("login"); err == nil {
|
if lp, err := exec.LookPath("login"); err == nil {
|
||||||
incubatorArgs = append(incubatorArgs, "--login-cmd="+lp)
|
incubatorArgs = append(incubatorArgs, "--login-cmd="+lp)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user