- update to 1.80.0:

* Hostname system policy is added for overriding the device hostname
    configured by the operating system, using an MDM solution.
  * Web interface displays a Login button instead of the Reauthenticate button
    when adding a new device to your tailnet.
  * Tailscale Funnel configuration on devices displays errors when incoming
    connections are not permitted and connections are disallowed.
  * Connections to a custom coordination server that does not support HTTPS
    will no longer fail when a custom port number is specified.
  * TLS certificate requests from Let’s Encrypt include the device's DNS name
    in the CSR’s SAN extension and set the Common Name field.
  * Tailscale Funnel disabled on a device no longer displays enabled in the
    admin console.
  * GitHub username change automatically updates tailnet name
  * 4via6 subnet routers GA
  * Auto approvers GA
  * Node attributes GA
  * Download invoices GA
  * Fast user switching GA
  * Configuration log streaming integration with S3 buckets GA
  * Network flow log streaming integration with S3 buckets GA
  * NextDNS profiles per device GA
  * GitHub secret scanning
- remove fix-CVE-2024-45337.patch, as it's now included

OBS-URL: https://build.opensuse.org/package/show/network:vpn/tailscale?expand=0&rev=63
This commit is contained in:
Richard Rahl
2025-01-31 17:27:15 +00:00
committed by Git OBS Bridge
commit aa509b69e0
22 changed files with 1483 additions and 0 deletions

23
.gitattributes vendored Normal file
View File

@@ -0,0 +1,23 @@
## Default LFS
*.7z filter=lfs diff=lfs merge=lfs -text
*.bsp filter=lfs diff=lfs merge=lfs -text
*.bz2 filter=lfs diff=lfs merge=lfs -text
*.gem filter=lfs diff=lfs merge=lfs -text
*.gz filter=lfs diff=lfs merge=lfs -text
*.jar filter=lfs diff=lfs merge=lfs -text
*.lz filter=lfs diff=lfs merge=lfs -text
*.lzma filter=lfs diff=lfs merge=lfs -text
*.obscpio filter=lfs diff=lfs merge=lfs -text
*.oxt filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.rpm filter=lfs diff=lfs merge=lfs -text
*.tbz filter=lfs diff=lfs merge=lfs -text
*.tbz2 filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.txz filter=lfs diff=lfs merge=lfs -text
*.whl filter=lfs diff=lfs merge=lfs -text
*.xz filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.zst filter=lfs diff=lfs merge=lfs -text

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.osc

17
_service Normal file
View File

@@ -0,0 +1,17 @@
<services>
<service name="tar_scm" mode="manual">
<param name="url">https://github.com/tailscale/tailscale.git</param>
<param name="scm">git</param>
<param name="package-meta">yes</param>
<param name="revision">refs/tags/v1.80.0</param>
<param name="versionformat">@PARENT_TAG@</param>
<param name="versionrewrite-pattern">v(.*)</param>
<param name="changesgenerate">disable</param>
</service>
<service name="recompress" mode="manual">
<param name="file">*.tar</param>
<param name="compression">gz</param>
</service>
<service name="go_modules" mode="manual">
</service>
</services>

4
_servicedata Normal file
View File

@@ -0,0 +1,4 @@
<servicedata>
<service name="tar_scm">
<param name="url">https://github.com/tailscale/tailscale.git</param>
<param name="changesrevision">aa448d5a9985378af04966c6d7aec8d9f4a166ca</param></service></servicedata>

13
build-verbose.patch Normal file
View File

@@ -0,0 +1,13 @@
diff --git a/build_dist.sh b/build_dist.sh
index 0c757c26..9639d596 100755
--- a/build_dist.sh
+++ b/build_dist.sh
@@ -9,7 +9,7 @@
# this script, or executing equivalent commands in your
# distro-specific build system.
-set -eu
+set -eux
go="go"
if [ -n "${TS_USE_TOOLCHAIN:-}" ]; then

25
disable-auto-update.patch Normal file
View File

