Skip to content

Commit

Permalink
feat(security): Fix redis start issue edgexfoundry#2863
Browse files Browse the repository at this point in the history
Now redis starts with conf file with credentials and thus insecure gap is removed

- Refactor security-bootstrap-redis to absorbed into security-bootstrapper as one of command
- Remove security-bootstrap-redis binary build
- Redis db server starts with config file with credentials
- Update snaps

Closes: edgexfoundry#2863

Signed-off-by: Jim Wang <yutsung.jim.wang@intel.com>
  • Loading branch information
jim-wang-intel committed Feb 6, 2021
1 parent eb1ffba commit b973ef5
Show file tree
Hide file tree
Showing 20 changed files with 587 additions and 284 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ cmd/support-notifications/support-notifications
cmd/support-scheduler/support-scheduler
cmd/sys-mgmt-agent/sys-mgmt-agent
cmd/sys-mgmt-executor/sys-mgmt-executor
cmd/security-bootstrap-redis/security-bootstrap-redis
cmd/secrets-config/secrets-config
cmd/security-bootstrapper/security-bootstrapper

Expand Down
4 changes: 0 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ MICROSERVICES= \
cmd/security-proxy-setup/security-proxy-setup \
cmd/security-secretstore-setup/security-secretstore-setup \
cmd/security-file-token-provider/security-file-token-provider \
cmd/security-bootstrap-redis/security-bootstrap-redis \
cmd/secrets-config/secrets-config \
cmd/security-bootstrapper/security-bootstrapper

Expand Down Expand Up @@ -82,9 +81,6 @@ cmd/security-secretstore-setup/security-secretstore-setup:
cmd/security-file-token-provider/security-file-token-provider:
$(GO) build $(GOFLAGS) -o ./cmd/security-file-token-provider/security-file-token-provider ./cmd/security-file-token-provider

cmd/security-bootstrap-redis/security-bootstrap-redis:
$(GO) build $(GOFLAGS) -o ./cmd/security-bootstrap-redis/security-bootstrap-redis ./cmd/security-bootstrap-redis

cmd/secrets-config/secrets-config:
$(GO) build $(GOFLAGS) -o ./cmd/secrets-config ./cmd/secrets-config

Expand Down
23 changes: 0 additions & 23 deletions cmd/security-bootstrap-redis/README.md

This file was deleted.

27 changes: 0 additions & 27 deletions cmd/security-bootstrap-redis/main.go

This file was deleted.

6 changes: 2 additions & 4 deletions cmd/security-bootstrapper/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ RUN go mod download

COPY . .

RUN make cmd/security-bootstrapper/security-bootstrapper && \
make cmd/security-bootstrap-redis/security-bootstrap-redis
RUN make cmd/security-bootstrapper/security-bootstrapper

FROM alpine:3.12

Expand All @@ -59,8 +58,7 @@ COPY --from=builder /edgex-go/cmd/security-bootstrapper/security-bootstrapper .
COPY --from=builder /edgex-go/cmd/security-bootstrapper/res/configuration.toml ./res/

# needed for bootstrapping Redis db
COPY --from=builder /edgex-go/cmd/security-bootstrap-redis/security-bootstrap-redis ${BOOTSTRAP_REDIS_DIR}/
COPY --from=builder /edgex-go/cmd/security-bootstrap-redis/res/configuration.toml ${BOOTSTRAP_REDIS_DIR}/res/
COPY --from=builder /edgex-go/cmd/security-bootstrapper/res-bootstrap-redis/configuration.toml ${BOOTSTRAP_REDIS_DIR}/res/

# Expose the file directory as a volume since there's long-running state
VOLUME ${SECURITY_INIT_DIR}
Expand Down
41 changes: 25 additions & 16 deletions cmd/security-bootstrapper/entrypoint-scripts/redis_wait_install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,37 @@ echo "$(date) Executing waitFor on Redis with waiting on TokensReadyPort \
-uri tcp://"${STAGEGATE_SECRETSTORESETUP_HOST}":"${STAGEGATE_SECRETSTORESETUP_TOKENS_READYPORT}" \
-timeout "${STAGEGATE_WAITFOR_TIMEOUT}"

# the bootstrap-redis needs the connection from Redis db to set it up.
# Hence, here bootstrap-redis runs in background and then after bootstrap-redis starts,
# the Redis db starts in background.
# the configureRedis retrieves the redis default user's credentials from secretstore (i.e. Vault) and
# generates the redis configuration file with ACL rules in it.
# The redis database server will start with the generated configuration file so that it is
# started securely.
echo "$(date) ${STAGEGATE_SECRETSTORESETUP_HOST} tokens ready, bootstrapping redis..."
/edgex-init/bootstrap-redis/security-bootstrap-redis --confdir=/edgex-init/bootstrap-redis/res &
redis_bootstrapper_pid=$!
/edgex-init/security-bootstrapper --confdir=/edgex-init/bootstrap-redis/res configureRedis

