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

Add to for Secrets to be generated before generating secrets #226

Merged
merged 20 commits into from
May 18, 2022
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
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 @@ -457,6 +465,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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to also mention that they should be sure to set

to the value of DRUPAL_DEFAULT_SALT to $settings['hash_salt'] in codebase/web/sites/default/settings.php and the value of DRUPAL_DEFAULT_DB_PASSWORD to the value $databases['default']['default']['password'] in the same file (it's actually in the file twice??)

Or maybe we should use the file path option instead of parsing it into the file? $settings['hash_salt'] = file_get_contents('/home/example/salt.txt');

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also will a make up update passwords if they are created after a make local or make up?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only see $databases['default']['default']['password'] once in my install.

I just pushed a warning to the user to manually update their settings.php file when it notices a difference between the secrets/live/DRUPAL_DEFAULT_SALT and web/sites/default/settings.php file. I felt like it might take too long to try to automatically do this for the user and restart their container because this script is running on the local and we'd need to account for Mac command discrepancies.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like it was my older version had some extra things in there


```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"