allow pomerium to be embedded as a library (#3415)

This commit is contained in:
Denis Mishin 2022-06-15 20:29:19 -04:00 committed by GitHub
parent 6e1ebffc59
commit d1037d784a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 292 additions and 207 deletions

6
.gitignore vendored
View file

@ -90,8 +90,8 @@ docs/.vuepress/dist/
.service-accounts .service-accounts
/bazel-* /bazel-*
internal/envoy/files/envoy-*-????? pkg/envoy/files/envoy-*-?????
internal/envoy/files/envoy-*-?????.sha256 pkg/envoy/files/envoy-*-?????.sha256
internal/envoy/files/envoy-*-?????.version pkg/envoy/files/envoy-*-?????.version
yarn-error.log yarn-error.log

View file

@ -113,8 +113,8 @@ clean: ## Cleanup any build binaries or packages.
@echo "==> $@" @echo "==> $@"
$(RM) -r $(BINDIR) $(RM) -r $(BINDIR)
$(RM) -r $(BUILDDIR) $(RM) -r $(BUILDDIR)
$(RM) internal/envoy/files/envoy-* $(RM) pkg/envoy/files/envoy-*
$(RM) $GOPATH/bin/protoc-gen-validate $(RM) $(GOPATH)/bin/protoc-gen-validate
$(RM) -r /tmp/pomerium-protoc $(RM) -r /tmp/pomerium-protoc
$(RM) -r /tmp/pomerium-protoc-3pp $(RM) -r /tmp/pomerium-protoc-3pp

View file

@ -6,10 +6,13 @@ import (
"flag" "flag"
"fmt" "fmt"
"github.com/pomerium/pomerium/internal/cmd/pomerium" "github.com/rs/zerolog"
"github.com/pomerium/pomerium/internal/envoy/files"
"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/version" "github.com/pomerium/pomerium/internal/version"
"github.com/pomerium/pomerium/pkg/cmd/pomerium"
"github.com/pomerium/pomerium/pkg/envoy/files"
) )
var ( var (
@ -33,5 +36,16 @@ func main() {
} }
func run(ctx context.Context) error { func run(ctx context.Context) error {
return pomerium.Run(ctx, *configFile) ctx = log.WithContext(ctx, func(c zerolog.Context) zerolog.Context {
return c.Str("config_file_source", *configFile).Bool("bootstrap", true)
})
var src config.Source
src, err := config.NewFileOrEnvironmentSource(*configFile, files.FullVersion())
if err != nil {
return err
}
return pomerium.Run(ctx, src)
} }

View file

@ -4,6 +4,7 @@ import (
"crypto/tls" "crypto/tls"
"github.com/pomerium/pomerium/internal/hashutil" "github.com/pomerium/pomerium/internal/hashutil"
"github.com/pomerium/pomerium/internal/netutil"
) )
// Config holds pomerium configuration options. // Config holds pomerium configuration options.
@ -58,3 +59,19 @@ func (cfg *Config) AllCertificates() ([]tls.Certificate, error) {
func (cfg *Config) Checksum() uint64 { func (cfg *Config) Checksum() uint64 {
return hashutil.MustHash(cfg) return hashutil.MustHash(cfg)
} }
// AllocatePorts populates
func (cfg *Config) AllocatePorts() error {
ports, err := netutil.AllocatePorts(5)
if err != nil {
return err
}
cfg.GRPCPort = ports[0]
cfg.HTTPPort = ports[1]
cfg.OutboundPort = ports[2]
cfg.MetricsPort = ports[3]
cfg.DebugPort = ports[4]
return nil
}

View file

@ -3,6 +3,7 @@ package config
import ( import (
"context" "context"
"crypto/sha256" "crypto/sha256"
"fmt"
"os" "os"
"sync" "sync"
@ -11,7 +12,6 @@ import (
"github.com/pomerium/pomerium/internal/fileutil" "github.com/pomerium/pomerium/internal/fileutil"
"github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/netutil"
"github.com/pomerium/pomerium/internal/telemetry/metrics" "github.com/pomerium/pomerium/internal/telemetry/metrics"
) )
@ -110,26 +110,15 @@ func NewFileOrEnvironmentSource(
return nil, err return nil, err
} }
ports, err := netutil.AllocatePorts(5)
if err != nil {
return nil, err
}
grpcPort := ports[0]
httpPort := ports[1]
outboundPort := ports[2]
metricsPort := ports[3]
debugPort := ports[4]
cfg := &Config{ cfg := &Config{
Options: options, Options: options,
EnvoyVersion: envoyVersion, EnvoyVersion: envoyVersion,
GRPCPort: grpcPort,
HTTPPort: httpPort,
OutboundPort: outboundPort,
MetricsPort: metricsPort,
DebugPort: debugPort,
} }
if err = cfg.AllocatePorts(); err != nil {
return nil, fmt.Errorf("allocating ports: %w", err)
}
metrics.SetConfigInfo(ctx, cfg.Options.Services, "local", cfg.Checksum(), true) metrics.SetConfigInfo(ctx, cfg.Options.Services, "local", cfg.Checksum(), true)
src := &FileOrEnvironmentSource{ src := &FileOrEnvironmentSource{

View file

@ -16,7 +16,6 @@ import (
"github.com/pomerium/pomerium/config" "github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/internal/directory" "github.com/pomerium/pomerium/internal/directory"
"github.com/pomerium/pomerium/internal/envoy/files"
"github.com/pomerium/pomerium/internal/events" "github.com/pomerium/pomerium/internal/events"
"github.com/pomerium/pomerium/internal/identity" "github.com/pomerium/pomerium/internal/identity"
"github.com/pomerium/pomerium/internal/identity/manager" "github.com/pomerium/pomerium/internal/identity/manager"
@ -24,6 +23,7 @@ import (
"github.com/pomerium/pomerium/internal/telemetry" "github.com/pomerium/pomerium/internal/telemetry"
"github.com/pomerium/pomerium/internal/version" "github.com/pomerium/pomerium/internal/version"
"github.com/pomerium/pomerium/pkg/cryptutil" "github.com/pomerium/pomerium/pkg/cryptutil"
"github.com/pomerium/pomerium/pkg/envoy/files"
"github.com/pomerium/pomerium/pkg/grpc/databroker" "github.com/pomerium/pomerium/pkg/grpc/databroker"
"github.com/pomerium/pomerium/pkg/grpc/registry" "github.com/pomerium/pomerium/pkg/grpc/registry"
"github.com/pomerium/pomerium/pkg/grpcutil" "github.com/pomerium/pomerium/pkg/grpcutil"

View file

@ -21,7 +21,6 @@ import (
"github.com/pomerium/pomerium/config/envoyconfig" "github.com/pomerium/pomerium/config/envoyconfig"
"github.com/pomerium/pomerium/config/envoyconfig/filemgr" "github.com/pomerium/pomerium/config/envoyconfig/filemgr"
"github.com/pomerium/pomerium/internal/controlplane/xdsmgr" "github.com/pomerium/pomerium/internal/controlplane/xdsmgr"
"github.com/pomerium/pomerium/internal/envoy/files"
"github.com/pomerium/pomerium/internal/events" "github.com/pomerium/pomerium/internal/events"
"github.com/pomerium/pomerium/internal/httputil/reproxy" "github.com/pomerium/pomerium/internal/httputil/reproxy"
"github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/internal/log"
@ -29,6 +28,7 @@ import (
"github.com/pomerium/pomerium/internal/telemetry/requestid" "github.com/pomerium/pomerium/internal/telemetry/requestid"
"github.com/pomerium/pomerium/internal/urlutil" "github.com/pomerium/pomerium/internal/urlutil"
"github.com/pomerium/pomerium/internal/version" "github.com/pomerium/pomerium/internal/version"
"github.com/pomerium/pomerium/pkg/envoy/files"
pom_grpc "github.com/pomerium/pomerium/pkg/grpc" pom_grpc "github.com/pomerium/pomerium/pkg/grpc"
"github.com/pomerium/pomerium/pkg/grpcutil" "github.com/pomerium/pomerium/pkg/grpcutil"
) )

View file

@ -1,71 +0,0 @@
package envoy
import (
"bytes"
"context"
"fmt"
"io/fs"
"os"
"path/filepath"
"sync"
"github.com/natefinch/atomic"
"github.com/pomerium/pomerium/internal/envoy/files"
"github.com/pomerium/pomerium/internal/log"
)
const (
embeddedEnvoyPermissions fs.FileMode = 0o700
embeddedDirectoryPermissions fs.FileMode = 0o755
)
// OverrideEnvoyPath is an override for using an envoy path instead of the embedded envoy path.
var OverrideEnvoyPath = ""
var (
embeddedFilesBaseDirectory = filepath.Join(os.TempDir(), "pomerium-embedded-files")
extractEmbeddedEnvoyOnce sync.Once
)
func extractEmbeddedEnvoy(ctx context.Context) (outPath string, err error) {
extractEmbeddedEnvoyOnce.Do(func() {
// clean up our base directory before starting
err = os.RemoveAll(embeddedFilesBaseDirectory)
if err != nil {
err = fmt.Errorf("error cleaning embedded file directory: (directory=%s): %w", embeddedFilesBaseDirectory, err)
return
}
// create known directory base to clean at startup
err = os.MkdirAll(embeddedFilesBaseDirectory, embeddedDirectoryPermissions)
if err != nil {
err = fmt.Errorf("error creating embedded file directory: (directory=%s): %w", embeddedFilesBaseDirectory, err)
return
}
// build a random temp directory inside our base directory to guarantee permissions
var tmpDir string
tmpDir, err = os.MkdirTemp(embeddedFilesBaseDirectory, "envoy-")
if err != nil {
err = fmt.Errorf("error creating embedded file tmp directory: (directory=%s): %w", embeddedFilesBaseDirectory, err)
return
}
outPath = filepath.Join(tmpDir, "envoy")
log.Info(ctx).Str("path", outPath).Msg("extracting envoy binary")
err = atomic.WriteFile(outPath, bytes.NewReader(files.Binary()))
if err != nil {
err = fmt.Errorf("error extracting embedded envoy binary to temporary directory (path=%s): %w", outPath, err)
return
}
err = os.Chmod(outPath, embeddedEnvoyPermissions)
if err != nil {
err = fmt.Errorf("error chmoding embedded envoy binary: %w", err)
return
}
})
return outPath, err
}

View file

@ -11,7 +11,6 @@ import (
"syscall" "syscall"
envoy_service_auth_v3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3" envoy_service_auth_v3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
"github.com/rs/zerolog"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"github.com/pomerium/pomerium/authenticate" "github.com/pomerium/pomerium/authenticate"
@ -21,29 +20,22 @@ import (
"github.com/pomerium/pomerium/internal/autocert" "github.com/pomerium/pomerium/internal/autocert"
"github.com/pomerium/pomerium/internal/controlplane" "github.com/pomerium/pomerium/internal/controlplane"
"github.com/pomerium/pomerium/internal/databroker" "github.com/pomerium/pomerium/internal/databroker"
"github.com/pomerium/pomerium/internal/envoy"
"github.com/pomerium/pomerium/internal/envoy/files"
"github.com/pomerium/pomerium/internal/events" "github.com/pomerium/pomerium/internal/events"
"github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/registry" "github.com/pomerium/pomerium/internal/registry"
"github.com/pomerium/pomerium/internal/version" "github.com/pomerium/pomerium/internal/version"
"github.com/pomerium/pomerium/pkg/envoy"
"github.com/pomerium/pomerium/pkg/envoy/files"
"github.com/pomerium/pomerium/proxy" "github.com/pomerium/pomerium/proxy"
) )
// Run runs the main pomerium application. // Run runs the main pomerium application.
func Run(ctx context.Context, configFile string) error { func Run(ctx context.Context, src config.Source) error {
log.Info(ctx). log.Info(ctx).
Str("envoy_version", files.FullVersion()). Str("envoy_version", files.FullVersion()).
Str("version", version.FullVersion()). Str("version", version.FullVersion()).
Msg("cmd/pomerium") Msg("cmd/pomerium")
var src config.Source
src, err := config.NewFileOrEnvironmentSource(configFile, files.FullVersion())
if err != nil {
return err
}
src = databroker.NewConfigSource(ctx, src) src = databroker.NewConfigSource(ctx, src)
logMgr := config.NewLogManager(ctx, src) logMgr := config.NewLogManager(ctx, src)
defer logMgr.Close() defer logMgr.Close()
@ -51,7 +43,7 @@ func Run(ctx context.Context, configFile string) error {
// trigger changes when underlying files are changed // trigger changes when underlying files are changed
src = config.NewFileWatcherSource(src) src = config.NewFileWatcherSource(src)
src, err = autocert.New(src) src, err := autocert.New(src)
if err != nil { if err != nil {
return err return err
} }
@ -78,9 +70,7 @@ func Run(ctx context.Context, configFile string) error {
} }
}) })
if err = controlPlane.OnConfigChange(log.WithContext(ctx, func(c zerolog.Context) zerolog.Context { if err = controlPlane.OnConfigChange(ctx, src.GetConfig()); err != nil {
return c.Str("config_file_source", configFile).Bool("bootstrap", true)
}), src.GetConfig()); err != nil {
return fmt.Errorf("applying config: %w", err) return fmt.Errorf("applying config: %w", err)
} }

View file

@ -1,20 +1,36 @@
package pomerium package pomerium_test
import ( import (
"context" "context"
"os" "os"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/require"
"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/pkg/cmd/pomerium"
"github.com/pomerium/pomerium/pkg/envoy/files"
) )
func Test_run(t *testing.T) { func Test_run(t *testing.T) {
os.Clearenv() os.Clearenv()
run := func(ctx context.Context, configFile string) error {
src, err := config.NewFileOrEnvironmentSource(configFile, files.FullVersion())
if err != nil {
return err
}
return pomerium.Run(ctx, src)
}
tests := []struct { tests := []struct {
name string name string
configFileFlag string configFileFlag string
wantErr bool check func(require.TestingT, error, ...any)
}{ }{
{"nil configuration", "", true}, {"nil configuration", "", require.Error},
{"bad proxy no authenticate url", ` {"bad proxy no authenticate url", `
{ {
"address": ":9433", "address": ":9433",
@ -26,7 +42,7 @@ func Test_run(t *testing.T) {
"services": "proxy", "services": "proxy",
"policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }] "policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }]
} }
`, true}, `, require.Error},
{"bad authenticate no cookie secret", ` {"bad authenticate no cookie secret", `
{ {
"address": ":9433", "address": ":9433",
@ -37,7 +53,7 @@ func Test_run(t *testing.T) {
"services": "authenticate", "services": "authenticate",
"policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }] "policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }]
} }
`, true}, `, require.Error},
{"bad authorize service bad shared key", ` {"bad authorize service bad shared key", `
{ {
"address": ":9433", "address": ":9433",
@ -49,7 +65,7 @@ func Test_run(t *testing.T) {
"services": "authorize", "services": "authorize",
"policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }] "policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }]
} }
`, true}, `, require.Error},
{"bad http port", ` {"bad http port", `
{ {
"address": ":-1", "address": ":-1",
@ -63,7 +79,7 @@ func Test_run(t *testing.T) {
"services": "proxy", "services": "proxy",
"policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }] "policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }]
} }
`, true}, `, require.Error},
{"bad redirect port", ` {"bad redirect port", `
{ {
"address": ":9433", "address": ":9433",
@ -78,7 +94,7 @@ func Test_run(t *testing.T) {
"services": "proxy", "services": "proxy",
"policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }] "policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }]
} }
`, true}, `, require.Error},
{"bad metrics port ", ` {"bad metrics port ", `
{ {
"address": ":9433", "address": ":9433",
@ -92,7 +108,7 @@ func Test_run(t *testing.T) {
"services": "proxy", "services": "proxy",
"policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }] "policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }]
} }
`, true}, `, require.Error},
{"malformed tracing provider", ` {"malformed tracing provider", `
{ {
"tracing_provider": "bad tracing provider", "tracing_provider": "bad tracing provider",
@ -107,7 +123,7 @@ func Test_run(t *testing.T) {
"services": "proxy", "services": "proxy",
"policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }] "policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }]
} }
`, true}, `, require.Error},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
@ -115,7 +131,7 @@ func Test_run(t *testing.T) {
if err != nil { if err != nil {
t.Fatal("Cannot create temporary file", err) t.Fatal("Cannot create temporary file", err)
} }
defer os.Remove(tmpFile.Name()) defer func() { _ = os.Remove(tmpFile.Name()) }()
fn := tmpFile.Name() fn := tmpFile.Name()
if _, err := tmpFile.Write([]byte(tt.configFileFlag)); err != nil { if _, err := tmpFile.Write([]byte(tt.configFileFlag)); err != nil {
tmpFile.Close() tmpFile.Close()
@ -126,10 +142,7 @@ func Test_run(t *testing.T) {
ctx, clearTimeout := context.WithTimeout(context.Background(), 500*time.Millisecond) ctx, clearTimeout := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer clearTimeout() defer clearTimeout()
err = Run(ctx, configFile) tt.check(t, run(ctx, configFile))
if (err != nil) != tt.wantErr {
t.Errorf("run() error = %v, wantErr %v", err, tt.wantErr)
}
}) })
} }
} }

