2021-10-14 11:56:08 -04:00
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
2023-02-02 17:15:17 -08:00
2020-09-24 03:31:26 -04:00
package base
import (
"context"
"fmt"
"strings"
2022-10-28 15:52:06 -04:00
"github.com/hashicorp/boundary/globals"
2020-09-24 03:31:26 -04:00
"github.com/hashicorp/boundary/internal/auth/password"
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/host/static"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/internal/kms"
2021-09-28 09:40:12 -04:00
hostplugin "github.com/hashicorp/boundary/internal/plugin/host"
2020-09-24 03:31:26 -04:00
"github.com/hashicorp/boundary/internal/target"
2021-09-29 13:13:49 -04:00
"github.com/hashicorp/boundary/internal/target/tcp"
2020-09-24 03:31:26 -04:00
"github.com/hashicorp/boundary/internal/types/scope"
2021-09-28 09:40:12 -04:00
plgpb "github.com/hashicorp/boundary/sdk/pbs/plugin"
2021-07-14 17:31:58 -07:00
"github.com/hashicorp/go-secure-stdlib/base62"
2020-09-24 03:31:26 -04:00
)
2020-10-01 10:51:54 -04:00
func ( b * Server ) CreateInitialLoginRole ( ctx context . Context ) ( * iam . Role , error ) {
rw := db . New ( b . Database )
2022-05-13 13:53:22 -04:00
kmsCache , err := kms . New ( ctx , rw , rw )
2020-10-01 10:51:54 -04:00
if err != nil {
return nil , fmt . Errorf ( "error creating kms cache: %w" , err )
}
if err := kmsCache . AddExternalWrappers (
2022-03-16 17:04:07 -04:00
b . Context ,
2020-10-01 10:51:54 -04:00
kms . WithRootWrapper ( b . RootKms ),
); err != nil {
return nil , fmt . Errorf ( "error adding config keys to kms: %w" , err )
}
iamRepo , err := iam . NewRepository ( rw , rw , kmsCache , iam . WithRandomReader ( b . SecureRandomReader ))
if err != nil {
return nil , fmt . Errorf ( "unable to create repo for initial login role: %w" , err )
}
pr , err := iam . NewRole ( scope . Global . String (),
iam . WithName ( "Login and Default Grants" ),
2021-02-11 13:14:18 -05:00
iam . WithDescription ( `Role created for login capability, account self-management, and other default grants for users of the global scope at its creation time` ),
2020-10-01 10:51:54 -04:00
)
if err != nil {
return nil , fmt . Errorf ( "error creating in memory role for generated grants: %w" , err )
}
2022-09-19 09:59:18 -04:00
role , err := iamRepo . CreateRole ( ctx , pr )
2020-10-01 10:51:54 -04:00
if err != nil {
return nil , fmt . Errorf ( "error creating role for default generated grants: %w" , err )
}
2022-09-19 09:59:18 -04:00
if _ , err := iamRepo . AddRoleGrants ( ctx , role . PublicId , role . Version , [] string {
2021-04-23 09:13:37 -05:00
"id=*;type=scope;actions=list,no-op" ,
2020-10-01 10:51:54 -04:00
"id=*;type=auth-method;actions=authenticate,list" ,
2022-10-27 09:01:05 -04:00
"id={{.Account.Id}};actions=read,change-password" ,
2021-04-23 12:45:08 -05:00
"id=*;type=auth-token;actions=list,read:self,delete:self" ,
2020-10-01 10:51:54 -04:00
}); err != nil {
return nil , fmt . Errorf ( "error creating grant for default generated grants: %w" , err )
}
2022-10-28 15:52:06 -04:00
if _ , err := iamRepo . AddPrincipalRoles ( ctx , role . PublicId , role . Version + 1 , [] string { globals . AnonymousUserId }, nil ); err != nil {
2020-10-01 10:51:54 -04:00
return nil , fmt . Errorf ( "error adding principal to role for default generated grants: %w" , err )
}
return role , nil
}
2021-04-08 20:54:32 -04:00
func ( b * Server ) CreateInitialPasswordAuthMethod ( ctx context . Context ) ( * password . AuthMethod , * iam . User , error ) {
2020-09-24 03:31:26 -04:00
rw := db . New ( b . Database )
2022-05-13 13:53:22 -04:00
kmsCache , err := kms . New ( ctx , rw , rw )
2020-09-24 03:31:26 -04:00
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , fmt . Errorf ( "error creating kms cache: %w" , err )
2020-09-24 03:31:26 -04:00
}
if err := kmsCache . AddExternalWrappers (
2022-03-16 17:04:07 -04:00
b . Context ,
2020-09-24 03:31:26 -04:00
kms . WithRootWrapper ( b . RootKms ),
); err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , fmt . Errorf ( "error adding config keys to kms: %w" , err )
2020-09-24 03:31:26 -04:00
}
// Create the dev auth method
pwRepo , err := password . NewRepository ( rw , rw , kmsCache )
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , fmt . Errorf ( "error creating password repo: %w" , err )
2020-09-24 03:31:26 -04:00
}
2020-09-24 12:54:40 -04:00
authMethod , err := password . NewAuthMethod ( scope . Global . String (),
2021-04-08 20:54:32 -04:00
password . WithName ( "Generated global scope initial password auth method" ),
password . WithDescription ( "Provides initial administrative and unprivileged authentication into Boundary" ),
2020-09-24 12:54:40 -04:00
)
2020-09-24 03:31:26 -04:00
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , fmt . Errorf ( "error creating new in memory auth method: %w" , err )
2020-09-24 03:31:26 -04:00
}
2021-04-08 20:54:32 -04:00
if b . DevPasswordAuthMethodId == "" {
2023-03-10 15:06:39 -05:00
b . DevPasswordAuthMethodId , err = db . NewPublicId ( globals . PasswordAuthMethodPrefix )
2020-09-24 03:31:26 -04:00
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , fmt . Errorf ( "error generating initial auth method id: %w" , err )
2020-09-24 03:31:26 -04:00
}
}
2022-09-19 09:59:18 -04:00
am , err := pwRepo . CreateAuthMethod ( ctx , authMethod ,
2021-04-08 20:54:32 -04:00
password . WithPublicId ( b . DevPasswordAuthMethodId ))
2020-09-24 03:31:26 -04:00
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , fmt . Errorf ( "error saving auth method to the db: %w" , err )
2020-09-24 03:31:26 -04:00
}
2021-04-08 20:54:32 -04:00
b . InfoKeys = append ( b . InfoKeys , "generated password auth method id" )
b . Info [ "generated password auth method id" ] = b . DevPasswordAuthMethodId
// we'll designate the initial password auth method as the primary auth
// method id for the global scope, which means the auth method will create
// users on first login. Otherwise, the operator would have to create both
// a password account and a user associated with the new account, before
// users could successfully login.
iamRepo , err := iam . NewRepository ( rw , rw , kmsCache )
if err != nil {
return nil , nil , fmt . Errorf ( "unable to create iam repo: %w" , err )
}
globalScope , err := iamRepo . LookupScope ( ctx , scope . Global . String ())
if err != nil {
return nil , nil , fmt . Errorf ( "unable to lookup global scope: %w" , err )
}
globalScope . PrimaryAuthMethodId = am . PublicId
if _ , _ , err := iamRepo . UpdateScope ( ctx , globalScope , globalScope . Version , [] string { "PrimaryAuthMethodId" }); err != nil {
return nil , nil , fmt . Errorf ( "unable to set primary auth method for global scope: %w" , err )
}
2020-09-24 03:31:26 -04:00
2021-06-04 09:35:51 -05:00
createUser := func ( loginName , loginPassword , userId , accountId string , admin bool ) ( * iam . User , error ) {
2021-02-11 13:14:18 -05:00
// Create the dev admin user
if loginName == "" {
2021-04-08 20:54:32 -04:00
return nil , fmt . Errorf ( "empty login name" )
2021-02-11 13:14:18 -05:00
}
2021-03-16 08:42:08 -07:00
if loginPassword == "" {
2021-04-08 20:54:32 -04:00
return nil , fmt . Errorf ( "empty login name" )
}
if userId == "" {
return nil , fmt . Errorf ( "empty user id" )
2021-02-11 13:14:18 -05:00
}
typeStr := "admin"
if ! admin {
typeStr = "unprivileged"
}
b . InfoKeys = append ( b . InfoKeys , fmt . Sprintf ( "generated %s password" , typeStr ))
b . Info [ fmt . Sprintf ( "generated %s password" , typeStr )] = loginPassword
acct , err := password . NewAccount ( am . PublicId , password . WithLoginName ( loginName ))
2020-09-24 03:31:26 -04:00
if err != nil {
2021-04-08 20:54:32 -04:00
return nil , fmt . Errorf ( "error creating new in memory password auth account: %w" , err )
2020-09-24 03:31:26 -04:00
}
2021-06-04 09:35:51 -05:00
acct , err = pwRepo . CreateAccount (
2022-09-19 09:59:18 -04:00
ctx ,
2021-06-04 09:35:51 -05:00
scope . Global . String (),
acct ,
password . WithPassword ( loginPassword ),
password . WithPublicId ( accountId ),
)
2020-09-24 03:31:26 -04:00
if err != nil {
2021-02-11 13:14:18 -05:00
return nil , fmt . Errorf ( "error saving auth account to the db: %w" , err )
2020-09-24 03:31:26 -04:00
}
2021-02-11 13:14:18 -05:00
b . InfoKeys = append ( b . InfoKeys , fmt . Sprintf ( "generated %s login name" , typeStr ))
b . Info [ fmt . Sprintf ( "generated %s login name" , typeStr )] = acct . GetLoginName ()
2020-09-24 03:31:26 -04:00
2021-02-11 13:14:18 -05:00
iamRepo , err := iam . NewRepository ( rw , rw , kmsCache , iam . WithRandomReader ( b . SecureRandomReader ))
if err != nil {
2021-04-08 20:54:32 -04:00
return nil , fmt . Errorf ( "unable to create iam repo: %w" , err )
2021-02-11 13:14:18 -05:00
}
2020-09-24 03:31:26 -04:00
2021-02-11 13:14:18 -05:00
// Create a new user and associate it with the account
opts := [] iam . Option {
iam . WithPublicId ( userId ),
}
if admin {
opts = append ( opts ,
iam . WithName ( "admin" ),
2021-11-04 09:34:01 -04:00
iam . WithDescription ( fmt . Sprintf ( `Initial admin user within the "%s" scope` , scope . Global . String ())),
2021-02-11 13:14:18 -05:00
)
} else {
opts = append ( opts ,
iam . WithName ( "user" ),
iam . WithDescription ( "Initial unprivileged user" ),
)
}
u , err := iam . NewUser ( scope . Global . String (), opts ... )
if err != nil {
return nil , fmt . Errorf ( "error creating in memory user: %w" , err )
}
2022-09-19 09:59:18 -04:00
if u , err = iamRepo . CreateUser ( ctx , u , opts ... ); err != nil {
2021-02-11 13:14:18 -05:00
return nil , fmt . Errorf ( "error creating initial %s user: %w" , typeStr , err )
}
2022-09-19 09:59:18 -04:00
if _ , err = iamRepo . AddUserAccounts ( ctx , u . GetPublicId (), u . GetVersion (), [] string { acct . GetPublicId ()}); err != nil {
2021-02-11 13:14:18 -05:00
return nil , fmt . Errorf ( "error associating initial %s user with account: %w" , typeStr , err )
}
if ! admin {
return u , nil
}
// Create a role tying them together
pr , err := iam . NewRole ( scope . Global . String (),
iam . WithName ( "Administration" ),
2021-11-04 09:34:01 -04:00
iam . WithDescription ( fmt . Sprintf ( `Provides admin grants within the "%s" scope to the initial user` , scope . Global . String ())),
2021-02-11 13:14:18 -05:00
)
if err != nil {
return nil , fmt . Errorf ( "error creating in memory role for generated grants: %w" , err )
}
2022-09-19 09:59:18 -04:00
defPermsRole , err := iamRepo . CreateRole ( ctx , pr )
2021-02-11 13:14:18 -05:00
if err != nil {
return nil , fmt . Errorf ( "error creating role for default generated grants: %w" , err )
}
2022-09-19 09:59:18 -04:00
if _ , err := iamRepo . AddRoleGrants ( ctx , defPermsRole . PublicId , defPermsRole . Version , [] string { "id=*;type=*;actions=*" }); err != nil {
2021-02-11 13:14:18 -05:00
return nil , fmt . Errorf ( "error creating grant for default generated grants: %w" , err )
}
2022-09-19 09:59:18 -04:00
if _ , err := iamRepo . AddPrincipalRoles ( ctx , defPermsRole . PublicId , defPermsRole . Version + 1 , [] string { u . GetPublicId ()}, nil ); err != nil {
2021-02-11 13:14:18 -05:00
return nil , fmt . Errorf ( "error adding principal to role for default generated grants: %w" , err )
}
return u , nil
2020-09-24 03:31:26 -04:00
}
2021-04-08 20:54:32 -04:00
switch {
case b . DevUnprivilegedLoginName == "" ,
b . DevUnprivilegedPassword == "" ,
b . DevUnprivilegedUserId == "" :
default :
2021-06-04 09:35:51 -05:00
_ , err := createUser ( b . DevUnprivilegedLoginName , b . DevUnprivilegedPassword , b . DevUnprivilegedUserId , b . DevUnprivilegedPasswordAccountId , false )
2020-09-24 03:31:26 -04:00
if err != nil {
2021-02-11 13:14:18 -05:00
return nil , nil , err
2020-09-24 03:31:26 -04:00
}
2021-04-08 20:54:32 -04:00
}
if b . DevLoginName == "" {
b . DevLoginName , err = base62 . Random ( 10 )
if err != nil {
return nil , nil , fmt . Errorf ( "unable to generate login name: %w" , err )
}
b . DevLoginName = strings . ToLower ( b . DevLoginName )
}
if b . DevPassword == "" {
b . DevPassword , err = base62 . Random ( 20 )
if err != nil {
return nil , nil , fmt . Errorf ( "unable to generate password: %w" , err )
}
}
if b . DevUserId == "" {
2023-03-10 15:06:39 -05:00
b . DevUserId , err = db . NewPublicId ( globals . UserPrefix )
2021-04-08 20:54:32 -04:00
if err != nil {
return nil , nil , fmt . Errorf ( "error generating initial user id: %w" , err )
}
2020-09-24 03:31:26 -04:00
}
2021-06-04 09:35:51 -05:00
u , err := createUser ( b . DevLoginName , b . DevPassword , b . DevUserId , b . DevPasswordAccountId , true )
2020-09-24 03:31:26 -04:00
if err != nil {
2021-02-11 13:14:18 -05:00
return nil , nil , err
2020-09-24 03:31:26 -04:00
}
2020-09-24 12:54:40 -04:00
return am , u , nil
2020-09-24 03:31:26 -04:00
}
2020-09-24 12:54:40 -04:00
func ( b * Server ) CreateInitialScopes ( ctx context . Context ) ( * iam . Scope , * iam . Scope , error ) {
2020-09-24 03:31:26 -04:00
rw := db . New ( b . Database )
2022-05-13 13:53:22 -04:00
kmsCache , err := kms . New ( ctx , rw , rw )
2020-09-24 03:31:26 -04:00
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , fmt . Errorf ( "error creating kms cache: %w" , err )
2020-09-24 03:31:26 -04:00
}
2022-03-16 17:04:07 -04:00
if err := kmsCache . AddExternalWrappers (
b . Context ,
kms . WithRootWrapper ( b . RootKms ),
); err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , fmt . Errorf ( "error adding config keys to kms: %w" , err )
2020-09-24 03:31:26 -04:00
}
iamRepo , err := iam . NewRepository ( rw , rw , kmsCache )
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , fmt . Errorf ( "error creating scopes repository: %w" , err )
2020-09-24 03:31:26 -04:00
}
// Create the scopes
if b . DevOrgId == "" {
b . DevOrgId , err = db . NewPublicId ( scope . Org . Prefix ())
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , fmt . Errorf ( "error generating initial org id: %w" , err )
2020-09-24 03:31:26 -04:00
}
}
opts := [] iam . Option {
iam . WithName ( "Generated org scope" ),
iam . WithDescription ( "Provides an initial org scope in Boundary" ),
iam . WithRandomReader ( b . SecureRandomReader ),
iam . WithPublicId ( b . DevOrgId ),
}
orgScope , err := iam . NewOrg ( opts ... )
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , fmt . Errorf ( "error creating new in memory org scope: %w" , err )
2020-09-24 03:31:26 -04:00
}
2022-09-19 09:59:18 -04:00
orgScope , err = iamRepo . CreateScope ( ctx , orgScope , b . DevUserId , opts ... )
2020-09-24 03:31:26 -04:00
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , fmt . Errorf ( "error saving org scope to the db: %w" , err )
2020-09-24 03:31:26 -04:00
}
b . InfoKeys = append ( b . InfoKeys , "generated org scope id" )
b . Info [ "generated org scope id" ] = b . DevOrgId
if b . DevProjectId == "" {
b . DevProjectId , err = db . NewPublicId ( scope . Project . Prefix ())
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , fmt . Errorf ( "error generating initial project id: %w" , err )
2020-09-24 03:31:26 -04:00
}
}
opts = [] iam . Option {
iam . WithName ( "Generated project scope" ),
iam . WithDescription ( "Provides an initial project scope in Boundary" ),
iam . WithRandomReader ( b . SecureRandomReader ),
iam . WithPublicId ( b . DevProjectId ),
}
projScope , err := iam . NewProject ( b . DevOrgId , opts ... )
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , fmt . Errorf ( "error creating new in memory project scope: %w" , err )
2020-09-24 03:31:26 -04:00
}
2022-09-19 09:59:18 -04:00
projScope , err = iamRepo . CreateScope ( ctx , projScope , b . DevUserId , opts ... )
2020-09-24 03:31:26 -04:00
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , fmt . Errorf ( "error saving project scope to the db: %w" , err )
2020-09-24 03:31:26 -04:00
}
b . InfoKeys = append ( b . InfoKeys , "generated project scope id" )
b . Info [ "generated project scope id" ] = b . DevProjectId
2020-09-24 12:54:40 -04:00
return orgScope , projScope , nil
2020-09-24 03:31:26 -04:00
}
2020-09-24 12:54:40 -04:00
func ( b * Server ) CreateInitialHostResources ( ctx context . Context ) ( * static . HostCatalog , * static . HostSet , * static . Host , error ) {
2020-09-24 03:31:26 -04:00
rw := db . New ( b . Database )
2022-05-13 13:53:22 -04:00
kmsCache , err := kms . New ( ctx , rw , rw )
2020-09-24 03:31:26 -04:00
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , nil , fmt . Errorf ( "error creating kms cache: %w" , err )
2020-09-24 03:31:26 -04:00
}
if err := kmsCache . AddExternalWrappers (
2022-03-16 17:04:07 -04:00
b . Context ,
2020-09-24 03:31:26 -04:00
kms . WithRootWrapper ( b . RootKms ),
); err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , nil , fmt . Errorf ( "error adding config keys to kms: %w" , err )
2020-09-24 03:31:26 -04:00
}
staticRepo , err := static . NewRepository ( rw , rw , kmsCache )
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , nil , fmt . Errorf ( "error creating static repository: %w" , err )
2020-09-24 03:31:26 -04:00
}
// Host Catalog
if b . DevHostCatalogId == "" {
2023-03-10 15:06:39 -05:00
b . DevHostCatalogId , err = db . NewPublicId ( globals . StaticHostCatalogPrefix )
2020-09-24 03:31:26 -04:00
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , nil , fmt . Errorf ( "error generating initial host catalog id: %w" , err )
2020-09-24 03:31:26 -04:00
}
}
opts := [] static . Option {
static . WithName ( "Generated host catalog" ),
static . WithDescription ( "Provides an initial host catalog in Boundary" ),
static . WithPublicId ( b . DevHostCatalogId ),
}
hc , err := static . NewHostCatalog ( b . DevProjectId , opts ... )
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , nil , fmt . Errorf ( "error creating in memory host catalog: %w" , err )
2020-09-24 03:31:26 -04:00
}
2022-09-19 09:59:18 -04:00
if hc , err = staticRepo . CreateCatalog ( ctx , hc , opts ... ); err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , nil , fmt . Errorf ( "error saving host catalog to the db: %w" , err )
2020-09-24 03:31:26 -04:00
}
b . InfoKeys = append ( b . InfoKeys , "generated host catalog id" )
b . Info [ "generated host catalog id" ] = b . DevHostCatalogId
// Host
if b . DevHostId == "" {
2023-03-10 15:06:39 -05:00
b . DevHostId , err = db . NewPublicId ( globals . StaticHostPrefix )
2020-09-24 03:31:26 -04:00
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , nil , fmt . Errorf ( "error generating initial host id: %w" , err )
2020-09-24 03:31:26 -04:00
}
}
if b . DevHostAddress == "" {
b . DevHostAddress = "localhost"
}
opts = [] static . Option {
static . WithName ( "Generated host" ),
static . WithDescription ( "Provides an initial host in Boundary" ),
static . WithAddress ( b . DevHostAddress ),
static . WithPublicId ( b . DevHostId ),
}
h , err := static . NewHost ( hc . PublicId , opts ... )
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , nil , fmt . Errorf ( "error creating in memory host: %w" , err )
2020-09-24 03:31:26 -04:00
}
2022-09-19 09:59:18 -04:00
if h , err = staticRepo . CreateHost ( ctx , b . DevProjectId , h , opts ... ); err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , nil , fmt . Errorf ( "error saving host to the db: %w" , err )
2020-09-24 03:31:26 -04:00
}
b . InfoKeys = append ( b . InfoKeys , "generated host id" )
b . Info [ "generated host id" ] = b . DevHostId
// Host Set
if b . DevHostSetId == "" {
2023-03-10 15:06:39 -05:00
b . DevHostSetId , err = db . NewPublicId ( globals . StaticHostSetPrefix )
2020-09-24 03:31:26 -04:00
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , nil , fmt . Errorf ( "error generating initial host set id: %w" , err )
2020-09-24 03:31:26 -04:00
}
}
opts = [] static . Option {
static . WithName ( "Generated host set" ),
static . WithDescription ( "Provides an initial host set in Boundary" ),
static . WithPublicId ( b . DevHostSetId ),
}
hs , err := static . NewHostSet ( hc . PublicId , opts ... )
if err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , nil , fmt . Errorf ( "error creating in memory host set: %w" , err )
2020-09-24 03:31:26 -04:00
}
2022-09-19 09:59:18 -04:00
if hs , err = staticRepo . CreateSet ( ctx , b . DevProjectId , hs , opts ... ); err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , nil , fmt . Errorf ( "error saving host set to the db: %w" , err )
2020-09-24 03:31:26 -04:00
}
b . InfoKeys = append ( b . InfoKeys , "generated host set id" )
b . Info [ "generated host set id" ] = b . DevHostSetId
// Associate members
2022-09-19 09:59:18 -04:00
if _ , err := staticRepo . AddSetMembers ( ctx , b . DevProjectId , b . DevHostSetId , hs . GetVersion (), [] string { h . GetPublicId ()}); err != nil {
2020-09-24 12:54:40 -04:00
return nil , nil , nil , fmt . Errorf ( "error associating host set to host in the db: %w" , err )
2020-09-24 03:31:26 -04:00
}
2020-09-24 12:54:40 -04:00
return hc , hs , h , nil
2020-09-24 03:31:26 -04:00
}
2022-12-20 20:51:56 +00:00
func ( b * Server ) CreateInitialTargetWithAddress ( ctx context . Context ) ( target . Target , error ) {
2020-09-24 03:31:26 -04:00
rw := db . New ( b . Database )
2022-05-13 13:53:22 -04:00
kmsCache , err := kms . New ( ctx , rw , rw )
2020-09-24 03:31:26 -04:00
if err != nil {
2022-12-20 20:51:56 +00:00
return nil , fmt . Errorf ( "failed to create kms cache: %w" , err )
}
if err := kmsCache . AddExternalWrappers ( ctx , kms . WithRootWrapper ( b . RootKms )); err != nil {
return nil , fmt . Errorf ( "failed to add config keys to kms: %w" , err )
}
targetRepo , err := target . NewRepository ( ctx , rw , rw , kmsCache )
if err != nil {
return nil , fmt . Errorf ( "failed to create target repository: %w" , err )
}
// When this function is not called as part of boundary dev (eg: as part of
// boundary database init or tests), generate random target ids.
if len ( b . DevTargetId ) == 0 {
2023-03-10 15:06:39 -05:00
b . DevTargetId , err = db . NewPublicId ( globals . TcpTargetPrefix )
2022-12-20 20:51:56 +00:00
if err != nil {
return nil , fmt . Errorf ( "failed to generate initial target id: %w" , err )
}
}
if b . DevTargetDefaultPort == 0 {
b . DevTargetDefaultPort = 22
}
if len ( b . DevTargetAddress ) == 0 {
b . DevTargetAddress = "127.0.0.1"
}
opts := [] target . Option {
target . WithName ( "Generated target with a direct address" ),
target . WithDescription ( "Provides an initial target using an address in Boundary" ),
target . WithDefaultPort ( uint32 ( b . DevTargetDefaultPort )),
target . WithSessionMaxSeconds ( uint32 ( b . DevTargetSessionMaxSeconds )),
target . WithSessionConnectionLimit ( int32 ( b . DevTargetSessionConnectionLimit )),
target . WithPublicId ( b . DevTargetId ),
target . WithAddress ( b . DevTargetAddress ),
}
t , err := target . New ( ctx , tcp . Subtype , b . DevProjectId , opts ... )
if err != nil {
return nil , fmt . Errorf ( "failed to create target object: %w" , err )
}
tt , _ , _ , err := targetRepo . CreateTarget ( ctx , t , opts ... )
if err != nil {
return nil , fmt . Errorf ( "failed to save target to the db: %w" , err )
}
b . InfoKeys = append ( b . InfoKeys , "generated target with address id" )
b . Info [ "generated target with address id" ] = b . DevTargetId
if b . DevUnprivilegedUserId != "" {
iamRepo , err := iam . NewRepository ( rw , rw , kmsCache , iam . WithRandomReader ( b . SecureRandomReader ))
if err != nil {
return nil , fmt . Errorf ( "failed to create iam repository: %w" , err )
}
err = unprivilegedDevUserRoleSetup ( ctx , iamRepo , b . DevUnprivilegedUserId , b . DevProjectId , b . DevTargetId )
if err != nil {
return nil , fmt . Errorf ( "failed to set up unprivileged dev user: %w" , err )
}
}
return tt , nil
}
func ( b * Server ) CreateInitialTargetWithHostSources ( ctx context . Context ) ( target . Target , error ) {
rw := db . New ( b . Database )
kmsCache , err := kms . New ( ctx , rw , rw )
if err != nil {
return nil , fmt . Errorf ( "failed to create kms cache: %w" , err )
2020-09-24 03:31:26 -04:00
}
if err := kmsCache . AddExternalWrappers (
2022-03-16 17:04:07 -04:00
b . Context ,
2020-09-24 03:31:26 -04:00
kms . WithRootWrapper ( b . RootKms ),
); err != nil {
2022-12-20 20:51:56 +00:00
return nil , fmt . Errorf ( "failed to add config keys to kms: %w" , err )
2020-09-24 03:31:26 -04:00
}
2022-08-23 18:44:10 +01:00
targetRepo , err := target . NewRepository ( ctx , rw , rw , kmsCache )
2020-09-24 03:31:26 -04:00
if err != nil {
2022-12-20 20:51:56 +00:00
return nil , fmt . Errorf ( "failed to create target repository: %w" , err )
2020-09-24 03:31:26 -04:00
}
2022-12-20 20:51:56 +00:00
// When this function is not called as part of boundary dev (eg: as part of
// boundary database init or tests), generate random target ids.
if len ( b . DevSecondaryTargetId ) == 0 {
2023-03-10 15:06:39 -05:00
b . DevSecondaryTargetId , err = db . NewPublicId ( globals . TcpTargetPrefix )
2020-09-24 03:31:26 -04:00
if err != nil {
2022-12-20 20:51:56 +00:00
return nil , fmt . Errorf ( "failed to generate initial secondary target id: %w" , err )
2020-09-24 03:31:26 -04:00
}
}
if b . DevTargetDefaultPort == 0 {
b . DevTargetDefaultPort = 22
}
2022-12-20 20:51:56 +00:00
2020-09-24 03:31:26 -04:00
opts := [] target . Option {
2022-12-20 20:51:56 +00:00
target . WithName ( "Generated target using host sources" ),
target . WithDescription ( "Provides a target using host sources in Boundary" ),
2020-09-24 03:31:26 -04:00
target . WithDefaultPort ( uint32 ( b . DevTargetDefaultPort )),
2020-09-24 17:29:12 -04:00
target . WithSessionMaxSeconds ( uint32 ( b . DevTargetSessionMaxSeconds )),
target . WithSessionConnectionLimit ( int32 ( b . DevTargetSessionConnectionLimit )),
2022-12-20 20:51:56 +00:00
target . WithPublicId ( b . DevSecondaryTargetId ),
2020-09-24 03:31:26 -04:00
}
2021-11-04 11:37:32 -04:00
t , err := target . New ( ctx , tcp . Subtype , b . DevProjectId , opts ... )
2020-09-24 03:31:26 -04:00
if err != nil {
2022-12-20 20:51:56 +00:00
return nil , fmt . Errorf ( "failed to create target object: %w" , err )
2020-09-24 03:31:26 -04:00
}
2022-09-19 09:59:18 -04:00
tt , _ , _ , err := targetRepo . CreateTarget ( ctx , t , opts ... )
2020-09-24 03:31:26 -04:00
if err != nil {
2022-12-20 20:51:56 +00:00
return nil , fmt . Errorf ( "failed to save target to the db: %w" , err )
2020-09-24 03:31:26 -04:00
}
2021-10-22 08:51:46 -04:00
tt , _ , _ , err = targetRepo . AddTargetHostSources ( ctx , tt . GetPublicId (), tt . GetVersion (), [] string { b . DevHostSetId })
if err != nil {
2022-12-20 20:51:56 +00:00
return nil , fmt . Errorf ( "failed to add host source %q to target: %w" , b . DevHostSetId , err )
2021-10-22 08:51:46 -04:00
}
2022-12-20 20:51:56 +00:00
b . InfoKeys = append ( b . InfoKeys , "generated target with host source id" )
b . Info [ "generated target with host source id" ] = b . DevSecondaryTargetId
2020-09-24 03:31:26 -04:00
2021-02-11 13:14:18 -05:00
if b . DevUnprivilegedUserId != "" {
iamRepo , err := iam . NewRepository ( rw , rw , kmsCache , iam . WithRandomReader ( b . SecureRandomReader ))
if err != nil {
2022-12-20 20:51:56 +00:00
return nil , fmt . Errorf ( "failed to create iam repository: %w" , err )
2021-02-11 13:14:18 -05:00
}
2022-12-20 20:51:56 +00:00
err = unprivilegedDevUserRoleSetup ( ctx , iamRepo , b . DevUnprivilegedUserId , b . DevProjectId , b . DevSecondaryTargetId )
2021-02-11 13:14:18 -05:00
if err != nil {
2022-12-20 20:51:56 +00:00
return nil , fmt . Errorf ( "failed to set up unprivileged dev user: %w" , err )
2021-02-11 13:14:18 -05:00
}
}
2020-09-24 03:31:26 -04:00
return tt , nil
}
2021-09-28 09:40:12 -04:00
2021-10-14 11:56:08 -04:00
// RegisterHostPlugin creates a host plugin in the database if not present.
2021-09-29 15:46:42 -07:00
// It also registers the plugin in the shared map of running plugins. Since
// all boundary provided host plugins must have a name, a name is required
2021-10-14 11:56:08 -04:00
// when calling RegisterHostPlugin and will be used even if WithName is provided.
func ( b * Server ) RegisterHostPlugin ( ctx context . Context , name string , plg plgpb . HostPluginServiceClient , opt ... hostplugin . Option ) ( * hostplugin . Plugin , error ) {
2021-09-29 15:46:42 -07:00
if name == "" {
return nil , fmt . Errorf ( "no name provided when creating plugin." )
}
2021-09-28 09:40:12 -04:00
rw := db . New ( b . Database )
2022-05-13 13:53:22 -04:00
kmsCache , err := kms . New ( ctx , rw , rw )
2021-09-28 09:40:12 -04:00
if err != nil {
return nil , fmt . Errorf ( "error creating kms cache: %w" , err )
}
if err := kmsCache . AddExternalWrappers (
2022-03-16 17:04:07 -04:00
ctx ,
2021-09-28 09:40:12 -04:00
kms . WithRootWrapper ( b . RootKms ),
); err != nil {
return nil , fmt . Errorf ( "error adding config keys to kms: %w" , err )
}
hpRepo , err := hostplugin . NewRepository ( rw , rw , kmsCache )
if err != nil {
return nil , fmt . Errorf ( "error creating host plugin repository: %w" , err )
}
2021-09-29 15:46:42 -07:00
plugin , err := hpRepo . LookupPluginByName ( ctx , name )
2021-09-28 09:40:12 -04:00
if err != nil {
2021-09-29 15:46:42 -07:00
return nil , fmt . Errorf ( "error looking up host plugin by name: %w" , err )
}
if plugin == nil {
opt = append ( opt , hostplugin . WithName ( name ))
plugin = hostplugin . NewPlugin ( opt ... )
2022-09-19 09:59:18 -04:00
plugin , err = hpRepo . CreatePlugin ( ctx , plugin , opt ... )
2021-09-29 15:46:42 -07:00
if err != nil {
return nil , fmt . Errorf ( "error creating host plugin: %w" , err )
}
2021-09-28 09:40:12 -04:00
}
if b . HostPlugins == nil {
2021-10-07 11:56:39 -04:00
b . HostPlugins = make ( map [ string ] plgpb . HostPluginServiceClient )
2021-09-28 09:40:12 -04:00
}
b . HostPlugins [ plugin . GetPublicId ()] = plg
return plugin , nil
}
2022-12-20 20:51:56 +00:00
// unprivilegedDevUserRoleSetup adds dev user to the role that grants
// list/read:self/cancel:self on sessions and read:self/delete:self/list on
// tokens. It also creates a role with an `authorize-session` grant for the
// provided targetId.
func unprivilegedDevUserRoleSetup ( ctx context . Context , repo * iam . Repository , userId , projectId , targetId string ) error {
roles , err := repo . ListRoles ( ctx , [] string { projectId })
if err != nil {
return fmt . Errorf ( "failed to list existing roles for project id %q: %w" , projectId , err )
}
// Look for default grants role to set unprivileged user as a principal.
defaultRoleIdx := - 1
for i , r := range roles {
// Hacky, I know, but saves a DB trip to look up other
// characteristics like "if any principals are currently attached".
// No matter what we pick here it's a bit heuristical.
if r . Name == "Default Grants" {
defaultRoleIdx = i
break
}
}
if defaultRoleIdx == - 1 {
return fmt . Errorf ( "couldn't find default grants role for project id %q" , projectId )
}
defaultRole := roles [ defaultRoleIdx ]
// This function may be called more than once for the same boundary
// deployment (eg: if we're creating more than one target), so we need to
// check if the unprivileged user is not already a principal for the default
// role in this project, as attempting to add an existing principal is an
// error.
principals , err := repo . ListPrincipalRoles ( ctx , defaultRole . GetPublicId ())
if err != nil {
return fmt . Errorf ( "failed to list principals for default project role: %w" , err )
}
found := false
for _ , p := range principals {
if p . PrincipalId == userId {
found = true
}
}
if ! found {
_ , err = repo . AddPrincipalRoles ( ctx , defaultRole . GetPublicId (), defaultRole . GetVersion (), [] string { userId })
if err != nil {
return fmt . Errorf ( "failed to add %q as principal for role id %q" , userId , defaultRole . GetPublicId ())
}
defaultRole . Version ++ // The above call increments the role version in the database, so we must also track that with our state.
}
// Create a new role for the "authorize-session" grant and add the
// unprivileged user as a principal.
asRole , err := iam . NewRole ( projectId ,
iam . WithName ( fmt . Sprintf ( "Session authorization for %s" , targetId )),
iam . WithDescription ( fmt . Sprintf ( "Provides grants within the dev project scope to allow the initial unprivileged user to authorize sessions against %s" , targetId )),
)
if err != nil {
return fmt . Errorf ( "failed to create role object: %w" , err )
}
asRole , err = repo . CreateRole ( ctx , asRole )
if err != nil {
return fmt . Errorf ( "failed to create role for unprivileged user: %w" , err )
}
if _ , err := repo . AddPrincipalRoles ( ctx , asRole . GetPublicId (), asRole . GetVersion (), [] string { userId }, nil ); err != nil {
return fmt . Errorf ( "failed to add unprivileged user as principal to new role: %w" , err )
}
asRole . Version ++
_ , err = repo . AddRoleGrants ( ctx , asRole . GetPublicId (), asRole . GetVersion (), [] string { fmt . Sprintf ( "id=%s;actions=authorize-session" , targetId )})
if err != nil {
return fmt . Errorf ( "failed to add authorize-session grant for unprivileged user: %w" , err )
}
return nil
}