2023-01-24 13:01:20 +00:00
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
2023-02-02 17:15:17 -08:00
2023-01-24 13:01:20 +00:00
package credentiallibrariescmd
import (
"fmt"
"strconv"
"github.com/hashicorp/boundary/api/credentiallibraries"
"github.com/hashicorp/boundary/internal/cmd/base"
"github.com/hashicorp/boundary/internal/cmd/common"
)
func init () {
extraVaultSshCertificateFlagsFunc = extraVaultSshCertificateFlagsFuncImpl
extraVaultSshCertificateActionsFlagsMapFunc = extraVaultSshCertificateActionsFlagsMapFuncImpl
extraVaultSshCertificateFlagsHandlingFunc = extraVaultSshCertificateFlagHandlingFuncImpl
}
const (
2023-10-24 12:44:51 -04:00
usernameName = "username"
keyTypeName = "key-type"
keyBitsName = "key-bits"
ttlName = "ttl"
keyIdName = "key-id"
criticalOptionsName = "critical-options"
piecewiseCriticalOptionsName = "critical-option"
extensionsName = "extensions"
piecewiseExtensionName = "extension"
additionalValidPrincipalsName = "additional-valid-principal"
2023-01-24 13:01:20 +00:00
)
type extraVaultSshCertificateCmdVars struct {
2023-10-24 12:44:51 -04:00
flagPath string
flagUsername string
flagKeyType string
flagKeyBits string
flagTtl string
flagKeyId string
flagCriticalOptions string
flagCriticalOpts [] base . CombinedSliceFlagValue
flagExtensions string
flagExtens [] base . CombinedSliceFlagValue
flagAdditionalValidPrincipals [] base . CombinedSliceFlagValue
2023-01-24 13:01:20 +00:00
}
func extraVaultSshCertificateActionsFlagsMapFuncImpl () map [ string ][] string {
flags := map [ string ][] string {
"create" : {
pathFlagName ,
usernameName ,
keyTypeName ,
keyBitsName ,
ttlName ,
keyIdName ,
criticalOptionsName ,
piecewiseCriticalOptionsName ,
extensionsName ,
piecewiseExtensionName ,
2023-10-24 12:44:51 -04:00
additionalValidPrincipalsName ,
2023-01-24 13:01:20 +00:00
},
"update" : {
pathFlagName ,
usernameName ,
keyTypeName ,
keyBitsName ,
ttlName ,
keyIdName ,
criticalOptionsName ,
piecewiseCriticalOptionsName ,
extensionsName ,
piecewiseExtensionName ,
2023-10-24 12:44:51 -04:00
additionalValidPrincipalsName ,
2023-01-24 13:01:20 +00:00
},
}
return flags
}
func extraVaultSshCertificateFlagsFuncImpl ( c * VaultSshCertificateCommand , set * base . FlagSets , _ * base . FlagSet ) {
f := set . NewFlagSet ( "Vault SSH Certificate Credential Library Options" )
for _ , name := range flagsVaultSshCertificateMap [ c . Func ] {
switch name {
case pathFlagName :
f . StringVar ( & base . StringVar {
Name : pathFlagName ,
Target : & c . flagPath ,
Usage : "The path in vault to request credentials from." ,
})
case usernameName :
f . StringVar ( & base . StringVar {
Name : usernameName ,
Target : & c . flagUsername ,
Usage : "The username to use with the ssh certificate." ,
})
case keyTypeName :
f . StringVar ( & base . StringVar {
Name : keyTypeName ,
Target : & c . flagKeyType ,
Usage : "The key type for the generated ssh private key. One of: ed25519, ecdsa, rsa." ,
})
case keyBitsName :
f . StringVar ( & base . StringVar {
Name : keyBitsName ,
Target : & c . flagKeyBits ,
Usage : "The number of bits when generating the ssh private key. Depends on key_type. If ed25519 this should not be set, or set to 0, if ecdsa one of 256, 384, 521, if rsa one of 2048, 3072, 4096." ,
})
case ttlName :
f . StringVar ( & base . StringVar {
Name : ttlName ,
Target : & c . flagTtl ,
Usage : "The time-to-live for the generated certificate." ,
})
case keyIdName :
f . StringVar ( & base . StringVar {
Name : keyIdName ,
Target : & c . flagKeyId ,
Usage : "The key id that the created certificate should have." ,
})
2023-10-24 12:44:51 -04:00
case additionalValidPrincipalsName :
f . CombinationSliceVar ( & base . CombinationSliceVar {
Name : additionalValidPrincipalsName ,
Target : & c . flagAdditionalValidPrincipals ,
Usage : "Principals to be signed as \"valid_principles\" in addition to username." ,
})
2023-01-24 13:01:20 +00:00
}
}
criticalOptsInput := common . CombinedSliceFlagValuePopulationInput {
FlagSet : f ,
FlagNames : flagsVaultSshCertificateMap [ c . Func ],
FullPopulationFlag : & c . flagCriticalOptions ,
FullPopulationInputName : criticalOptionsName ,
PiecewisePopulationFlag : & c . flagCriticalOpts ,
PiecewisePopulationInputBaseName : piecewiseCriticalOptionsName ,
PiecewiseNoProtoCompat : true ,
}
common . PopulateCombinedSliceFlagValue ( criticalOptsInput )
extensionsInput := common . CombinedSliceFlagValuePopulationInput {
FlagSet : f ,
FlagNames : flagsVaultSshCertificateMap [ c . Func ],
FullPopulationFlag : & c . flagExtensions ,
FullPopulationInputName : extensionsName ,
PiecewisePopulationFlag : & c . flagExtens ,
PiecewisePopulationInputBaseName : piecewiseExtensionName ,
PiecewiseNoProtoCompat : true ,
}
common . PopulateCombinedSliceFlagValue ( extensionsInput )
}
func extraVaultSshCertificateFlagHandlingFuncImpl ( c * VaultSshCertificateCommand , _ * base . FlagSets , opts * [] credentiallibraries . Option ) bool {
switch c . flagPath {
case "" :
default :
* opts = append ( * opts , credentiallibraries . WithVaultCredentialLibraryPath ( c . flagPath ))
}
switch c . flagUsername {
case "" :
default :
* opts = append ( * opts , credentiallibraries . WithVaultSSHCertificateCredentialLibraryUsername ( c . flagUsername ))
}
switch c . flagKeyType {
case "" :
case "null" :
* opts = append ( * opts , credentiallibraries . DefaultVaultSSHCertificateCredentialLibraryKeyType ())
default :
* opts = append ( * opts , credentiallibraries . WithVaultSSHCertificateCredentialLibraryKeyType ( c . flagKeyType ))
}
switch c . flagKeyBits {
case "" :
case "0" , "null" :
* opts = append ( * opts , credentiallibraries . DefaultVaultSSHCertificateCredentialLibraryKeyBits ())
default :
var final uint32
keyBits , err := strconv . ParseUint ( c . flagKeyBits , 10 , 32 )
if err != nil {
c . UI . Error ( fmt . Sprintf ( "Error parsing %q: %s" , c . flagKeyBits , err ))
return false
}
final = uint32 ( keyBits )
* opts = append ( * opts , credentiallibraries . WithVaultSSHCertificateCredentialLibraryKeyBits ( final ))
}
switch c . flagTtl {
case "" :
case "null" :
* opts = append ( * opts , credentiallibraries . DefaultVaultSSHCertificateCredentialLibraryTtl ())
default :
* opts = append ( * opts , credentiallibraries . WithVaultSSHCertificateCredentialLibraryTtl ( c . flagTtl ))
}
switch c . flagKeyId {
case "" :
case "null" :
* opts = append ( * opts , credentiallibraries . DefaultVaultSSHCertificateCredentialLibraryKeyId ())
default :
* opts = append ( * opts , credentiallibraries . WithVaultSSHCertificateCredentialLibraryKeyId ( c . flagKeyId ))
}
2023-10-24 12:44:51 -04:00
// the weird formatting of this switch is to determine if there was only 0 or 1 principals passed, and if that signifies using default (nil)
switch len ( c . flagAdditionalValidPrincipals ) {
case 0 :
case 1 :
if len ( c . flagAdditionalValidPrincipals [ 0 ]. Keys ) == 1 && c . flagAdditionalValidPrincipals [ 0 ]. Keys [ 0 ] == "null" && c . flagAdditionalValidPrincipals [ 0 ]. Value == nil {
* opts = append ( * opts , credentiallibraries . DefaultVaultSSHCertificateCredentialLibraryAdditionalValidPrincipals ())
break
}
fallthrough
default :
avp := make ([] string , len ( c . flagAdditionalValidPrincipals ))
for i , p := range c . flagAdditionalValidPrincipals {
avp [ i ] = p . Value . GetValue ()
}
* opts = append ( * opts , credentiallibraries . WithVaultSSHCertificateCredentialLibraryAdditionalValidPrincipals ( avp ))
}
2023-01-24 13:01:20 +00:00
if err := common . HandleAttributeFlags (
c . Command ,
piecewiseCriticalOptionsName ,
c . flagCriticalOptions ,
c . flagCriticalOpts ,
func () {
* opts = append ( * opts , credentiallibraries . DefaultVaultSSHCertificateCredentialLibraryCriticalOptions ())
},
func ( in map [ string ] any ) {
inn := make ( map [ string ] string , len ( in ))
for k , v := range in {
switch vv := v .( type ) {
case nil :
inn [ k ] = ""
case string :
inn [ k ] = vv
default :
continue
}
}
* opts = append ( * opts , credentiallibraries . WithVaultSSHCertificateCredentialLibraryCriticalOptions ( inn ))
}); err != nil {
return false
}
if err := common . HandleAttributeFlags (
c . Command ,
piecewiseExtensionName ,
c . flagExtensions ,
c . flagExtens ,
func () {
* opts = append ( * opts , credentiallibraries . DefaultVaultSSHCertificateCredentialLibraryExtensions ())
},
func ( in map [ string ] any ) {
inn := make ( map [ string ] string , len ( in ))
for k , v := range in {
switch vv := v .( type ) {
case nil :
inn [ k ] = ""
case string :
inn [ k ] = vv
default :
continue
}
}
* opts = append ( * opts , credentiallibraries . WithVaultSSHCertificateCredentialLibraryExtensions ( inn ))
}); err != nil {
return false
}
return true
}
func ( c * VaultSshCertificateCommand ) extraVaultSshCertificateHelpFunc ( _ map [ string ] func () string ) string {
var helpStr string
switch c . Func {
case "create" :
helpStr = base . WrapForHelpText ([] string {
"Usage: boundary credential-libraries create vault-ssh-certificate -credential-store-id [options] [args]" ,
"" ,
" Create a vault-ssh-certificate-type credential library. Example:" ,
"" ,
` $ boundary credential-libraries create vault-ssh-certificate -credential-store-id csvlt_1234567890 -vault-path "/ssh/sign/role" -username user` ,
"" ,
"" ,
})
case "update" :
helpStr = base . WrapForHelpText ([] string {
"Usage: boundary credential-libraries update vault-ssh-certificate [options] [args]" ,
"" ,
" Update a vault-ssh-certificate-type credential library given its ID. Example:" ,
"" ,
` $ boundary credential-libraries update vault-ssh-certificate -id clvsclt_1234567890 -name devops -description "For DevOps usage"` ,
"" ,
"" ,
})
}
return helpStr + c . Flags (). Help ()
}