diff --git a/.gitignore b/.gitignore index 5743f1bae..f04cee414 100644 --- a/.gitignore +++ b/.gitignore @@ -90,8 +90,8 @@ docs/.vuepress/dist/ .service-accounts /bazel-* -internal/envoy/files/envoy-*-????? -internal/envoy/files/envoy-*-?????.sha256 -internal/envoy/files/envoy-*-?????.version +pkg/envoy/files/envoy-*-????? +pkg/envoy/files/envoy-*-?????.sha256 +pkg/envoy/files/envoy-*-?????.version yarn-error.log diff --git a/Makefile b/Makefile index 4943426e9..8ed09dd11 100644 --- a/Makefile +++ b/Makefile @@ -113,8 +113,8 @@ clean: ## Cleanup any build binaries or packages. @echo "==> $@" $(RM) -r $(BINDIR) $(RM) -r $(BUILDDIR) - $(RM) internal/envoy/files/envoy-* - $(RM) $GOPATH/bin/protoc-gen-validate + $(RM) pkg/envoy/files/envoy-* + $(RM) $(GOPATH)/bin/protoc-gen-validate $(RM) -r /tmp/pomerium-protoc $(RM) -r /tmp/pomerium-protoc-3pp diff --git a/cmd/pomerium/main.go b/cmd/pomerium/main.go index 32e823307..9199a08ef 100644 --- a/cmd/pomerium/main.go +++ b/cmd/pomerium/main.go @@ -6,10 +6,13 @@ import ( "flag" "fmt" - "github.com/pomerium/pomerium/internal/cmd/pomerium" - "github.com/pomerium/pomerium/internal/envoy/files" + "github.com/rs/zerolog" + + "github.com/pomerium/pomerium/config" "github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/internal/version" + "github.com/pomerium/pomerium/pkg/cmd/pomerium" + "github.com/pomerium/pomerium/pkg/envoy/files" ) var ( @@ -33,5 +36,16 @@ func main() { } 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) } diff --git a/config/config.go b/config/config.go index 14cdacb4b..0b5c6d3db 100644 --- a/config/config.go +++ b/config/config.go @@ -4,6 +4,7 @@ import ( "crypto/tls" "github.com/pomerium/pomerium/internal/hashutil" + "github.com/pomerium/pomerium/internal/netutil" ) // Config holds pomerium configuration options. @@ -58,3 +59,19 @@ func (cfg *Config) AllCertificates() ([]tls.Certificate, error) { func (cfg *Config) Checksum() uint64 { 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 +} diff --git a/config/config_source.go b/config/config_source.go index 4ebcb3f62..71695aaf8 100644 --- a/config/config_source.go +++ b/config/config_source.go @@ -3,6 +3,7 @@ package config import ( "context" "crypto/sha256" + "fmt" "os" "sync" @@ -11,7 +12,6 @@ import ( "github.com/pomerium/pomerium/internal/fileutil" "github.com/pomerium/pomerium/internal/log" - "github.com/pomerium/pomerium/internal/netutil" "github.com/pomerium/pomerium/internal/telemetry/metrics" ) @@ -110,26 +110,15 @@ func NewFileOrEnvironmentSource( 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{ Options: options, 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) src := &FileOrEnvironmentSource{ diff --git a/databroker/cache.go b/databroker/cache.go index e26e5ef00..5ec7f660d 100644 --- a/databroker/cache.go +++ b/databroker/cache.go @@ -16,7 +16,6 @@ import ( "github.com/pomerium/pomerium/config" "github.com/pomerium/pomerium/internal/directory" - "github.com/pomerium/pomerium/internal/envoy/files" "github.com/pomerium/pomerium/internal/events" "github.com/pomerium/pomerium/internal/identity" "github.com/pomerium/pomerium/internal/identity/manager" @@ -24,6 +23,7 @@ import ( "github.com/pomerium/pomerium/internal/telemetry" "github.com/pomerium/pomerium/internal/version" "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/registry" "github.com/pomerium/pomerium/pkg/grpcutil" diff --git a/internal/controlplane/server.go b/internal/controlplane/server.go index 154d824e2..b0f007ab1 100644 --- a/internal/controlplane/server.go +++ b/internal/controlplane/server.go @@ -21,7 +21,6 @@ import ( "github.com/pomerium/pomerium/config/envoyconfig" "github.com/pomerium/pomerium/config/envoyconfig/filemgr" "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/httputil/reproxy" "github.com/pomerium/pomerium/internal/log" @@ -29,6 +28,7 @@ import ( "github.com/pomerium/pomerium/internal/telemetry/requestid" "github.com/pomerium/pomerium/internal/urlutil" "github.com/pomerium/pomerium/internal/version" + "github.com/pomerium/pomerium/pkg/envoy/files" pom_grpc "github.com/pomerium/pomerium/pkg/grpc" "github.com/pomerium/pomerium/pkg/grpcutil" ) diff --git a/internal/envoy/embed.go b/internal/envoy/embed.go deleted file mode 100644 index 88645d87f..000000000 --- a/internal/envoy/embed.go +++ /dev/null @@ -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 -} diff --git a/internal/cmd/pomerium/pomerium.go b/pkg/cmd/pomerium/pomerium.go similarity index 91% rename from internal/cmd/pomerium/pomerium.go rename to pkg/cmd/pomerium/pomerium.go index 239a938fa..d56084ca9 100644 --- a/internal/cmd/pomerium/pomerium.go +++ b/pkg/cmd/pomerium/pomerium.go @@ -11,7 +11,6 @@ import ( "syscall" envoy_service_auth_v3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3" - "github.com/rs/zerolog" "golang.org/x/sync/errgroup" "github.com/pomerium/pomerium/authenticate" @@ -21,29 +20,22 @@ import ( "github.com/pomerium/pomerium/internal/autocert" "github.com/pomerium/pomerium/internal/controlplane" "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/log" "github.com/pomerium/pomerium/internal/registry" "github.com/pomerium/pomerium/internal/version" + "github.com/pomerium/pomerium/pkg/envoy" + "github.com/pomerium/pomerium/pkg/envoy/files" "github.com/pomerium/pomerium/proxy" ) // 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). Str("envoy_version", files.FullVersion()). Str("version", version.FullVersion()). Msg("cmd/pomerium") - var src config.Source - - src, err := config.NewFileOrEnvironmentSource(configFile, files.FullVersion()) - if err != nil { - return err - } - src = databroker.NewConfigSource(ctx, src) logMgr := config.NewLogManager(ctx, src) defer logMgr.Close() @@ -51,7 +43,7 @@ func Run(ctx context.Context, configFile string) error { // trigger changes when underlying files are changed src = config.NewFileWatcherSource(src) - src, err = autocert.New(src) + src, err := autocert.New(src) if err != nil { 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 { - return c.Str("config_file_source", configFile).Bool("bootstrap", true) - }), src.GetConfig()); err != nil { + if err = controlPlane.OnConfigChange(ctx, src.GetConfig()); err != nil { return fmt.Errorf("applying config: %w", err) } diff --git a/internal/cmd/pomerium/pomerium_test.go b/pkg/cmd/pomerium/pomerium_test.go similarity index 84% rename from internal/cmd/pomerium/pomerium_test.go rename to pkg/cmd/pomerium/pomerium_test.go index 67b3b7628..2443ac2a7 100644 --- a/internal/cmd/pomerium/pomerium_test.go +++ b/pkg/cmd/pomerium/pomerium_test.go @@ -1,20 +1,36 @@ -package pomerium +package pomerium_test import ( "context" "os" "testing" "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) { 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 { name string configFileFlag string - wantErr bool + check func(require.TestingT, error, ...any) }{ - {"nil configuration", "", true}, + {"nil configuration", "", require.Error}, {"bad proxy no authenticate url", ` { "address": ":9433", @@ -26,7 +42,7 @@ func Test_run(t *testing.T) { "services": "proxy", "policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }] } - `, true}, + `, require.Error}, {"bad authenticate no cookie secret", ` { "address": ":9433", @@ -37,7 +53,7 @@ func Test_run(t *testing.T) { "services": "authenticate", "policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }] } - `, true}, + `, require.Error}, {"bad authorize service bad shared key", ` { "address": ":9433", @@ -49,7 +65,7 @@ func Test_run(t *testing.T) { "services": "authorize", "policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }] } - `, true}, + `, require.Error}, {"bad http port", ` { "address": ":-1", @@ -63,7 +79,7 @@ func Test_run(t *testing.T) { "services": "proxy", "policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }] } - `, true}, + `, require.Error}, {"bad redirect port", ` { "address": ":9433", @@ -78,7 +94,7 @@ func Test_run(t *testing.T) { "services": "proxy", "policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }] } - `, true}, + `, require.Error}, {"bad metrics port ", ` { "address": ":9433", @@ -92,7 +108,7 @@ func Test_run(t *testing.T) { "services": "proxy", "policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }] } - `, true}, + `, require.Error}, {"malformed tracing provider", ` { "tracing_provider": "bad tracing provider", @@ -107,7 +123,7 @@ func Test_run(t *testing.T) { "services": "proxy", "policy": [{ "from": "https://pomerium.io", "to": "https://httpbin.org" }] } - `, true}, + `, require.Error}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -115,7 +131,7 @@ func Test_run(t *testing.T) { if err != nil { t.Fatal("Cannot create temporary file", err) } - defer os.Remove(tmpFile.Name()) + defer func() { _ = os.Remove(tmpFile.Name()) }() fn := tmpFile.Name() if _, err := tmpFile.Write([]byte(tt.configFileFlag)); err != nil { tmpFile.Close() @@ -126,10 +142,7 @@ func Test_run(t *testing.T) { ctx, clearTimeout := context.WithTimeout(context.Background(), 500*time.Millisecond) defer clearTimeout() - err = Run(ctx, configFile) - if (err != nil) != tt.wantErr { - t.Errorf("run() error = %v, wantErr %v", err, tt.wantErr) - } + tt.check(t, run(ctx, configFile)) }) } } diff --git a/internal/envoy/envoy.go b/pkg/envoy/envoy.go similarity index 88% rename from internal/envoy/envoy.go rename to pkg/envoy/envoy.go index c2f6914dd..e32cfc299 100644 --- a/internal/envoy/envoy.go +++ b/pkg/envoy/envoy.go @@ -5,13 +5,12 @@ import ( "bufio" "bytes" "context" - "crypto/sha256" - "encoding/hex" "errors" "fmt" "io" "os" "os/exec" + "path" "path/filepath" "regexp" "strconv" @@ -30,14 +29,13 @@ import ( "github.com/pomerium/pomerium/config" "github.com/pomerium/pomerium/config/envoyconfig" - "github.com/pomerium/pomerium/internal/envoy/files" "github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/internal/telemetry" + "github.com/pomerium/pomerium/pkg/envoy/files" ) const ( - workingDirectoryName = ".pomerium-envoy" - configFileName = "envoy-config.yaml" + configFileName = "envoy-config.yaml" ) type serverOptions struct { @@ -62,38 +60,13 @@ type Server struct { // NewServer creates a new server with traffic routed by envoy. func NewServer(ctx context.Context, src config.Source, builder *envoyconfig.Builder) (*Server, error) { - wd := filepath.Join(os.TempDir(), workingDirectoryName) - err := os.MkdirAll(wd, embeddedEnvoyPermissions) + envoyPath, err := Extract() if err != nil { - return nil, fmt.Errorf("error creating temporary working directory for 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!") - } + return nil, fmt.Errorf("extracting envoy: %w", err) } srv := &Server{ - wd: wd, + wd: path.Dir(envoyPath), builder: builder, grpcPort: src.GetConfig().GRPCPort, httpPort: src.GetConfig().HTTPPort, diff --git a/internal/envoy/envoy_darwin.go b/pkg/envoy/envoy_darwin.go similarity index 100% rename from internal/envoy/envoy_darwin.go rename to pkg/envoy/envoy_darwin.go diff --git a/internal/envoy/envoy_linux.go b/pkg/envoy/envoy_linux.go similarity index 100% rename from internal/envoy/envoy_linux.go rename to pkg/envoy/envoy_linux.go diff --git a/internal/envoy/envoy_other.go b/pkg/envoy/envoy_other.go similarity index 100% rename from internal/envoy/envoy_other.go rename to pkg/envoy/envoy_other.go diff --git a/internal/envoy/envoy_test.go b/pkg/envoy/envoy_test.go similarity index 100% rename from internal/envoy/envoy_test.go rename to pkg/envoy/envoy_test.go diff --git a/pkg/envoy/extract.go b/pkg/envoy/extract.go new file mode 100644 index 000000000..be5961185 --- /dev/null +++ b/pkg/envoy/extract.go @@ -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 +} diff --git a/internal/envoy/files/files.go b/pkg/envoy/files/files.go similarity index 100% rename from internal/envoy/files/files.go rename to pkg/envoy/files/files.go diff --git a/internal/envoy/files/files_darwin_amd64.go b/pkg/envoy/files/files_darwin_amd64.go similarity index 81% rename from internal/envoy/files/files_darwin_amd64.go rename to pkg/envoy/files/files_darwin_amd64.go index 0176d8f45..faf90da6a 100644 --- a/internal/envoy/files/files_darwin_amd64.go +++ b/pkg/envoy/files/files_darwin_amd64.go @@ -1,5 +1,4 @@ -//go:build darwin && amd64 -// +build darwin,amd64 +//go:build darwin && amd64 && !embed_pomerium package files diff --git a/internal/envoy/files/files_darwin_arm64.go b/pkg/envoy/files/files_darwin_arm64.go similarity index 71% rename from internal/envoy/files/files_darwin_arm64.go rename to pkg/envoy/files/files_darwin_arm64.go index d9b4a9b7f..c54c40833 100644 --- a/internal/envoy/files/files_darwin_arm64.go +++ b/pkg/envoy/files/files_darwin_arm64.go @@ -1,5 +1,5 @@ -//go:build darwin && arm64 -// +build darwin,arm64 +//go:build darwin && arm64 && !embed_pomerium +// +build darwin,arm64,!embed_pomerium package files diff --git a/pkg/envoy/files/files_external.go b/pkg/envoy/files/files_external.go new file mode 100644 index 000000000..3d1b29ab0 --- /dev/null +++ b/pkg/envoy/files/files_external.go @@ -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 +} diff --git a/internal/envoy/files/files_linux_amd64.go b/pkg/envoy/files/files_linux_amd64.go similarity index 71% rename from internal/envoy/files/files_linux_amd64.go rename to pkg/envoy/files/files_linux_amd64.go index f7f90a2e6..131b51e50 100644 --- a/internal/envoy/files/files_linux_amd64.go +++ b/pkg/envoy/files/files_linux_amd64.go @@ -1,5 +1,5 @@ -//go:build linux && amd64 -// +build linux,amd64 +//go:build linux && amd64 && !embed_pomerium +// +build linux,amd64,!embed_pomerium package files diff --git a/internal/envoy/files/files_linux_arm64.go b/pkg/envoy/files/files_linux_arm64.go similarity index 71% rename from internal/envoy/files/files_linux_arm64.go rename to pkg/envoy/files/files_linux_arm64.go index 9932070f0..39e10f33c 100644 --- a/internal/envoy/files/files_linux_arm64.go +++ b/pkg/envoy/files/files_linux_arm64.go @@ -1,5 +1,5 @@ -//go:build linux && arm64 -// +build linux,arm64 +//go:build linux && arm64 && !embed_pomerium +// +build linux,arm64,!embed_pomerium package files diff --git a/internal/envoy/misc.go b/pkg/envoy/misc.go similarity index 100% rename from internal/envoy/misc.go rename to pkg/envoy/misc.go diff --git a/scripts/get-envoy.bash b/scripts/get-envoy.bash index 6b24a9a3b..ad4728273 100755 --- a/scripts/get-envoy.bash +++ b/scripts/get-envoy.bash @@ -6,22 +6,24 @@ export PATH _project_root="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)/.." _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)"}" _url="https://github.com/pomerium/envoy-binaries/releases/download/v${_envoy_version}/envoy-${_target}" curl \ - --compressed \ --silent \ + --fail \ + --compressed \ --location \ --time-cond "$_dir/envoy-$_target" \ --output "$_dir/envoy-$_target" \ "$_url" curl \ - --compressed \ --silent \ + --fail \ + --compressed \ --location \ --time-cond "$_dir/envoy-$_target.sha256" \ --output "$_dir/envoy-$_target.sha256" \ diff --git a/ui/embed.go b/ui/embed.go index 5f3e27c8a..d0fc0e9f4 100644 --- a/ui/embed.go +++ b/ui/embed.go @@ -3,27 +3,18 @@ package ui import ( "bytes" - "embed" "encoding/json" - "fmt" "io" - "io/fs" "net/http" - "os" "path/filepath" "time" "github.com/pomerium/csrf" ) -var ( - //go:embed dist/* - uiFS embed.FS -) - // ServeFile serves a file. 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 { return err } @@ -47,7 +38,7 @@ func ServePage(w http.ResponseWriter, r *http.Request, page string, data map[str return err } - f, _, err := openLocalOrEmbeddedFile("dist/index.html") + f, _, err := openFile("dist/index.html") if err != nil { return err } @@ -67,27 +58,3 @@ func ServePage(w http.ResponseWriter, r *http.Request, page string, data map[str } 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 -} diff --git a/ui/embed_ext.go b/ui/embed_ext.go new file mode 100644 index 000000000..caf61c66f --- /dev/null +++ b/ui/embed_ext.go @@ -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 +} diff --git a/ui/embed_local.go b/ui/embed_local.go new file mode 100644 index 000000000..bef1f6804 --- /dev/null +++ b/ui/embed_local.go @@ -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 +}