Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(security): Fix redis start issue from #2863 #3115

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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