diff --git a/cmd/security-bootstrapper/entrypoint-scripts/consul_wait_install.sh b/cmd/security-bootstrapper/entrypoint-scripts/consul_wait_install.sh index 3225ec0737..5fc58b5a01 100755 --- a/cmd/security-bootstrapper/entrypoint-scripts/consul_wait_install.sh +++ b/cmd/security-bootstrapper/entrypoint-scripts/consul_wait_install.sh @@ -93,6 +93,7 @@ if [ "${ENABLE_REGISTRY_ACL}" == "true" ]; then echo "$(date) failed to set up Consul ACL" fi set -e + # no need to wait for Consul's port since it is in ready state after all ACL stuff else echo "$(date) Starting edgex-core-consul with ACL disabled ..." docker-entrypoint.sh agent \ @@ -101,6 +102,7 @@ else -server \ -client 0.0.0.0 & # wait for the consul port + # this waitFor is not necessary in the other ACL case, as it is already in the ready state echo "$(date) Executing waitFor on Consul with waiting on its own port \ tcp://${STAGEGATE_REGISTRY_HOST}:${STAGEGATE_REGISTRY_PORT}" /edgex-init/security-bootstrapper --confdir=/edgex-init/res waitFor \ diff --git a/cmd/security-bootstrapper/res/configuration.toml b/cmd/security-bootstrapper/res/configuration.toml index 194a3ff7bd..f1eef43f69 100644 --- a/cmd/security-bootstrapper/res/configuration.toml +++ b/cmd/security-bootstrapper/res/configuration.toml @@ -26,6 +26,8 @@ LogLevel = 'INFO' BootstrapTokenPath = "/tmp/edgex/secrets/edgex-consul/admin/bootstrap_token.json" # this is the filepath for the Vault token created from secretstore-setup SecretsAdminTokenPath = "/tmp/edgex/secrets/edgex-consul/admin/token.json" + # this is the filepath for the sentinel file to indicate the registry ACL is set up successfully + SentinelFilePath = "/edgex-init/consul-bootstrapper/consul_acl_done" [StageGate.KongDb] Host = "kong-db" Port = 5432 @@ -41,5 +43,5 @@ LogLevel = 'INFO' [SecretStore] Type = 'vault' Protocol = 'http' -Host = 'edgex-vault' +Host = 'localhost' Port = 8200 diff --git a/cmd/security-secretstore-setup/res-file-token-provider/configuration.toml b/cmd/security-secretstore-setup/res-file-token-provider/configuration.toml index ac532a1108..7ea1a65be4 100644 --- a/cmd/security-secretstore-setup/res-file-token-provider/configuration.toml +++ b/cmd/security-secretstore-setup/res-file-token-provider/configuration.toml @@ -3,7 +3,7 @@ LogLevel = 'DEBUG' [SecretStore] Type = "vault" Protocol = "http" -Host = "edgex-vault" +Host = "localhost" Port = 8200 ServerName = "" CaFilePath = "" diff --git a/cmd/security-secretstore-setup/res/configuration.toml b/cmd/security-secretstore-setup/res/configuration.toml index f9dc1f56f9..56cf2697dc 100644 --- a/cmd/security-secretstore-setup/res/configuration.toml +++ b/cmd/security-secretstore-setup/res/configuration.toml @@ -21,7 +21,7 @@ LogLevel = 'DEBUG' [SecretStore] Type = "vault" Protocol = "http" -Host = "edgex-vault" +Host = "localhost" Port = 8200 CertPath = "" CaFilePath = "" diff --git a/internal/security/bootstrapper/command/setupacl/aclbootstrap.go b/internal/security/bootstrapper/command/setupacl/aclbootstrap.go index ff87f7dafd..9c649b2d59 100644 --- a/internal/security/bootstrapper/command/setupacl/aclbootstrap.go +++ b/internal/security/bootstrapper/command/setupacl/aclbootstrap.go @@ -29,10 +29,8 @@ import ( // BootStrapACLTokenInfo is the key portion of the response metadata from consulACLBootstrapAPI type BootStrapACLTokenInfo struct { - AccessorID string `json:"AccessorID"` - SecretID string `json:"SecretID"` - Policies []Policy `json:"Policies"` - CreateTime string `json:"CreateTime"` + SecretID string `json:"SecretID"` + Policies []Policy `json:"Policies"` } // Policy is the metadata for ACL policy diff --git a/internal/security/bootstrapper/command/setupacl/command.go b/internal/security/bootstrapper/command/setupacl/command.go index 1420b18031..3d13ea8f3e 100644 --- a/internal/security/bootstrapper/command/setupacl/command.go +++ b/internal/security/bootstrapper/command/setupacl/command.go @@ -39,6 +39,8 @@ import ( "github.com/edgexfoundry/go-mod-bootstrap/v2/bootstrap/startup" "github.com/edgexfoundry/go-mod-secrets/v2/pkg" + "github.com/edgexfoundry/go-mod-secrets/v2/pkg/token/authtokenloader" + "github.com/edgexfoundry/go-mod-secrets/v2/pkg/token/fileioperformer" "github.com/edgexfoundry/go-mod-core-contracts/v2/clients" "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/logger" @@ -55,7 +57,6 @@ const ( defaultRetryTimeout = 30 * time.Second emptyLeader = `""` emptyToken = "" - sentinelFile = "consul_acl_done" ) type cmd struct { @@ -102,7 +103,12 @@ func (c *cmd) Execute() (statusCode int, err error) { // need to have a sentinel file to guard against the re-run of the command once we have successfully bootstrap ACL // if we already have a sentinelFile exists then skip this whole process since we already done this // process successfully before, otherwise Consul's ACL bootstrap will cause a panic - if c.hasSentinelFile() { + sentinelFileAbsPath, err := filepath.Abs(c.configuration.StageGate.Registry.ACL.SentinelFilePath) + if err != nil { + return interfaces.StatusCodeExitWithError, fmt.Errorf("failed to get the absolute path of the sentinel file: %v", err) + } + + if helper.CheckIfFileExists(sentinelFileAbsPath) { c.loggingClient.Info("Registry ACL had been setup successfully already, skip") return } @@ -260,27 +266,16 @@ func (c *cmd) getSecretStoreTokenFromFile() (string, error) { return emptyToken, fmt.Errorf("secretstore token file %s not found", tokenFileAbsPath) } - type SecretStoreToken struct { - Authentication struct { - Token string `json:"client_token"` - } `json:"auth"` - } - - tokenJSONFile, err := os.Open(trimmedFilePath) - defer func() { tokenJSONFile.Close() }() - + fileOpener := fileioperformer.NewDefaultFileIoPerformer() + tokenLoader := authtokenloader.NewAuthTokenLoader(fileOpener) + secretStoreToken, err := tokenLoader.Load(tokenFileAbsPath) if err != nil { - return emptyToken, fmt.Errorf("failed to open secretstore token file: %v", err) - } - - var tokenData SecretStoreToken - if err := json.NewDecoder(tokenJSONFile).Decode(&tokenData); err != nil { - return emptyToken, fmt.Errorf("failed to decode secretstore json token file: %v", err) + return emptyToken, fmt.Errorf("tokenLoader failed to load secretstore token: %v", err) } c.loggingClient.Infof("successfully retrieved secretstore management token from %s", trimmedFilePath) - return tokenData.Authentication.Token, nil + return secretStoreToken, nil } // configureConsulAccess is to enable the Consul config access to the SecretStore via consul/config/access API @@ -343,30 +338,26 @@ func (c *cmd) configureConsulAccess(secretStoreToken string, bootstrapACLToken s } func (c *cmd) writeSentinelFile() error { - filePathToSave := c.getSentinelFilePath() - fileHandle, err := os.OpenFile(filePathToSave, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) - defer func() { fileHandle.Close() }() - + absPath, err := filepath.Abs(c.configuration.StageGate.Registry.ACL.SentinelFilePath) if err != nil { - return fmt.Errorf("failed to open sentinel file %s: %v", filePathToSave, err) + return fmt.Errorf("failed to get the absolute path of the sentinel file: %v", err) } - if _, err := fileHandle.Write([]byte("done")); err != nil { - return fmt.Errorf("failed to write out to sentinel file %s: %v", filePathToSave, err) + dirToWrite := filepath.Dir(absPath) + filePerformer := fileioperformer.NewDefaultFileIoPerformer() + if err := filePerformer.MkdirAll(dirToWrite, 0700); err != nil { + return fmt.Errorf("failed to create sentinel base dir: %s", err.Error()) } - return nil -} + writer, err := filePerformer.OpenFileWriter(absPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600) + if err != nil { + return fmt.Errorf("failed to open file writer %s: %s", absPath, err.Error()) + } + defer func() { _ = writer.Close() }() -func (c *cmd) hasSentinelFile() bool { - sentinelFilePath := c.getSentinelFilePath() - return helper.CheckIfFileExists(sentinelFilePath) -} + if _, err := writer.Write([]byte("done")); err != nil { + return fmt.Errorf("failed to write out to sentinel file %s: %v", absPath, err) + } -func (c *cmd) getSentinelFilePath() string { - // use the same directory as the bootstrap acl token for this sentinel file directory - // as it is the only writable directory in terms of volume mount in docker - absPath, _ := filepath.Abs(c.configuration.StageGate.Registry.ACL.BootstrapTokenPath) - sentinelDir := filepath.Dir(absPath) - return filepath.Join(sentinelDir, sentinelFile) + return nil } diff --git a/internal/security/bootstrapper/command/setupacl/command_test.go b/internal/security/bootstrapper/command/setupacl/command_test.go index 34814bfb4e..886803fcf3 100644 --- a/internal/security/bootstrapper/command/setupacl/command_test.go +++ b/internal/security/bootstrapper/command/setupacl/command_test.go @@ -126,6 +126,7 @@ func TestExecute(t *testing.T) { // setup token related configs conf.StageGate.Registry.ACL.SecretsAdminTokenPath = filepath.Join(test.adminDir, "secret_token.json") conf.StageGate.Registry.ACL.BootstrapTokenPath = filepath.Join(test.adminDir, "bootstrap_token.json") + conf.StageGate.Registry.ACL.SentinelFilePath = filepath.Join(test.adminDir, "sentinel_test_file") setupRegistryACL, err := NewCommand(ctx, wg, lc, conf, []string{}) require.NoError(t, err) @@ -162,7 +163,7 @@ func TestExecute(t *testing.T) { require.Equal(t, interfaces.StatusCodeExitNormal, statusCode) require.FileExists(t, conf.StageGate.Registry.ACL.BootstrapTokenPath) require.FileExists(t, conf.StageGate.Registry.ACL.SecretsAdminTokenPath) - require.FileExists(t, localcmd.getSentinelFilePath()) + require.FileExists(t, conf.StageGate.Registry.ACL.SentinelFilePath) } }) } diff --git a/internal/security/bootstrapper/config/types.go b/internal/security/bootstrapper/config/types.go index ca24eb690c..694b7170af 100644 --- a/internal/security/bootstrapper/config/types.go +++ b/internal/security/bootstrapper/config/types.go @@ -67,6 +67,8 @@ type ACLInfo struct { BootstrapTokenPath string // filepath for the secretstore's token created from secretstore-setup SecretsAdminTokenPath string + // filepath for the sentinel file to indicate the registry ACL is set up successfully + SentinelFilePath string } // KongDBInfo defines the fields related to