mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-25 19:15:34 +00:00
cmd/dist,release/dist: add distsign signing hooks (#9070)
Add `dist.Signer` hook which can arbitrarily sign linux/synology artifacts. Plumb it through in `cmd/dist` and remove existing tarball signing key. Distsign signing will happen on a remote machine, not using a local key. Updates #755 Updates #8760 Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
This commit is contained in:
parent
dc8287ab3b
commit
b42c4e2da1
6
cmd/dist/dist.go
vendored
6
cmd/dist/dist.go
vendored
@ -19,10 +19,10 @@
|
|||||||
|
|
||||||
var synologyPackageCenter bool
|
var synologyPackageCenter bool
|
||||||
|
|
||||||
func getTargets(signers unixpkgs.Signers) ([]dist.Target, error) {
|
func getTargets() ([]dist.Target, error) {
|
||||||
var ret []dist.Target
|
var ret []dist.Target
|
||||||
|
|
||||||
ret = append(ret, unixpkgs.Targets(signers)...)
|
ret = append(ret, unixpkgs.Targets(unixpkgs.Signers{})...)
|
||||||
// Synology packages can be built either for sideloading, or for
|
// Synology packages can be built either for sideloading, or for
|
||||||
// distribution by Synology in their package center. When
|
// distribution by Synology in their package center. When
|
||||||
// distributed through the package center, apps can request
|
// distributed through the package center, apps can request
|
||||||
@ -33,7 +33,7 @@ func getTargets(signers unixpkgs.Signers) ([]dist.Target, error) {
|
|||||||
// Since only we can provide packages to Synology for
|
// Since only we can provide packages to Synology for
|
||||||
// distribution, we default to building the "sideload" variant of
|
// distribution, we default to building the "sideload" variant of
|
||||||
// packages that we distribute on pkgs.tailscale.com.
|
// packages that we distribute on pkgs.tailscale.com.
|
||||||
ret = append(ret, synology.Targets(synologyPackageCenter)...)
|
ret = append(ret, synology.Targets(synologyPackageCenter, nil)...)
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
release/dist/cli/cli.go
vendored
13
release/dist/cli/cli.go
vendored
@ -20,7 +20,6 @@
|
|||||||
"github.com/peterbourgon/ff/v3/ffcli"
|
"github.com/peterbourgon/ff/v3/ffcli"
|
||||||
"tailscale.com/clientupdate/distsign"
|
"tailscale.com/clientupdate/distsign"
|
||||||
"tailscale.com/release/dist"
|
"tailscale.com/release/dist"
|
||||||
"tailscale.com/release/dist/unixpkgs"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CLI returns a CLI root command to build release packages.
|
// CLI returns a CLI root command to build release packages.
|
||||||
@ -28,7 +27,7 @@
|
|||||||
// getTargets is a function that gets run in the Exec function of commands that
|
// getTargets is a function that gets run in the Exec function of commands that
|
||||||
// need to know the target list. Its execution is deferred in this way to allow
|
// need to know the target list. Its execution is deferred in this way to allow
|
||||||
// customization of command FlagSets with flags that influence the target list.
|
// customization of command FlagSets with flags that influence the target list.
|
||||||
func CLI(getTargets func(unixpkgs.Signers) ([]dist.Target, error)) *ffcli.Command {
|
func CLI(getTargets func() ([]dist.Target, error)) *ffcli.Command {
|
||||||
return &ffcli.Command{
|
return &ffcli.Command{
|
||||||
Name: "dist",
|
Name: "dist",
|
||||||
ShortUsage: "dist [flags] <command> [command flags]",
|
ShortUsage: "dist [flags] <command> [command flags]",
|
||||||
@ -38,7 +37,7 @@ func CLI(getTargets func(unixpkgs.Signers) ([]dist.Target, error)) *ffcli.Comman
|
|||||||
{
|
{
|
||||||
Name: "list",
|
Name: "list",
|
||||||
Exec: func(ctx context.Context, args []string) error {
|
Exec: func(ctx context.Context, args []string) error {
|
||||||
targets, err := getTargets(unixpkgs.Signers{})
|
targets, err := getTargets()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -54,11 +53,7 @@ func CLI(getTargets func(unixpkgs.Signers) ([]dist.Target, error)) *ffcli.Comman
|
|||||||
{
|
{
|
||||||
Name: "build",
|
Name: "build",
|
||||||
Exec: func(ctx context.Context, args []string) error {
|
Exec: func(ctx context.Context, args []string) error {
|
||||||
tgzSigner, err := parseSigningKey(buildArgs.tgzSigningKey)
|
targets, err := getTargets()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
targets, err := getTargets(unixpkgs.Signers{Tarball: tgzSigner})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -70,7 +65,6 @@ func CLI(getTargets func(unixpkgs.Signers) ([]dist.Target, error)) *ffcli.Comman
|
|||||||
fs := flag.NewFlagSet("build", flag.ExitOnError)
|
fs := flag.NewFlagSet("build", flag.ExitOnError)
|
||||||
fs.StringVar(&buildArgs.manifest, "manifest", "", "manifest file to write")
|
fs.StringVar(&buildArgs.manifest, "manifest", "", "manifest file to write")
|
||||||
fs.BoolVar(&buildArgs.verbose, "verbose", false, "verbose logging")
|
fs.BoolVar(&buildArgs.verbose, "verbose", false, "verbose logging")
|
||||||
fs.StringVar(&buildArgs.tgzSigningKey, "tgz-signing-key", "", "path to private signing key for release tarballs")
|
|
||||||
fs.StringVar(&buildArgs.webClientRoot, "web-client-root", "", "path to root of web client source to build")
|
fs.StringVar(&buildArgs.webClientRoot, "web-client-root", "", "path to root of web client source to build")
|
||||||
return fs
|
return fs
|
||||||
})(),
|
})(),
|
||||||
@ -147,7 +141,6 @@ func runList(ctx context.Context, filters []string, targets []dist.Target) error
|
|||||||
var buildArgs struct {
|
var buildArgs struct {
|
||||||
manifest string
|
manifest string
|
||||||
verbose bool
|
verbose bool
|
||||||
tgzSigningKey string
|
|
||||||
webClientRoot string
|
webClientRoot string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22
release/dist/dist.go
vendored
22
release/dist/dist.go
vendored
@ -8,6 +8,7 @@
|
|||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -29,6 +30,27 @@ type Target interface {
|
|||||||
Build(build *Build) ([]string, error)
|
Build(build *Build) ([]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Signer is pluggable signer for a Target.
|
||||||
|
type Signer func(io.Reader) ([]byte, error)
|
||||||
|
|
||||||
|
// SignFile signs the file at filePath with s and writes the signature to
|
||||||
|
// sigPath.
|
||||||
|
func (s Signer) SignFile(filePath, sigPath string) error {
|
||||||
|
f, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
sig, err := s(f)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return os.WriteFile(sigPath, sig, 0644)
|
||||||
|
}
|
||||||
|
|
||||||
// A Build is a build context for Targets.
|
// A Build is a build context for Targets.
|
||||||
type Build struct {
|
type Build struct {
|
||||||
// Repo is a path to the root Go module for the build.
|
// Repo is a path to the root Go module for the build.
|
||||||
|
30
release/dist/synology/pkgs.go
vendored
30
release/dist/synology/pkgs.go
vendored
@ -25,6 +25,7 @@ type target struct {
|
|||||||
dsmMajorVersion int
|
dsmMajorVersion int
|
||||||
goenv map[string]string
|
goenv map[string]string
|
||||||
packageCenter bool
|
packageCenter bool
|
||||||
|
signer dist.Signer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *target) String() string {
|
func (t *target) String() string {
|
||||||
@ -37,15 +38,10 @@ func (t *target) Build(b *dist.Build) ([]string, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := t.buildSPK(b, inner)
|
return t.buildSPK(b, inner)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return []string{out}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *target) buildSPK(b *dist.Build, inner *innerPkg) (string, error) {
|
func (t *target) buildSPK(b *dist.Build, inner *innerPkg) ([]string, error) {
|
||||||
filename := fmt.Sprintf("tailscale-%s-%s-%d-dsm%d.spk", t.filenameArch, b.Version.Short, b.Version.Synology[t.dsmMajorVersion], t.dsmMajorVersion)
|
filename := fmt.Sprintf("tailscale-%s-%s-%d-dsm%d.spk", t.filenameArch, b.Version.Short, b.Version.Synology[t.dsmMajorVersion], t.dsmMajorVersion)
|
||||||
out := filepath.Join(b.Out, filename)
|
out := filepath.Join(b.Out, filename)
|
||||||
log.Printf("Building %s", filename)
|
log.Printf("Building %s", filename)
|
||||||
@ -57,7 +53,7 @@ func (t *target) buildSPK(b *dist.Build, inner *innerPkg) (string, error) {
|
|||||||
|
|
||||||
f, err := os.Create(out)
|
f, err := os.Create(out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
tw := tar.NewWriter(f)
|
tw := tar.NewWriter(f)
|
||||||
@ -78,17 +74,27 @@ func (t *target) buildSPK(b *dist.Build, inner *innerPkg) (string, error) {
|
|||||||
static("scripts/preupgrade", "scripts/preupgrade", 0644),
|
static("scripts/preupgrade", "scripts/preupgrade", 0644),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tw.Close(); err != nil {
|
if err := tw.Close(); err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := f.Close(); err != nil {
|
if err := f.Close(); err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return out, nil
|
files := []string{out}
|
||||||
|
|
||||||
|
if t.signer != nil {
|
||||||
|
outSig := out + ".sig"
|
||||||
|
if err := t.signer.SignFile(out, outSig); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
files = append(files, outSig)
|
||||||
|
}
|
||||||
|
|
||||||
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *target) mkInfo(b *dist.Build, uncompressedSz int64) []byte {
|
func (t *target) mkInfo(b *dist.Build, uncompressedSz int64) []byte {
|
||||||
|
7
release/dist/synology/targets.go
vendored
7
release/dist/synology/targets.go
vendored
@ -26,7 +26,7 @@
|
|||||||
"monaco",
|
"monaco",
|
||||||
}
|
}
|
||||||
|
|
||||||
func Targets(forPackageCenter bool) []dist.Target {
|
func Targets(forPackageCenter bool, signer dist.Signer) []dist.Target {
|
||||||
var ret []dist.Target
|
var ret []dist.Target
|
||||||
for _, dsmVersion := range []int{6, 7} {
|
for _, dsmVersion := range []int{6, 7} {
|
||||||
ret = append(ret,
|
ret = append(ret,
|
||||||
@ -38,6 +38,7 @@ func Targets(forPackageCenter bool) []dist.Target {
|
|||||||
"GOARCH": "amd64",
|
"GOARCH": "amd64",
|
||||||
},
|
},
|
||||||
packageCenter: forPackageCenter,
|
packageCenter: forPackageCenter,
|
||||||
|
signer: signer,
|
||||||
},
|
},
|
||||||
&target{
|
&target{
|
||||||
filenameArch: "i686",
|
filenameArch: "i686",
|
||||||
@ -47,6 +48,7 @@ func Targets(forPackageCenter bool) []dist.Target {
|
|||||||
"GOARCH": "386",
|
"GOARCH": "386",
|
||||||
},
|
},
|
||||||
packageCenter: forPackageCenter,
|
packageCenter: forPackageCenter,
|
||||||
|
signer: signer,
|
||||||
},
|
},
|
||||||
&target{
|
&target{
|
||||||
filenameArch: "armv8",
|
filenameArch: "armv8",
|
||||||
@ -56,6 +58,7 @@ func Targets(forPackageCenter bool) []dist.Target {
|
|||||||
"GOARCH": "arm64",
|
"GOARCH": "arm64",
|
||||||
},
|
},
|
||||||
packageCenter: forPackageCenter,
|
packageCenter: forPackageCenter,
|
||||||
|
signer: signer,
|
||||||
})
|
})
|
||||||
|
|
||||||
// On older ARMv5 and ARMv7 platforms, synology used a whole
|
// On older ARMv5 and ARMv7 platforms, synology used a whole
|
||||||
@ -71,6 +74,7 @@ func Targets(forPackageCenter bool) []dist.Target {
|
|||||||
"GOARM": "5",
|
"GOARM": "5",
|
||||||
},
|
},
|
||||||
packageCenter: forPackageCenter,
|
packageCenter: forPackageCenter,
|
||||||
|
signer: signer,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
for _, v7Arch := range v7Models {
|
for _, v7Arch := range v7Models {
|
||||||
@ -83,6 +87,7 @@ func Targets(forPackageCenter bool) []dist.Target {
|
|||||||
"GOARM": "7",
|
"GOARM": "7",
|
||||||
},
|
},
|
||||||
packageCenter: forPackageCenter,
|
packageCenter: forPackageCenter,
|
||||||
|
signer: signer,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
25
release/dist/unixpkgs/pkgs.go
vendored
25
release/dist/unixpkgs/pkgs.go
vendored
@ -7,9 +7,6 @@
|
|||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"crypto"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/sha512"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -26,7 +23,7 @@
|
|||||||
type tgzTarget struct {
|
type tgzTarget struct {
|
||||||
filenameArch string // arch to use in filename instead of deriving from goEnv["GOARCH"]
|
filenameArch string // arch to use in filename instead of deriving from goEnv["GOARCH"]
|
||||||
goEnv map[string]string
|
goEnv map[string]string
|
||||||
signer crypto.Signer
|
signer dist.Signer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tgzTarget) arch() string {
|
func (t *tgzTarget) arch() string {
|
||||||
@ -73,11 +70,7 @@ func (t *tgzTarget) Build(b *dist.Build) ([]string, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
// Hash the final output we're writing to the file, after tar and gzip
|
gw := gzip.NewWriter(f)
|
||||||
// writers did their thing.
|
|
||||||
h := sha512.New()
|
|
||||||
hw := io.MultiWriter(f, h)
|
|
||||||
gw := gzip.NewWriter(hw)
|
|
||||||
defer gw.Close()
|
defer gw.Close()
|
||||||
tw := tar.NewWriter(gw)
|
tw := tar.NewWriter(gw)
|
||||||
defer tw.Close()
|
defer tw.Close()
|
||||||
@ -161,15 +154,11 @@ func (t *tgzTarget) Build(b *dist.Build) ([]string, error) {
|
|||||||
files := []string{filename}
|
files := []string{filename}
|
||||||
|
|
||||||
if t.signer != nil {
|
if t.signer != nil {
|
||||||
sig, err := t.signer.Sign(rand.Reader, h.Sum(nil), crypto.SHA512)
|
outSig := out + ".sig"
|
||||||
if err != nil {
|
if err := t.signer.SignFile(out, outSig); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
sigFilename := out + ".sig"
|
files = append(files, filepath.Base(outSig))
|
||||||
if err := os.WriteFile(sigFilename, sig, 0644); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
files = append(files, filename+".sig")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return files, nil
|
return files, nil
|
||||||
@ -291,7 +280,7 @@ func (t *debTarget) Build(b *dist.Build) ([]string, error) {
|
|||||||
|
|
||||||
type rpmTarget struct {
|
type rpmTarget struct {
|
||||||
goEnv map[string]string
|
goEnv map[string]string
|
||||||
signFn func(io.Reader) ([]byte, error)
|
signer dist.Signer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *rpmTarget) os() string {
|
func (t *rpmTarget) os() string {
|
||||||
@ -387,7 +376,7 @@ func (t *rpmTarget) Build(b *dist.Build) ([]string, error) {
|
|||||||
Group: "Network",
|
Group: "Network",
|
||||||
Signature: nfpm.RPMSignature{
|
Signature: nfpm.RPMSignature{
|
||||||
PackageSignature: nfpm.PackageSignature{
|
PackageSignature: nfpm.PackageSignature{
|
||||||
SignFn: t.signFn,
|
SignFn: t.signer,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
8
release/dist/unixpkgs/targets.go
vendored
8
release/dist/unixpkgs/targets.go
vendored
@ -4,9 +4,7 @@
|
|||||||
package unixpkgs
|
package unixpkgs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -17,8 +15,8 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Signers struct {
|
type Signers struct {
|
||||||
Tarball crypto.Signer
|
Tarball dist.Signer
|
||||||
RPM func(io.Reader) ([]byte, error)
|
RPM dist.Signer
|
||||||
}
|
}
|
||||||
|
|
||||||
func Targets(signers Signers) []dist.Target {
|
func Targets(signers Signers) []dist.Target {
|
||||||
@ -49,7 +47,7 @@ func Targets(signers Signers) []dist.Target {
|
|||||||
"GOOS": goos,
|
"GOOS": goos,
|
||||||
"GOARCH": goarch,
|
"GOARCH": goarch,
|
||||||
},
|
},
|
||||||
signFn: signers.RPM,
|
signer: signers.RPM,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user