mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-17 19:17:17 +02:00
allow pomerium to be embedded as a library (#3415)
This commit is contained in:
parent
6e1ebffc59
commit
d1037d784a
27 changed files with 292 additions and 207 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -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
|
||||
|
|
4
Makefile
4
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
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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))
|
||||
})
|
||||
}
|
||||
}
|
|
@ -5,13 +5,12 @@ import (
|
|||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
@ -30,13 +29,12 @@ 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"
|
||||
)
|
||||
|
||||
|
@ -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,
|
99
pkg/envoy/extract.go
Normal file
99
pkg/envoy/extract.go
Normal 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
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
//go:build darwin && amd64
|
||||
// +build darwin,amd64
|
||||
//go:build darwin && amd64 && !embed_pomerium
|
||||
|
||||
package files
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
//go:build darwin && arm64
|
||||
// +build darwin,arm64
|
||||
//go:build darwin && arm64 && !embed_pomerium
|
||||
// +build darwin,arm64,!embed_pomerium
|
||||
|
||||
package files
|
||||
|
16
pkg/envoy/files/files_external.go
Normal file
16
pkg/envoy/files/files_external.go
Normal 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
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
//go:build linux && amd64
|
||||
// +build linux,amd64
|
||||
//go:build linux && amd64 && !embed_pomerium
|
||||
// +build linux,amd64,!embed_pomerium
|
||||
|
||||
package files
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
//go:build linux && arm64
|
||||
// +build linux,arm64
|
||||
//go:build linux && arm64 && !embed_pomerium
|
||||
// +build linux,arm64,!embed_pomerium
|
||||
|
||||
package files
|
||||
|
|
@ -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" \
|
||||
|
|
37
ui/embed.go
37
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
|
||||
}
|
||||
|
|
37
ui/embed_ext.go
Normal file
37
ui/embed_ext.go
Normal 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
40
ui/embed_local.go
Normal 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
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue