Skip to content

Commit

Permalink
Add to for Secrets to be generated before generating secrets (#226)
Browse files Browse the repository at this point in the history
  • Loading branch information
DonRichards authored May 18, 2022
1 parent f4c2e29 commit efd5d5f
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 5 deletions.
15 changes: 15 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -298,12 +298,17 @@ reindex-triplestore:
.PHONY: generate-secrets
.SILENT: generate-secrets
generate-secrets:
ifeq ($(USE_SECRETS), false)
docker run --rm -t \
-v "$(CURDIR)/secrets":/secrets \
-v "$(CURDIR)/scripts/generate-secrets.sh":/generate-secrets.sh \
-w / \
--entrypoint bash \
$(REPOSITORY)/drupal:$(TAG) -c "/generate-secrets.sh && chown -R `id -u`:`id -g` /secrets"
else
@echo "'Uses Secrets' is set to 'true'."
$(MAKE) secrets_warning
endif

# Helper function to generate keys for the user to use in their docker-compose.env.yml
.PHONY: download-default-certs
Expand Down Expand Up @@ -336,6 +341,7 @@ demo: generate-secrets
$(MAKE) reindex-fcrepo-metadata ENVIROMENT=demo
$(MAKE) reindex-solr ENVIROMENT=demo
$(MAKE) reindex-triplestore ENVIROMENT=demo
$(MAKE) secrets_warning

.PHONY: local
.SILENT: local
Expand All @@ -355,6 +361,7 @@ local: generate-secrets
$(MAKE) install ENVIRONMENT=local
$(MAKE) hydrate ENVIRONMENT=local
$(MAKE) set-files-owner SRC="$(CURDIR)/codebase" ENVIROMENT=local
$(MAKE) secrets_warning

.PHONY: demo-install-profile
.SILENT: demo-instal-profile
Expand Down Expand Up @@ -421,6 +428,7 @@ up:
@echo "\n Sleeping for 10 seconds to wait for Drupal to finish building.\n"
sleep 10
docker-compose exec -T drupal with-contenv bash -lc "for_all_sites update_settings_php"
$(MAKE) secrets_warning

.PHONY: down
.SILENT: down
Expand Down Expand Up @@ -477,6 +485,13 @@ help:
} \
{lastLine = $$0}' $(MAKEFILE_LIST)

.PHONY: secrets_warning
.SILENT: secrets_warning
## Check to see if the secrets directory contains default secrets.
secrets_warning:
@echo 'Starting scripts/check-secrets.sh'
@bash scripts/check-secrets.sh || (echo "check-secrets exited $$?"; exit 1)

IS_DRUPAL_PSSWD_FILE_READABLE := $(shell test -r secrets/live/DRUPAL_DEFAULT_ACCOUNT_PASSWORD -a -w secrets/live/DRUPAL_DEFAULT_ACCOUNT_PASSWORD && echo 1 || echo 0)
CMD := $(shell [ $(IS_DRUPAL_PSSWD_FILE_READABLE) -eq 1 ] && echo 'tee' || echo 'sudo -k tee')

Expand Down
20 changes: 15 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,19 +193,24 @@ make up
## Secrets

When running Islandora in the wild, you'll want to use secrets to store sensitive
information such as credentials. Secrets are communicated from the docker host
information such as credentials. Secrets are communicated from the docker host
to the individual containers over an encrypted channel, making it much safer
to run in production.

Some `confd` backends, such as `etcd`, can be used to serve secrets directly.
Simply expose `etcd` over `https` and nothing else needs to be done. But for
Simply expose `etcd` over `https` and nothing else needs to be done. But for
other backends, particularly environment variables, you must mount the secrets
into containers as files using docker-compose. During startup, the files'
contents are read into the container environment and made available to `confd`.

To enable using secrets, set `USE_SECRETS=true` in your .env file. When you run
`make docker-compose.yml`, a large block of `secrets` will be added at the top of
your `docker-compose.yml` file.
To enable using secrets prior to running the `make` commands, copy sample.env
to .env. Set `USE_SECRETS=true` in your .env file. Make a copy of the files in
/secrets/template/ to /secrets/live/.

To enable using secrets after run `make local` or `make up`, set
`USE_SECRETS=true` in your .env file. When you run `make docker-compose.yml`, a
large block of `secrets` will be added at the top of your `docker-compose.yml`
file.

```yml
secrets:
Expand All @@ -221,6 +226,11 @@ generated by `make`. Each secrets file is named the exact same as the
environment variable it intends to replace. The contents of each file will be
used as the value for the secret.

To automatically run secret generator without prompting (for creating a CICD/sandbox process) use:
```shell
bash scripts/check-secrets.sh yes
```

### Quick Drupal "admin" password reset
Run `make set_admin_password` and it will prompt the user to enter in a new password. Enter it in and the password for the "admin" user will be set to the new password.
```shell
Expand Down
170 changes: 170 additions & 0 deletions scripts/check-secrets.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#!/usr/bin/env bash
set -e

RED=$(tput -Txterm setaf 1)
GREEN=$(tput -Txterm setaf 2)
YELLOW=$(tput -Txterm setaf 3)
BLUE=$(tput -Txterm setaf 4)
RESET=$(tput -Txterm sgr0)
TARGET_MAX_CHAR_NUM=20

source .env || {
echo "${RED}ERROR: .env file not found.${RESET}"
exit 1
}
FOUND_INSECURE_SECRETS=false

function print_security_warning() {
if [ "${FOUND_INSECURE_SECRETS}" == true ]; then
cat << EOF
${YELLOW} --- --- WARNING --- --- ${RESET}${RED} --- --- WARNING --- --- ${RESET}
${RED}
Using default values for secrets in a production environment is a
Security Risk${RESET}
Default values are identified in ${GREEN}$(pwd)/secrets/live/${RESET}
If you are using the default values, you can either change the values of
the file found in $(pwd)/secrets/live/
Or generate new secrets by running:
${GREEN}make generate-secrets ${RESET}
This will generate new secrets in /secrets/live/ but will not update
the ISLE containers.
If you are not sure how to push updated secrets to ISLE, please consult
the documentation.${BLUE}
https://islandora.github.io/documentation/installation/docker-custom/#secrets
${RESET}
${YELLOW} --- --- WARNING --- --- ${RESET}${RED} --- --- WARNING --- --- ${RESET}
EOF
fi
}

function main() {
unameOut="$(uname -s)"
case "${unameOut}" in
Linux*) hash=sha1sum;;
*) hash="UNKNOWN"
esac
# Check if $USE_SECRETS is set to true.
if [ "$USE_SECRETS" = true ]; then
local secret_live=[];
# Check if the $(pwd)/secrets/live directory is empty.
if [ "$(ls $(pwd)/secrets/live)" ]; then
local secret_live=($(find $(pwd)/secrets/live/* -exec basename {} \;))
fi
fi

local secret_templates=($(find $(pwd)/secrets/template/* -exec basename {} \;))

if [ ! "$(ls $(pwd)/secrets/live)" ]; then
echo -e "\n${YELLOW}Checking secrets...${RESET}"
echo " No secrets found in $(pwd)/secrets/live/"
echo -e "\nThere are 2 basic methods to create secrets:"
echo " [1] - Generate new secrets via a script"
echo -e " [2] - Copy secrets from a $(pwd)/secrets/template directory into $(pwd)/secrets/live/ and then modify them\n"
echo -n "Would you like to generate random secrets? Run a script to create secrets? [y/N] "
read ans
if [[ ${ans} == [yY] ]] ; then
docker run --rm -t \
-v $(pwd)/secrets:/secrets \
-v $(pwd)/scripts/generate-secrets.sh:/generate-secrets.sh \
-w / \
--entrypoint bash \
${REPOSITORY}/drupal:${TAG} -c "/generate-secrets.sh && chown -R `id -u`:`id -g` /secrets"
echo -e "\n${GREEN}Secrets generated.${RESET}"
else
echo ""
echo -n "Would you like to copy the default secrets? Run a script to copy secrets? [y/N] " && \
read second_ans
if [[ ${second_ans:-N} == [yY] ]] ; then
echo -e "\nCopying secrets from $(pwd)/secrets/template/ to $(pwd)/secrets/live/\n"
echo -e "${GREEN}Suggestion${RESET}:\n It is much easier to modify these before you start isle than to try to figure out how to push them to the containers."
cp -n $(pwd)/secrets/template/* $(pwd)/secrets/live/
echo -e "This is optional, but it is recommended to modify the secrets in $(pwd)/secrets/live/ before running on a production environment.\n\n"
echo -e "Would you like to ${RED}exit${RESET} this build process to change the default values of the secrets manually? [y/N] "
read exit_answer
if [[ ${exit_answer} == [yY] ]] ; then
echo -e "\n${RED}Exiting build${RESET}: Please modify the secrets in $(pwd)/secrets/live/ and then run ${BLUE}make up${RESET} command to continue the build process.\n\n\n\n${RED}Exiting build now!...${RESET}"
exit 1
fi
fi
fi
fi

local secret_live=($(find $(pwd)/secrets/live/* -exec basename {} \;))
for secret in "${secret_templates[@]}"; do
if [[ ! "${secret_live[@]}" =~ "${secret}" ]]; then
missing_secret_identified=true
break;
fi

if [[ $hash == "UNKNOWN" ]]; then
if [[ $(cat secrets/template/${secret}) == $(cat secrets/live/${secret}) ]]; then
# Ignore the config location directory. This won't pose a security risk.
if [[ ! "${secret}" = "DRUPAL_DEFAULT_CONFIGDIR" ]]; then
echo -e "${RED}Default Secret${RESET} ${BLUE}->${RESET} $(pwd)/secrets/live/${secret}"
FOUND_INSECURE_SECRETS=true
fi
fi
else
if [[ "$($hash $(pwd)/secrets/template/${secret}| awk '{print $1}')" == "$($hash $(pwd)/secrets/live/${secret}| awk '{print $1}')" ]]; then
# Ignore the config location directory. This won't pose a security risk.
if [[ ! "${secret}" = "DRUPAL_DEFAULT_CONFIGDIR" ]]; then
echo -e "${RED}Default Secret${RESET} ${BLUE}->${RESET} $(pwd)/secrets/live/${secret}"
FOUND_INSECURE_SECRETS=true
fi
fi
fi
done

if [ "${missing_secret_identified}" = true ]; then
echo -e "\n\nIdentified a few missing SECRETS.\n"
echo -e " Would you like to copy the missing secrets from $(pwd)/secrets/template/? [y/N] "
read thr_ans
if [[ ${thr_ans} == [yY] ]] ; then
echo ""
for secret in "${secret_templates[@]}"; do
if [[ ! "${secret_live[@]}" =~ "${secret}" ]]; then
echo "MISSING: $(pwd)/secrets/live/${secret}"
echo -e " Copying ${RED}${secret}${RESET} to $(pwd)/secrets/live/${GREEN}${secret}${RESET}\n"
cp -n $(pwd)/secrets/template/${secret} $(pwd)/secrets/live/${secret}
echo ""
fi
done
else
echo -e "\nPlease update the missing secrets before continuing.\n\n"
exit 1
fi
fi

# Check if Salt matches the one in secrets/live/.
SALT=$(echo $(docker-compose exec drupal with-contenv bash -lc "cat web/sites/default/settings.php | grep hash_salt | grep '^\$settings' | cut -d\= -f2| cut -d\' -f2 | cut -f1 -d\"'\" | tr -d '\n' | cut -f1 -d\"%\""))
SETTINGS_SALT=$(echo $(cat secrets/live/DRUPAL_DEFAULT_SALT | tr -d '\n' | cut -f1 -d"%"))
if [[ $(echo "${SALT}") != $(echo "${SETTINGS_SALT}") ]]; then
echo "${SALT} ${SETTINGS_SALT} Updates to the salt are not automatically added to web/sites/default/settings.php file. Please make this change manually and then run the same ${BLUE}make down && make up${RESET} command again."
fi
}

# Just incase the wishes to automate generation of secrets.
if [[ $1 == 'yes' ]]; then
docker run --rm -t \
-v $(pwd)/secrets:/secrets \
-v $(pwd)/scripts/generate-secrets.sh:/generate-secrets.sh \
-w / \
--entrypoint bash \
${REPOSITORY}/drupal:${TAG} -c "/generate-secrets.sh && chown -R `id -u`:`id -g` /secrets"
echo -e "\n${GREEN}Secrets generated.${RESET}"
fi

main
print_security_warning
echo -e "\nCheck secrets is ${GREEN}done${RESET}.\n\n"

0 comments on commit efd5d5f

Please sign in to comment.