View file

@ -5,13 +5,12 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"context" "context"
"crypto/sha256"
"encoding/hex"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"os" "os"
"os/exec" "os/exec"
"path"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strconv" "strconv"
@ -30,14 +29,13 @@ import (
"github.com/pomerium/pomerium/config" "github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/config/envoyconfig" "github.com/pomerium/pomerium/config/envoyconfig"
"github.com/pomerium/pomerium/internal/envoy/files"
"github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/telemetry" "github.com/pomerium/pomerium/internal/telemetry"
"github.com/pomerium/pomerium/pkg/envoy/files"
) )
const ( const (
workingDirectoryName = ".pomerium-envoy" configFileName = "envoy-config.yaml"
configFileName = "envoy-config.yaml"
) )
type serverOptions struct { type serverOptions struct {
@ -62,38 +60,13 @@ type Server struct {
// NewServer creates a new server with traffic routed by envoy. // NewServer creates a new server with traffic routed by envoy.
func NewServer(ctx context.Context, src config.Source, builder *envoyconfig.Builder) (*Server, error) { func NewServer(ctx context.Context, src config.Source, builder *envoyconfig.Builder) (*Server, error) {
wd := filepath.Join(os.TempDir(), workingDirectoryName) envoyPath, err := Extract()
err := os.MkdirAll(wd, embeddedEnvoyPermissions)
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating temporary working directory for envoy: %w", err) return nil, fmt.Errorf("extracting envoy: %w", err)
}
envoyPath := OverrideEnvoyPath
if envoyPath == "" {
envoyPath, err = extractEmbeddedEnvoy(ctx)
if err != nil {
return nil, fmt.Errorf("error extracting embedded envoy binary: %w", err)
}
// Checksum is written at build time, if it's not empty we verify the binary
if files.Checksum() != "" {
bs, err := os.ReadFile(envoyPath)
if err != nil {
return nil, fmt.Errorf("error reading envoy binary for checksum verification: %w", err)
}
h := sha256.New()
h.Write(bs)
s := hex.EncodeToString(h.Sum(nil))
if files.Checksum() != s {
return nil, fmt.Errorf("invalid envoy binary, expected %s but got %s", files.Checksum(), s)
}
} else {
log.Info(ctx).Msg("no checksum defined, envoy binary will not be verified!")
}
} }
srv := &Server{ srv := &Server{
wd: wd, wd: path.Dir(envoyPath),
builder: builder, builder: builder,
grpcPort: src.GetConfig().GRPCPort, grpcPort: src.GetConfig().GRPCPort,
httpPort: src.GetConfig().HTTPPort, httpPort: src.GetConfig().HTTPPort,

99
pkg/envoy/extract.go Normal file
View file

@ -0,0 +1,99 @@
package envoy
import (
"bytes"
"crypto/sha256"
"encoding/hex"
"fmt"
"hash"
"io"
"os"
"path/filepath"
"strings"
"sync"
"github.com/pomerium/pomerium/pkg/envoy/files"
)
const (
ownerRX = os.FileMode(0o500)
maxExpandedEnvoySize = 1 << 30
)
type hashReader struct {
hash.Hash
r io.Reader
}
func (hr *hashReader) Read(p []byte) (n int, err error) {
n, err = hr.r.Read(p)
_, _ = hr.Write(p[:n])
return n, err
}
var (
setupLock sync.Mutex
setupDone bool
setupFullEnvoyPath string
setupErr error
)
// Extract extracts envoy binary and returns its location
func Extract() (fullEnvoyPath string, err error) {
setupLock.Lock()
defer setupLock.Unlock()
// if we've extract at least once, and the file we previously extracted no longer exists, force a new extraction
if setupFullEnvoyPath != "" {
if _, err := os.Stat(setupFullEnvoyPath); os.IsNotExist(err) {
setupDone = false
}
}
if setupDone {
return setupFullEnvoyPath, setupErr
}
dir, err := os.MkdirTemp(os.TempDir(), "pomerium-envoy")
if err != nil {
setupErr = fmt.Errorf("envoy: failed making temporary working dir: %w", err)
return
}
setupFullEnvoyPath = filepath.Join(dir, "envoy")
err = extract(setupFullEnvoyPath)
if err != nil {
setupErr = fmt.Errorf("envoy: failed to extract embedded envoy binary: %w", err)
return
}
setupDone = true
return setupFullEnvoyPath, setupErr
}
func extract(dstName string) (err error) {
checksum, err := hex.DecodeString(strings.Fields(files.Checksum())[0])
if err != nil {
return fmt.Errorf("checksum %s: %w", files.Checksum(), err)
}
hr := &hashReader{
Hash: sha256.New(),
r: bytes.NewReader(files.Binary()),
}
dst, err := os.OpenFile(dstName, os.O_CREATE|os.O_WRONLY, ownerRX)
if err != nil {
return err
}
defer func() { err = dst.Close() }()
if _, err = io.Copy(dst, io.LimitReader(hr, maxExpandedEnvoySize)); err != nil {
return err
}
sum := hr.Sum(nil)
if !bytes.Equal(sum, checksum) {
return fmt.Errorf("expected %x, got %x checksum", checksum, sum)
}
return nil
}

View file

@ -1,5 +1,4 @@
//go:build darwin && amd64 //go:build darwin && amd64 && !embed_pomerium
// +build darwin,amd64
package files package files

View file

@ -1,5 +1,5 @@
//go:build darwin && arm64 //go:build darwin && arm64 && !embed_pomerium
// +build darwin,arm64 // +build darwin,arm64,!embed_pomerium
package files package files

View file

@ -0,0 +1,16 @@
//go:build embed_pomerium
package files
var rawBinary []byte
var rawChecksum string
var rawVersion string
// SetFiles sets external source for envoy
func SetFiles(bin []byte, checksum, version string) {
rawBinary = bin
rawChecksum = checksum
rawVersion = version
}

View file

@ -1,5 +1,5 @@
//go:build linux && amd64 //go:build linux && amd64 && !embed_pomerium
// +build linux,amd64 // +build linux,amd64,!embed_pomerium
package files package files

View file

@ -1,5 +1,5 @@
//go:build linux && arm64 //go:build linux && arm64 && !embed_pomerium
// +build linux,arm64 // +build linux,arm64,!embed_pomerium
package files package files

View file

@ -6,22 +6,24 @@ export PATH
_project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)/.." _project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)/.."
_envoy_version=1.21.3 _envoy_version=1.21.3
_dir="$_project_root/internal/envoy/files" _dir="$_project_root/pkg/envoy/files"
_target="${TARGET:-"$(go env GOOS)-$(go env GOARCH)"}" _target="${TARGET:-"$(go env GOOS)-$(go env GOARCH)"}"
_url="https://github.com/pomerium/envoy-binaries/releases/download/v${_envoy_version}/envoy-${_target}" _url="https://github.com/pomerium/envoy-binaries/releases/download/v${_envoy_version}/envoy-${_target}"
curl \ curl \
--compressed \
--silent \ --silent \
--fail \
--compressed \
--location \ --location \
--time-cond "$_dir/envoy-$_target" \ --time-cond "$_dir/envoy-$_target" \
--output "$_dir/envoy-$_target" \ --output "$_dir/envoy-$_target" \
"$_url" "$_url"
curl \ curl \
--compressed \
--silent \ --silent \
--fail \
--compressed \
--location \ --location \
--time-cond "$_dir/envoy-$_target.sha256" \ --time-cond "$_dir/envoy-$_target.sha256" \
--output "$_dir/envoy-$_target.sha256" \ --output "$_dir/envoy-$_target.sha256" \

View file

@ -3,27 +3,18 @@ package ui
import ( import (
"bytes" "bytes"
"embed"
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"io/fs"
"net/http" "net/http"
"os"
"path/filepath" "path/filepath"
"time" "time"
"github.com/pomerium/csrf" "github.com/pomerium/csrf"
) )
var (
//go:embed dist/*
uiFS embed.FS
)
// ServeFile serves a file. // ServeFile serves a file.
func ServeFile(w http.ResponseWriter, r *http.Request, filePath string) error { func ServeFile(w http.ResponseWriter, r *http.Request, filePath string) error {
f, etag, err := openLocalOrEmbeddedFile(filepath.Join("dist", filePath)) f, etag, err := openFile(filepath.Join("dist", filePath))
if err != nil { if err != nil {
return err return err
} }
@ -47,7 +38,7 @@ func ServePage(w http.ResponseWriter, r *http.Request, page string, data map[str
return err return err
} }
f, _, err := openLocalOrEmbeddedFile("dist/index.html") f, _, err := openFile("dist/index.html")
if err != nil { if err != nil {
return err return err
} }
@ -67,27 +58,3 @@ func ServePage(w http.ResponseWriter, r *http.Request, page string, data map[str
} }
var startTime = time.Now() var startTime = time.Now()
func openLocalOrEmbeddedFile(name string) (f fs.File, etag string, err error) {
f, err = os.Open(filepath.Join("ui", name))
if os.IsNotExist(err) {
f, err = uiFS.Open(name)
}
if err != nil {
return nil, "", err
}
fi, err := f.Stat()
if err != nil {
_ = f.Close()
return nil, "", err
}
modTime := fi.ModTime()
if modTime.IsZero() {
modTime = startTime
}
etag = fmt.Sprintf("%x", modTime.UnixNano())
return f, etag, nil
}

37
ui/embed_ext.go Normal file
View file

@ -0,0 +1,37 @@
//go:build embed_pomerium
package ui
import (
"fmt"
"io/fs"
)
var (
// ExtUIFS must be set to provide access to UI dist/ files
ExtUIFS fs.FS
)
func openFile(name string) (f fs.File, etag string, err error) {
if ExtUIFS == nil {
return nil, "", fmt.Errorf("ui package was incorrectly compiled with embed_pomerium yet no FS was provided")
}
f, err = ExtUIFS.Open(name)
if err != nil {
return nil, "", fmt.Errorf("open %s: %w", name, err)
}
fi, err := f.Stat()
if err != nil {
_ = f.Close()
return nil, "", err
}
modTime := fi.ModTime()
if modTime.IsZero() {
modTime = startTime
}
etag = fmt.Sprintf("%x", modTime.UnixNano())
return f, etag, nil
}

40
ui/embed_local.go Normal file
View file

@ -0,0 +1,40 @@
//go:build !embed_pomerium
package ui
import (
"embed"
"fmt"
"io/fs"
"os"
"path/filepath"
)
var (
//go:embed dist/*
uiFS embed.FS
)
func openFile(name string) (f fs.File, etag string, err error) {
f, err = os.Open(filepath.Join("ui", name))
if os.IsNotExist(err) {
f, err = uiFS.Open(name)
}
if err != nil {
return nil, "", err
}
fi, err := f.Stat()
if err != nil {
_ = f.Close()
return nil, "", err
}
modTime := fi.ModTime()
if modTime.IsZero() {
modTime = startTime
}
etag = fmt.Sprintf("%x", modTime.UnixNano())
return f, etag, nil
}