Add some target fields and move some things around (#3879)
In preparation for putting proxy code in the api package this creates some necessary fields in the target output and it pre-moves credential parsing and proxy handshake code to their new places. This will make the diff for the actual proxy code move quite a bit smaller. Co-authored-by: Johan Brandhorst-Satzkorn <johan.brandhorst@gmail.com>
This commit is contained in:
1 parent
82b3f202c0
commit
fb4a5a98dc
27 files changed
+733
-444
No files matched your search
@@ -878,6 +878,11 @@ var inputStructs = []*structInfo{
|
||||
outFile: "targets/session_authorization.gen.go",
|
||||
subtypeName: "SessionAuthorization",
|
||||
},
|
||||
{
|
||||
inProto: &targets.SessionAuthorizationData{},
|
||||
outFile: "targets/session_authorization_data.gen.go",
|
||||
subtypeName: "SessionAuthorizationData",
|
||||
},
|
||||
{
|
||||
inProto: &targets.WorkerInfo{},
|
||||
outFile: "targets/worker_info.gen.go",
|
||||
|
||||
@@ -21,11 +21,12 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
apiproxy "github.com/hashicorp/boundary/api/proxy"
|
||||
"github.com/hashicorp/boundary/api/targets"
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/proxy"
|
||||
targetspb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets"
|
||||
"github.com/hashicorp/boundary/sdk/pbs/proxy"
|
||||
"github.com/hashicorp/go-cleanhttp"
|
||||
"github.com/hashicorp/go-secure-stdlib/base62"
|
||||
"github.com/mitchellh/cli"
|
||||
@@ -824,10 +825,10 @@ func (c *Command) handleExec(passthroughArgs []string) {
|
||||
var envs []string
|
||||
var argsErr error
|
||||
|
||||
var creds credentials
|
||||
var creds apiproxy.Credentials
|
||||
if c.sessionAuthz != nil {
|
||||
var err error
|
||||
creds, err = parseCredentials(c.sessionAuthz.Credentials)
|
||||
creds, err = apiproxy.ParseCredentials(c.sessionAuthz.Credentials)
|
||||
if err != nil {
|
||||
c.PrintCliError(fmt.Errorf("Error interpreting secret: %w", err))
|
||||
c.execCmdReturnValue.Store(int32(3))
|
||||
@@ -884,7 +885,7 @@ func (c *Command) handleExec(passthroughArgs []string) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.printCredentials(creds.unconsumedSessionCredentials()); err != nil {
|
||||
if err := c.printCredentials(creds.UnconsumedSessionCredentials()); err != nil {
|
||||
c.PrintCliError(fmt.Errorf("Failed to print credentials: %w", err))
|
||||
c.execCmdReturnValue.Store(int32(2))
|
||||
return
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package connect
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/hashicorp/boundary/api/targets"
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
type usernamePassword struct {
|
||||
Username string `mapstructure:"username"`
|
||||
Password string `mapstructure:"password"`
|
||||
|
||||
raw *targets.SessionCredential
|
||||
consumed bool
|
||||
}
|
||||
|
||||
type sshPrivateKey struct {
|
||||
Username string `mapstructure:"username"`
|
||||
PrivateKey string `mapstructure:"private_key"`
|
||||
Passphrase string `mapstructure:"private_key_passphrase"`
|
||||
|
||||
raw *targets.SessionCredential
|
||||
consumed bool
|
||||
}
|
||||
|
||||
type credentials struct {
|
||||
usernamePassword []usernamePassword
|
||||
sshPrivateKey []sshPrivateKey
|
||||
unspecified []*targets.SessionCredential
|
||||
}
|
||||
|
||||
func (c credentials) unconsumedSessionCredentials() []*targets.SessionCredential {
|
||||
out := make([]*targets.SessionCredential, 0, len(c.sshPrivateKey)+len(c.usernamePassword)+len(c.unspecified))
|
||||
|
||||
// Unspecified credentials cannot be consumed
|
||||
out = append(out, c.unspecified...)
|
||||
|
||||
for _, c := range c.sshPrivateKey {
|
||||
if !c.consumed {
|
||||
out = append(out, c.raw)
|
||||
}
|
||||
}
|
||||
for _, c := range c.usernamePassword {
|
||||
if !c.consumed {
|
||||
out = append(out, c.raw)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func parseCredentials(creds []*targets.SessionCredential) (credentials, error) {
|
||||
if creds == nil {
|
||||
return credentials{}, nil
|
||||
}
|
||||
var out credentials
|
||||
for _, cred := range creds {
|
||||
if cred.CredentialSource == nil {
|
||||
return credentials{}, errors.New("missing credential source")
|
||||
}
|
||||
|
||||
var upCred usernamePassword
|
||||
var spkCred sshPrivateKey
|
||||
switch globals.CredentialType(cred.CredentialSource.CredentialType) {
|
||||
case globals.UsernamePasswordCredentialType:
|
||||
// Decode attributes from credential struct
|
||||
if err := mapstructure.Decode(cred.Credential, &upCred); err != nil {
|
||||
return credentials{}, err
|
||||
}
|
||||
|
||||
if upCred.Username != "" && upCred.Password != "" {
|
||||
upCred.raw = cred
|
||||
out.usernamePassword = append(out.usernamePassword, upCred)
|
||||
continue
|
||||
}
|
||||
|
||||
case globals.SshPrivateKeyCredentialType:
|
||||
// Decode attributes from credential struct
|
||||
if err := mapstructure.Decode(cred.Credential, &spkCred); err != nil {
|
||||
return credentials{}, err
|
||||
}
|
||||
|
||||
if spkCred.Username != "" && spkCred.PrivateKey != "" {
|
||||
spkCred.raw = cred
|
||||
out.sshPrivateKey = append(out.sshPrivateKey, spkCred)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Credential type is unspecified, make a best effort attempt to parse
|
||||
// a credential from the Decoded field if it exists
|
||||
if cred.Secret != nil && cred.Secret.Decoded != nil {
|
||||
// Attempt unmarshaling into username password creds
|
||||
if err := mapstructure.Decode(cred.Secret.Decoded, &upCred); err != nil {
|
||||
return credentials{}, err
|
||||
}
|
||||
if upCred.Username != "" && upCred.Password != "" {
|
||||
upCred.raw = cred
|
||||
out.usernamePassword = append(out.usernamePassword, upCred)
|
||||
continue
|
||||
}
|
||||
|
||||
// Attempt unmarshaling into ssh private key creds
|
||||
if err := mapstructure.Decode(cred.Secret.Decoded, &spkCred); err != nil {
|
||||
return credentials{}, err
|
||||
}
|
||||
if spkCred.Username != "" && spkCred.PrivateKey != "" {
|
||||
spkCred.raw = cred
|
||||
out.sshPrivateKey = append(out.sshPrivateKey, spkCred)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// We could not parse the credential
|
||||
out.unspecified = append(out.unspecified, cred)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
@@ -1,625 +0,0 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package connect
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/api/targets"
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/credential/static"
|
||||
"github.com/hashicorp/boundary/internal/credential/vault"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
typedUsernamePassword = &targets.SessionCredential{
|
||||
CredentialSource: &targets.CredentialSource{
|
||||
CredentialType: string(globals.UsernamePasswordCredentialType),
|
||||
},
|
||||
Credential: map[string]any{
|
||||
"username": "user",
|
||||
"password": "pass",
|
||||
},
|
||||
}
|
||||
|
||||
typedSshPrivateKey = &targets.SessionCredential{
|
||||
CredentialSource: &targets.CredentialSource{
|
||||
CredentialType: string(globals.SshPrivateKeyCredentialType),
|
||||
},
|
||||
Credential: map[string]any{
|
||||
"username": "user",
|
||||
"private_key": "my-pk",
|
||||
},
|
||||
}
|
||||
|
||||
vaultUsernamePasswordDeprecatedSubtype = &targets.SessionCredential{
|
||||
CredentialSource: &targets.CredentialSource{
|
||||
Type: vault.Subtype.String(),
|
||||
},
|
||||
Secret: &targets.SessionSecret{
|
||||
Decoded: map[string]any{
|
||||
"username": "vault-decoded-user",
|
||||
"password": "vault-decoded-pass",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
vaultSshPrivateKeyDeprecatedSubtype = &targets.SessionCredential{
|
||||
CredentialSource: &targets.CredentialSource{
|
||||
Type: vault.Subtype.String(),
|
||||
},
|
||||
Secret: &targets.SessionSecret{
|
||||
Decoded: map[string]any{
|
||||
"username": "vault-decoded-user",
|
||||
"private_key": "vault-decoded-pk",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
vaultUsernamePassword = &targets.SessionCredential{
|
||||
CredentialSource: &targets.CredentialSource{
|
||||
Type: vault.GenericLibrarySubtype.String(),
|
||||
},
|
||||
Secret: &targets.SessionSecret{
|
||||
Decoded: map[string]any{
|
||||
"username": "vault-decoded-user",
|
||||
"password": "vault-decoded-pass",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
vaultSshPrivateKey = &targets.SessionCredential{
|
||||
CredentialSource: &targets.CredentialSource{
|
||||
Type: vault.GenericLibrarySubtype.String(),
|
||||
},
|
||||
Secret: &targets.SessionSecret{
|
||||
Decoded: map[string]any{
|
||||
"username": "vault-decoded-user",
|
||||
"private_key": "vault-decoded-pk",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
unknownUsernamePassword = &targets.SessionCredential{
|
||||
CredentialSource: &targets.CredentialSource{},
|
||||
Secret: &targets.SessionSecret{
|
||||
Decoded: map[string]any{
|
||||
"username": "unknown-decoded-user",
|
||||
"password": "unknown-decoded-pass",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
unknownSshPrivateKey = &targets.SessionCredential{
|
||||
CredentialSource: &targets.CredentialSource{},
|
||||
Secret: &targets.SessionSecret{
|
||||
Decoded: map[string]any{
|
||||
"username": "unknown-decoded-user",
|
||||
"private_key": "unknown-decoded-pk",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
staticUsernamePassword = &targets.SessionCredential{
|
||||
CredentialSource: &targets.CredentialSource{
|
||||
Type: static.Subtype.String(),
|
||||
},
|
||||
Secret: &targets.SessionSecret{
|
||||
Decoded: map[string]any{
|
||||
"username": "static-decoded-user",
|
||||
"password": "static-decoded-pass",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
staticSshPrivateKey = &targets.SessionCredential{
|
||||
CredentialSource: &targets.CredentialSource{
|
||||
Type: static.Subtype.String(),
|
||||
},
|
||||
Secret: &targets.SessionSecret{
|
||||
Decoded: map[string]any{
|
||||
"username": "static-decoded-user",
|
||||
"private_key": "static-decoded-pk",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
staticKv = &targets.SessionCredential{
|
||||
CredentialSource: &targets.CredentialSource{
|
||||
Type: static.Subtype.String(),
|
||||
CredentialType: "json",
|
||||
CredentialStoreId: "csst_id",
|
||||
Description: "test",
|
||||
Name: "test unspecified json cred",
|
||||
Id: "credjson_id",
|
||||
},
|
||||
Secret: &targets.SessionSecret{
|
||||
Decoded: map[string]any{
|
||||
"secret": map[string]any{
|
||||
"username": "password",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
unspecifiedCred = &targets.SessionCredential{
|
||||
CredentialSource: &targets.CredentialSource{
|
||||
Type: static.Subtype.String(),
|
||||
},
|
||||
Secret: &targets.SessionSecret{
|
||||
Decoded: map[string]any{
|
||||
"username": "decoded-user",
|
||||
"some-value": "decoded-some-value",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
unspecifiedCred1 = &targets.SessionCredential{
|
||||
CredentialSource: &targets.CredentialSource{
|
||||
Type: static.Subtype.String(),
|
||||
},
|
||||
Secret: &targets.SessionSecret{
|
||||
Decoded: map[string]any{
|
||||
"username": "decoded-user",
|
||||
"some-value1": "decoded-some-value1",
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func Test_parseCredentials(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
creds []*targets.SessionCredential
|
||||
wantCreds credentials
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "no-creds",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "no-credential-source",
|
||||
creds: []*targets.SessionCredential{
|
||||
{
|
||||
Secret: &targets.SessionSecret{
|
||||
Decoded: map[string]any{
|
||||
"username": "decoded-user",
|
||||
"private_key": "decoded-pk",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "username-password-typed",
|
||||
creds: []*targets.SessionCredential{
|
||||
typedUsernamePassword,
|
||||
},
|
||||
wantCreds: credentials{
|
||||
usernamePassword: []usernamePassword{
|
||||
{
|
||||
Username: "user",
|
||||
Password: "pass",
|
||||
raw: typedUsernamePassword,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "ssh-private-key-typed",
|
||||
creds: []*targets.SessionCredential{
|
||||
typedSshPrivateKey,
|
||||
},
|
||||
wantCreds: credentials{
|
||||
sshPrivateKey: []sshPrivateKey{
|
||||
{
|
||||
Username: "user",
|
||||
PrivateKey: "my-pk",
|
||||
raw: typedSshPrivateKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "vault-username-password-decoded",
|
||||
creds: []*targets.SessionCredential{
|
||||
vaultUsernamePassword,
|
||||
},
|
||||
wantCreds: credentials{
|
||||
usernamePassword: []usernamePassword{
|
||||
{
|
||||
Username: "vault-decoded-user",
|
||||
Password: "vault-decoded-pass",
|
||||
raw: vaultUsernamePassword,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "vault-private-key-decoded",
|
||||
creds: []*targets.SessionCredential{
|
||||
vaultSshPrivateKey,
|
||||
},
|
||||
wantCreds: credentials{
|
||||
sshPrivateKey: []sshPrivateKey{
|
||||
{
|
||||
Username: "vault-decoded-user",
|
||||
PrivateKey: "vault-decoded-pk",
|
||||
raw: vaultSshPrivateKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "vault-deprecated-username-password-decoded",
|
||||
creds: []*targets.SessionCredential{
|
||||
vaultUsernamePasswordDeprecatedSubtype,
|
||||
},
|
||||
wantCreds: credentials{
|
||||
usernamePassword: []usernamePassword{
|
||||
{
|
||||
Username: "vault-decoded-user",
|
||||
Password: "vault-decoded-pass",
|
||||
raw: vaultUsernamePasswordDeprecatedSubtype,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "vault-deprecated-private-key-decoded",
|
||||
creds: []*targets.SessionCredential{
|
||||
vaultSshPrivateKeyDeprecatedSubtype,
|
||||
},
|
||||
wantCreds: credentials{
|
||||
sshPrivateKey: []sshPrivateKey{
|
||||
{
|
||||
Username: "vault-decoded-user",
|
||||
PrivateKey: "vault-decoded-pk",
|
||||
raw: vaultSshPrivateKeyDeprecatedSubtype,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "unknown-username-password-decoded",
|
||||
creds: []*targets.SessionCredential{
|
||||
unknownUsernamePassword,
|
||||
},
|
||||
wantCreds: credentials{
|
||||
usernamePassword: []usernamePassword{
|
||||
{
|
||||
Username: "unknown-decoded-user",
|
||||
Password: "unknown-decoded-pass",
|
||||
raw: unknownUsernamePassword,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "unknown-private-key-decoded",
|
||||
creds: []*targets.SessionCredential{
|
||||
unknownSshPrivateKey,
|
||||
},
|
||||
wantCreds: credentials{
|
||||
sshPrivateKey: []sshPrivateKey{
|
||||
{
|
||||
Username: "unknown-decoded-user",
|
||||
PrivateKey: "unknown-decoded-pk",
|
||||
raw: unknownSshPrivateKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "static-username-password-decoded",
|
||||
creds: []*targets.SessionCredential{
|
||||
staticUsernamePassword,
|
||||
},
|
||||
wantCreds: credentials{
|
||||
usernamePassword: []usernamePassword{
|
||||
{
|
||||
Username: "static-decoded-user",
|
||||
Password: "static-decoded-pass",
|
||||
raw: staticUsernamePassword,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "static-private-key-decoded",
|
||||
creds: []*targets.SessionCredential{
|
||||
staticSshPrivateKey,
|
||||
},
|
||||
wantCreds: credentials{
|
||||
sshPrivateKey: []sshPrivateKey{
|
||||
{
|
||||
Username: "static-decoded-user",
|
||||
PrivateKey: "static-decoded-pk",
|
||||
raw: staticSshPrivateKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "unspecified",
|
||||
creds: []*targets.SessionCredential{
|
||||
unspecifiedCred,
|
||||
},
|
||||
wantCreds: credentials{
|
||||
unspecified: []*targets.SessionCredential{
|
||||
unspecifiedCred,
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "unspecified-static-json",
|
||||
creds: []*targets.SessionCredential{
|
||||
staticKv,
|
||||
},
|
||||
wantCreds: credentials{
|
||||
unspecified: []*targets.SessionCredential{
|
||||
staticKv,
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "mixed",
|
||||
creds: []*targets.SessionCredential{
|
||||
staticSshPrivateKey, unspecifiedCred1, vaultSshPrivateKey, typedUsernamePassword,
|
||||
unspecifiedCred, vaultUsernamePassword, typedSshPrivateKey, staticUsernamePassword,
|
||||
staticKv,
|
||||
},
|
||||
wantCreds: credentials{
|
||||
sshPrivateKey: []sshPrivateKey{
|
||||
{
|
||||
Username: "static-decoded-user",
|
||||
PrivateKey: "static-decoded-pk",
|
||||
raw: staticSshPrivateKey,
|
||||
},
|
||||
{
|
||||
Username: "vault-decoded-user",
|
||||
PrivateKey: "vault-decoded-pk",
|
||||
raw: vaultSshPrivateKey,
|
||||
},
|
||||
{
|
||||
Username: "user",
|
||||
PrivateKey: "my-pk",
|
||||
raw: typedSshPrivateKey,
|
||||
},
|
||||
},
|
||||
usernamePassword: []usernamePassword{
|
||||
{
|
||||
Username: "static-decoded-user",
|
||||
Password: "static-decoded-pass",
|
||||
raw: staticUsernamePassword,
|
||||
},
|
||||
{
|
||||
Username: "vault-decoded-user",
|
||||
Password: "vault-decoded-pass",
|
||||
raw: vaultUsernamePassword,
|
||||
},
|
||||
{
|
||||
Username: "user",
|
||||
Password: "pass",
|
||||
raw: typedUsernamePassword,
|
||||
},
|
||||
},
|
||||
unspecified: []*targets.SessionCredential{
|
||||
unspecifiedCred, unspecifiedCred1, staticKv,
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
creds, err := parseCredentials(tt.creds)
|
||||
if tt.wantErr {
|
||||
require.Error(err)
|
||||
assert.Empty(creds)
|
||||
return
|
||||
}
|
||||
require.NoError(err)
|
||||
|
||||
assert.ElementsMatch(tt.wantCreds.usernamePassword, creds.usernamePassword)
|
||||
assert.ElementsMatch(tt.wantCreds.sshPrivateKey, creds.sshPrivateKey)
|
||||
assert.ElementsMatch(tt.wantCreds.unspecified, creds.unspecified)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_unconsumedSessionCredentials(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
creds credentials
|
||||
wantCreds []*targets.SessionCredential
|
||||
}{
|
||||
{
|
||||
name: "no-creds",
|
||||
wantCreds: nil,
|
||||
},
|
||||
{
|
||||
name: "spk-consumed",
|
||||
creds: credentials{
|
||||
sshPrivateKey: []sshPrivateKey{
|
||||
{
|
||||
raw: staticSshPrivateKey,
|
||||
consumed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantCreds: nil,
|
||||
},
|
||||
{
|
||||
name: "spk",
|
||||
creds: credentials{
|
||||
sshPrivateKey: []sshPrivateKey{
|
||||
{
|
||||
raw: staticSshPrivateKey,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantCreds: []*targets.SessionCredential{staticSshPrivateKey},
|
||||
},
|
||||
{
|
||||
name: "up",
|
||||
creds: credentials{
|
||||
usernamePassword: []usernamePassword{
|
||||
{
|
||||
raw: vaultUsernamePassword,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantCreds: []*targets.SessionCredential{vaultUsernamePassword},
|
||||
},
|
||||
{
|
||||
name: "up-consumed",
|
||||
creds: credentials{
|
||||
usernamePassword: []usernamePassword{
|
||||
{
|
||||
raw: vaultUsernamePassword,
|
||||
consumed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
wantCreds: nil,
|
||||
},
|
||||
{
|
||||
name: "unspecified",
|
||||
creds: credentials{
|
||||
unspecified: []*targets.SessionCredential{unspecifiedCred},
|
||||
},
|
||||
wantCreds: []*targets.SessionCredential{unspecifiedCred},
|
||||
},
|
||||
{
|
||||
name: "mixed",
|
||||
creds: credentials{
|
||||
sshPrivateKey: []sshPrivateKey{
|
||||
{
|
||||
raw: staticSshPrivateKey,
|
||||
consumed: true,
|
||||
},
|
||||
{
|
||||
raw: vaultSshPrivateKey,
|
||||
},
|
||||
{
|
||||
raw: typedSshPrivateKey,
|
||||
},
|
||||
},
|
||||
usernamePassword: []usernamePassword{
|
||||
{
|
||||
raw: staticUsernamePassword,
|
||||
consumed: true,
|
||||
},
|
||||
{
|
||||
raw: vaultUsernamePassword,
|
||||
},
|
||||
{
|
||||
raw: typedUsernamePassword,
|
||||
consumed: true,
|
||||
},
|
||||
},
|
||||
unspecified: []*targets.SessionCredential{unspecifiedCred, unspecifiedCred1},
|
||||
},
|
||||
wantCreds: []*targets.SessionCredential{
|
||||
vaultSshPrivateKey, typedSshPrivateKey, vaultUsernamePassword, unspecifiedCred, unspecifiedCred1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mixed-all-consumed",
|
||||
creds: credentials{
|
||||
sshPrivateKey: []sshPrivateKey{
|
||||
{
|
||||
raw: staticSshPrivateKey,
|
||||
consumed: true,
|
||||
},
|
||||
{
|
||||
raw: vaultSshPrivateKey,
|
||||
consumed: true,
|
||||
},
|
||||
{
|
||||
raw: typedSshPrivateKey,
|
||||
consumed: true,
|
||||
},
|
||||
},
|
||||
usernamePassword: []usernamePassword{
|
||||
{
|
||||
raw: staticUsernamePassword,
|
||||
consumed: true,
|
||||
},
|
||||
{
|
||||
raw: vaultUsernamePassword,
|
||||
consumed: true,
|
||||
},
|
||||
{
|
||||
raw: typedUsernamePassword,
|
||||
consumed: true,
|
||||
},
|
||||
},
|
||||
unspecified: []*targets.SessionCredential{unspecifiedCred, unspecifiedCred1},
|
||||
},
|
||||
wantCreds: []*targets.SessionCredential{
|
||||
unspecifiedCred1, unspecifiedCred,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mixed-all-unconsumed",
|
||||
creds: credentials{
|
||||
sshPrivateKey: []sshPrivateKey{
|
||||
{
|
||||
raw: staticSshPrivateKey,
|
||||
},
|
||||
{
|
||||
raw: vaultSshPrivateKey,
|
||||
},
|
||||
{
|
||||
raw: typedSshPrivateKey,
|
||||
},
|
||||
},
|
||||
usernamePassword: []usernamePassword{
|
||||
{
|
||||
raw: staticUsernamePassword,
|
||||
},
|
||||
{
|
||||
raw: vaultUsernamePassword,
|
||||
},
|
||||
{
|
||||
raw: typedUsernamePassword,
|
||||
},
|
||||
},
|
||||
unspecified: []*targets.SessionCredential{unspecifiedCred, unspecifiedCred1},
|
||||
},
|
||||
wantCreds: []*targets.SessionCredential{
|
||||
staticSshPrivateKey, unspecifiedCred1, vaultSshPrivateKey, typedUsernamePassword,
|
||||
unspecifiedCred, vaultUsernamePassword, typedSshPrivateKey, staticUsernamePassword,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
creds := tt.creds.unconsumedSessionCredentials()
|
||||
assert.ElementsMatch(tt.wantCreds, creds)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/boundary/api/proxy"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/posener/complete"
|
||||
)
|
||||
@@ -53,17 +54,17 @@ func (p *postgresFlags) defaultExec() string {
|
||||
return strings.ToLower(p.flagPostgresStyle)
|
||||
}
|
||||
|
||||
func (p *postgresFlags) buildArgs(c *Command, port, ip, _ string, creds credentials) (args, envs []string, retCreds credentials, retErr error) {
|
||||
func (p *postgresFlags) buildArgs(c *Command, port, ip, _ string, creds proxy.Credentials) (args, envs []string, retCreds proxy.Credentials, retErr error) {
|
||||
var username, password string
|
||||
|
||||
retCreds = creds
|
||||
if len(retCreds.usernamePassword) > 0 {
|
||||
if len(retCreds.UsernamePassword) > 0 {
|
||||
// Mark credential as consumed so it is not printed to user
|
||||
retCreds.usernamePassword[0].consumed = true
|
||||
retCreds.UsernamePassword[0].Consumed = true
|
||||
|
||||
// For now just grab the first username password credential brokered
|
||||
username = retCreds.usernamePassword[0].Username
|
||||
password = retCreds.usernamePassword[0].Password
|
||||
username = retCreds.UsernamePassword[0].Username
|
||||
password = retCreds.UsernamePassword[0].Password
|
||||
}
|
||||
|
||||
switch p.flagPostgresStyle {
|
||||
@@ -84,7 +85,7 @@ func (p *postgresFlags) buildArgs(c *Command, port, ip, _ string, creds credenti
|
||||
if password != "" {
|
||||
passfile, err := os.CreateTemp("", "*")
|
||||
if err != nil {
|
||||
return nil, nil, credentials{}, fmt.Errorf("Error saving postgres password to tmp file: %w", err)
|
||||
return nil, nil, proxy.Credentials{}, fmt.Errorf("Error saving postgres password to tmp file: %w", err)
|
||||
}
|
||||
c.cleanupFuncs = append(c.cleanupFuncs, func() error {
|
||||
if err := os.Remove(passfile.Name()); err != nil {
|
||||
@@ -94,10 +95,10 @@ func (p *postgresFlags) buildArgs(c *Command, port, ip, _ string, creds credenti
|
||||
})
|
||||
_, err = passfile.WriteString(fmt.Sprintf("*:*:*:*:%s", password))
|
||||
if err != nil {
|
||||
return nil, nil, credentials{}, fmt.Errorf("Error writing password file to %s: %w", passfile.Name(), err)
|
||||
return nil, nil, proxy.Credentials{}, fmt.Errorf("Error writing password file to %s: %w", passfile.Name(), err)
|
||||
}
|
||||
if err := passfile.Close(); err != nil {
|
||||
return nil, nil, credentials{}, fmt.Errorf("Error closing password file after writing to %s: %w", passfile.Name(), err)
|
||||
return nil, nil, proxy.Credentials{}, fmt.Errorf("Error closing password file after writing to %s: %w", passfile.Name(), err)
|
||||
}
|
||||
envs = append(envs, fmt.Sprintf("PGPASSFILE=%s", passfile.Name()))
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
apiproxy "github.com/hashicorp/boundary/api/proxy"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/target"
|
||||
"github.com/posener/complete"
|
||||
@@ -54,7 +55,7 @@ func (s *sshFlags) defaultExec() string {
|
||||
return strings.ToLower(s.flagSshStyle)
|
||||
}
|
||||
|
||||
func (s *sshFlags) buildArgs(c *Command, port, ip, _ string, creds credentials) (args, envs []string, retCreds credentials, retErr error) {
|
||||
func (s *sshFlags) buildArgs(c *Command, port, ip, _ string, creds apiproxy.Credentials) (args, envs []string, retCreds apiproxy.Credentials, retErr error) {
|
||||
var username string
|
||||
retCreds = creds
|
||||
|
||||
@@ -89,20 +90,20 @@ func (s *sshFlags) buildArgs(c *Command, port, ip, _ string, creds credentials)
|
||||
|
||||
case "sshpass":
|
||||
if !tryConsume {
|
||||
return nil, nil, credentials{}, errors.New("Credentials must be consumed when using sshpass")
|
||||
return nil, nil, apiproxy.Credentials{}, errors.New("Credentials must be consumed when using sshpass")
|
||||
}
|
||||
var password string
|
||||
if len(retCreds.usernamePassword) > 0 {
|
||||
if len(retCreds.UsernamePassword) > 0 {
|
||||
// For now just grab the first username password credential brokered
|
||||
// Mark credential as consumed so that it is not printed to user
|
||||
retCreds.usernamePassword[0].consumed = true
|
||||
retCreds.UsernamePassword[0].Consumed = true
|
||||
|
||||
username = retCreds.usernamePassword[0].Username
|
||||
password = retCreds.usernamePassword[0].Password
|
||||
username = retCreds.UsernamePassword[0].Username
|
||||
password = retCreds.UsernamePassword[0].Password
|
||||
}
|
||||
|
||||
if password == "" {
|
||||
return nil, nil, credentials{}, errors.New("Password is required when using sshpass")
|
||||
return nil, nil, apiproxy.Credentials{}, errors.New("Password is required when using sshpass")
|
||||
}
|
||||
|
||||
// sshpass requires that the password is passed as env-var "SSHPASS"
|
||||
@@ -130,24 +131,24 @@ func (s *sshFlags) buildArgs(c *Command, port, ip, _ string, creds credentials)
|
||||
// Do nothing
|
||||
|
||||
// If we want to consume check if we have a private key available first
|
||||
case len(creds.sshPrivateKey) > 0:
|
||||
case len(creds.SshPrivateKey) > 0:
|
||||
// For now just grab the first ssh private key credential brokered
|
||||
cred := retCreds.sshPrivateKey[0]
|
||||
cred := retCreds.SshPrivateKey[0]
|
||||
|
||||
username = cred.Username
|
||||
privateKey := cred.PrivateKey
|
||||
cred.consumed = true
|
||||
cred.Consumed = true
|
||||
if cred.Passphrase != "" {
|
||||
// Don't re-print everything, but print the passphrase they'll need
|
||||
cred.consumed = false
|
||||
delete(cred.raw.Credential, "username")
|
||||
delete(cred.raw.Credential, "private_key")
|
||||
cred.Consumed = false
|
||||
delete(cred.Raw.Credential, "username")
|
||||
delete(cred.Raw.Credential, "private_key")
|
||||
}
|
||||
retCreds.sshPrivateKey[0] = cred
|
||||
retCreds.SshPrivateKey[0] = cred
|
||||
|
||||
pkFile, err := os.CreateTemp("", "*")
|
||||
if err != nil {
|
||||
return nil, nil, credentials{}, fmt.Errorf("Error saving ssh private key to tmp file: %w", err)
|
||||
return nil, nil, apiproxy.Credentials{}, fmt.Errorf("Error saving ssh private key to tmp file: %w", err)
|
||||
}
|
||||
c.cleanupFuncs = append(c.cleanupFuncs, func() error {
|
||||
if err := os.Remove(pkFile.Name()); err != nil {
|
||||
@@ -163,15 +164,15 @@ func (s *sshFlags) buildArgs(c *Command, port, ip, _ string, creds credentials)
|
||||
}
|
||||
_, err = pkFile.WriteString(privateKey)
|
||||
if err != nil {
|
||||
return nil, nil, credentials{}, fmt.Errorf("Error writing private key file to %s: %w", pkFile.Name(), err)
|
||||
return nil, nil, apiproxy.Credentials{}, fmt.Errorf("Error writing private key file to %s: %w", pkFile.Name(), err)
|
||||
}
|
||||
if err := pkFile.Close(); err != nil {
|
||||
return nil, nil, credentials{}, fmt.Errorf("Error closing private key file after writing to %s: %w", pkFile.Name(), err)
|
||||
return nil, nil, apiproxy.Credentials{}, fmt.Errorf("Error closing private key file after writing to %s: %w", pkFile.Name(), err)
|
||||
}
|
||||
args = append(args, "-i", pkFile.Name())
|
||||
|
||||
// Next check if we have a username password credential
|
||||
case len(creds.usernamePassword) > 0:
|
||||
case len(creds.UsernamePassword) > 0:
|
||||
// We cannot use the password of the credential outside of sshpass, but we
|
||||
// can use the username.
|
||||
// N.B. Do not mark credential as consumed, as user will still need enter
|
||||
@@ -180,7 +181,7 @@ func (s *sshFlags) buildArgs(c *Command, port, ip, _ string, creds credentials)
|
||||
if c.flagUsername == "" {
|
||||
// If the user did not actively provide a username flag set the
|
||||
// username to that of the first credential we got.
|
||||
username = retCreds.usernamePassword[0].Username
|
||||
username = retCreds.UsernamePassword[0].Username
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1083,6 +1083,8 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
|
||||
TargetId: t.GetPublicId(),
|
||||
Scope: authResults.Scope,
|
||||
CreatedTime: sess.CreateTime.GetTimestamp(),
|
||||
Expiration: sess.ExpirationTime.GetTimestamp(),
|
||||
EndpointPort: t.GetDefaultPort(),
|
||||
Type: t.GetType().String(),
|
||||
Certificate: sess.Certificate,
|
||||
PrivateKey: sess.CertificatePrivateKey,
|
||||
@@ -1103,6 +1105,8 @@ func (s Service) AuthorizeSession(ctx context.Context, req *pbs.AuthorizeSession
|
||||
TargetId: t.GetPublicId(),
|
||||
Scope: authResults.Scope,
|
||||
CreatedTime: sess.CreateTime.GetTimestamp(),
|
||||
Expiration: sess.ExpirationTime.GetTimestamp(),
|
||||
EndpointPort: t.GetDefaultPort(),
|
||||
Type: t.GetType().String(),
|
||||
AuthorizationToken: encodedMarshaledSad,
|
||||
UserId: authResults.UserId,
|
||||
|
||||
@@ -2652,15 +2652,18 @@ func TestAuthorizeSession(t *testing.T) {
|
||||
HostId: wantedHostId,
|
||||
Type: "tcp",
|
||||
Endpoint: fmt.Sprintf("tcp://%s", tc.wantedEndpoint),
|
||||
Credentials: []*pb.SessionCredential{{
|
||||
CredentialSource: &pb.CredentialSource{
|
||||
Id: clsResp.GetItem().GetId(),
|
||||
Name: clsResp.GetItem().GetName().GetValue(),
|
||||
Description: clsResp.GetItem().GetDescription().GetValue(),
|
||||
CredentialStoreId: vaultStore.GetPublicId(),
|
||||
Type: vault.GenericLibrarySubtype.String(),
|
||||
Credentials: []*pb.SessionCredential{
|
||||
{
|
||||
CredentialSource: &pb.CredentialSource{
|
||||
Id: clsResp.GetItem().GetId(),
|
||||
Name: clsResp.GetItem().GetName().GetValue(),
|
||||
Description: clsResp.GetItem().GetDescription().GetValue(),
|
||||
CredentialStoreId: vaultStore.GetPublicId(),
|
||||
Type: vault.GenericLibrarySubtype.String(),
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
EndpointPort: uint32(defaultPort),
|
||||
// TODO: validate the contents of the authorization token is what is expected
|
||||
}
|
||||
wantSecret := map[string]any{
|
||||
@@ -2697,7 +2700,7 @@ func TestAuthorizeSession(t *testing.T) {
|
||||
gotCred.Secret = nil
|
||||
|
||||
got.AuthorizationToken, got.SessionId, got.CreatedTime = "", "", nil
|
||||
assert.Empty(t, cmp.Diff(got, want, protocmp.Transform()))
|
||||
assert.Empty(t, cmp.Diff(got, want, protocmp.Transform(), protocmp.IgnoreFields(&pb.SessionAuthorization{}, "expiration")))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -3269,13 +3272,15 @@ func TestAuthorizeSessionTypedCredentials(t *testing.T) {
|
||||
Description: proj.GetDescription(),
|
||||
ParentScopeId: proj.GetParentId(),
|
||||
},
|
||||
TargetId: tar.GetPublicId(),
|
||||
UserId: at.GetIamUserId(),
|
||||
HostSetId: tc.hostSourceId,
|
||||
HostId: tc.wantedHostId,
|
||||
Type: "tcp",
|
||||
Endpoint: fmt.Sprintf("tcp://%s:%d", tc.wantedEndpoint, defaultPort),
|
||||
Credentials: []*pb.SessionCredential{tc.wantedCred},
|
||||
TargetId: tar.GetPublicId(),
|
||||
UserId: at.GetIamUserId(),
|
||||
HostSetId: tc.hostSourceId,
|
||||
HostId: tc.wantedHostId,
|
||||
Type: "tcp",
|
||||
Endpoint: fmt.Sprintf("tcp://%s:%d", tc.wantedEndpoint, defaultPort),
|
||||
Credentials: []*pb.SessionCredential{tc.wantedCred},
|
||||
EndpointPort: uint32(defaultPort),
|
||||
Expiration: asRes.Item.Expiration,
|
||||
// TODO: validate the contents of the authorization token is what is expected
|
||||
}
|
||||
got := asRes.GetItem()
|
||||
|
||||
@@ -22,8 +22,8 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/event"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/servers/services"
|
||||
"github.com/hashicorp/boundary/internal/proxy"
|
||||
"github.com/hashicorp/boundary/internal/util"
|
||||
"github.com/hashicorp/boundary/sdk/pbs/proxy"
|
||||
"github.com/hashicorp/go-secure-stdlib/listenerutil"
|
||||
"github.com/hashicorp/nodeenrollment"
|
||||
"github.com/hashicorp/nodeenrollment/types"
|
||||
|
||||
@@ -33,23 +33,30 @@ func TestDeleteConnectedWorkers(t *testing.T) {
|
||||
|
||||
serverRepo, err := c.Controller().ServersRepoFn()
|
||||
require.NoError(t, err)
|
||||
workers, err := serverRepo.ListWorkers(ctx, []string{"global"}, server.WithLiveness(-1))
|
||||
require.NoError(t, err)
|
||||
workerTimeoutCtx, workerTimeoutCancel := context.WithTimeout(ctx, 5*time.Minute)
|
||||
defer workerTimeoutCancel()
|
||||
var pkiWorker, childPkiWorker, childKmsWorker *server.Worker
|
||||
for _, w := range workers {
|
||||
if w.Type == "pki" && w.GetAddress() == multiHoppedPkiWorker.ProxyAddrs()[0] {
|
||||
childPkiWorker = w
|
||||
}
|
||||
if w.Type == "pki" && w.GetAddress() == multiHoppedKmsWorker.ProxyAddrs()[0] {
|
||||
childKmsWorker = w
|
||||
}
|
||||
if w.Type == "pki" && w.GetAddress() == directPkiWorker.ProxyAddrs()[0] {
|
||||
pkiWorker = w
|
||||
for pkiWorker == nil || childPkiWorker == nil || childKmsWorker == nil {
|
||||
time.Sleep(time.Second)
|
||||
select {
|
||||
case <-workerTimeoutCtx.Done():
|
||||
require.FailNow(t, "timeout waiting for all workers to connect")
|
||||
default:
|
||||
workers, err := serverRepo.ListWorkers(workerTimeoutCtx, []string{"global"}, server.WithLiveness(-1))
|
||||
require.NoError(t, err)
|
||||
for _, w := range workers {
|
||||
if w.Type == "pki" && w.GetAddress() == multiHoppedPkiWorker.ProxyAddrs()[0] {
|
||||
childPkiWorker = w
|
||||
}
|
||||
if w.Type == "pki" && w.GetAddress() == multiHoppedKmsWorker.ProxyAddrs()[0] {
|
||||
childKmsWorker = w
|
||||
}
|
||||
if w.Type == "pki" && w.GetAddress() == directPkiWorker.ProxyAddrs()[0] {
|
||||
pkiWorker = w
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
require.NotNil(t, childKmsWorker)
|
||||
require.NotNil(t, childPkiWorker)
|
||||
require.NotNil(t, pkiWorker)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
|
||||
@@ -6433,6 +6433,18 @@
|
||||
"description": "Output only. The endpoint address that the worker will connect to, useful for setting TLS parameters.",
|
||||
"readOnly": true
|
||||
},
|
||||
"endpoint_port": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "Output only. The endpoint port that will be connected to, either from a\nport directly on the target or from a service definition.",
|
||||
"readOnly": true
|
||||
},
|
||||
"expiration": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Output only. The expiration time of the session.",
|
||||
"readOnly": true
|
||||
},
|
||||
"credentials": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
||||
@@ -295,7 +295,8 @@ message WorkerInfo {
|
||||
string address = 10; // @gotags: `class:"public"`
|
||||
}
|
||||
|
||||
// SessionAuthorizationData contains the fields needed by the proxy command to connect to a worker. It is marshaled inside the SessionAuthorization message.
|
||||
// SessionAuthorizationData contains the fields needed by the proxy command to
|
||||
// connect to a worker. It is marshaled inside the SessionAuthorization message.
|
||||
message SessionAuthorizationData {
|
||||
// Output only. The ID of the session.
|
||||
string session_id = 10 [json_name = "session_id"]; // @gotags: `class:"public" eventstream:"observation"`
|
||||
@@ -315,6 +316,13 @@ message SessionAuthorizationData {
|
||||
// Output only. The connection limit being applied to this session. -1 means unlimited. This is not actually enforced on the client side but it provides for better listener handling by including it.
|
||||
int32 connection_limit = 90 [json_name = "connection_limit"];
|
||||
|
||||
// Output only. The endpoint port that will be connected to, either from a
|
||||
// port directly on the target or from a service definition.
|
||||
uint32 endpoint_port = 102 [json_name = "endpoint_port"]; // @gotags: `class:"public" eventstream:"observation"`
|
||||
|
||||
// Output only. The expiration time of the session.
|
||||
google.protobuf.Timestamp expiration = 105; // @gotags: `class:"public" eventstream:"observation"`
|
||||
|
||||
// Output only. The certificate to use when connecting. Raw DER bytes.
|
||||
bytes certificate = 120; // @gotags: `class:"sensitive"`
|
||||
|
||||
@@ -366,6 +374,13 @@ message SessionAuthorization {
|
||||
// Output only. The endpoint address that the worker will connect to, useful for setting TLS parameters.
|
||||
string endpoint = 100; // @gotags: `class:"public"`
|
||||
|
||||
// Output only. The endpoint port that will be connected to, either from a
|
||||
// port directly on the target or from a service definition.
|
||||
uint32 endpoint_port = 102 [json_name = "endpoint_port"]; // @gotags: `class:"public" eventstream:"observation"`
|
||||
|
||||
// Output only. The expiration time of the session.
|
||||
google.protobuf.Timestamp expiration = 105; // @gotags: `class:"public" eventstream:"observation"`
|
||||
|
||||
// Output only. The credentials for this session.
|
||||
repeated SessionCredential credentials = 110 [json_name = "credentials"];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
schema_version = 1
|
||||
|
||||
project {
|
||||
license = "MPL-2.0"
|
||||
copyright_year = 2020
|
||||
|
||||
header_ignore = []
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
@@ -7,7 +7,7 @@ package worker.proxy.v1;
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
option go_package = "github.com/hashicorp/boundary/internal/proxy;proxy";
|
||||
option go_package = "github.com/hashicorp/boundary/sdk/pbs/proxy;proxy";
|
||||
|
||||
enum HANDSHAKECOMMAND {
|
||||
// Note: Unspecified is the desired zero value based on protolint, but for
|
||||
|
||||
@@ -1,310 +0,0 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc (unknown)
|
||||
// source: worker/proxy/v1/proxy.proto
|
||||
|
||||
package proxy
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type HANDSHAKECOMMAND int32
|
||||
|
||||
const (
|
||||
// Note: Unspecified is the desired zero value based on protolint, but for
|
||||
// our purposes it simply means a normal connection.
|
||||
HANDSHAKECOMMAND_HANDSHAKECOMMAND_UNSPECIFIED HANDSHAKECOMMAND = 0
|
||||
HANDSHAKECOMMAND_HANDSHAKECOMMAND_SESSION_CANCEL HANDSHAKECOMMAND = 1
|
||||
)
|
||||
|
||||
// Enum value maps for HANDSHAKECOMMAND.
|
||||
var (
|
||||
HANDSHAKECOMMAND_name = map[int32]string{
|
||||
0: "HANDSHAKECOMMAND_UNSPECIFIED",
|
||||
1: "HANDSHAKECOMMAND_SESSION_CANCEL",
|
||||
}
|
||||
HANDSHAKECOMMAND_value = map[string]int32{
|
||||
"HANDSHAKECOMMAND_UNSPECIFIED": 0,
|
||||
"HANDSHAKECOMMAND_SESSION_CANCEL": 1,
|
||||
}
|
||||
)
|
||||
|
||||
func (x HANDSHAKECOMMAND) Enum() *HANDSHAKECOMMAND {
|
||||
p := new(HANDSHAKECOMMAND)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x HANDSHAKECOMMAND) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (HANDSHAKECOMMAND) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_worker_proxy_v1_proxy_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (HANDSHAKECOMMAND) Type() protoreflect.EnumType {
|
||||
return &file_worker_proxy_v1_proxy_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x HANDSHAKECOMMAND) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use HANDSHAKECOMMAND.Descriptor instead.
|
||||
func (HANDSHAKECOMMAND) EnumDescriptor() ([]byte, []int) {
|
||||
return file_worker_proxy_v1_proxy_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type ClientHandshake struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
TofuToken string `protobuf:"bytes,10,opt,name=tofu_token,json=tofuToken,proto3" json:"tofu_token,omitempty"`
|
||||
Command HANDSHAKECOMMAND `protobuf:"varint,20,opt,name=command,proto3,enum=worker.proxy.v1.HANDSHAKECOMMAND" json:"command,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ClientHandshake) Reset() {
|
||||
*x = ClientHandshake{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_worker_proxy_v1_proxy_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ClientHandshake) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ClientHandshake) ProtoMessage() {}
|
||||
|
||||
func (x *ClientHandshake) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_worker_proxy_v1_proxy_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ClientHandshake.ProtoReflect.Descriptor instead.
|
||||
func (*ClientHandshake) Descriptor() ([]byte, []int) {
|
||||
return file_worker_proxy_v1_proxy_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *ClientHandshake) GetTofuToken() string {
|
||||
if x != nil {
|
||||
return x.TofuToken
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ClientHandshake) GetCommand() HANDSHAKECOMMAND {
|
||||
if x != nil {
|
||||
return x.Command
|
||||
}
|
||||
return HANDSHAKECOMMAND_HANDSHAKECOMMAND_UNSPECIFIED
|
||||
}
|
||||
|
||||
type HandshakeResult struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Expiration *timestamppb.Timestamp `protobuf:"bytes,10,opt,name=expiration,proto3" json:"expiration,omitempty"`
|
||||
ConnectionLimit int32 `protobuf:"varint,20,opt,name=connection_limit,json=connectionLimit,proto3" json:"connection_limit,omitempty"`
|
||||
ConnectionsLeft int32 `protobuf:"varint,30,opt,name=connections_left,json=connectionsLeft,proto3" json:"connections_left,omitempty"`
|
||||
}
|
||||
|
||||
func (x *HandshakeResult) Reset() {
|
||||
*x = HandshakeResult{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_worker_proxy_v1_proxy_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *HandshakeResult) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HandshakeResult) ProtoMessage() {}
|
||||
|
||||
func (x *HandshakeResult) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_worker_proxy_v1_proxy_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use HandshakeResult.ProtoReflect.Descriptor instead.
|
||||
func (*HandshakeResult) Descriptor() ([]byte, []int) {
|
||||
return file_worker_proxy_v1_proxy_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *HandshakeResult) GetExpiration() *timestamppb.Timestamp {
|
||||
if x != nil {
|
||||
return x.Expiration
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *HandshakeResult) GetConnectionLimit() int32 {
|
||||
if x != nil {
|
||||
return x.ConnectionLimit
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *HandshakeResult) GetConnectionsLeft() int32 {
|
||||
if x != nil {
|
||||
return x.ConnectionsLeft
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_worker_proxy_v1_proxy_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_worker_proxy_v1_proxy_proto_rawDesc = []byte{
|
||||
0x0a, 0x1b, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76,
|
||||
0x31, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x77,
|
||||
0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x31, 0x1a, 0x1f,
|
||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f,
|
||||
0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
|
||||
0x6d, 0x0a, 0x0f, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61,
|
||||
0x6b, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x66, 0x75, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
|
||||
0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x74, 0x6f, 0x66, 0x75, 0x54, 0x6f, 0x6b, 0x65,
|
||||
0x6e, 0x12, 0x3b, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x14, 0x20, 0x01,
|
||||
0x28, 0x0e, 0x32, 0x21, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x78,
|
||||
0x79, 0x2e, 0x76, 0x31, 0x2e, 0x48, 0x41, 0x4e, 0x44, 0x53, 0x48, 0x41, 0x4b, 0x45, 0x43, 0x4f,
|
||||
0x4d, 0x4d, 0x41, 0x4e, 0x44, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22, 0xa3,
|
||||
0x01, 0x0a, 0x0f, 0x48, 0x61, 0x6e, 0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x75,
|
||||
0x6c, 0x74, 0x12, 0x3a, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
|
||||
0x6d, 0x70, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29,
|
||||
0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6c, 0x69, 0x6d,
|
||||
0x69, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6e,
|
||||
0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x6c, 0x65, 0x66, 0x74, 0x18, 0x1e, 0x20,
|
||||
0x01, 0x28, 0x05, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73,
|
||||
0x4c, 0x65, 0x66, 0x74, 0x2a, 0x59, 0x0a, 0x10, 0x48, 0x41, 0x4e, 0x44, 0x53, 0x48, 0x41, 0x4b,
|
||||
0x45, 0x43, 0x4f, 0x4d, 0x4d, 0x41, 0x4e, 0x44, 0x12, 0x20, 0x0a, 0x1c, 0x48, 0x41, 0x4e, 0x44,
|
||||
0x53, 0x48, 0x41, 0x4b, 0x45, 0x43, 0x4f, 0x4d, 0x4d, 0x41, 0x4e, 0x44, 0x5f, 0x55, 0x4e, 0x53,
|
||||
0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x23, 0x0a, 0x1f, 0x48, 0x41,
|
||||
0x4e, 0x44, 0x53, 0x48, 0x41, 0x4b, 0x45, 0x43, 0x4f, 0x4d, 0x4d, 0x41, 0x4e, 0x44, 0x5f, 0x53,
|
||||
0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x10, 0x01, 0x42,
|
||||
0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61,
|
||||
0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79,
|
||||
0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x3b,
|
||||
0x70, 0x72, 0x6f, 0x78, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_worker_proxy_v1_proxy_proto_rawDescOnce sync.Once
|
||||
file_worker_proxy_v1_proxy_proto_rawDescData = file_worker_proxy_v1_proxy_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_worker_proxy_v1_proxy_proto_rawDescGZIP() []byte {
|
||||
file_worker_proxy_v1_proxy_proto_rawDescOnce.Do(func() {
|
||||
file_worker_proxy_v1_proxy_proto_rawDescData = protoimpl.X.CompressGZIP(file_worker_proxy_v1_proxy_proto_rawDescData)
|
||||
})
|
||||
return file_worker_proxy_v1_proxy_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_worker_proxy_v1_proxy_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_worker_proxy_v1_proxy_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_worker_proxy_v1_proxy_proto_goTypes = []interface{}{
|
||||
(HANDSHAKECOMMAND)(0), // 0: worker.proxy.v1.HANDSHAKECOMMAND
|
||||
(*ClientHandshake)(nil), // 1: worker.proxy.v1.ClientHandshake
|
||||
(*HandshakeResult)(nil), // 2: worker.proxy.v1.HandshakeResult
|
||||
(*timestamppb.Timestamp)(nil), // 3: google.protobuf.Timestamp
|
||||
}
|
||||
var file_worker_proxy_v1_proxy_proto_depIdxs = []int32{
|
||||
0, // 0: worker.proxy.v1.ClientHandshake.command:type_name -> worker.proxy.v1.HANDSHAKECOMMAND
|
||||
3, // 1: worker.proxy.v1.HandshakeResult.expiration:type_name -> google.protobuf.Timestamp
|
||||
2, // [2:2] is the sub-list for method output_type
|
||||
2, // [2:2] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_worker_proxy_v1_proxy_proto_init() }
|
||||
func file_worker_proxy_v1_proxy_proto_init() {
|
||||
if File_worker_proxy_v1_proxy_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_worker_proxy_v1_proxy_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ClientHandshake); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_worker_proxy_v1_proxy_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*HandshakeResult); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_worker_proxy_v1_proxy_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_worker_proxy_v1_proxy_proto_goTypes,
|
||||
DependencyIndexes: file_worker_proxy_v1_proxy_proto_depIdxs,
|
||||
EnumInfos: file_worker_proxy_v1_proxy_proto_enumTypes,
|
||||
MessageInfos: file_worker_proxy_v1_proxy_proto_msgTypes,
|
||||
}.Build()
|
||||
File_worker_proxy_v1_proxy_proto = out.File
|
||||
file_worker_proxy_v1_proxy_proto_rawDesc = nil
|
||||
file_worker_proxy_v1_proxy_proto_goTypes = nil
|
||||
file_worker_proxy_v1_proxy_proto_depIdxs = nil
|
||||
}
|
||||
@@ -495,7 +495,7 @@ func TestUpdateAfterKeyRotation(t *testing.T) {
|
||||
// Should start asynchronous rewrapping of the encrypted JSON credential
|
||||
assert.Equal("pending", result.State)
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Minute)
|
||||
ctx, cancel := context.WithTimeout(ctx, 3*time.Minute)
|
||||
defer cancel()
|
||||
for {
|
||||
jobs, err := scopesClient.ListKeyVersionDestructionJobs(ctx, proj.PublicId)
|
||||
|
||||
@@ -22,9 +22,9 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/connect"
|
||||
"github.com/hashicorp/boundary/internal/daemon/controller/common"
|
||||
"github.com/hashicorp/boundary/internal/daemon/worker"
|
||||
"github.com/hashicorp/boundary/internal/proxy"
|
||||
"github.com/hashicorp/boundary/internal/session"
|
||||
targetspb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/targets"
|
||||
"github.com/hashicorp/boundary/sdk/pbs/proxy"
|
||||
"github.com/hashicorp/go-cleanhttp"
|
||||
"github.com/hashicorp/go-secure-stdlib/base62"
|
||||
"github.com/mr-tron/base58"
|
||||
@@ -333,8 +333,8 @@ type TestSessionConnection struct {
|
||||
}
|
||||
|
||||
// Close a test connection
|
||||
func (t *TestSessionConnection) Close() error {
|
||||
return t.conn.Close()
|
||||
func (c *TestSessionConnection) Close() error {
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
// Connect returns a TestSessionConnection for a TestSession. Check
|
||||
|
||||
Reference in new issue
Block a user