# give some time for bootstrap-redis to start up
sleep 1

echo "$(date) Starting edgex-redis..."
exec /usr/local/bin/docker-entrypoint.sh redis-server &

# wait for bootstrap-redis to finish before signal the redis is ready
wait $redis_bootstrapper_pid
redis_bootstrapping_status=$?
if [ $redis_bootstrapping_status -eq 0 ]; then
echo "$(date) redis is bootstrapped and ready"
else
if [ $redis_bootstrapping_status -ne 0 ]; then
echo "$(date) failed to bootstrap redis"
exit 1
fi

# make sure the config file is present before redis server starts up
/edgex-init/security-bootstrapper --confdir=/edgex-init/res waitFor \
-uri file://"${DATABASECONFIG_PATH}"/"${DATABASECONFIG_NAME}" \
-timeout "${STAGEGATE_WAITFOR_TIMEOUT}"

# starting redis with config file
echo "$(date) Starting edgex-redis ..."
exec /usr/local/bin/docker-entrypoint.sh redis-server "${DATABASECONFIG_PATH}"/"${DATABASECONFIG_NAME}" &

# wait for the Redis port
echo "$(date) Executing waitFor on database redis with waiting on its own port \
tcp://${STAGEGATE_DATABASE_HOST}:${STAGEGATE_DATABASE_PORT}"
/edgex-init/security-bootstrapper --confdir=/edgex-init/res waitFor \
-uri tcp://"${STAGEGATE_DATABASE_HOST}":"${STAGEGATE_DATABASE_PORT}" \
-timeout "${STAGEGATE_WAITFOR_TIMEOUT}"

echo "$(date) redis is bootstrapped and ready"

# Signal that Redis is ready for services blocked waiting on Redis
/edgex-init/security-bootstrapper --confdir=/edgex-init/res listenTcp \
--port="${STAGEGATE_DATABASE_READYPORT}" --host="${DATABASES_PRIMARY_HOST}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,6 @@ TokenFile = '/vault/config/assets/resp-init.json'
Timeout = 5000
Type = 'redisdb'

[DatabaseConfig]
Path = '/user/local/etc/redis/conf'
Name = 'redis.conf'
62 changes: 62 additions & 0 deletions internal/security/bootstrapper/helper/helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*******************************************************************************
* Copyright 2021 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*
*******************************************************************************/

package helper

import (
"io/ioutil"
"os"
"path/filepath"
"strconv"
"time"
)

// MarkComplete creates a doneFile file
func MarkComplete(dirPath, doneFile string) error {
doneFilePath := filepath.Join(dirPath, doneFile)
if !checkIfFileExists(doneFilePath) {
if err := writeFile(doneFilePath); err != nil {
return err
}
}

return nil
}

// CreateDirectoryIfNotExists makes a directory if not exists yet
func CreateDirectoryIfNotExists(dirName string) (err error) {
if _, err = os.Stat(dirName); err == nil {
// already exists, skip
return nil
} else if os.IsNotExist(err) {
// dirName not exists yet, create it
err = os.MkdirAll(dirName, os.ModePerm)
}

return
}

func checkIfFileExists(fileName string) bool {
fileInfo, statErr := os.Stat(fileName)
if os.IsNotExist(statErr) {
return false
}
return !fileInfo.IsDir()
}

func writeFile(aFileName string) error {
timestamp := []byte(strconv.FormatInt(time.Now().Unix(), 10))
return ioutil.WriteFile(aFileName, timestamp, 0400)
}
65 changes: 65 additions & 0 deletions internal/security/bootstrapper/helper/helper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*******************************************************************************
* Copyright 2021 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*
*******************************************************************************/

package helper

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"
)

func TestMarkComplete(t *testing.T) {
testDir := "testDir"
doneFile := "testDone"

defer (cleanupDir(testDir))()

err := os.MkdirAll(testDir, os.ModePerm)
require.NoError(t, err)

err = MarkComplete(testDir, doneFile)
require.NoError(t, err)

require.FileExists(t, filepath.Join(testDir, doneFile))
}

func TestCreateDirectoryIfNotExists(t *testing.T) {
testDir := "testDirNew"
require.NoDirExists(t, testDir)
defer (cleanupDir(testDir))()

err := CreateDirectoryIfNotExists(testDir)
require.NoError(t, err)
require.DirExists(t, testDir)

testPreCreatedDir := "pre-created-dir"
defer (cleanupDir(testPreCreatedDir))()

err = os.MkdirAll(testPreCreatedDir, os.ModePerm)
require.NoError(t, err)
err = CreateDirectoryIfNotExists(testPreCreatedDir)
require.NoError(t, err)
require.DirExists(t, testPreCreatedDir)
}

// cleanupDir deletes all files in the directory and files in the directory
func cleanupDir(dir string) func() {
return func() {
_ = os.RemoveAll(dir)
}
}
Loading

0 comments on commit b973ef5

Please sign in to comment.