Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c50945e
Bumped product version to 0.20.1.
hc-github-team-es-release-engineering Sep 25, 2025
a8875a8
backport of commit b0b97ae71e0d18089ca3e107073f4916032fda3b (#6091)
hc-github-team-secure-boundary Sep 26, 2025
da8012b
backport of commit ab521f92c3214d2253709f68d0b8a82191306fea (#6099)
hc-github-team-secure-boundary Sep 30, 2025
27a9866
backport of commit e0ef9be90f27fd56fd8b60d4e3f70a8402a22d84 (#6100)
hc-github-team-secure-boundary Sep 30, 2025
f7ced86
backport of commit 3b9ac7b907de3f245a4b5491ffb2009fe6c05dca (#6105)
hc-github-team-secure-boundary Oct 1, 2025
68185d2
chore(e2e): Update framework to remove boundary_docker_image_name (#6…
hc-github-team-secure-boundary Oct 1, 2025
407f8ff
backport of commit 4a794abbc130254422f93ca4a4a4e84078157106 (#6124)
hc-github-team-secure-boundary Oct 7, 2025
88d9fd9
backport of commit 3e3cb39835a7508a8a12e9b47f071b3e7d808e1f (#6122)
hc-github-team-secure-boundary Oct 7, 2025
0595138
Docs: clarifies supported vault cred library templating parameters (#…
Dan-Heath Oct 9, 2025
baff85b
chore(errors): Add early disconnection error (#6126) (#6135)
AprilMay0 Oct 10, 2025
6284f54
chore(proxy): Reduce noisy error logs (#6136)
AprilMay0 Oct 10, 2025
f02f8bf
Merge pull request #6142 from hashicorp/am-manual-merge-release-0.20.x
AprilMay0 Oct 10, 2025
ac7c152
chore: Update version (#6141)
AprilMay0 Oct 10, 2025
93ac68e
backport of commit a3dadd8c9dd5db1d23b8f65fcd0d73096f236397 (#6147)
hc-github-team-secure-boundary Oct 13, 2025
0125e13
backport of commit 204d8ec011347a89a14cf6b2c28a0f554b327f48 (#6149)
hc-github-team-secure-boundary Oct 13, 2025
1aef0fa
docs: Fix version 0.19.x redirects (#6128) (#6158)
Dan-Heath Oct 15, 2025
5fcc7cf
backport of commit 3cde7d282153dcb8dec10d8d803e08779780112c (#6160)
hc-github-team-secure-boundary Oct 15, 2025
18059db
docs: Fixes redirects (#6165) (#6170)
Dan-Heath Oct 20, 2025
e41afe4
backport of commit 929562f35612f223e03e8ae2ac0e6fa52d917134 (#6174)
hc-github-team-secure-boundary Oct 20, 2025
db7fcd5
docs: Fix broken link in transparent sessions troubleshooting doc (#6…
Dan-Heath Oct 23, 2025
33343ed
Backport of docs: Explain storage capacity in concept topic into rele…
hc-github-team-secure-boundary Oct 24, 2025
e861bf0
docs: Fixes redirects - batch 3 (#6178) (#6197)
Dan-Heath Oct 27, 2025
8b85001
docs: Security model (#6031) (#6200)
Dan-Heath Oct 27, 2025
fcafffd
Backport of docs: Update macOS client phrasing into release/0.20.x (#…
hc-github-team-secure-boundary Oct 28, 2025
3ecb1fc
feat(plugins): Add IBM Key Protect (IBM Cloud KMS) wrapper (#6112) (#…
mikemountain Oct 29, 2025
b5bf19e
update changelog (#6217)
mikemountain Nov 3, 2025
c7555cd
Bumped product version to 0.20.2.
hc-github-team-es-release-engineering Nov 3, 2025
8a19c54
fix(credential/vault): add case for upd creds in injected creds switc…
kheina Nov 17, 2025
5e0d0e7
feat(clientproxy): automatically close boundary connect when proxy is…
kheina Nov 17, 2025
eba1221
fix(e2e): Update tmpfs permissions in worker docker container (#6253)…
moduli Nov 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,6 @@ jobs:
artifact-name: "boundary_${{ needs.set-product-version.outputs.product-version }}_linux_amd64.zip"
go-version: ${{ needs.product-metadata.outputs.go-version }}
edition: ${{ needs.product-metadata.outputs.product-edition }}
docker-image-name: ${{ needs.build-docker.outputs.name }}
docker-image-file: "boundary_default_linux_amd64_${{ needs.set-product-version.outputs.product-version }}_${{ github.sha }}.docker.dev.tar"
secrets: inherit
bats:
Expand Down
4 changes: 0 additions & 4 deletions .github/workflows/enos-run.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ on:
go-version:
required: true
type: string
docker-image-name:
required: false
type: string
docker-image-file:
required: false
type: string
Expand Down Expand Up @@ -96,7 +93,6 @@ jobs:
ENOS_VAR_crt_bundle_path: ./support/boundary.zip
ENOS_VAR_test_email: ${{ secrets.SERVICE_USER_EMAIL }}
ENOS_VAR_boundary_edition: ${{ inputs.edition }}
ENOS_VAR_boundary_docker_image_name: ${{ inputs.docker-image-name }}
ENOS_VAR_boundary_docker_image_file: ./support/boundary_docker_image.tar
ENOS_VAR_go_version: ${{ inputs.go-version }}
ENOS_VAR_gcp_project_id: ${{ secrets.GCP_PROJECT_ID_CI }}
Expand Down
12 changes: 10 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

Canonical reference for changes, improvements, and bugfixes for Boundary.

## Next

## 0.20.1 (2025/11/03)

### New and Improved

* Added a complete IBM Key Protect wrapper implementation with configuration options and KMS client integration ([PR](https://github.com/hashicorp/go-kms-wrapping/pull/292))

## 0.20.0 (2025/09/25)

### New and Improved
Expand All @@ -17,8 +25,8 @@ Canonical reference for changes, improvements, and bugfixes for Boundary.
* Adds support to parse User-Agent headers and emit them in telemetry events
([PR](https://github.com/hashicorp/boundary/pull/5645)).
* cli: Added `boundary connect cassandra` command for connecting to Cassandra targets.
This new helper command allows users to authorize sessions against Cassandra
targets and automatically invoke a Cassandra client with the appropriate
This new helper command allows users to authorize sessions against Cassandra
targets and automatically invoke a Cassandra client with the appropriate
connection parameters and credentials. Currently only username/password credentials are automatically attached.
* ui: Improved load times for resource tables with search and filtering capabilities by replacing indexeddb for local data storage with sqlite (WASM) and OPFS ([PR](https://github.com/hashicorp/boundary-ui/pull/2984))

Expand Down
10 changes: 10 additions & 0 deletions api/proxy/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type Options struct {
WithSkipSessionTeardown bool
withSessionTeardownTimeout time.Duration
withApiClient *api.Client
withInactivityTimeout time.Duration
}

// Option is a function that takes in an options struct and sets values or
Expand Down Expand Up @@ -142,3 +143,12 @@ func WithApiClient(with *api.Client) Option {
return nil
}
}

// WithInactivityTimeout provides an optional duration after which a session
// with no active connections will be cancelled
func WithInactivityTimeout(with time.Duration) Option {
return func(o *Options) error {
o.withInactivityTimeout = with
return nil
}
}
121 changes: 85 additions & 36 deletions api/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,28 @@ import (
const sessionCancelTimeout = 30 * time.Second

type ClientProxy struct {
tofuToken string
cachedListenerAddress *ua.String
connectionsLeft *atomic.Int32
connsLeftCh chan int32
callerConnectionsLeftCh chan int32
apiClient *api.Client
sessionAuthzData *targets.SessionAuthorizationData
createTime time.Time
expiration time.Time
ctx context.Context
cancel context.CancelFunc
transport *http.Transport
workerAddr string
listenAddrPort netip.AddrPort
listener *atomic.Value
listenerCloseOnce *sync.Once
clientTlsConf *tls.Config
connWg *sync.WaitGroup
started *atomic.Bool
skipSessionTeardown bool
tofuToken string
cachedListenerAddress *ua.String
connectionsLeft *atomic.Int32
activeConns *atomic.Int32
connsLeftCh chan int32
callerConnsLeftCh chan int32
apiClient *api.Client
sessionAuthzData *targets.SessionAuthorizationData
createTime time.Time
expiration time.Time
ctx context.Context
cancel context.CancelFunc
transport *http.Transport
workerAddr string
listenAddrPort netip.AddrPort
listener *atomic.Value
listenerCloseOnce *sync.Once
clientTlsConf *tls.Config
connWg *sync.WaitGroup
started *atomic.Bool
skipSessionTeardown bool
closeReason *atomic.Value
}

// New creates a new client proxy. The given context should be cancelable; once
Expand Down Expand Up @@ -90,17 +92,19 @@ func New(ctx context.Context, authzToken string, opt ...Option) (*ClientProxy, e
}

p := &ClientProxy{
cachedListenerAddress: ua.NewString(""),
connsLeftCh: make(chan int32),
connectionsLeft: new(atomic.Int32),
listener: new(atomic.Value),
listenerCloseOnce: new(sync.Once),
connWg: new(sync.WaitGroup),
listenAddrPort: opts.WithListenAddrPort,
callerConnectionsLeftCh: opts.WithConnectionsLeftCh,
started: new(atomic.Bool),
skipSessionTeardown: opts.WithSkipSessionTeardown,
apiClient: opts.withApiClient,
cachedListenerAddress: ua.NewString(""),
connsLeftCh: make(chan int32),
connectionsLeft: new(atomic.Int32),
activeConns: new(atomic.Int32),
listener: new(atomic.Value),
listenerCloseOnce: new(sync.Once),
connWg: new(sync.WaitGroup),
listenAddrPort: opts.WithListenAddrPort,
callerConnsLeftCh: opts.WithConnectionsLeftCh,
started: new(atomic.Bool),
skipSessionTeardown: opts.WithSkipSessionTeardown,
apiClient: opts.withApiClient,
closeReason: new(atomic.Value),
}

if opts.WithListener != nil {
Expand Down Expand Up @@ -142,7 +146,7 @@ func New(ctx context.Context, authzToken string, opt ...Option) (*ClientProxy, e
// We don't _rely_ on client-side timeout verification but this prevents us
// seeming to be ready for a connection that will immediately fail when we
// try to actually make it
p.ctx, p.cancel = context.WithDeadline(ctx, p.expiration)
p.ctx, p.cancel = context.WithDeadlineCause(ctx, p.expiration, fmt.Errorf("Session has expired"))

transport := cleanhttp.DefaultTransport()
transport.DisableKeepAlives = false
Expand Down Expand Up @@ -212,6 +216,17 @@ func (p *ClientProxy) Start(opt ...Option) (retErr error) {
// Ensure closing the listener runs on any other return condition
defer listenerCloseFunc()

// automatically close the proxy when inactive
proxyAutoClose := time.AfterFunc(10*time.Minute, func() {
p.cancel()
p.setCloseReason("Inactivity timeout reached")
})

activeConnCh := make(chan int32)
activeConnFn := func(d int32) {
activeConnCh <- p.activeConns.Add(d)
}

fin := make(chan error, 10)
p.connWg.Add(1)
go func() {
Expand Down Expand Up @@ -243,8 +258,10 @@ func (p *ClientProxy) Start(opt ...Option) (retErr error) {
return
}
}
activeConnFn(1)
p.connWg.Add(1)
go func() {
defer activeConnFn(-1)
defer listeningConn.Close()
defer p.connWg.Done()
wsConn, err := p.getWsConn(p.ctx)
Expand Down Expand Up @@ -305,27 +322,40 @@ func (p *ClientProxy) Start(opt ...Option) (retErr error) {
}()
defer p.connWg.Done()
defer listenerCloseFunc()

for {
select {
case <-p.ctx.Done():
if err := context.Cause(p.ctx); !errors.Is(err, context.Canceled) {
p.setCloseReason(err.Error())
}
return
case connsLeft := <-p.connsLeftCh:
p.connectionsLeft.Store(connsLeft)
if p.callerConnectionsLeftCh != nil {
p.callerConnectionsLeftCh <- connsLeft
if p.callerConnsLeftCh != nil {
p.callerConnsLeftCh <- connsLeft
}
if connsLeft == 0 {
// Close the listener as we can't authorize any more
// connections
p.setCloseReason("No connections left in session")
return
}
case activeConns := <-activeConnCh:
switch {
case activeConns > 0:
// always stop the timer when a new connection is made,
// even if timeout opt is 0
proxyAutoClose.Stop()
case opts.withInactivityTimeout <= 0:
// no timeout was set, timer should not be reset for inactivity
case activeConns == 0:
proxyAutoClose.Reset(opts.withInactivityTimeout)
}
}
}
}()

p.connWg.Wait()
defer p.cancel()

{
// the go funcs are done, so we can safely close the chan and range over any errors
Expand Down Expand Up @@ -367,6 +397,25 @@ func (p *ClientProxy) CloseSession(sessionTeardownTimeout time.Duration) error {
return nil
}

// CloseReason returns the reason why the proxy was closed, if the proxy closed
// itself. If the proxy is still running or the proxy was closed externally, an
// empty string is returned.
func (p *ClientProxy) CloseReason() string {
switch r := p.closeReason.Load().(type) {
case string:
return r
default:
return ""
}
}

// setCloseReason updates the reason the proxy closed from an empty string to the
// provided string. setCloseReason only accepts the first provided reason for
// closing, all other calls are ignored.
func (p *ClientProxy) setCloseReason(reason string) {
p.closeReason.CompareAndSwap(nil, reason)
}

// ListenerAddress returns the address of the client proxy listener. Because the
// listener is started with Start(), this could be called before listening
// occurs. To avoid returning until we have a valid value, pass a context;
Expand Down
2 changes: 2 additions & 0 deletions enos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ following lines
127.0.0.1 localhost worker
127.0.0.1 localhost vault
```
### AWS Credentials
Copy the AWS Account credentials from doormat and set it in the terminal, where the enos commands are run.

## Executing Scenarios
From the `enos` directory:
Expand Down
2 changes: 1 addition & 1 deletion enos/enos-scenario-e2e-docker-base-plus.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ scenario "e2e_docker_base_plus" {
step.build_boundary_docker_image
]
variables {
image_name = matrix.builder == "crt" ? var.boundary_docker_image_name : step.build_boundary_docker_image.image_name
image_name = step.build_boundary_docker_image.image_name
network_name = [local.network_cluster]
database_network = local.network_cluster
postgres_address = step.create_boundary_database.address
Expand Down
2 changes: 1 addition & 1 deletion enos/enos-scenario-e2e-docker-base-with-gcp.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ scenario "e2e_docker_base_with_gcp" {
step.build_boundary_docker_image
]
variables {
image_name = matrix.builder == "crt" ? var.boundary_docker_image_name : step.build_boundary_docker_image.image_name
image_name = step.build_boundary_docker_image.image_name
network_name = [local.network_cluster]
database_network = local.network_cluster
postgres_address = step.create_boundary_database.address
Expand Down
2 changes: 1 addition & 1 deletion enos/enos-scenario-e2e-docker-base-with-vault.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ scenario "e2e_docker_base_with_vault" {
step.build_boundary_docker_image
]
variables {
image_name = matrix.builder == "crt" ? var.boundary_docker_image_name : step.build_boundary_docker_image.image_name
image_name = step.build_boundary_docker_image.image_name
network_name = [local.network_cluster]
database_network = local.network_cluster
postgres_address = step.create_boundary_database.address
Expand Down
4 changes: 2 additions & 2 deletions enos/enos-scenario-e2e-docker-base-with-worker.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ scenario "e2e_docker_base_with_worker" {
step.build_boundary_docker_image
]
variables {
image_name = matrix.builder == "crt" ? var.boundary_docker_image_name : step.build_boundary_docker_image.image_name
image_name = step.build_boundary_docker_image.image_name
network_name = [local.network_cluster, local.network_database]
database_network = local.network_database
postgres_address = step.create_boundary_database.address
Expand Down Expand Up @@ -143,7 +143,7 @@ scenario "e2e_docker_base_with_worker" {
step.create_boundary
]
variables {
image_name = matrix.builder == "crt" ? var.boundary_docker_image_name : step.build_boundary_docker_image.image_name
image_name = step.build_boundary_docker_image.image_name
boundary_license = var.boundary_edition != "oss" ? step.read_license.license : ""
config_file = "worker-config.hcl"
container_name = "worker"
Expand Down
2 changes: 1 addition & 1 deletion enos/enos-scenario-e2e-docker-base.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ scenario "e2e_docker_base" {
step.build_boundary_docker_image
]
variables {
image_name = matrix.builder == "crt" ? var.boundary_docker_image_name : step.build_boundary_docker_image.image_name
image_name = step.build_boundary_docker_image.image_name
network_name = [local.network_cluster]
database_network = local.network_cluster
postgres_address = step.create_boundary_database.address
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ scenario "e2e_docker_worker_registration_controller_led" {
step.build_boundary_docker_image
]
variables {
image_name = matrix.builder == "crt" ? var.boundary_docker_image_name : step.build_boundary_docker_image.image_name
image_name = step.build_boundary_docker_image.image_name
network_name = [local.network_cluster, local.network_database]
database_network = local.network_database
postgres_address = step.create_boundary_database.address
Expand All @@ -113,7 +113,7 @@ scenario "e2e_docker_worker_registration_controller_led" {
depends_on = [step.create_boundary]
variables {
address = step.create_boundary.address
image_name = matrix.builder == "crt" ? var.boundary_docker_image_name : step.build_boundary_docker_image.image_name
image_name = step.build_boundary_docker_image.image_name
network_name = local.network_cluster
login_name = step.create_boundary.login_name
password = step.create_boundary.password
Expand Down Expand Up @@ -157,7 +157,7 @@ scenario "e2e_docker_worker_registration_controller_led" {
step.create_boundary
]
variables {
image_name = matrix.builder == "crt" ? var.boundary_docker_image_name : step.build_boundary_docker_image.image_name
image_name = step.build_boundary_docker_image.image_name
boundary_license = var.boundary_edition != "oss" ? step.read_license.license : ""
config_file = "worker-config-controller-led.hcl"
container_name = "worker"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ scenario "e2e_docker_worker_registration_worker_led" {
step.build_boundary_docker_image
]
variables {
image_name = matrix.builder == "crt" ? var.boundary_docker_image_name : step.build_boundary_docker_image.image_name
image_name = step.build_boundary_docker_image.image_name
network_name = [local.network_cluster, local.network_database]
database_network = local.network_database
postgres_address = step.create_boundary_database.address
Expand Down Expand Up @@ -144,7 +144,7 @@ scenario "e2e_docker_worker_registration_worker_led" {
step.create_boundary
]
variables {
image_name = matrix.builder == "crt" ? var.boundary_docker_image_name : step.build_boundary_docker_image.image_name
image_name = step.build_boundary_docker_image.image_name
boundary_license = var.boundary_edition != "oss" ? step.read_license.license : ""
config_file = "worker-config-worker-led.hcl"
container_name = "worker"
Expand All @@ -165,7 +165,7 @@ scenario "e2e_docker_worker_registration_worker_led" {
]
variables {
address = step.create_boundary.address
image_name = matrix.builder == "crt" ? var.boundary_docker_image_name : step.build_boundary_docker_image.image_name
image_name = step.build_boundary_docker_image.image_name
network_name = local.network_cluster
login_name = step.create_boundary.login_name
password = step.create_boundary.password
Expand Down
4 changes: 2 additions & 2 deletions enos/enos-scenario-e2e-ui-docker.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ scenario "e2e_ui_docker" {
step.build_boundary_docker_image
]
variables {
image_name = matrix.builder == "crt" ? var.boundary_docker_image_name : step.build_boundary_docker_image.image_name
image_name = step.build_boundary_docker_image.image_name
network_name = [local.network_cluster]
database_network = local.network_cluster
postgres_address = step.create_boundary_database.address
Expand Down Expand Up @@ -124,7 +124,7 @@ scenario "e2e_ui_docker" {
step.create_boundary
]
variables {
image_name = matrix.builder == "crt" ? var.boundary_docker_image_name : step.build_boundary_docker_image.image_name
image_name = step.build_boundary_docker_image.image_name
boundary_license = var.boundary_edition != "oss" ? step.read_license.license : ""
config_file = "worker-config.hcl"
container_name = "worker"
Expand Down
Loading
Loading