Skip to content

Commit

Permalink
feat(security): Fix redis start issue from #2863 (#3115)
Browse files Browse the repository at this point in the history
* feat(security): Fix redis start issue #2863

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: #2863

Signed-off-by: Jim Wang <[email protected]>

Change the redis.conf file permission to 0600
Make chown for redis' conf to redis:redis 999:1000 as part of redis' uid and gid creation
Add doc's url and detailed explanation for redis' conf EdgeX is currently using

Remove the change ownership from golang code and only do the change ownership inside the docker's entrypoint script because
snap doesn't work with chow to a non-existing userId.

Signed-off-by: Jim Wang <[email protected]>

* feat(snap): add patch contnets

 patch -p1 < ./0001-fix-snap-update-the-snap-optimization-patch.patch.txt
patching file snap/local/patches/0001-optimize-build-for-pipeline-CI-check.patch

Signed-off-by: Jim Wang <[email protected]>
  • Loading branch information
jim-wang-intel authored Feb 8, 2021
1 parent 9ee6a91 commit cb6997b
Show file tree
Hide file tree
Showing 22 changed files with 578 additions and 292 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
44 changes: 23 additions & 21 deletions cmd/security-bootstrapper/entrypoint-scripts/redis_wait_install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,31 +33,33 @@ 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

# 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}"
if [ $? -ne 0 ]; then
echo "$(date) failed to gating the redis ready port, exits"
# make sure the config file is present before redis server starts up
if [ ! -f "${DATABASECONFIG_PATH}"/"${DATABASECONFIG_NAME}" ]; then
ehco "$(date) Error: conf file ${DATABASECONFIG_PATH}/${DATABASECONFIG_NAME} not exists"
exit 1
else
# before using the generated config file we need to change the ownership to redis:redis
# as the redis server for docker is running as that permission
# based on the Redis' alpine Dockerfile:
# https://github.com/docker-library/redis/blob/68595be6067839e5c5c1a35bdbb6357d017a8a4e/6.0/alpine/Dockerfile#L4
# redis server runs with redis uid 999 and redis group gid 1000
chown -Rh 999:1000 "${DATABASECONFIG_PATH}"/
fi

# starting redis with config file
# security-bootstrapper in this case should just wait for the Redis's port
echo "$(date) Starting edgex-redis ..."
exec /usr/local/bin/docker-entrypoint.sh redis-server "${DATABASECONFIG_PATH}"/"${DATABASECONFIG_NAME}"
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 = '/path/to/redis/conf/dir'
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 cb6997b

Please sign in to comment.