Skip to content

Commit

Permalink
Issue #3718 - NodeSecret: hzn deploycheck checks node secret
Browse files Browse the repository at this point in the history
Signed-off-by: Le Zhang <[email protected]>
  • Loading branch information
LiilyZhang committed Sep 12, 2023
1 parent ee7ac9e commit 64f50d3
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 22 deletions.
1 change: 1 addition & 0 deletions agreementbot/agreementworker.go
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,7 @@ func (b *BaseAgreementWorker) ValidateAndExtractSecrets(consumerPolicy *policy.P
nil,
"",
exchange.GetOrg(deviceId),
exchange.GetId(deviceId),
msgPrinter)

if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cli/deploycheck/secretbinding.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
// check if the user inputs for services are compatible
func SecretBindingCompatible(org string, userPw string, nodeId string, nodeArch string, nodeType string, nodeOrg string,
businessPolId string, businessPolFile string, patternId string, patternFile string,
svcDefFiles []string, checkAllSvcs bool, showDetail bool) {
svcDefFiles []string, checkAllSvcs bool, showDetail bool, checkNodeLevelSec bool) {

msgPrinter := i18n.GetMessagePrinter()

Expand Down
2 changes: 1 addition & 1 deletion cli/exchange/business.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ func verifySecretBindingForPolicy(policy *businesspolicy.BusinessPolicy, polOrg
// make sure the vault secret exists
agbotUrl := cliutils.GetAgbotSecureAPIUrlBase()
vaultSecretExists := exchange.GetHTTPVaultSecretExistsHandler(ec)
msgMap, err := compcheck.VerifyVaultSecrets(neededSB, polOrg, agbotUrl, vaultSecretExists, msgPrinter)
msgMap, err := compcheck.VerifyVaultSecrets(neededSB, polOrg, "", agbotUrl, vaultSecretExists, msgPrinter)
if err != nil {
cliutils.Fatal(cliutils.CLI_INPUT_ERROR, msgPrinter.Sprintf("Failed to verify the binding secret in the secret manager. %v", err))
} else if msgMap != nil && len(msgMap) > 0 {
Expand Down
2 changes: 1 addition & 1 deletion cli/exchange/pattern.go
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ func verifySecretBindingForPattern(secretBinding []exchangecommon.SecretBinding,
// make sure the vault secret exists.
agbotUrl := cliutils.GetAgbotSecureAPIUrlBase()
vaultSecretExists := exchange.GetHTTPVaultSecretExistsHandler(ec)
msgMap, err := compcheck.VerifyVaultSecrets(neededSB, patOrg, agbotUrl, vaultSecretExists, msgPrinter)
msgMap, err := compcheck.VerifyVaultSecrets(neededSB, patOrg, "", agbotUrl, vaultSecretExists, msgPrinter)
if err != nil {
cliutils.Fatal(cliutils.CLI_INPUT_ERROR, msgPrinter.Sprintf("Failed to verify the binding secret in the secret manager. %v", err))
} else if msgMap != nil && len(msgMap) > 0 {
Expand Down
3 changes: 2 additions & 1 deletion cli/hzn.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ Environment Variables:
secretCompSvcFile := secretCompCmd.Flag("service", msgPrinter.Sprintf("(optional) The JSON input file name containing the service definition. If omitted, the service defined in the deployment policy or pattern will be retrieved from the Exchange. This flag can be repeated to specify different versions of the service.")).Strings()
secretCompPatternId := secretCompCmd.Flag("pattern-id", msgPrinter.Sprintf("The Horizon exchange pattern ID. Mutually exclusive with -P, -b and -B. If you don't prepend it with the organization id, it will automatically be prepended with the node's organization id.")).Short('p').String()
secretCompPatternFile := secretCompCmd.Flag("pattern", msgPrinter.Sprintf("The JSON input file name containing the pattern. Mutually exclusive with -p, -b and -B.")).Short('P').String()
secretCompCheckNodeLevel := secretCompCmd.Flag("check-node-secret", msgPrinter.Sprintf("check secretbinding against node level secret")).Bool()
userinputCompCmd := deploycheckCmd.Command("userinput | u", msgPrinter.Sprintf("Check user input compatibility.")).Alias("u").Alias("userinput")
userinputCompNodeArch := userinputCompCmd.Flag("arch", msgPrinter.Sprintf("The architecture of the node. It is required when -n is not specified. If omitted, the service of all the architectures referenced in the deployment policy or pattern will be checked for compatibility.")).Short('a').String()
userinputCompNodeType := userinputCompCmd.Flag("node-type", msgPrinter.Sprintf("The node type. The valid values are 'device' and 'cluster'. The default value is the type of the node provided by -n or current registered device, if omitted.")).Short('t').String()
Expand Down Expand Up @@ -1363,7 +1364,7 @@ Environment Variables:
case userinputCompCmd.FullCommand():
deploycheck.UserInputCompatible(*deploycheckOrg, *deploycheckUserPw, *userinputCompNodeId, *userinputCompNodeArch, *userinputCompNodeType, *userinputCompNodeUIFile, *userinputCompBPolId, *userinputCompBPolFile, *userinputCompPatternId, *userinputCompPatternFile, *userinputCompSvcFile, *deploycheckCheckAll, *deploycheckLong)
case secretCompCmd.FullCommand():
deploycheck.SecretBindingCompatible(*deploycheckOrg, *deploycheckUserPw, *secretCompNodeId, *secretCompNodeArch, *secretCompNodeType, *secretCompNodeOrg, *secretCompDepPolId, *secretCompDepPolFile, *secretCompPatternId, *secretCompPatternFile, *secretCompSvcFile, *deploycheckCheckAll, *deploycheckLong)
deploycheck.SecretBindingCompatible(*deploycheckOrg, *deploycheckUserPw, *secretCompNodeId, *secretCompNodeArch, *secretCompNodeType, *secretCompNodeOrg, *secretCompDepPolId, *secretCompDepPolFile, *secretCompPatternId, *secretCompPatternFile, *secretCompSvcFile, *deploycheckCheckAll, *deploycheckLong, *secretCompCheckNodeLevel)
case allCompCmd.FullCommand():
deploycheck.AllCompatible(*deploycheckOrg, *deploycheckUserPw, *allCompNodeId, *allCompHAGroup, *allCompNodeArch, *allCompNodeType, *allCompNodeNs, *allCompNodIsNamespaceScoped, *allCompNodeOrg, *allCompNodePolFile, *allCompNodeUIFile, *allCompBPolId, *allCompBPolFile, *allCompPatternId, *allCompPatternFile, *allCompSPolFile, *allCompSvcFile, *deploycheckCheckAll, *deploycheckLong)
case agreementListCmd.FullCommand():
Expand Down
65 changes: 47 additions & 18 deletions compcheck/secretbinding_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ func secretBindingCompatible(getDeviceHandler exchange.DeviceHandler,
checkAllSvcs bool,
msgPrinter *message.Printer) (*CompCheckOutput, error) {

// Lily: TODO - remove "checkNodeLevelSec bool" and hzn flag if not needed

// get default message printer if nil
if msgPrinter == nil {
msgPrinter = i18n.GetMessagePrinter()
Expand Down Expand Up @@ -236,7 +238,7 @@ func secretBindingCompatible(getDeviceHandler exchange.DeviceHandler,
continue
}
sSpec := NewServiceSpec(serviceRef.ServiceURL, serviceRef.ServiceOrg, workload.Version, serviceRef.ServiceArch)
if compatible, reason, imap, topSvcDef, _, depSvcDefs, err := VerifySecretBindingForService(sSpec, serviceDefResolverHandler, vaultSecretExists, agbotUrl, secretBinding, resources.NodeOrg, msgPrinter); err != nil {
if compatible, reason, imap, topSvcDef, _, depSvcDefs, err := VerifySecretBindingForService(sSpec, serviceDefResolverHandler, vaultSecretExists, agbotUrl, secretBinding, resources.NodeOrg, resources.NodeId, msgPrinter); err != nil {
return nil, err
} else {
// for performance, save the services that gotten from the exchange for use later
Expand All @@ -258,6 +260,9 @@ func secretBindingCompatible(getDeviceHandler exchange.DeviceHandler,
service_compatible = true
service_comp[sId] = topSvcDef
messages[sId] = msg_compatible
if reason != "" {
messages[sId] = msgPrinter.Sprintf("%v, Warning: %v", msg_compatible, reason)
}
if !checkAllSvcs {
break
}
Expand All @@ -277,7 +282,7 @@ func secretBindingCompatible(getDeviceHandler exchange.DeviceHandler,
if !needHandleService(sId, input.ServiceToCheck) {
continue
}
if compatible, reason, imap, depSvcDefs, err := VerifySecretBindingForServiceDef(&svc, resources.DepServices, serviceDefResolverHandler, vaultSecretExists, agbotUrl, secretBinding, resources.NodeOrg, msgPrinter); err != nil {
if compatible, reason, imap, depSvcDefs, err := VerifySecretBindingForServiceDef(&svc, resources.DepServices, serviceDefResolverHandler, vaultSecretExists, agbotUrl, secretBinding, resources.NodeOrg, resources.NodeId, msgPrinter); err != nil {
return nil, err
} else {
// for performance, save the services that gotten from the exchange for use later
Expand All @@ -299,6 +304,9 @@ func secretBindingCompatible(getDeviceHandler exchange.DeviceHandler,
service_compatible = true
service_comp[sId] = &svc
messages[sId] = msg_compatible
if reason != "" {
messages[sId] = msgPrinter.Sprintf("%v, Warning: %v", msg_compatible, reason)
}
if !checkAllSvcs {
break
}
Expand Down Expand Up @@ -329,7 +337,7 @@ func secretBindingCompatible(getDeviceHandler exchange.DeviceHandler,
if useSDef.GetOrg() == "" {
useSDef.(*common.ServiceFile).Org = serviceRef.ServiceOrg
}
if compatible, reason, imap, depSvcDefs, err := VerifySecretBindingForServiceDef(useSDef, resources.DepServices, serviceDefResolverHandler, vaultSecretExists, agbotUrl, secretBinding, resources.NodeOrg, msgPrinter); err != nil {
if compatible, reason, imap, depSvcDefs, err := VerifySecretBindingForServiceDef(useSDef, resources.DepServices, serviceDefResolverHandler, vaultSecretExists, agbotUrl, secretBinding, resources.NodeOrg, resources.NodeId, msgPrinter); err != nil {
return nil, err
} else {
// for performance, save the services that gotten from the exchange for use later
Expand All @@ -351,6 +359,9 @@ func secretBindingCompatible(getDeviceHandler exchange.DeviceHandler,
service_compatible = true
service_comp[sId] = useSDef
messages[sId] = msg_compatible
if reason != "" {
messages[sId] = msgPrinter.Sprintf("%v, Warning: %v", msg_compatible, reason)
}
if !checkAllSvcs {
break
}
Expand Down Expand Up @@ -435,7 +446,7 @@ func VerifySecretBindingForServiceCache(sTopDef common.AbstractServiceFile,
dependentServices map[string]exchange.ServiceDefinition,
secretBinding []exchangecommon.SecretBinding,
vaultSecretExists exchange.VaultSecretExistsHandler,
agbotUrl string, nodeOrg string,
agbotUrl string, nodeOrg string, nodeId string,
msgPrinter *message.Printer) (bool, string, map[int]map[string]bool, error) {

// get default message printer if nil
Expand Down Expand Up @@ -474,7 +485,7 @@ func VerifySecretBindingForServiceCache(sTopDef common.AbstractServiceFile,
// verify secrets exist in the secret manager
if agbotUrl != "" && vaultSecretExists != nil {
neededSB, _ := GroupSecretBindings(secretBinding, index_map)
if verified, reason, err := VerifyVaultSecrets_strict(neededSB, nodeOrg, agbotUrl, vaultSecretExists, msgPrinter); err != nil {
if verified, reason, err := VerifyVaultSecrets_strict(neededSB, nodeOrg, nodeId, agbotUrl, vaultSecretExists, msgPrinter); err != nil {
return false, "", index_map, fmt.Errorf(msgPrinter.Sprintf("Error verifying secret in the secret manager. %v", err))
} else {
return verified, reason, index_map, nil
Expand All @@ -497,7 +508,7 @@ func VerifySecretBindingForServiceCache(sTopDef common.AbstractServiceFile,
func VerifySecretBindingForService(svcSpec *ServiceSpec,
serviceDefResolverHandler exchange.ServiceDefResolverHandler,
vaultSecretExists exchange.VaultSecretExistsHandler, agbotUrl string,
secretBinding []exchangecommon.SecretBinding, nodeOrg string,
secretBinding []exchangecommon.SecretBinding, nodeOrg string, nodeId string,
msgPrinter *message.Printer) (bool, string, map[int]map[string]bool, common.AbstractServiceFile, string, map[string]exchange.ServiceDefinition, error) {

// get default message printer if nil
Expand All @@ -517,7 +528,7 @@ func VerifySecretBindingForService(svcSpec *ServiceSpec,

compSDef := ServiceDefinition{svcSpec.ServiceOrgid, *sDef}

compatible, reason, inxex_map, err := VerifySecretBindingForServiceCache(&compSDef, svc_map, secretBinding, vaultSecretExists, agbotUrl, nodeOrg, msgPrinter)
compatible, reason, inxex_map, err := VerifySecretBindingForServiceCache(&compSDef, svc_map, secretBinding, vaultSecretExists, agbotUrl, nodeOrg, nodeId, msgPrinter)
return compatible, reason, inxex_map, &compSDef, sId, svc_map, err
}

Expand All @@ -535,7 +546,7 @@ func VerifySecretBindingForServiceDef(sDef common.AbstractServiceFile,
dependentServices map[string]exchange.ServiceDefinition, // can be nil
serviceDefResolverHandler exchange.ServiceDefResolverHandler,
vaultSecretExists exchange.VaultSecretExistsHandler, agbotUrl string,
secretBinding []exchangecommon.SecretBinding, nodeOrg string,
secretBinding []exchangecommon.SecretBinding, nodeOrg string, nodeId string,
msgPrinter *message.Printer) (bool, string, map[int]map[string]bool, map[string]exchange.ServiceDefinition, error) {

// get default message printer if nil
Expand All @@ -554,7 +565,7 @@ func VerifySecretBindingForServiceDef(sDef common.AbstractServiceFile,
return false, "", nil, nil, NewCompCheckError(fmt.Errorf(msgPrinter.Sprintf("Failed to find the dependent services for %v/%v %v %v. %v", sDef.GetOrg(), sDef.GetURL(), sDef.GetArch(), sDef.GetVersion(), err)), COMPCHECK_GENERAL_ERROR)
}

compatible, reason, inxex_map, err := VerifySecretBindingForServiceCache(sDef, service_map, secretBinding, vaultSecretExists, agbotUrl, nodeOrg, msgPrinter)
compatible, reason, inxex_map, err := VerifySecretBindingForServiceCache(sDef, service_map, secretBinding, vaultSecretExists, agbotUrl, nodeOrg, nodeId, msgPrinter)

return compatible, reason, inxex_map, service_map, err
}
Expand Down Expand Up @@ -706,7 +717,7 @@ func GetSecretBindingForService(secretBinding []exchangecommon.SecretBinding, sv
// It does not return when the vault secret does not exist or there is an error accessing
// the vault api. Instead it will return a messages for each vault secret name that could
// not be verified.
func VerifyVaultSecrets(secretBinding []exchangecommon.SecretBinding, nodeOrg string, agbotURL string,
func VerifyVaultSecrets(secretBinding []exchangecommon.SecretBinding, nodeOrg string, nodeId string, agbotURL string,
vaultSecretExists exchange.VaultSecretExistsHandler, msgPrinter *message.Printer) (map[string]string, error) {

if secretBinding == nil || len(secretBinding) == 0 {
Expand All @@ -730,6 +741,7 @@ func VerifyVaultSecrets(secretBinding []exchangecommon.SecretBinding, nodeOrg st
ret := map[string]string{}
vs_checked := map[string]bool{}
for _, sn := range secretBinding {
enableNodeSecret := sn.EnableNodeLevelSecrets
for _, vbind := range sn.Secrets {

// make sure each vault get checked only once
Expand All @@ -740,7 +752,7 @@ func VerifyVaultSecrets(secretBinding []exchangecommon.SecretBinding, nodeOrg st
vs_checked[vaultSecretName] = true
}

if exists, err := VerifySingleVaultSecret(vaultSecretName, nodeOrg, agbotURL, vaultSecretExists, msgPrinter); err != nil {
if exists, err := VerifySingleVaultSecret(vaultSecretName, nodeOrg, nodeId, agbotURL, vaultSecretExists, enableNodeSecret, msgPrinter); err != nil {
ret[vaultSecretName] = err.Error()
} else if !exists {
msg := msgPrinter.Sprintf("Secret %v does not exist in the secret manager.", vaultSecretName)
Expand All @@ -758,7 +770,7 @@ func VerifyVaultSecrets(secretBinding []exchangecommon.SecretBinding, nodeOrg st
// Call the agbot API to verify the vault secrets exists.
// It returns immediately when a vault secret does not exist or there is an error accessing
// the vault api.
func VerifyVaultSecrets_strict(secretBinding []exchangecommon.SecretBinding, nodeOrg string, agbotURL string,
func VerifyVaultSecrets_strict(secretBinding []exchangecommon.SecretBinding, nodeOrg string, nodeId string, agbotURL string,
vaultSecretExists exchange.VaultSecretExistsHandler, msgPrinter *message.Printer) (bool, string, error) {
if secretBinding == nil || len(secretBinding) == 0 {
return true, "", nil
Expand All @@ -780,6 +792,7 @@ func VerifyVaultSecrets_strict(secretBinding []exchangecommon.SecretBinding, nod
// go through each secret binding making sure the vault secret exist in vault
vs_checked := map[string]bool{}
for _, sn := range secretBinding {
enableNodeSecret := sn.EnableNodeLevelSecrets
for _, vbind := range sn.Secrets {
_, vaultSecretName := vbind.GetBinding()

Expand All @@ -790,8 +803,10 @@ func VerifyVaultSecrets_strict(secretBinding []exchangecommon.SecretBinding, nod
vs_checked[vaultSecretName] = true
}

if exists, err := VerifySingleVaultSecret(vaultSecretName, nodeOrg, agbotURL, vaultSecretExists, msgPrinter); err != nil {
if exists, err := VerifySingleVaultSecret(vaultSecretName, nodeOrg, nodeId, agbotURL, vaultSecretExists, enableNodeSecret, msgPrinter); !exists && err != nil {
return false, "", err
} else if exists && err != nil {
return true, msgPrinter.Sprintf("%v, use non node-level secret", err), nil
} else if !exists {
return false, msgPrinter.Sprintf("Secret %v does not exist in the secret manager.", vaultSecretName), nil
}
Expand All @@ -802,23 +817,37 @@ func VerifyVaultSecrets_strict(secretBinding []exchangecommon.SecretBinding, nod
}

// It calls the agbot API to verify whether the given secret name exist in vault or not.
func VerifySingleVaultSecret(vaultSecretName string, nodeOrg string, agbotURL string,
vaultSecretExists exchange.VaultSecretExistsHandler, msgPrinter *message.Printer) (bool, error) {
func VerifySingleVaultSecret(vaultSecretName string, nodeOrg string, nodeId string, agbotURL string,
vaultSecretExists exchange.VaultSecretExistsHandler, enableNodeSecret bool, msgPrinter *message.Printer) (bool, error) {

// get default message printer if nil
if msgPrinter == nil {
msgPrinter = i18n.GetMessagePrinter()
}

// parse the name
userName, nodeName, sName, err_parse := ParseVaultSecretName(vaultSecretName, msgPrinter)
userName, nName, sName, err_parse := ParseVaultSecretName(vaultSecretName, msgPrinter)
if err_parse != nil {
return false, fmt.Errorf(msgPrinter.Sprintf("Error parsing secret name in the secret binding. %v", err_parse))
}

// nName == "" from ParseVaultSecretName() function if this is deploycheck CLI
if nodeId != "" && nName == "" {
nodeName := exchange.GetId(nodeId)
nName = nodeName
}

// check the existance
if exists, err := vaultSecretExists(agbotURL, nodeOrg, userName, nodeName, sName); err != nil {
return false, fmt.Errorf(msgPrinter.Sprintf("Error checking secret %v in the secret manager. %v", vaultSecretName, err))
if exists, err := vaultSecretExists(agbotURL, nodeOrg, userName, nName, sName); err != nil {
return false, fmt.Errorf(msgPrinter.Sprintf("Error checking secret %v for node %v in the secret manager. %v", vaultSecretName, nName, err))
} else if !exists && nName != "" {
// then check set nName == "" to check non-node level
if exists, err = vaultSecretExists(agbotURL, nodeOrg, userName, "", sName); err != nil {
return false, fmt.Errorf(msgPrinter.Sprintf("Error checking secret %v in the secret manager. %v", vaultSecretName, err))
}

// return exists and
return exists, fmt.Errorf(msgPrinter.Sprintf("Node level secret %v doesn't exist for node %v.", vaultSecretName, nName))
} else {
return exists, nil
}
Expand Down

0 comments on commit 64f50d3

Please sign in to comment.