@@ -0,0 +1,25 @@
diff -rub tailscale/clientupdate/clientupdate.go tailscale-patched/clientupdate/clientupdate.go
--- tailscale/clientupdate/clientupdate.go 2024-06-16 15:26:31.323022871 +0200
+++ tailscale-patched/clientupdate/clientupdate.go 2024-06-16 15:57:08.732315446 +0200
@@ -205,6 +205,8 @@
// The distro.Debian switch case above should catch most apt-based
// systems, but add this fallback just in case.
return up.updateDebLike, true
+ case haveExecutable("zypper"):
+ return up.updateSUSE, false
case haveExecutable("dnf"):
return up.updateFedoraLike("dnf"), true
case haveExecutable("yum"):
@@ -526,6 +528,12 @@
you can use "pacman --sync --refresh --sysupgrade" or "pacman -Syu" to upgrade the system, including Tailscale.`)
}
+func (up *Updater) updateSUSE() error {
+ // SUSE-based distros should update manually.
+ // The package can come from official Tailscale repos or not and the system can be transactional or not.
+ return errors.New(`Use Zypper or transactional-update (on applicable systems) to update Tailscale on openSUSE or SUSE Linux Enterprise installations.`)
+}
+
func (up *Updater) updateNixos() error {
// NixOS package updates are managed on a system level and not individually.
// Direct users to update their nix channel or nixpkgs flake input to

727
fix-CVE-2024-45337.patch Normal file
View File

@@ -0,0 +1,727 @@
From 73128e25230fda8c82696ed0ffef991bce68cecc Mon Sep 17 00:00:00 2001
From: Brad Fitzpatrick <bradfitz@tailscale.com>
Date: Thu, 12 Dec 2024 09:38:07 -0800
Subject: [PATCH] ssh/tailssh: remove unused public key support
When we first made Tailscale SSH, we assumed people would want public
key support soon after. Turns out that hasn't been the case; people
love the Tailscale identity authentication and check mode.
In light of CVE-2024-45337, just remove all our public key code to not
distract people, and to make the code smaller. We can always get it
back from git if needed.
Updates tailscale/corp#25131
Updates golang/go#70779
Co-authored-by: Percy Wegmann <percy@tailscale.com>
Change-Id: I87a6e79c2215158766a81942227a18b247333c22
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
---
Makefile | 1 -
ssh/tailssh/tailssh.go | 277 ++++--------------------------------
ssh/tailssh/tailssh_test.go | 88 +-----------
tailcfg/tailcfg.go | 18 ++-
tailcfg/tailcfg_clone.go | 12 +-
tailcfg/tailcfg_view.go | 22 +--
6 files changed, 54 insertions(+), 364 deletions(-)
diff --git a/Makefile b/Makefile
index 960f13885c11c..d3e50af0571b7 100644
--- a/Makefile
+++ b/Makefile
@@ -116,7 +116,6 @@ sshintegrationtest: ## Run the SSH integration tests in various Docker container
GOOS=linux GOARCH=amd64 ./tool/go build -o ssh/tailssh/testcontainers/tailscaled ./cmd/tailscaled && \
echo "Testing on ubuntu:focal" && docker build --build-arg="BASE=ubuntu:focal" -t ssh-ubuntu-focal ssh/tailssh/testcontainers && \
echo "Testing on ubuntu:jammy" && docker build --build-arg="BASE=ubuntu:jammy" -t ssh-ubuntu-jammy ssh/tailssh/testcontainers && \
- echo "Testing on ubuntu:mantic" && docker build --build-arg="BASE=ubuntu:mantic" -t ssh-ubuntu-mantic ssh/tailssh/testcontainers && \
echo "Testing on ubuntu:noble" && docker build --build-arg="BASE=ubuntu:noble" -t ssh-ubuntu-noble ssh/tailssh/testcontainers && \
echo "Testing on alpine:latest" && docker build --build-arg="BASE=alpine:latest" -t ssh-alpine-latest ssh/tailssh/testcontainers
diff --git a/ssh/tailssh/tailssh.go b/ssh/tailssh/tailssh.go
index 7cb99c3813104..7f21ccd1182ee 100644
--- a/ssh/tailssh/tailssh.go
+++ b/ssh/tailssh/tailssh.go
@@ -10,7 +10,6 @@ import (
"bytes"
"context"
"crypto/rand"
- "encoding/base64"
"encoding/json"
"errors"
"fmt"
@@ -45,7 +44,6 @@ import (
"tailscale.com/util/clientmetric"
"tailscale.com/util/httpm"
"tailscale.com/util/mak"
- "tailscale.com/util/slicesx"
)
var (
@@ -80,16 +78,14 @@ type server struct {
logf logger.Logf
tailscaledPath string
- pubKeyHTTPClient *http.Client // or nil for http.DefaultClient
- timeNow func() time.Time // or nil for time.Now
+ timeNow func() time.Time // or nil for time.Now
sessionWaitGroup sync.WaitGroup
// mu protects the following
- mu sync.Mutex
- activeConns map[*conn]bool // set; value is always true
- fetchPublicKeysCache map[string]pubKeyCacheEntry // by https URL
- shutdownCalled bool
+ mu sync.Mutex
+ activeConns map[*conn]bool // set; value is always true
+ shutdownCalled bool
}
func (srv *server) now() time.Time {
@@ -204,7 +200,6 @@ func (srv *server) OnPolicyChange() {
//
// Do the user auth
// - NoClientAuthHandler
-// - PublicKeyHandler (only if NoClientAuthHandler returns errPubKeyRequired)
//
// Once auth is done, the conn can be multiplexed with multiple sessions and
// channels concurrently. At which point any of the following can be called
@@ -234,10 +229,9 @@ type conn struct {
finalAction *tailcfg.SSHAction // set by doPolicyAuth or resolveNextAction
finalActionErr error // set by doPolicyAuth or resolveNextAction
- info *sshConnInfo // set by setInfo
- localUser *userMeta // set by doPolicyAuth
- userGroupIDs []string // set by doPolicyAuth
- pubKey gossh.PublicKey // set by doPolicyAuth
+ info *sshConnInfo // set by setInfo
+ localUser *userMeta // set by doPolicyAuth
+ userGroupIDs []string // set by doPolicyAuth
acceptEnv []string
// mu protects the following fields.
@@ -268,9 +262,6 @@ func (c *conn) isAuthorized(ctx ssh.Context) error {
action := c.currentAction
for {
if action.Accept {
- if c.pubKey != nil {
- metricPublicKeyAccepts.Add(1)
- }
return nil
}
if action.Reject || action.HoldAndDelegate == "" {
@@ -293,10 +284,6 @@ func (c *conn) isAuthorized(ctx ssh.Context) error {
// policy.
var errDenied = errors.New("ssh: access denied")
-// errPubKeyRequired is returned by NoClientAuthCallback to make the client
-// resort to public-key auth; not user visible.
-var errPubKeyRequired = errors.New("ssh publickey required")
-
// NoClientAuthCallback implements gossh.NoClientAuthCallback and is called by
// the ssh.Server when the client first connects with the "none"
// authentication method.
@@ -305,13 +292,12 @@ var errPubKeyRequired = errors.New("ssh publickey required")
// starting it afresh). It returns an error if the policy evaluation fails, or
// if the decision is "reject"
//
-// It either returns nil (accept) or errPubKeyRequired or errDenied
-// (reject). The errors may be wrapped.
+// It either returns nil (accept) or errDenied (reject). The errors may be wrapped.
func (c *conn) NoClientAuthCallback(ctx ssh.Context) error {
if c.insecureSkipTailscaleAuth {
return nil
}
- if err := c.doPolicyAuth(ctx, nil /* no pub key */); err != nil {
+ if err := c.doPolicyAuth(ctx); err != nil {
return err
}
if err := c.isAuthorized(ctx); err != nil {
@@ -332,8 +318,6 @@ func (c *conn) nextAuthMethodCallback(cm gossh.ConnMetadata, prevErrors []error)
switch {
case c.anyPasswordIsOkay:
nextMethod = append(nextMethod, "password")
- case slicesx.LastEqual(prevErrors, errPubKeyRequired):
- nextMethod = append(nextMethod, "publickey")
}
// The fake "tailscale" method is always appended to next so OpenSSH renders
@@ -353,41 +337,20 @@ func (c *conn) fakePasswordHandler(ctx ssh.Context, password string) bool {
return c.anyPasswordIsOkay
}
-// PublicKeyHandler implements ssh.PublicKeyHandler is called by the
-// ssh.Server when the client presents a public key.
-func (c *conn) PublicKeyHandler(ctx ssh.Context, pubKey ssh.PublicKey) error {
- if err := c.doPolicyAuth(ctx, pubKey); err != nil {
- // TODO(maisem/bradfitz): surface the error here.
- c.logf("rejecting SSH public key %s: %v", bytes.TrimSpace(gossh.MarshalAuthorizedKey(pubKey)), err)
- return err
- }
- if err := c.isAuthorized(ctx); err != nil {
- return err
- }
- c.logf("accepting SSH public key %s", bytes.TrimSpace(gossh.MarshalAuthorizedKey(pubKey)))
- return nil
-}
-
-// doPolicyAuth verifies that conn can proceed with the specified (optional)
-// pubKey. It returns nil if the matching policy action is Accept or
-// HoldAndDelegate. If pubKey is nil, there was no policy match but there is a
-// policy that might match a public key it returns errPubKeyRequired. Otherwise,
-// it returns errDenied.
-func (c *conn) doPolicyAuth(ctx ssh.Context, pubKey ssh.PublicKey) error {
+// doPolicyAuth verifies that conn can proceed.
+// It returns nil if the matching policy action is Accept or
+// HoldAndDelegate. Otherwise, it returns errDenied.
+func (c *conn) doPolicyAuth(ctx ssh.Context) error {
if err := c.setInfo(ctx); err != nil {
c.logf("failed to get conninfo: %v", err)
return errDenied
}
- a, localUser, acceptEnv, err := c.evaluatePolicy(pubKey)
+ a, localUser, acceptEnv, err := c.evaluatePolicy()
if err != nil {
- if pubKey == nil && c.havePubKeyPolicy() {
- return errPubKeyRequired
- }
return fmt.Errorf("%w: %v", errDenied, err)
}
c.action0 = a
c.currentAction = a
- c.pubKey = pubKey
c.acceptEnv = acceptEnv
if a.Message != "" {
if err := ctx.SendAuthBanner(a.Message); err != nil {
@@ -448,7 +411,6 @@ func (srv *server) newConn() (*conn, error) {
ServerConfigCallback: c.ServerConfig,
NoClientAuthHandler: c.NoClientAuthCallback,
- PublicKeyHandler: c.PublicKeyHandler,
PasswordHandler: c.fakePasswordHandler,
Handler: c.handleSessionPostSSHAuth,
@@ -516,34 +478,6 @@ func (c *conn) mayForwardLocalPortTo(ctx ssh.Context, destinationHost string, de
return false
}
-// havePubKeyPolicy reports whether any policy rule may provide access by means
-// of a ssh.PublicKey.
-func (c *conn) havePubKeyPolicy() bool {
- if c.info == nil {
- panic("havePubKeyPolicy called before setInfo")
- }
- // Is there any rule that looks like it'd require a public key for this
- // sshUser?
- pol, ok := c.sshPolicy()
- if !ok {
- return false
- }
- for _, r := range pol.Rules {
- if c.ruleExpired(r) {
- continue
- }
- if mapLocalUser(r.SSHUsers, c.info.sshUser) == "" {
- continue
- }
- for _, p := range r.Principals {
- if len(p.PubKeys) > 0 && c.principalMatchesTailscaleIdentity(p) {
- return true
- }
- }
- }
- return false
-}
-
// sshPolicy returns the SSHPolicy for current node.
// If there is no SSHPolicy in the netmap, it returns a debugPolicy
// if one is defined.
@@ -620,117 +554,19 @@ func (c *conn) setInfo(ctx ssh.Context) error {
}
// evaluatePolicy returns the SSHAction and localUser after evaluating
-// the SSHPolicy for this conn. The pubKey may be nil for "none" auth.
-func (c *conn) evaluatePolicy(pubKey gossh.PublicKey) (_ *tailcfg.SSHAction, localUser string, acceptEnv []string, _ error) {
+// the SSHPolicy for this conn.
+func (c *conn) evaluatePolicy() (_ *tailcfg.SSHAction, localUser string, acceptEnv []string, _ error) {
pol, ok := c.sshPolicy()
if !ok {
return nil, "", nil, fmt.Errorf("tailssh: rejecting connection; no SSH policy")
}
- a, localUser, acceptEnv, ok := c.evalSSHPolicy(pol, pubKey)
+ a, localUser, acceptEnv, ok := c.evalSSHPolicy(pol)
if !ok {
return nil, "", nil, fmt.Errorf("tailssh: rejecting connection; no matching policy")
}
return a, localUser, acceptEnv, nil
}
-// pubKeyCacheEntry is the cache value for an HTTPS URL of public keys (like
-// "https://github.com/foo.keys")
-type pubKeyCacheEntry struct {
- lines []string
- etag string // if sent by server
- at time.Time
-}
-
-const (
- pubKeyCacheDuration = time.Minute // how long to cache non-empty public keys
- pubKeyCacheEmptyDuration = 15 * time.Second // how long to cache empty responses
-)
-
-func (srv *server) fetchPublicKeysURLCached(url string) (ce pubKeyCacheEntry, ok bool) {
- srv.mu.Lock()
- defer srv.mu.Unlock()
- // Mostly don't care about the size of this cache. Clean rarely.
- if m := srv.fetchPublicKeysCache; len(m) > 50 {
- tooOld := srv.now().Add(pubKeyCacheDuration * 10)
- for k, ce := range m {
- if ce.at.Before(tooOld) {
- delete(m, k)
- }
- }
- }
- ce, ok = srv.fetchPublicKeysCache[url]
- if !ok {
- return ce, false
- }
- maxAge := pubKeyCacheDuration
- if len(ce.lines) == 0 {
- maxAge = pubKeyCacheEmptyDuration
- }
- return ce, srv.now().Sub(ce.at) < maxAge
-}
-
-func (srv *server) pubKeyClient() *http.Client {
- if srv.pubKeyHTTPClient != nil {
- return srv.pubKeyHTTPClient
- }
- return http.DefaultClient
-}
-
-// fetchPublicKeysURL fetches the public keys from a URL. The strings are in the
-// the typical public key "type base64-string [comment]" format seen at e.g.
-// https://github.com/USER.keys
-func (srv *server) fetchPublicKeysURL(url string) ([]string, error) {
- if !strings.HasPrefix(url, "https://") {
- return nil, errors.New("invalid URL scheme")
- }
-
- ce, ok := srv.fetchPublicKeysURLCached(url)
- if ok {
- return ce.lines, nil
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
- defer cancel()
- req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
- if err != nil {
- return nil, err
- }
- if ce.etag != "" {
- req.Header.Add("If-None-Match", ce.etag)
- }
- res, err := srv.pubKeyClient().Do(req)
- if err != nil {
- return nil, err
- }
- defer res.Body.Close()
- var lines []string
- var etag string
- switch res.StatusCode {
- default:
- err = fmt.Errorf("unexpected status %v", res.Status)
- srv.logf("fetching public keys from %s: %v", url, err)
- case http.StatusNotModified:
- lines = ce.lines
- etag = ce.etag
- case http.StatusOK:
- var all []byte
- all, err = io.ReadAll(io.LimitReader(res.Body, 4<<10))
- if s := strings.TrimSpace(string(all)); s != "" {
- lines = strings.Split(s, "\n")
- }
- etag = res.Header.Get("Etag")
- }
-
- srv.mu.Lock()
- defer srv.mu.Unlock()
- mak.Set(&srv.fetchPublicKeysCache, url, pubKeyCacheEntry{
- at: srv.now(),
- lines: lines,
- etag: etag,
- })
- return lines, err
-}
-
// handleSessionPostSSHAuth runs an SSH session after the SSH-level authentication,
// but not necessarily before all the Tailscale-level extra verification has
// completed. It also handles SFTP requests.
@@ -832,18 +668,6 @@ func (c *conn) expandDelegateURLLocked(actionURL string) string {
).Replace(actionURL)
}
-func (c *conn) expandPublicKeyURL(pubKeyURL string) string {
- if !strings.Contains(pubKeyURL, "$") {
- return pubKeyURL
- }
- loginName := c.info.uprof.LoginName
- localPart, _, _ := strings.Cut(loginName, "@")
- return strings.NewReplacer(
- "$LOGINNAME_EMAIL", loginName,
- "$LOGINNAME_LOCALPART", localPart,
- ).Replace(pubKeyURL)
-}
-
// sshSession is an accepted Tailscale SSH session.
type sshSession struct {
ssh.Session
@@ -894,7 +718,7 @@ func (c *conn) newSSHSession(s ssh.Session) *sshSession {
// isStillValid reports whether the conn is still valid.
func (c *conn) isStillValid() bool {
- a, localUser, _, err := c.evaluatePolicy(c.pubKey)
+ a, localUser, _, err := c.evaluatePolicy()
c.vlogf("stillValid: %+v %v %v", a, localUser, err)
if err != nil {
return false
@@ -1277,9 +1101,9 @@ func (c *conn) ruleExpired(r *tailcfg.SSHRule) bool {
return r.RuleExpires.Before(c.srv.now())
}
-func (c *conn) evalSSHPolicy(pol *tailcfg.SSHPolicy, pubKey gossh.PublicKey) (a *tailcfg.SSHAction, localUser string, acceptEnv []string, ok bool) {
+func (c *conn) evalSSHPolicy(pol *tailcfg.SSHPolicy) (a *tailcfg.SSHAction, localUser string, acceptEnv []string, ok bool) {
for _, r := range pol.Rules {
- if a, localUser, acceptEnv, err := c.matchRule(r, pubKey); err == nil {
+ if a, localUser, acceptEnv, err := c.matchRule(r); err == nil {
return a, localUser, acceptEnv, true
}
}
@@ -1296,7 +1120,7 @@ var (
errInvalidConn = errors.New("invalid connection state")
)
-func (c *conn) matchRule(r *tailcfg.SSHRule, pubKey gossh.PublicKey) (a *tailcfg.SSHAction, localUser string, acceptEnv []string, err error) {
+func (c *conn) matchRule(r *tailcfg.SSHRule) (a *tailcfg.SSHAction, localUser string, acceptEnv []string, err error) {
defer func() {
c.vlogf("matchRule(%+v): %v", r, err)
}()
@@ -1326,9 +1150,7 @@ func (c *conn) matchRule(r *tailcfg.SSHRule, pubKey gossh.PublicKey) (a *tailcfg
return nil, "", nil, errUserMatch
}
}
- if ok, err := c.anyPrincipalMatches(r.Principals, pubKey); err != nil {
- return nil, "", nil, err
- } else if !ok {
+ if !c.anyPrincipalMatches(r.Principals) {
return nil, "", nil, errPrincipalMatch
}
return r.Action, localUser, r.AcceptEnv, nil
@@ -1345,30 +1167,20 @@ func mapLocalUser(ruleSSHUsers map[string]string, reqSSHUser string) (localUser
return v
}
-func (c *conn) anyPrincipalMatches(ps []*tailcfg.SSHPrincipal, pubKey gossh.PublicKey) (bool, error) {
+func (c *conn) anyPrincipalMatches(ps []*tailcfg.SSHPrincipal) bool {
for _, p := range ps {
if p == nil {
continue
}
- if ok, err := c.principalMatches(p, pubKey); err != nil {
- return false, err
- } else if ok {
- return true, nil
+ if c.principalMatchesTailscaleIdentity(p) {
+ return true
}
}
- return false, nil
-}
-
-func (c *conn) principalMatches(p *tailcfg.SSHPrincipal, pubKey gossh.PublicKey) (bool, error) {
- if !c.principalMatchesTailscaleIdentity(p) {
- return false, nil
- }
- return c.principalMatchesPubKey(p, pubKey)
+ return false
}
// principalMatchesTailscaleIdentity reports whether one of p's four fields
// that match the Tailscale identity match (Node, NodeIP, UserLogin, Any).
-// This function does not consider PubKeys.
func (c *conn) principalMatchesTailscaleIdentity(p *tailcfg.SSHPrincipal) bool {
ci := c.info
if p.Any {
@@ -1388,42 +1200,6 @@ func (c *conn) principalMatchesTailscaleIdentity(p *tailcfg.SSHPrincipal) bool {
return false
}
-func (c *conn) principalMatchesPubKey(p *tailcfg.SSHPrincipal, clientPubKey gossh.PublicKey) (bool, error) {
- if len(p.PubKeys) == 0 {
- return true, nil
- }
- if clientPubKey == nil {
- return false, nil
- }
- knownKeys := p.PubKeys
- if len(knownKeys) == 1 && strings.HasPrefix(knownKeys[0], "https://") {
- var err error
- knownKeys, err = c.srv.fetchPublicKeysURL(c.expandPublicKeyURL(knownKeys[0]))
- if err != nil {
- return false, err
- }
- }
- for _, knownKey := range knownKeys {
- if pubKeyMatchesAuthorizedKey(clientPubKey, knownKey) {
- return true, nil
- }
- }
- return false, nil
-}
-
-func pubKeyMatchesAuthorizedKey(pubKey ssh.PublicKey, wantKey string) bool {
- wantKeyType, rest, ok := strings.Cut(wantKey, " ")
- if !ok {
- return false
- }
- if pubKey.Type() != wantKeyType {
- return false
- }
- wantKeyB64, _, _ := strings.Cut(rest, " ")
- wantKeyData, _ := base64.StdEncoding.DecodeString(wantKeyB64)
- return len(wantKeyData) > 0 && bytes.Equal(pubKey.Marshal(), wantKeyData)
-}
-
func randBytes(n int) []byte {
b := make([]byte, n)
if _, err := rand.Read(b); err != nil {
@@ -1749,7 +1525,6 @@ func envEq(a, b string) bool {
var (
metricActiveSessions = clientmetric.NewGauge("ssh_active_sessions")
metricIncomingConnections = clientmetric.NewCounter("ssh_incoming_connections")
- metricPublicKeyAccepts = clientmetric.NewCounter("ssh_publickey_accepts") // accepted subset of ssh_publickey_connections
metricTerminalAccept = clientmetric.NewCounter("ssh_terminalaction_accept")
metricTerminalReject = clientmetric.NewCounter("ssh_terminalaction_reject")
metricTerminalMalformed = clientmetric.NewCounter("ssh_terminalaction_malformed")
diff --git a/ssh/tailssh/tailssh_test.go b/ssh/tailssh/tailssh_test.go
index ad9cb1e57b53d..9f3616d8ca8ab 100644
--- a/ssh/tailssh/tailssh_test.go
+++ b/ssh/tailssh/tailssh_test.go
@@ -10,7 +10,6 @@ import (
"context"
"crypto/ed25519"
"crypto/rand"
- "crypto/sha256"
"encoding/json"
"errors"
"fmt"
@@ -229,7 +228,7 @@ func TestMatchRule(t *testing.T) {
info: tt.ci,
srv: &server{logf: t.Logf},
}
- got, gotUser, gotAcceptEnv, err := c.matchRule(tt.rule, nil)
+ got, gotUser, gotAcceptEnv, err := c.matchRule(tt.rule)
if err != tt.wantErr {
t.Errorf("err = %v; want %v", err, tt.wantErr)
}
@@ -348,7 +347,7 @@ func TestEvalSSHPolicy(t *testing.T) {
info: tt.ci,
srv: &server{logf: t.Logf},
}
- got, gotUser, gotAcceptEnv, match := c.evalSSHPolicy(tt.policy, nil)
+ got, gotUser, gotAcceptEnv, match := c.evalSSHPolicy(tt.policy)
if match != tt.wantMatch {
t.Errorf("match = %v; want %v", match, tt.wantMatch)
}
@@ -1129,89 +1128,6 @@ func parseEnv(out []byte) map[string]string {
return e
}
-func TestPublicKeyFetching(t *testing.T) {
- var reqsTotal, reqsIfNoneMatchHit, reqsIfNoneMatchMiss int32
- ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- atomic.AddInt32((&reqsTotal), 1)
- etag := fmt.Sprintf("W/%q", sha256.Sum256([]byte(r.URL.Path)))
- w.Header().Set("Etag", etag)
- if v := r.Header.Get("If-None-Match"); v != "" {
- if v == etag {
- atomic.AddInt32(&reqsIfNoneMatchHit, 1)
- w.WriteHeader(304)
- return
- }
- atomic.AddInt32(&reqsIfNoneMatchMiss, 1)
- }
- io.WriteString(w, "foo\nbar\n"+string(r.URL.Path)+"\n")
- }))
- ts.StartTLS()
- defer ts.Close()
- keys := ts.URL
-
- clock := &tstest.Clock{}
- srv := &server{
- pubKeyHTTPClient: ts.Client(),
- timeNow: clock.Now,
- }
- for range 2 {
- got, err := srv.fetchPublicKeysURL(keys + "/alice.keys")
- if err != nil {
- t.Fatal(err)
- }
- if want := []string{"foo", "bar", "/alice.keys"}; !reflect.DeepEqual(got, want) {
- t.Errorf("got %q; want %q", got, want)
- }
- }
- if got, want := atomic.LoadInt32(&reqsTotal), int32(1); got != want {
- t.Errorf("got %d requests; want %d", got, want)
- }
- if got, want := atomic.LoadInt32(&reqsIfNoneMatchHit), int32(0); got != want {
- t.Errorf("got %d etag hits; want %d", got, want)
- }
- clock.Advance(5 * time.Minute)
- got, err := srv.fetchPublicKeysURL(keys + "/alice.keys")
- if err != nil {
- t.Fatal(err)
- }
- if want := []string{"foo", "bar", "/alice.keys"}; !reflect.DeepEqual(got, want) {
- t.Errorf("got %q; want %q", got, want)
- }
- if got, want := atomic.LoadInt32(&reqsTotal), int32(2); got != want {
- t.Errorf("got %d requests; want %d", got, want)
- }
- if got, want := atomic.LoadInt32(&reqsIfNoneMatchHit), int32(1); got != want {
- t.Errorf("got %d etag hits; want %d", got, want)
- }
- if got, want := atomic.LoadInt32(&reqsIfNoneMatchMiss), int32(0); got != want {
- t.Errorf("got %d etag misses; want %d", got, want)
- }
-
-}
-
-func TestExpandPublicKeyURL(t *testing.T) {
- c := &conn{
- info: &sshConnInfo{
- uprof: tailcfg.UserProfile{
- LoginName: "bar@baz.tld",
- },
- },
- }
- if got, want := c.expandPublicKeyURL("foo"), "foo"; got != want {
- t.Errorf("basic: got %q; want %q", got, want)
- }
- if got, want := c.expandPublicKeyURL("https://example.com/$LOGINNAME_LOCALPART.keys"), "https://example.com/bar.keys"; got != want {
- t.Errorf("localpart: got %q; want %q", got, want)
- }
- if got, want := c.expandPublicKeyURL("https://example.com/keys?email=$LOGINNAME_EMAIL"), "https://example.com/keys?email=bar@baz.tld"; got != want {
- t.Errorf("email: got %q; want %q", got, want)
- }
- c.info = new(sshConnInfo)
- if got, want := c.expandPublicKeyURL("https://example.com/keys?email=$LOGINNAME_EMAIL"), "https://example.com/keys?email="; got != want {
- t.Errorf("on empty: got %q; want %q", got, want)
- }
-}
-
func TestAcceptEnvPair(t *testing.T) {
tests := []struct {
in string
diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go
index 897e8d27f7f7b..be6c4f0be6b82 100644
--- a/tailcfg/tailcfg.go
+++ b/tailcfg/tailcfg.go
@@ -152,7 +152,8 @@ type CapabilityVersion int
// - 107: 2024-10-30: add App Connector to conffile (PR #13942)
// - 108: 2024-11-08: Client sends ServicesHash in Hostinfo, understands c2n GET /vip-services.
// - 109: 2024-11-18: Client supports filtertype.Match.SrcCaps (issue #12542)
-const CurrentCapabilityVersion CapabilityVersion = 109
+// - 110: 2024-12-12: removed never-before-used Tailscale SSH public key support (#14373)
+const CurrentCapabilityVersion CapabilityVersion = 110
type StableID string
@@ -2525,16 +2526,13 @@ type SSHPrincipal struct {
Any bool `json:"any,omitempty"` // if true, match any connection
// TODO(bradfitz): add StableUserID, once that exists
- // PubKeys, if non-empty, means that this SSHPrincipal only
- // matches if one of these public keys is presented by the user.
+ // UnusedPubKeys was public key support. It never became an official product
+ // feature and so as of 2024-12-12 is being removed.
+ // This stub exists to remind us not to re-use the JSON field name "pubKeys"
+ // in the future if we bring it back with different semantics.
//
- // As a special case, if len(PubKeys) == 1 and PubKeys[0] starts
- // with "https://", then it's fetched (like https://github.com/username.keys).
- // In that case, the following variable expansions are also supported
- // in the URL:
- // * $LOGINNAME_EMAIL ("foo@bar.com" or "foo@github")
- // * $LOGINNAME_LOCALPART (the "foo" from either of the above)
- PubKeys []string `json:"pubKeys,omitempty"`
+ // Deprecated: do not use. It does nothing.
+ UnusedPubKeys []string `json:"pubKeys,omitempty"`
}
// SSHAction is how to handle an incoming connection.
diff --git a/tailcfg/tailcfg_clone.go b/tailcfg/tailcfg_clone.go
index f4f02c01721dc..bf9bac2980df9 100644
--- a/tailcfg/tailcfg_clone.go
+++ b/tailcfg/tailcfg_clone.go
@@ -556,17 +556,17 @@ func (src *SSHPrincipal) Clone() *SSHPrincipal {
}
dst := new(SSHPrincipal)
*dst = *src
- dst.PubKeys = append(src.PubKeys[:0:0], src.PubKeys...)
+ dst.UnusedPubKeys = append(src.UnusedPubKeys[:0:0], src.UnusedPubKeys...)
return dst
}
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
var _SSHPrincipalCloneNeedsRegeneration = SSHPrincipal(struct {
- Node StableNodeID
- NodeIP string
- UserLogin string
- Any bool
- PubKeys []string
+ Node StableNodeID
+ NodeIP string
+ UserLogin string
+ Any bool
+ UnusedPubKeys []string
}{})
// Clone makes a deep copy of ControlDialPlan.
diff --git a/tailcfg/tailcfg_view.go b/tailcfg/tailcfg_view.go
index f275a6a9da5f2..6c21e5f450340 100644
--- a/tailcfg/tailcfg_view.go
+++ b/tailcfg/tailcfg_view.go
@@ -1260,19 +1260,21 @@ func (v *SSHPrincipalView) UnmarshalJSON(b []byte) error {
return nil
}
-func (v SSHPrincipalView) Node() StableNodeID { return v.ж.Node }
-func (v SSHPrincipalView) NodeIP() string { return v.ж.NodeIP }
-func (v SSHPrincipalView) UserLogin() string { return v.ж.UserLogin }
-func (v SSHPrincipalView) Any() bool { return v.ж.Any }
-func (v SSHPrincipalView) PubKeys() views.Slice[string] { return views.SliceOf(v.ж.PubKeys) }
+func (v SSHPrincipalView) Node() StableNodeID { return v.ж.Node }
+func (v SSHPrincipalView) NodeIP() string { return v.ж.NodeIP }
+func (v SSHPrincipalView) UserLogin() string { return v.ж.UserLogin }
+func (v SSHPrincipalView) Any() bool { return v.ж.Any }
+func (v SSHPrincipalView) UnusedPubKeys() views.Slice[string] {
+ return views.SliceOf(v.ж.UnusedPubKeys)
+}
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
var _SSHPrincipalViewNeedsRegeneration = SSHPrincipal(struct {
- Node StableNodeID
- NodeIP string
- UserLogin string
- Any bool
- PubKeys []string
+ Node StableNodeID
+ NodeIP string
+ UserLogin string
+ Any bool
+ UnusedPubKeys []string
}{})
// View returns a readonly view of ControlDialPlan.

3
tailscale-1.70.0.tar.gz Normal file
View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:294d6df3f4585152bd612eed9b34a6c2062589c8989f86ee25e750c37164fcd5
size 55014834

3
tailscale-1.72.1.tar.gz Normal file
View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:03e15ea076362eda1a44712351ba2a19bf746970fee8ddc4013513a07337cbe0
size 11331158

3
tailscale-1.74.0.tar.gz Normal file
View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:65adec42c6b6c42a107d63b5c9eb2c10ae0e87f4d701aa5e35c4e31a81bcd381
size 11323679

3
tailscale-1.74.1.tar.gz Normal file
View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7357c9fe3b0dabbb35847d8181f8500007299ec93586c23cd1c50af4183ccd19
size 11462868

3
tailscale-1.76.1.tar.gz Normal file
View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:87ebf950ec15274f6e7105acfe3d5565ea39bfc7cdd9762248df26da9874d9fc
size 11842133

3
tailscale-1.76.3.tar.gz Normal file
View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:dab7ef3240df51e7b51238d4239822ac8dec8106282acf1f07208bd699da99b7
size 12050220

3
tailscale-1.76.6.tar.gz Normal file
View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:627769855263d35d26e3b855efdf79167d42f08a3087f5a678b7aa5298e30a72
size 12438906

3
tailscale-1.78.1.tar.gz Normal file
View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a035f99f9bdc8c0a3de278a538c1e8df1e886d8f2bfe0bd4567a3c2850e31d48
size 11935577

3
tailscale-1.78.3.tar.gz Normal file
View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1b10020e1b94fce5556f7ef67e5bd529fd1a209dcb7694bf13c1edafbce097cd
size 12121603

3
tailscale-1.80.0.tar.gz Normal file
View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3c7a09a5a96c0c21f70aa4e1a1a934c8d5b1ef3db80e8aab98d53ee664585277
size 12573438

454
tailscale.changes Normal file
View File

@@ -0,0 +1,454 @@
-------------------------------------------------------------------
Fri Jan 31 17:20:29 UTC 2025 - Richard Rahl <rrahl0@opensuse.org>
- update to 1.80.0:
* Hostname system policy is added for overriding the device hostname
configured by the operating system, using an MDM solution.
* Web interface displays a Login button instead of the Reauthenticate button
when adding a new device to your tailnet.
* Tailscale Funnel configuration on devices displays errors when incoming
connections are not permitted and connections are disallowed.
* Connections to a custom coordination server that does not support HTTPS
will no longer fail when a custom port number is specified.
* TLS certificate requests from Lets Encrypt include the device's DNS name
in the CSRs SAN extension and set the Common Name field.
* Tailscale Funnel disabled on a device no longer displays enabled in the
admin console.
* GitHub username change automatically updates tailnet name
* 4via6 subnet routers GA
* Auto approvers GA
* Node attributes GA
* Download invoices GA
* Fast user switching GA
* Configuration log streaming integration with S3 buckets GA
* Network flow log streaming integration with S3 buckets GA
* NextDNS profiles per device GA
* GitHub secret scanning
- remove fix-CVE-2024-45337.patch, as it's now included
-------------------------------------------------------------------
Wed Dec 18 17:33:23 UTC 2024 - Richard Rahl <rrahl0@opensuse.org>
- add patch fix-CVE-2024-45337.patch, to circumevent a possibility
of exploiting the golang-x-crypto security hole. (fix #1234506)
-------------------------------------------------------------------
Fri Dec 13 05:06:26 UTC 2024 - Richard Rahl <rrahl0@opensuse.org>
- update to 1.78.3:
* cmd/containerboot: fix nil pointer exception
* hostinfo: fix testing in container
-------------------------------------------------------------------
Fri Dec 6 01:22:05 UTC 2024 - Richard Rahl <rrahl0@opensuse.org>
- update to 1.78.1:
* health: fix TestHealthMetric
-------------------------------------------------------------------
Thu Dec 5 22:10:32 UTC 2024 - Richard Rahl <rrahl0@opensuse.org>
- update to 1.78.0:
* Client metrics have been added, to provide insights into Tailscale client
behavior, health, and performance.
* tailscale metrics command has been added, to expose and collect client
metrics for use with third-party monitoring systems.
* tailscale syspolicy command has been added, to list system policies, reload
system policies, or view errors related to the system policies configured
on the device.
* Tailscale system policies are applied immediately when pushed via mobile
device management (MDM) or Group Policy, without requiring a client restart.
* Tailscale SSH session recording detects the disappearance of the recorder
node sooner. This fix addresses a security vulnerability described
in TS-2024-013.
* New scopes for OAuth clients have been added with more granular permissions.
Existing OAuth clients using the previous set of scopes, and keys generated
using these clients, are still valid.
-------------------------------------------------------------------
Fri Nov 8 03:46:50 UTC 2024 - Richard Rahl <rrahl0@opensuse.org>
- update to 1.76.6:
* Logging for when clients move home DERP regions is improved.
* Tailscale clients no longer move their home DERP server prematurely in
response to unusual latency at very specific times.
-------------------------------------------------------------------
Tue Oct 22 18:34:42 UTC 2024 - Richard Rahl <rrahl0@opensuse.org>
- update to 1.76.3:
* no relevant changelog
- update to 1.76.2:
* no relevant changelog
- switch over to the new %{default_fw_backend} macro
- create old init file only for < leap 16
-------------------------------------------------------------------
Wed Oct 16 20:40:31 UTC 2024 - Richard Rahl <rrahl0@opensuse.org>
- update to 1.76.1:
* tailscale netcheck CLI command no longer crashes when performing diagnostics
on networks lacking UDP connectivity.
* Improperly formatted SERVFAIL responses no longer cause DNS timeouts when using an exit node.
* dbus login sessions no longer fail on systems where /bin/login is missing.
-------------------------------------------------------------------
Mon Oct 14 13:06:13 UTC 2024 - Alexandre Vicenzi <alexandre.vicenzi@suse.com>
- Require a firewall backend (boo#1228829)
- Add simple test check to ensure binaries are working
-------------------------------------------------------------------
Fri Oct 11 06:07:28 UTC 2024 - Richard Rahl <rrahl0@opensuse.org>
- update to 1.76.0:
* Clients lacking UDP connectivity no longer skip performing fallback latency
measurements with DERP servers.
* Warnings no longer display unnecessarily.
* Tailscale connectivity on in-flight internet on airplanes (such as Alaska Airlines) no longer fails.
* Service-related processes no longer run unnecessarily when services are disabled on the tailnet.
* Error messages include explanations in addition to the HTTP status code.
* Tailscale SSH supports sending environment variables to hosts. It's also possible to specify
permitted environment variables using the acceptEnv field.
* Tailscale SSH no longer breaks some terminal applications by omitting pixel width and height when
resizing the application window.
-------------------------------------------------------------------
Sat Sep 21 05:28:42 UTC 2024 - Eric Torres <eric.torres@its-et.me>
- Change path of zsh completion file to make zsh properly recognize completions
* /usr/share/zsh/site-functions/tailscale moved to /usr/share/zsh/site-functions/_tailscale
-------------------------------------------------------------------
Wed Sep 18 19:10:19 UTC 2024 - Richard Rahl <rrahl0@opensuse.org>
- update to 1.74.1:
* wgengine/magicsock: disable raw disco by default; add envknob to enable
-------------------------------------------------------------------
Fri Sep 13 10:48:17 UTC 2024 - Richard Rahl <rrahl0@opensuse.org>
- update to 1.74.0
* AuthKey system policy can be used to authenticate a device with Tailscale using an MDM solution.
* tailscale dns CLI command is added for accessing Tailscale DNS settings and status.
* Tailnet Lock long rotation signatures are truncated automatically to avoid excessive growth.
* Log In option in the client works as expected.
* TCP generic receive offload (GRO) support is added for improved userspace mode throughput.
* TCP generic segmentation offload (GSO) is re-introduced for supporting improved userspace mode throughput.
This was initially introduced in Tailscale v1.72.0 and then rolled back in v1.72.1.
* Device posture integration with CrowdStrike Falcon can now use MAC addresses to match devices that lack serial numbers.
When Falcon integration is configured, Device Identity Collection will automatically collect MAC addresses.
-------------------------------------------------------------------
Thu Aug 22 22:08:51 UTC 2024 - Richard Rahl <rrahl0@opensuse.org>
- update to 1.72.1:
* DNS over TCP failures when querying the Tailscale-internal resolver are fixed.
-------------------------------------------------------------------
Wed Aug 21 16:05:02 UTC 2024 - rrahl0@opensuse.org
- Update to version 1.72.0:
* posture: deduplicate MAC addresses before returning them
* health/dns: reduce severity of DNS unavailable warning
* safeweb: add Server.Close method
* go.mod.sri: update SRI hash for go.mod changes
* go.{mod,sum}: migrate from nhooyr.io/websocket to github.com/coder/websocket
* cmd/viewer: add support for map-like container types
- update golang(API) to 1.23
- export version variables, to circumvent a bug
-------------------------------------------------------------------
Thu Jul 18 06:31:58 UTC 2024 - Richard Rahl <rrahl0@opensuse.org>
- update to 1.70.0:
* New: Restrict recommended and automatically selected exit nodes using the
new AllowedSuggestedExitNodes system policy. Applies only to platforms that
support system policies.
* Changed: Improved NAT traversal for some uncommon scenarios.
* Changed: Optimized sending firewall rules to clients more efficiently.
* Fixed: Exit node suggestion CLI command now prints the hostname.
* Fixed: Taildrive share paths configured through the CLI resolve relative
to where you run the tailscale command.
-------------------------------------------------------------------
Tue Jul 2 20:35:35 UTC 2024 - Richard Rahl <rrahl0@opensuse.org>
- update to 1.68.2:
* Fixed: Tailnet lock validation of rotation signatures now permits multiple nodes
signed by the same pre-signed reusable auth key.
-------------------------------------------------------------------
Sun Jun 16 13:30:20 UTC 2024 - Richard Rahl <rrahl0@disroot.org>
- update to 1.68.1:
* Fixed: 4via6 subnet router advertisement works as expected.
* Fixed: Tailscale SSH access to Security-Enhanced Linux (SELinux) machines works as expected.
- update to 1.68.0:
* New: Auto-updates are allowed in containers, but ignore the tailnet-wide default
* New: Apply auto-updates even if the node is down or disconnected from the coordination server.
* New: tailscale lock status now prints the node's signature.
-------------------------------------------------------------------
Wed May 22 08:36:37 UTC 2024 - Richard Rahl <rrahl0@disroot.org>
- update to 1.66.4:
* Fixed: Restored UDP connectivity through Mullvad exit nodes
* Stateful filtering is now off by default
- update to 1.66.3:
* Login URLs did not always appear in the console when running tailscale up
* Starting with v1.66, the Kubernetes operator must always run the same or later version
as the proxies it manages.
* Expose cloud services on cluster network to the tailnet, using Kubernetes ExternalName Services
* Expose tailnet services that use Tailscale HTTPS to cluster workloads
* Cluster workloads can now refer to Tailscale Ingress resources by their MagicDNS names
* Configure environment variables for Tailscale Kubernetes operator proxies using ProxyClass CRD
* Expose tailscaled metrics endpoint for Tailscale Kubernetes operator proxies through ProxyClass CRD
* Configure labels for the Kubernetes operator Pods with Helm chart values
* Configure affinity rules for Kubernetes operator proxy Pods with ProxyClass
* Kubernetes operator proxy init container no longer attempts to enable IPv6 forwarding on systems
that don't have IPv6 module loaded
* Tailscale containers running on Kubernetes no longer error if an empty Kubernetes Secret is
pre-created for the tailscaled state
* Improved the ambiguous error messages when Tailscale running on Kubernetes does not have the right
permissions to perform actions against the tailscaled state Secret
-------------------------------------------------------------------
Fri May 10 15:16:33 UTC 2024 - Richard Rahl <rrahl0@disroot.org>
- update to 1.66.1:
* Resolved issues with nftables rules for stateful filtering,
introduced in v1.66.0.
* tailscale set command flags --netfilter-mode, --snat-subnet-routes,
and --stateful-filtering are added.
- update to 1.66.0:
* Implemented client-side quarantining for shared-in exit nodes,
as a mitigation for a security vulnerability described in TS-2024-005.
* Use the --stateful-filtering flag for the tailscale up to enable stateful filtering for
subnet routers and exit nodes, as a mitigation for a security vulnerability described
in TS-2024-005.
* Added tab completions
* Use the tailscale exit-node suggest command to automatically pick an available exit node
that is likely to perform best.
* Site-to-site networking now also requires --stateful-filtering=false in addition to
--snat-subnet-routes=false on new subnet routers. Existing subnet routers with --snat-subnet-routes=false
will default to --stateful-filtering=false.
- update to 1.64.2:
* nothing relevant for linux
- update to 1.64.1:
* nothing relevant for linux
- update to 1.64.0:
* New: tailscale configure kubeconfig now respects KUBECONFIG environment variable.
* Fixed: tailscale configure kubeconfig now works with partially empty kubeconfig.
* Fixed: MSS clamping for Kubernetes operator proxies using nftables.
* Fixed: Containers on hosts with partial support for ip6tables no longer crash.
- turn of changelog generation
- add completions for bash
-------------------------------------------------------------------
Sat Mar 30 08:28:56 UTC 2024 - Richard Rahl <rrahl0@proton.me>
- update to 1.62.1:
* Send load balancing hint HTTP request header
* Fixed: Kubernetes operator proxies should not accept subnet routes
-------------------------------------------------------------------
Thu Mar 14 03:13:54 UTC 2024 - rrahl0@proton.me
- update to 1.62.0:
* IPv6 support detection in a container environment is improved
* New: Web interface now uses ACL grants to manage access on tagged devices
* Tailscale SSH connections now disable unnecessary hostname canonicalization
* tailscale bugreport command for generating diagnostic logs now contain ethtool information
* Mullvad's family-friendly server is added to the list of well known DNS over HTTPS (DoH) servers
* DNS over HTTP requests now contain a timeout
* TCP forwarding attempts in userspace mode now have a per-client limit
* Endpoints with link-local IPv6 addresses is preferred over private addresses
* WireGuard logs are less verbose
* Go min. version 1.22.1
* DERP server region no longer changes if connectivity to the new DERP region is degraded
- update to 1.60.1:
* Exposing port 8080 to other devices on your tailnet works as expected
-------------------------------------------------------------------
Tue Feb 20 22:10:41 UTC 2024 - Alexandre Vicenzi <alexandre.vicenzi@suse.com>
- Add disable-auto-update.patch to prevent auto updates and instead
ask users to use Zypper to update manually
-------------------------------------------------------------------
Tue Feb 20 14:52:46 UTC 2024 - Richard Rahl <rrahl0@proton.me>
- change to the non deprecated manualrun
-------------------------------------------------------------------
Fri Feb 16 14:38:14 UTC 2024 - alexandre.vicenzi@suse.com
- Spec cleanup
* Use tar_scm to avoid commit hashes in the spec
* Use tailscale build scripts
* Drop ProtectClock fix for Leap, DeviceAllow fixes it
- Add build-verbose.patch to get go flags into build log
- Enable PrivateDevices but allow access to /dev/net/tun in tailscaled.service
-------------------------------------------------------------------
Fri Feb 16 00:50:26 UTC 2024 - Richard Rahl <rrahl0@proton.me>
- update to 1.60.0:
* minimum go version 1.22
* authentication: present users with a valid login page when
attempting to login even after leaving device unattended for several days
* networking: mute noisy peer mtu discovery errors
* networking: expose gVisor metrics in debug mode
* port mapper: support legacy "urn:dslforum-org" port mapping services
* port mapper: fix crash when no support mapping services found
* ssh: log warning when unable to find SSH host keys
* serve: improve error message when running as non-root
* Detect when Tailscale is running on Digital Ocean and automatically
use Digital Ocean's DNS resolvers
* enable app connectors to install routes for domains that resolve to CNAME
records
* support pre-configured routes from control server
* add new read-only mode
* tailscale status command: fix output formatting Tailnet
includes location-based exit nodes
* a new ProxyClass custom resource that allows to provide custom
configuration for cluster resources that the operator creates
* ACL tags for the operator can now be configured via Helm chart values
* routing to Ingress backends that require an exact path without a slash
-------------------------------------------------------------------
Wed Feb 7 14:52:53 UTC 2024 - Richard Rahl <rrahl0@proton.me>
- make rpm not overwrite /etc/default/taiscaled
- defattr everything to root
-------------------------------------------------------------------
Sat Feb 3 11:18:05 UTC 2024 - Richard Rahl <rrahl0@proton.me>
- no stripping of binaries
- add commitID to binaries for upstream
- add directory for saved configs
-------------------------------------------------------------------
Tue Jan 23 23:54:36 UTC 2024 - Richard Rahl <rrahl0@proton.me>
- switch services to manual
- update to version 1.58.2:
* Fixed: [App connectors][app-connectors] have improved scheduling
and merging of route changes under some conditions
* Fixed: Crash when performing UPnP portmapping on older routers
with no supported portmapping services
-------------------------------------------------------------------
Fri Jan 19 08:06:27 UTC 2024 - Richard Rahl <rrahl0@proton.me>
- update to version 1.58.0:
* portmap: check the epoch from NAT-PMP & PCP, establish new portmapping if it changes
* portmap: better handle multiple interfaces
* portmap: handle multiple UPnP discovery responses
* increase the number of 4via6 site IDs from 256 to 65,536
* taildrop: allow category Z unicode characters
* increased binary size with 1.56 is resolved in 1.58
* Reduce home DERP flapping when there's still an active connection
* device web ui: fixed issue when accessing shared devices
* device web ui: fixed login issue when accessed over https
-------------------------------------------------------------------
Wed Jan 10 02:17:57 UTC 2024 - Richard Rahl <rrahl0@proton.me>
- fix an issue with Leap, where ProtectClock prevents to connect to
/dev/net/tun
-------------------------------------------------------------------
Fri Dec 15 21:22:39 UTC 2023 - Richard Rahl <rrahl0@proton.me>
- update to version 1.56.1:
* Fixed: Web interface redirects to the correct self IP known by source peer
* Fixed: Usage of slices.Compact from app connector domains list
-------------------------------------------------------------------
Fri Dec 15 13:48:28 UTC 2023 - Richard Rahl <rrahl0@proton.me>
- fix version output to what upstream expects
-------------------------------------------------------------------
Wed Dec 13 22:08:30 UTC 2023 - rrahl0@proton.me
- Update to version 1.56.0:
* improve responsiveness under load, especially with bidirectional traffic
* improve UPnP portmapping
* add tailscale whois subcommand to observe metadata associated with a Tailscale IP
* include tailnet name and profile ID in tailscale switch --list to disambiguate
profiles with common login names
* improve tailscale web interface for configuring some device settings such as exit nodes,
subnet routers, and Tailscale SSH
* improve containerboot to symlink its socket file if possible,
making the tailscale CLI work without --socket=/tmp/tailscale.sock
* add support in Kubernetes operator cluster egress for referring to a tailnet service
by its MagicDNS name
- Update to version 1.54.1:
* no relevant updates to the linux version
-------------------------------------------------------------------
Fri Nov 24 21:59:11 UTC 2023 - Richard Rahl <rrahl0@proton.me>
- tailscale couldn't connect to /dev/net/tun
-------------------------------------------------------------------
Thu Nov 23 06:51:24 UTC 2023 - rrahl0@proton.me
- Update to version 1.54.0:
* improve throughput substantially for UDP packets over TUN device with recent Linux kernels
- Update to version 1.52.1:
* no linux improvements
- Update to version 1.52.0:
* tailscale set command flag --auto-update is added to opt in to automatic client updates
* tailscale serve and tailscale funnel commands are updated for improved usability
* tailscale update command for manual updates is now in beta
* Taildrop file transfer displays a progress meter
* nftables auto-detection is improved when TS_DEBUG_FIREWALL_MODE=auto is used
* DNS detection of NetworkManager with configured but absent systemd-resolved
* Taildrop now resumes file transfers after partial transfers are interrupted
* tailscale up command displays a message about client updates when newer versions are available
* tailscale status command displays a message about client updates when newer versions are available
* tailscale cert command renews in the background. The current certificate only displays if it has expired.
-------------------------------------------------------------------
Mon Oct 02 23:51:03 UTC 2023 - rrahl0@proton.me
- Update to version 1.50.1:
* fix bug where serve config could get wiped
* Funnel support for tsnet apps
* fix potential crash with UPnP
-------------------------------------------------------------------
Sat Sep 30 19:38:50 UTC 2023 - rrahl0@proton.me
- Update to version 1.50.0:
* Update tailscale{,d} licenses
* Update Quad9 addresses and references
* Adds support for Wikimedia DNS using DNS-over-HTTPS
- Update to version 1.48.1:
* no relevant updates
- Update to version 1.48.2:
* Improvements to Mullvad exit nodes
-------------------------------------------------------------------
Fri Aug 18 15:56:24 UTC 2023 - Richard Rahl <rrahl0@proton.me>
- Initial revision

143
tailscale.spec Normal file
View File

@@ -0,0 +1,143 @@
#
# spec file for package tailscale
#
# Copyright (c) 2025 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via https://bugs.opensuse.org/
#
Name: tailscale
Version: 1.80.0
Release: 0
Summary: The easiest, most secure way to use WireGuard and 2FA
License: BSD-3-Clause
URL: https://github.com/tailscale/tailscale
Source: %{name}-%{version}.tar.gz
Source1: vendor.tar.gz
Source2: %{name}d.service
Source3: %{name}d.defaults
Patch0: build-verbose.patch
Patch1: disable-auto-update.patch
BuildRequires: bash-completion
BuildRequires: fish
BuildRequires: git-core
BuildRequires: golang-packaging
BuildRequires: zsh
BuildRequires: golang(API) = 1.23
Requires: %{default_firewall_backend}
ExcludeArch: i586
%{?systemd_requires}
%description
Tailscale is a modern VPN built on top of Wireguard. It works like an overlay
network between the computers of your networks using NAT traversal.
%package bash-completion
Summary: Tailscale bash completion
Supplements: (%{name} and bash-completion)
BuildArch: noarch
%description bash-completion
bash completions for %{name}
%package zsh-completion
Summary: Tailsacle zsh completion
Supplements: (%{name} and zsh)
BuildArch: noarch
%description zsh-completion
zsh completion for %{name}
%package fish-completion
Summary: Tailscale fish completion
Supplements: (%{name} and fish)
BuildArch: noarch
%description fish-completion
fish completion for %{name}
%prep
%autosetup -a1 -p1
%build
%ifnarch ppc64
export GOFLAGS="-buildmode=pie"
%endif
export VERSION_SHORT=%{version}
export VERSION_LONG=%{version}
export VERSION_GIT_HASH='$(git rev-parse v%{version})'
./build_dist.sh ./cmd/%{name}
./build_dist.sh ./cmd/%{name}d
#generate completions
./%{name} completion bash > ./%{name}.bash
./%{name} completion zsh > ./%{name}.zsh
./%{name} completion fish > ./%{name}.fish
%check
./%{name} version
./%{name}d -version
%install
mkdir -p %{buildroot}%{_sharedstatedir}/%{name}
install -D -p -m 0755 %{name} %{buildroot}%{_bindir}/%{name}
install -D -p -m 0755 %{name}d %{buildroot}%{_sbindir}/%{name}d
# service
install -D -p -m 0644 %{SOURCE2} %{buildroot}%{_unitdir}/%{name}d.service
%if 0%{?suse_version} < 1600
ln -sf %{_sbindir}/service %{buildroot}%{_sbindir}/rc%{name}d
%endif
# defaults
install -D -p -m 0644 %{SOURCE3} %{buildroot}%{_sysconfdir}/default/%{name}d
install -D -p -m 0644 ./%{name}.bash %{buildroot}%{_datadir}/bash-completion/completions/%{name}
install -D -p -m 0644 ./%{name}.zsh %{buildroot}%{_datadir}/zsh/site-functions/_%{name}
install -D -p -m 0644 ./%{name}.fish %{buildroot}%{_datadir}/fish/vendor_completions.d/%{name}
%pre
%service_add_pre %{name}d.service
%post
%service_add_post %{name}d.service
%preun
%service_del_preun %{name}d.service
%postun
%service_del_postun %{name}d.service
%files
%license LICENSE PATENTS
%doc README.md SECURITY.md
%config(noreplace) %{_sysconfdir}/default/%{name}d
%dir %{_sharedstatedir}/%{name}
%{_bindir}/%{name}
%{_sbindir}/%{name}d
%{_unitdir}/%{name}d.service
%if 0%{?suse_version} < 1600
%{_sbindir}/rc%{name}d
%endif
%files bash-completion
%{_datadir}/bash-completion/completions/%{name}
%files zsh-completion
%{_datadir}/zsh/site-functions/_%{name}
%files fish-completion
%{_datadir}/fish/vendor_completions.d/%{name}
%changelog

8
tailscaled.defaults Normal file
View File

@@ -0,0 +1,8 @@
# Set the port to listen on for incoming VPN packets.
# Remote nodes will automatically be informed about the new port number,
# but you might want to configure this in order to set external firewall
# settings.
PORT="41641"
# Extra flags you might want to pass to tailscaled.
FLAGS=""

35
tailscaled.service Normal file
View File

@@ -0,0 +1,35 @@
[Unit]
Description=Tailscale node agent
Documentation=https://tailscale.com/kb/
Wants=network-pre.target
After=network-pre.target NetworkManager.service systemd-resolved.service
[Service]
EnvironmentFile=/etc/default/tailscaled
ExecStartPre=/usr/sbin/tailscaled --cleanup
ExecStart=/usr/sbin/tailscaled --state=/var/lib/tailscale/tailscaled.state --socket=/run/tailscale/tailscaled.sock --port=${PORT} $FLAGS
ExecStopPost=/usr/sbin/tailscaled --cleanup
Restart=on-failure
RuntimeDirectory=tailscale
RuntimeDirectoryMode=0755
StateDirectory=tailscale
StateDirectoryMode=0700
CacheDirectory=tailscale
CacheDirectoryMode=0750
Type=notify
# https://en.opensuse.org/openSUSE:Security_Features#Systemd_hardening_effort
PrivateDevices=true
ProtectClock=true
ProtectControlGroups=true
ProtectHome=true
ProtectHostname=true
ProtectKernelLogs=true
ProtectKernelModules=true
ProtectKernelTunables=true
RestrictRealtime=true
# give permission to TUN
BindPaths=/dev/net/tun
DeviceAllow=/dev/net/tun rw
[Install]
WantedBy=multi-user.target

3
vendor.tar.gz Normal file
View File

@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:67f60a722b71f96f7ba6519f96f9217c9885a17a7216ec0184af1be61467f0a9
size 19236295