Port over changes (#3061) (#3062)

This commit is contained in:
Jeff Mitchell authored and GitHub committed 2023-03-07 16:29:34 -05:00
1 parent 4819d17ee8
commit b2bab45c13
20 files changed
+145 -105

No files matched your search

+7 -7
View File
@@ -36,17 +36,13 @@ golangci-lint:
$(eval GOLINT_INSTALLED := $(shell which golangci-lint))
if [ "$(GOLINT_INSTALLED)" = "" ]; then \
sh scripts/install-golangci-lint.sh -b $(GO_PATH)/bin v1.51.0; \
sh scripts/install-golangci-lint.sh -b $(GO_PATH)/bin v1.51.2; \
fi;
.PHONY: cleangen
cleangen:
@rm -f $(shell find ${THIS_DIR} -name '*.gen.go' && find ${THIS_DIR} -name '*.pb.go' && find ${THIS_DIR} -name '*.pb.gw.go')
.PHONY: install-no-plugins
install-no-plugins: export SKIP_PLUGIN_BUILD=1
install-no-plugins: install
.PHONY: dev
dev:
@echo "This command has changed. Please use:"
@@ -65,6 +61,10 @@ build: build-ui-ifne
install: export BOUNDARY_INSTALL_BINARY=1
install: build
.PHONY: install-no-plugins
install-no-plugins: export SKIP_PLUGIN_BUILD=1
install-no-plugins: install
.PHONY: build-memprof
build-memprof: BUILD_TAGS+=memprofiler
build-memprof:
@@ -283,7 +283,7 @@ generate-database-dumps:
test-ci: export CI_BUILD=1
test-ci:
CGO_ENABLED=$(CGO_ENABLED) BUILD_TAGS='$(BUILD_TAGS)' sh -c "'$(CURDIR)/scripts/build.sh'"
go test "$(TEST_PACKAGE)" -v $(TESTARGS) -json -cover -timeout 120m | tparse -follow
go test "$(TEST_PACKAGE)" -tags="$(BUILD_TAGS)" -v $(TESTARGS) -json -cover -timeout 120m | tparse -follow
.PHONY: test-sql
test-sql:
@@ -291,7 +291,7 @@ test-sql:
.PHONY: test
test:
go test "$(TEST_PACKAGE)" $(TESTARGS) -json -cover -timeout $(TEST_TIMEOUT) | tparse -follow
go test "$(TEST_PACKAGE)" -tags="$(BUILD_TAGS)" $(TESTARGS) -json -cover -timeout $(TEST_TIMEOUT) | tparse -follow
.PHONY: test-sdk
test-sdk:
+1
View File
@@ -40,6 +40,7 @@ type WorkerAuthInfo struct {
Description string `json:"description"`
ConnectionNonce string `json:"connection_nonce"`
ProxyAddress string `json:"proxy_address"`
BoundaryVersion string `json:"boundary_version"`
}
// Factory is the factory function to create a listener.
+6
View File
@@ -48,6 +48,8 @@ var (
_ cli.CommandAutocomplete = (*Command)(nil)
)
var extraSelfTerminationConditionFuncs []func(context.Context, chan struct{})
type Command struct {
*base.Server
opsServer *ops.Server
@@ -921,6 +923,10 @@ func (c *Command) Run(args []string) int {
}
}
for _, f := range extraSelfTerminationConditionFuncs {
f(c.Context, c.ServerSideShutdownCh)
}
for !errorEncountered.Load() && !shutdownCompleted.Load() {
select {
case <-c.ServerSideShutdownCh:
+6
View File
@@ -41,6 +41,8 @@ var (
_ cli.CommandAutocomplete = (*Command)(nil)
)
var extraSelfTerminationConditionFuncs []func(context.Context, chan struct{})
type Command struct {
*base.Server
opsServer *ops.Server
@@ -697,6 +699,10 @@ func (c *Command) WaitForInterrupt() int {
}
}
for _, f := range extraSelfTerminationConditionFuncs {
f(c.Context, c.ServerSideShutdownCh)
}
for !shutdownCompleted.Load() {
select {
case <-c.ServerSideShutdownCh:
+3
View File
@@ -73,6 +73,9 @@ func (c *Command) Run(args []string) int {
if verInfo.VersionMetadata != "" {
nonAttributeMap["Metadata"] = verInfo.VersionMetadata
}
if verInfo.BuildDate != "" {
nonAttributeMap["Build Date"] = verInfo.BuildDate
}
maxLength := base.MaxAttributesLength(nonAttributeMap, nil, nil)
+11
View File
@@ -37,6 +37,8 @@ import (
"github.com/mitchellh/mapstructure"
)
var extraParsingFuncs []func(*Config) error
const (
desktopCorsOrigin = "serve://boundary"
@@ -188,6 +190,9 @@ type Controller struct {
//
// TODO: This field is currently internal.
SchedulerRunJobInterval time.Duration `hcl:"-"`
// License is the license used by HCP builds
License string `hcl:"license"`
}
func (c *Controller) InitNameIfEmpty() error {
@@ -854,6 +859,12 @@ func Parse(d string) (*Config, error) {
}
}
for _, f := range extraParsingFuncs {
if err := f(result); err != nil {
return nil, err
}
}
return result, nil
}
+5 -2
View File
@@ -5,6 +5,7 @@ package cluster
import (
"context"
stderror "errors"
"net"
"github.com/fatih/structs"
@@ -13,6 +14,8 @@ import (
"google.golang.org/protobuf/types/known/structpb"
)
var errStateNotFound = stderror.New("no state attached to the connection")
// WorkerConnectionInfo contains information about a worker that gets attached
// to outgoing connections to an upstream worker or the controller through the
// state of a *protocol.Conn.
@@ -48,11 +51,11 @@ func GetWorkerInfoFromStateMap(ctx context.Context, c net.Conn) (*WorkerConnecti
var downstreamInfo WorkerConnectionInfo
pc, ok := c.(stateProvider)
if !ok {
return nil, errors.New(ctx, errors.InvalidParameter, op, "connection does not provide a State structpb.Struct")
return nil, errors.Wrap(ctx, errStateNotFound, op, errors.WithMsg("conn is not a state provider"))
}
st := pc.State()
if st == nil {
return nil, errors.New(ctx, errors.InvalidParameter, op, "no state attached to connection")
return nil, errors.Wrap(ctx, errStateNotFound, op, errors.WithMsg("no state attached to connection"))
}
if err := mapstructure.Decode(st.AsMap(), &downstreamInfo); err != nil {
return nil, errors.Wrap(ctx, err, op)
+1 -1
View File
@@ -43,7 +43,7 @@ func TestWorkerConnectionInfo_errors(t *testing.T) {
t.Run("wrong connection type", func(t *testing.T) {
c, _ := net.Pipe()
got, err := GetWorkerInfoFromStateMap(context.Background(), c)
assert.ErrorContains(t, err, "connection does not provide a State structpb.Struct")
assert.ErrorContains(t, err, "conn is not a state provider")
assert.Nil(t, got)
})
t.Run("no state on connection", func(t *testing.T) {
+31 -3
View File
@@ -6,11 +6,13 @@ package cluster
import (
"context"
"crypto/tls"
stderrors "errors"
"fmt"
"net"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/observability/event"
"github.com/hashicorp/boundary/version"
nodee "github.com/hashicorp/nodeenrollment"
"github.com/hashicorp/nodeenrollment/protocol"
)
@@ -65,8 +67,31 @@ func (e *trackingListener) Accept() (net.Conn, error) {
case *protocol.Conn:
tlsConn = c.Conn
wi, err := GetWorkerInfoFromStateMap(e.ctx, c)
if err != nil || wi == nil || len(wi.WorkerId) == 0 {
event.WriteSysEvent(e.ctx, op, "did not get worker information from state map")
switch {
case err != nil && errors.Is(err, errStateNotFound) && !version.SupportsFeature(version.Binary, version.RequireVersionInWorkerInfo):
// This will cause us to break below
wi = new(WorkerConnectionInfo)
case err != nil:
// We want to check that if we are supporting metadata that it is supplied
innerErr := fmt.Errorf("error trying to get worker information from state map: %w", err)
event.WriteError(e.ctx, op, innerErr)
conn.Close()
return conn, nil
case wi == nil:
event.WriteError(e.ctx, op, stderrors.New("nil worker info in state map"))
conn.Close()
return conn, nil
case version.Get().VersionMetadata != "":
incomingVer := version.FromVersionString(wi.BoundaryVersion)
if (incomingVer == nil || incomingVer.VersionMetadata == "") && version.SupportsFeature(version.Binary, version.RequireVersionInWorkerInfo) {
err := stderrors.New("build contains version with metadata, incoming worker version is nil or has mismatched metadata")
event.WriteError(e.ctx, op, err)
conn.Close()
return conn, nil
}
}
if len(wi.WorkerId) == 0 {
event.WriteSysEvent(e.ctx, op, "did not find worker id in state map")
break
}
workerId = wi.WorkerId
@@ -75,15 +100,18 @@ func (e *trackingListener) Accept() (net.Conn, error) {
tlsConn = c
default:
event.WriteError(e.ctx, op, fmt.Errorf("unexpected connection type: %T", c), event.WithInfo(eventingOpts...))
conn.Close()
return conn, nil
}
if tlsConn == nil {
event.WriteError(e.ctx, op, fmt.Errorf("nil tlsConn"), event.WithInfo(eventingOpts...))
conn.Close()
return conn, nil
}
if len(tlsConn.ConnectionState().PeerCertificates) == 0 {
event.WriteError(e.ctx, op, fmt.Errorf("tls conn without any peer certificates"), event.WithInfo(eventingOpts...))
conn.Close()
return conn, nil
}
@@ -93,7 +121,7 @@ func (e *trackingListener) Accept() (net.Conn, error) {
}
if keyId == "" {
// No key id means there is nothing to track.
event.WriteError(e.ctx, op, fmt.Errorf("no key id found for connection"), event.WithInfo(eventingOpts...))
event.WriteError(e.ctx, op, stderrors.New("no key id found for connection"), event.WithInfo(eventingOpts...))
return conn, nil
}
eventingOpts = append(eventingOpts, "key_id", keyId)
@@ -1,71 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package common
import (
"context"
"crypto/tls"
"net"
"github.com/hashicorp/boundary/internal/errors"
"github.com/hashicorp/boundary/internal/observability/event"
nodee "github.com/hashicorp/nodeenrollment"
"github.com/hashicorp/nodeenrollment/protocol"
)
// EventingListener simply sends an event when a worker has connected
// successfully
type eventingListener struct {
ctx context.Context
baseLn net.Listener
}
func NewEventingListener(ctx context.Context, baseLn net.Listener) (net.Listener, error) {
const op = "common.(EventingListener).Accept"
switch {
case ctx == nil:
return nil, errors.New(ctx, errors.InvalidParameter, op, "nil context")
case baseLn == nil:
return nil, errors.New(ctx, errors.InvalidParameter, op, "nil base listener")
}
return &eventingListener{
ctx: ctx,
baseLn: baseLn,
}, nil
}
func (e *eventingListener) Accept() (net.Conn, error) {
const op = "common.(EventingListener).Accept"
conn, err := e.baseLn.Accept()
if err != nil || conn == nil {
return conn, err
}
var tlsConn *tls.Conn
switch c := conn.(type) {
case *tls.Conn:
tlsConn = c
case *protocol.Conn:
tlsConn = c.Conn
default:
return conn, nil
}
if tlsConn != nil && len(tlsConn.ConnectionState().PeerCertificates) > 0 {
keyId, err := nodee.KeyIdFromPkix(tlsConn.ConnectionState().PeerCertificates[0].SubjectKeyId)
if err == nil {
event.WriteSysEvent(e.ctx, op, "worker successfully authenticated", "key_id", keyId)
}
}
return conn, err
}
func (e *eventingListener) Close() error {
return e.baseLn.Close()
}
func (e *eventingListener) Addr() net.Addr {
return e.baseLn.Addr()
}
@@ -95,6 +95,7 @@ var (
action.List,
}
validateCredentialSourcesFn = func(context.Context, subtypes.Subtype, []target.CredentialSource) error { return nil }
ValidateIngressWorkerFilterFn = IngressWorkerFilterUnsupported
AuthorizeSessionWorkerFilterFn = AuthorizeSessionWithWorkerFilter
WorkerFilterDeprecationMessage = fmt.Sprintf("This field is deprecated. Use %s instead.", globals.EgressWorkerFilterField)
@@ -721,6 +722,11 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
if t == nil {
return nil, handlers.NotFoundErrorf("Target %q not found.", t.GetPublicId())
}
if len(credSources) > 0 {
if err := validateCredentialSourcesFn(ctx, t.GetType(), credSources); err != nil {
return nil, err
}
}
// Instantiate some repos
sessionRepo, err := s.sessionRepoFn()
+1 -7
View File
@@ -162,16 +162,10 @@ func (c *Controller) configureForCluster(ln *base.ServerListener) (func(), error
if err != nil {
return nil, fmt.Errorf("error instantiating node enrollment authed split listener: %w", err)
}
// This wraps the normal worker connections with something that events with
// the worker ID on successful auth/connection
eventingAuthedListener, err := common.NewEventingListener(c.baseContext, nodeeAuthedListener)
if err != nil {
return nil, fmt.Errorf("%s: error creating eventing listener: %w", op, err)
}
// This wraps the normal pki worker connections with a listener which adds
// the worker key id of the connections to the controller's pkiConnManager.
pkiWorkerTrackingListener, err := cluster.NewTrackingListener(c.baseContext, eventingAuthedListener, c.pkiConnManager, sourcePurpose(grpcListenerPurpose))
pkiWorkerTrackingListener, err := cluster.NewTrackingListener(c.baseContext, nodeeAuthedListener, c.pkiConnManager, sourcePurpose(grpcListenerPurpose))
if err != nil {
return nil, fmt.Errorf("%s: error creating pki worker tracking listener: %w", op, err)
}
+23
View File
@@ -23,13 +23,16 @@ import (
"github.com/hashicorp/boundary/internal/authtoken"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/config"
"github.com/hashicorp/boundary/internal/credential/vault"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/db/schema"
"github.com/hashicorp/boundary/internal/gen/testing/interceptor"
"github.com/hashicorp/boundary/internal/host/plugin"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/intglobals"
"github.com/hashicorp/boundary/internal/kms"
"github.com/hashicorp/boundary/internal/observability/event"
"github.com/hashicorp/boundary/internal/scheduler"
"github.com/hashicorp/boundary/internal/server"
"github.com/hashicorp/boundary/internal/session"
"github.com/hashicorp/go-hclog"
@@ -134,6 +137,26 @@ func (tc *TestController) ConnectionsRepo() *session.ConnectionRepository {
return repo
}
func (tc *TestController) PluginHostRepo() *plugin.Repository {
repo, err := tc.c.PluginHostRepoFn()
if err != nil {
tc.t.Fatal(err)
}
return repo
}
func (tc *TestController) VaultCredentialRepo() *vault.Repository {
repo, err := tc.c.VaultCredentialRepoFn()
if err != nil {
tc.t.Fatal(err)
}
return repo
}
func (tc *TestController) Scheduler() *scheduler.Scheduler {
return tc.Controller().scheduler
}
func (tc *TestController) Cancel() {
tc.cancel()
}
@@ -15,7 +15,9 @@ import (
"strings"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/observability/event"
"github.com/hashicorp/boundary/internal/server"
"github.com/hashicorp/boundary/version"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"google.golang.org/protobuf/proto"
)
@@ -71,6 +73,7 @@ func (c Controller) validateWorkerTls(hello *tls.ClientHelloInfo) (*tls.Config,
// * Ensures that the nonce is unique to prevent replay attacks
// * Returns the shared TLS configuration that is used to establish the connection
func (c Controller) v1WorkerAuthConfig(protos []string) (*tls.Config, *base.WorkerAuthInfo, error) {
const op = "controller.(Controller).v1WorkerAuthConfig"
var firstMatchProto string
var encString string
for _, p := range protos {
@@ -104,6 +107,14 @@ func (c Controller) v1WorkerAuthConfig(protos []string) (*tls.Config, *base.Work
if err := json.Unmarshal(marshaledInfo, info); err != nil {
return nil, nil, err
}
if version.Get().VersionMetadata != "" {
incomingVer := version.FromVersionString(info.BoundaryVersion)
if (incomingVer == nil || incomingVer.VersionMetadata == "") && version.SupportsFeature(version.Binary, version.RequireVersionInWorkerInfo) {
err := errors.New("build contains version with metadata, incoming worker version is nil or has mismatched metadata")
event.WriteError(c.baseContext, op, err)
return nil, nil, err
}
}
// Check for replays
serversRepo, err := c.ServersRepoFn()
@@ -253,9 +253,10 @@ func (w *Worker) createClientConn(addr string) error {
func (w *Worker) workerAuthTLSConfig(extraAlpnProtos ...string) (*tls.Config, *base.WorkerAuthInfo, error) {
var err error
info := &base.WorkerAuthInfo{
Name: w.conf.RawConfig.Worker.Name,
Description: w.conf.RawConfig.Worker.Description,
ProxyAddress: w.conf.RawConfig.Worker.PublicAddr,
Name: w.conf.RawConfig.Worker.Name,
Description: w.conf.RawConfig.Worker.Description,
ProxyAddress: w.conf.RawConfig.Worker.PublicAddr,
BoundaryVersion: version.Get().VersionNumber(),
}
info.ConnectionNonce, err = w.nonceFn(20)
+1 -6
View File
@@ -230,14 +230,9 @@ func (w *Worker) configureForWorker(ln *base.ServerListener, logger *log.Logger,
ln.GrpcServer = downstreamServer
eventingListener, err := common.NewEventingListener(cancelCtx, nodeeAuthListener)
if err != nil {
return nil, fmt.Errorf("%s: error creating eventing listener: %w", op, err)
}
// This wraps the normal pki worker connections with a listener which adds
// the worker key id of the connections to the worker's pkiConnManager.
pkiWorkerTrackingListener, err := cluster.NewTrackingListener(cancelCtx, eventingListener, w.pkiConnManager, sourcePurpose(grpcListenerPurpose))
pkiWorkerTrackingListener, err := cluster.NewTrackingListener(cancelCtx, nodeeAuthListener, w.pkiConnManager, sourcePurpose(grpcListenerPurpose))
if err != nil {
return nil, fmt.Errorf("%s: error creating pki worker tracking listener: %w", op, err)
}
+13 -3
View File
@@ -28,6 +28,15 @@ echo "==> Build tags: ${BUILD_TAGS}"
GIT_COMMIT="$(git rev-parse HEAD)"
GIT_DIRTY="$(test -n "`git status --porcelain`" && echo "+CHANGES" || true)"
# Get the build date from the latest commit since it can be used across all
# builds
function build_date() {
# It's tricky to do an RFC3339 format in a cross platform way, so we hardcode UTC
: "${DATE_FORMAT:="%Y-%m-%dT%H:%M:%SZ"}"
git show --no-show-signature -s --format=%cd --date=format:"$DATE_FORMAT" HEAD
}
BUILD_DATE=$(build_date)
# If not explicitly cross-compiling, build for the current platform
if [ "${GOOS}x" == "x" ]; then
GOOS=$(go env GOOS)
@@ -57,7 +66,7 @@ if [ "${CI_BUILD}x" != "x" ]; then
exit
fi
PRODUCT_VERSION=${PRODUCT_VERSION:=$(cat version/VERSION)}
BASE_PRODUCT_VERSION=${BASE_PRODUCT_VERSION:=$(cat version/VERSION)}
# Declare binary paths!
BINARY_NAME="boundary${BINARY_SUFFIX}"
@@ -77,10 +86,11 @@ ${GO_CMD} build \
-trimpath \
-buildvcs=false \
-ldflags "
-X github.com/hashicorp/boundary/version.GitCommit=${GIT_COMMIT}${GIT_DIRTY}
-X 'github.com/hashicorp/boundary/version.Version=$PRODUCT_VERSION'
-X 'github.com/hashicorp/boundary/version.GitCommit=${GIT_COMMIT}${GIT_DIRTY}'
-X 'github.com/hashicorp/boundary/version.Version=$BASE_PRODUCT_VERSION'
-X 'github.com/hashicorp/boundary/version.VersionPrerelease=$PRERELEASE_PRODUCT_VERSION'
-X 'github.com/hashicorp/boundary/version.VersionMetadata=$METADATA_PRODUCT_VERSION'
-X 'github.com/hashicorp/boundary/version.BuildDate=$BUILD_DATE'
" \
-o "$BIN_PATH" \
./cmd/boundary
+6
View File
@@ -19,6 +19,7 @@ const (
IncludeStatusInCli
CredentialLibraryVaultSubtype
UseTargetIdForHostId
RequireVersionInWorkerInfo
)
var featureMap map[Feature]MetadataConstraint
@@ -62,6 +63,11 @@ func init() {
featureMap[UseTargetIdForHostId] = MetadataConstraint{
Constraints: mustNewConstraints("< 0.14.0"),
}
// RequireVersionInWorkerInfo allows us to take action on various workers
// based on their version, e.g. to prevent incompatibilities
featureMap[RequireVersionInWorkerInfo] = MetadataConstraint{
Constraints: mustNewConstraints(">= 0.13.0"),
}
}
func mustNewConstraints(v string) gvers.Constraints {
+3
View File
@@ -19,6 +19,7 @@ type Info struct {
Version string `json:"version,omitempty"`
VersionPrerelease string `json:"version_prerelease,omitempty"`
VersionMetadata string `json:"version_metadata,omitempty"`
BuildDate string `json:"build_date,omitempty"`
CgoEnabled bool `json:"cgo_enabled,omitempty"`
}
@@ -26,6 +27,7 @@ func Get() *Info {
ver := Version
rel := VersionPrerelease
md := VersionMetadata
bd := BuildDate
if GitDescribe != "" {
ver = GitDescribe
}
@@ -43,6 +45,7 @@ func Get() *Info {
Version: ver,
VersionPrerelease: rel,
VersionMetadata: md,
BuildDate: bd,
}
}
+6 -2
View File
@@ -16,8 +16,12 @@ var (
Version = "0.12.0"
// VersionPrerelease is also set at compile time, similarly to Version.
VersionPrerelease = ""
VersionPrerelease string
// VersionMetadata is also set at compile time.
VersionMetadata = ""
VersionMetadata string
// BuildDate is the date of the build, which corresponds to the timestamp of
// the most recent commit
BuildDate string
)