Skip to content

Optional provider builds via Go build tags #1054

@vlsi

Description

@vlsi

Summary

The vals binary currently includes all 36+ providers and their dependencies, resulting in a ~140 MB stripped binary. Many users only need a subset (e.g., Vault + AWS + GCP + Azure). Introducing Go build tags would allow users to compile only the providers they need, significantly reducing binary size and attack surface.

Motivation

Binary size

The current binary bundles SDKs for every supported backend. Some of these are very heavy:

Dependency Approx. size in binary Provider
yandex-cloud/go-genproto + go-sdk ~10.5 MB yclockbox
1password/onepassword-sdk-go ~8.7 MB op
k8s.io (client-go, api, apimachinery) ~8.7 MB k8s
envoyproxy/go-control-plane ~3.1 MB transitive (yandex, spiffe)
tetratelabs/wazero ~1.1 MB transitive (extism/sops)
hashicorp/hcp-sdk-go ~0.7 MB hcpvaultsecrets

Sizes measured with go tool nm -size on current binary (darwin/arm64). Total potential savings from dropping unused providers: ~25-30 MB (~20-25% of the stripped binary).

Security surface

Every included SDK is a potential source of CVEs. Users who only need Vault + AWS still transitively depend on Yandex Cloud gRPC stubs, 1Password WASM runtime, Kubernetes client, etc. Reducing the dependency set reduces the number of packages that need to be monitored and patched.

A quick way to see the current exposure:

# Count direct+indirect modules
go list -m all | wc -l

# Check known vulnerabilities
govulncheck ./...

Proposed approach

Use Go build tags — the standard mechanism for optional compilation in Go — to make provider groups opt-in at build time.

  1. Replace the switch-based provider instantiation with a registry
// registry.go
var providers = map[string]ProviderFactory{}

func registerProvider(name string, factory ProviderFactory) {
    providers[name] = factory
}
  1. One file pair per provider group (build tag + stub)
// vals_aws.go
//go:build aws || all

package vals

func init() {
    registerProvider("s3", s3.New)
    registerProvider("awssecrets", awssecrets.New)
    registerProvider("ssm", ssm.New)
    registerProvider("awskms", awskms.New)
}

// vals_aws_stub.go
//go:build !aws && !all

package vals
// provider not included in this build
  1. Build with selected providers
# minimal build — only Vault and AWS
go build -tags "vault,aws" ./cmd/vals

# full build (backwards-compatible default for releases)
go build -tags "all" ./cmd/vals

Suggested tag groups

  • vault — vault
  • aws — awssecrets, awsssm, awskms, s3
  • gcp — gcpsecrets, gkms, gcs
  • azure — azurekeyvault
  • k8s — k8s
  • onepassword — op, onepasswordconnect
  • yandex — yclockbox
  • terraform — tfstate, tfstategs, tfstates3, tfstateazurerm, tfstateremote
  • sops — sops
  • One tag per remaining provider or small group
  • all — everything (current behavior)

How to measure the impact

Binary size

# full build (baseline)
go build -tags all -ldflags="-s -w" -o vals-full ./cmd/vals
ls -lh vals-full

# minimal build
go build -tags "vault,aws,gcp,azure" -ldflags="-s -w" -o vals-minimal ./cmd/vals
ls -lh vals-minimal

# per-symbol breakdown
go tool nm -size vals-full | \
awk '{sizes[$4]+=$2} END {for (s in sizes) printf "%10.1f MB  %s\n", sizes[s]/1048576, s}' | \
sort -rn | head -30

Security vulnerabilities

# compare vulnerability exposure
govulncheck -tags all ./...
govulncheck -tags "vault,aws,gcp,azure" ./...

# compare dependency count
go list -tags all -deps ./cmd/vals | wc -l
go list -tags "vault,aws,gcp,azure" -deps ./cmd/vals | wc -l

Compatibility

  • Official release binaries and container images continue to be built with -tags all — non-breaking change
  • Users who build from source get the ability to produce smaller, tighter binaries
  • The existing provider interface (api.Provider) stays the same — only the registration mechanism changes

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions