diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..925836120858a3f4f5dc6561e137b37d2a37ac22 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Ignore build artifacts +*.tar.gz diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..e4d53bf4cca97a9f86e59531a868298e7db8151b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,58 @@ +ARG BASE_REGISTRY=registry1.dsop.io +ARG BASE_IMAGE=ironbank/opensource/nginx/nginx +ARG BASE_TAG=1.19.2 + + +# Down with the bloat +FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG} as extractor + +ARG jitt_version=5.6.33 +COPY /jitt-${jitt_version}.tar.gz / + +USER root +RUN mkdir -p /jitt \ + && tar -zxf /jitt-${jitt_version}.tar.gz -C /jitt + + +FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG} + +ARG jitt_version=5.6.33 +ENV VENDOR=security-compass +LABEL name="SD Elements Just In Time Training (JITT) Container" \ + maintainer="devops-support@securitycompass.com" \ + vendor="Security Compass Ltd." \ + version="${jitt_version}" \ + release='1' \ + summary="SD Elements Automatically Builds In And Enables Compliance Throughout The Software Lifecycle." \ + description="SD Elements automatically identifies and classifies risks and translates complex requirements into actionable tasks that are assigned to your personnel to improve your security posture. It automates Risk Assessments, Threat Modeling, Secure Development, and Regulatory Compliance - at scale." + + +USER root + +RUN set -x \ + && dnf -y upgrade \ + && dnf -y install gettext \ + && dnf clean all \ + && mkdir -p /var/nginx/proxy_temp \ + && mkdir -p /var/nginx/client_body_temp \ + && chown nginx:root /var/nginx/proxy_temp \ + && chown nginx:root /var/nginx/client_body_temp \ + && rm -f /etc/nginx/conf.d/* \ + && rm -f /etc/nginx/nginx.conf \ + && rm -f /var/log/nginx/access.log \ + && rm -f /var/log/nginx/error.log \ + && groupadd --gid 49 www-data \ + && usermod nginx --groups www-data \ + && mkdir --mode 2775 --parents /etc/nginx /var/log/nginx /var/cache/nginx \ + ; chown --recursive www-data:www-data /etc/nginx \ + ; find /etc/nginx/ -type d -exec chmod g+rwx {} \; \ + ; chown --recursive nginx:www-data /var/log/nginx /var/cache/nginx + +COPY --from=extractor /jitt /jitt/ +COPY /scripts/rtenvsub.sh /bin/rtenvsub.sh +COPY /scripts/shtdlib_dccscr.sh /bin/shtdlib_dccscr.sh +COPY /scripts/run_nginx.sh /bin/run_nginx.sh + +USER nginx + +HEALTHCHECK --interval=15s --timeout=10s --retries=3 CMD pgrep -lf nginx || exit 1 diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000000000000000000000000000000000000..1f9f45ac91ecd5e0f13f00cb0f27d9235fdcd78e --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,2 @@ +@Library('DCCSCR@master') _ +dccscrPipeline(version: "5.6.33") diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..b728b68c85805aea114ddd011adb57ce224ed471 --- /dev/null +++ b/LICENSE @@ -0,0 +1,177 @@ +SD ELEMENTS END USER LICENSE AGREEMENT + +This End User License Agreement (this “Agreement”) is a legal contract between you, as either an +individual, Entity or Government Agency (as per the Order), and Infotek Solutions Inc. dba Security +Compass, or its affiliates (collectively “Security Compass”). + +THIS SOFTWARE IS COPYRIGHTED AND IT IS LICENSED TO YOU UNDER THIS AGREEMENT, NOT +SOLD TO YOU. BY DOWNLOADING, INSTALLING, OBTAINING A LICENSE KEY, OR OTHERWISE +ACCESSING OR USING THIS SOFTWARE, YOU ACKNOWLEDGE THAT YOU HAVE READ THIS +AGREEMENT, YOU UNDERSTAND IT, AND THAT YOU ACCEPT AND AGREE TO BE BOUND BY ITS +TERMS. + +IF YOU ARE ACCEPTING THIS AGREEMENT ON BEHALF OF A COMPANY, ORGANIZATION, OR +OTHER LEGAL ENTITY (AN “ENTITY”), YOU REPRESENT AND WARRANT THAT YOU HAVE FULL +POWER AND AUTHORITY TO BIND SUCH ENTITY TO THESE TERMS, AND REFERENCES TO “YOU” +OR “YOUR” HEREIN REFER TO BOTH YOU, THE INDIVIDUAL END USER, AND THE ENTITY ON +WHOSE BEHALF YOU ARE ACCEPTING THIS AGREEMENT. + +1. Intellectual Property Rights. Security Compass or its licensors retain ownership of all intellectual +property rights in and to the Software, including any modifications, translations, or derivatives thereof, +even if unauthorized, and all applicable rights in patents, copyrights, trade secrets, and trademarks. +The Software is valuable, proprietary, and unique, and you agree to be bound by and observe the +proprietary nature thereof. The Software contains material that is protected by patent, copyright, and +trade secret laws. Your rights to use the Software are limited to those expressly granted by this +Agreement. All rights not granted to you in this Agreement are reserved to Security Compass. No +ownership of the Software passes to you. Security Compass may make changes to the Software at any +time without notice. You may not remove any proprietary notice of Security Compass or any third party +from the Software. + + +2. Protection and Restrictions. + +2.1. You agree to take all reasonable steps to safeguard access to the Software to ensure that no +unauthorized person has access thereto and that no unauthorized copy, publication, disclosure, +or distribution, in whole or in part, in any form is made. + +2.2. You acknowledge that the Software contains valuable, confidential information and trade secrets +and that unauthorized use and/or copying is harmful to Security Compass. You also understand +and agree that the copying or modifying of the Documentation provided with or as part of the +Software is strictly prohibited. Any third-party software included in the Software may not be used +independently from the Software. + +2.3. You will not, and will not allow a third party to, directly or indirectly: sell, sublicense, transfer, assign, +publish, display, disclose, rent, lease, timeshare, modify, loan, distribute, market, commercialize, +or create derivative works based on the Software or any part thereof, incorporate the Software into +or with other products, or use the Software for timesharing or service bureau purposes. + +2.4. You will not reverse engineer, decompile, translate, adapt, or disassemble the Software, nor will +you attempt to reconstruct or discover any source code, underlying ideas, algorithms, file formats +or programming interfaces of the Software by any means whatsoever (except and only to the +extent that applicable law prohibits or restricts reverse engineering restrictions, and then only with +prior written notice to Security Compass). + + +3. Limitation of Liability. TO THE FULLEST EXTENT PERMITTED BY LAW, UNDER NO +CIRCUMSTANCES WILL SECURITY COMPASS, ITS AFFILIATES, ITS LICENSORS OR +RESELLERS BE LIABLE FOR ANY INDIRECT, CONSEQUENTIAL, SPECIAL, PUNITIVE OR + +SD Elements Corporate End User License Agreement (July 2017) +INCIDENTAL DAMAGES, WHETHER FORESEEABLE OR UNFORESEEABLE, ARISING OUT OF +OR RELATED TO THIS AGREEMENT INCLUDING, BUT NOT LIMITED TO CLAIMS FOR +INACCURACY, LOSS OF DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES, GOODWILL, OPPORTUNITY, REVENUE, PROFITS, OR USE OF THE PRODUCTS, +INTERRUPTION IN USE OR AVAILABILITY OF DATA, STOPPAGE OF OTHER WORK OR +IMPAIRMENT OF OTHER ASSETS OR OTHER BUSINESS LOSS, PRIVACY, NEGLIGENCE, +BREACH OF CONTRACT, TORT OR OTHERWISE AND THIRD PARTY CLAIMS, EVEN IF +SECURITY COMPASS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN NO +EVENT WILL SECURITY COMPASS’ AGGREGATE LIABILITY ARISING OUT OF OR RELATED TO +THIS AGREEMENT, BASED ON ANY LEGAL THEORY, INCLUDING BUT NOT LIMITED TO +CONTRACT, TORT, BREACH OF WARRANTY INFRINGEMENT OR OTHERWISE, EXCEED THE +TOTAL AMOUNT ACTUALLY PAID BY YOU TO SECURITY COMPASS FOR THE LICENSE. + + +4. Usage Review. Where you host the Software, Security Compass may at its option request from you a +record of your usage to review and ensure compliance with this Agreement. You agree to cooperate +with Security Compass’ audit and provide reasonable assistance and access to information. Any such +audit shall not unreasonably interfere with your normal business operations. If any audit reveals a +breach of this Agreement by you, you will reimburse any amount revealed to be due to Security +Compass as a result of such breach within thirty (30) days after receipt of an invoice. +5. SD Elements Specific Terms. Your use of SD Elements shall be subject to Licensor’s per-application usage +and pricing terms and conditions as set out in Schedule A to this Agreement. + + +SCHEDULE A + +PER-APPLICATION PRICING TERMS AND CONDITIONS + +Additional or alternate terms and conditions that apply to SD Elements are provided below and form part of the +Agreement. + + +1. Definitions + +1.1. “Active Application(s)” shall mean an Application being developed within the SD Elements Software, which +has not been archived, and for which at least one (1) Project has been created. + +1.2. “Application” shall have the meaning set out in Section 3.1 below. + +1.3. “Archived Application(s)” shall mean an Active Application which has been moved to an archive within the +Software, whereupon it shall cease to be an Active Application. + +1.4. “Licensee” shall mean the individual, entity or government agency entering into this Agreement + +1.5. “License Year” shall mean a license year within the License Term + +1.6. “Project” shall mean an instance, component or release of Licensee’s software code base(s) being +developed/managed within an Application + +1.7. All Capitalized terms not defined in this Schedule shall have the meanings assigned to such terms in the +Agreement + + +2. License Metric + +2.1. The License granted to the SD Elements Software shall entitle Licensee to utilize the Software in the +development of a maximum number of Applications stated in the Order Form (hereinafter the “License +Limit”). + +2.2. Active Applications shall apply towards the usage of the License Limit. Archiving an Active Application shall +not free up the license for the Archived Application in the current License Year. + +2.3. The License Limit utilization cycle shall be reset upon the expiry of a License Year. As of the first day of the +renewal License Year, only Active Applications shall apply towards the License Limit. + + +3. Application + +3.1. For the purpose of the Agreement, an “Application” is a set of software instructions (source code, bytecode), +which compile and/or execute in a single run time environment within the Software, subject to any exception +stated below: + +(a) Licensee may create an unlimited number of new releases as Projects within an Application. Such +new releases shall not count as additional usage against the License Limit + +(b) Where Licensee utilizes the Software in the development of a web application, the browser space +code and server side code may be considered different parts of the same Application where the +technical profile of each code base is intended to produce a single list of requirements within the SD +Elements Software. + +(c) Technologies that operate as independent Licensee Applications shall be considered separate +Applications. This includes but is not limited to Java applets and browser plugins. The development +of the same Application for different mobile operating systems shall be considered to be separate +Applications, whereby each such Application shall apply as usage against the License Limit. + +(d) Server side applications which include components that run in a different run time space may be +considered the same Application where (i) a similar technology stack is utilized; and (ii) a single list +of requirements is intended for all components. + +(e) Where the Software is used to develop micro services architecture, all services shall be considered +to be a single application for the purpose of licensing where (i) all services use a similar technology +stack; and (ii) a single list of requirements is intended for all services. + + +4. Usage reporting obligations and auditing + +4.1. Where Licensee hosts the SD Elements Software On-Site, Licensee shall be required to report the number +of Applications developed using the Software, once at the end of each quarter in each License Year. A quarter +shall be measured as each three (3) month period starting from the License Effective Date stated on the +Order Form. Licensor reserves the right to refuse access to Standard Technical Support and Software +Updates until Licensee usage data is provided to Licensor. Usage reports shall be sent to +usagereport@sdelements.com + + +5. Pricing + +5.1. Pricing for the SD Elements Software is stated in the Order Form. Prices represent the License Limit and +SD Elements Corporate End User License Agreement (July 2017) +type of license granted. All prices are in United States Dollars, and are based upon an annual subscription +with a minimum one (1) year License Term. + + +6. Over-Usage + +6.1. At any time during the License Term, where Licensee’s usage exceeds the License Limit, Licensee shall pay +Licensor over-usage fees for the number of Active Applications used in excess of the License Limit at the per +Application rate set forth in the Order. Over-usage fees shall be calculated and invoiced annually after each +License Year. diff --git a/README.md b/README.md index a9972609ac8bb4c97eb42fc856b6e1c2110eb640..3b0a85cb8d65b2c5fd6ce1283bd2a21c7ac124ad 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,35 @@ -# Nginx +# nginx-jitt +## Summary + +This container hosts SDElements Just In Time Training (JITT) content using Nginx to serve the static content + + +## Local build + +1. Download NGINX version 1.19.0 as a tarball from `https://dcar.dsop.io/repomap/opensource/nginx/nginx`. For this example, we will use `nginx-1.19.0.tar` as the file downloaded. + + Load the tarball into docker + + ```bash + docker load -i nginx-1.19.0.tar + ``` + +2. Download the memcached tarball defined in `download.yaml`. The URL below is used as an example. Note +the version of memcached, in this case `5.6.33` + + ```bash + wget --http-user=user --ask-password https://tar.sdelements.com/pulp/isos/Default_Organization/Library/custom/sde/SDElements_Dependency_RPMs/jitt-5.6.33.tar.gz + ``` + + +3. Use this command to build locally: + + ```bash + export jitt_version='5.6.33' && \ + docker build . -t localhost/security-compass/jitt/nginx-jitt:"local" \ + --build-arg BASE_REGISTRY="registry1.dsop.io" \ + --build-arg BASE_IMAGE="ironbank/opensource/nginx/nginx" \ + --build-arg BASE_TAG="1.19.2" + --build-arg jitt_version="${jitt_version}" + ``` diff --git a/download.yaml b/download.yaml new file mode 100644 index 0000000000000000000000000000000000000000..93bc8daaaacf5a5fe87019138b3783a5f0b0bbed --- /dev/null +++ b/download.yaml @@ -0,0 +1,9 @@ +resources: + - url: "https://tar.sdelements.com/pulp/isos/Default_Organization/Library/custom/sde/SDElements_Dependency_RPMs/jitt-5.6.33.tar.gz" + filename: "jitt-5.6.33.tar.gz" + validation: + type: sha256 + value: "472ad942998b0a444e51637ccf8bda039c475ee4f0bccc714bd620485bb2d631" + auth: + type: "basic" + id: "scompass-credential" diff --git a/scripts/rtenvsub.sh b/scripts/rtenvsub.sh new file mode 100755 index 0000000000000000000000000000000000000000..3377536042931a91b3910052bf05a9a04e7ebdd4 --- /dev/null +++ b/scripts/rtenvsub.sh @@ -0,0 +1,374 @@ +#!/bin/bash +# +# Copyright (c) 2018 SD Elements Inc. +# +# All Rights Reserved. +# +# NOTICE: All information contained herein is, and remains +# the property of SD Elements Incorporated and its suppliers, +# if any. The intellectual and technical concepts contained +# herein are proprietary to SD Elements Incorporated +# and its suppliers and may be covered by U.S., Canadian and other Patents, +# patents in process, and are protected by trade secret or copyright law. +# Dissemination of this information or reproduction of this material +# is strictly forbidden unless prior written permission is obtained +# from SD Elements Inc.. +# Version + +version='0.2' + +# Set a safe umask +umask 0077 + +dev_mode="${DEV_MODE:-false}" + +# Import the shell standard library +source /bin/shtdlib_dccscr.sh + + +echo "Running ${0} with PID: ${$}" + +if ! whichs envsubst ; then + echo "Unable to locate envsubst command, please make sure it's available" + echo 'Perhaps this can be fixed with: apt-get -y install gettext-base' + exit 1 +fi +if ! whichs inotifywait && ${dev_mode} ; then + echo "Unable to locate the inotifywait command, please make sure it's available" + echo 'Perhaps this can be fixed with: apt-get install inotify-tools' + exit 1 +fi + +# Print usage and argument list +function print_usage { +cat << EOF +usage: ${0} destination_path file(s) director(y/ies) + +rtenvsub.sh + +Real time environment variable based templating engine + +This script uses the Linux inotify interface in combination with the envsubst +program and optionally named pipes to mirror directories and files replacing environment +variables in realtime in an efficent manner. In addition any changes to the +template files can trigger service/process reload or restart by signaling them +(default SIGHUP). + +To refresh environment variables loaded by this script you can send it the HUP signal. + +For more info see: + +man inotifywait +man mkfifo +man envsubst +man kill +man pgrep/pkill + +OPTIONS: + -p, --process Process PID or name to signal if config files change + -s, --signal Signal to send (defaults to HUP, see man kill for details) + -o, --overlay Set up mirror even if the destination directory contains files/subdirectories + -n, --nofifo Write to files instead of using named pipes + -h, --help Show this message + -d, --daemon Daemonize, run in the background + -v, --verbose {verbosity_level} Set verbose mode (optionally accepts a integer level) + +Examples: +${0} /etc/nginx /usr/share/doc/nginx # Recursively map all files and directories from /usr/share/doc/nginx to /etc/nginx +${0} /etc /usr/share/doc/ntp.conf -p ntpd # Map /usr/share/doc/ntp.conf to /etc/ntp.conf and send a HUP signal to the ntpd process if the file changes + +Version: ${version:-${shtdlib_version}} +EOF +} + +# Store all parameters as an array for `parse_opt_arg` +# shellcheck disable=2034 +parameter_array=( "${@}" ) +# Parse command line arguments +function parse_arguments { + echo "Parse Arguments got argument: ${1}" + case ${1} in + '-') + # This uses the parse_arguments logic to parse a tag and it's value + # The value is passed on in the OPTARG variable which is standard + # when parsing arguments with optarg. + tag="${OPTARG}" + echo "Found long argument/option" + parse_opt_arg OPTARG '' + parse_arguments "${tag}" + ;; + 'p'|'process') + export process="${OPTARG}" + echo "Set process name to signal to: ${process}" + ;; + 's'|'signal') + export signal="${OPTARG}" + echo "Set signal to: ${signal}" + ;; + 'o'|'overlay') + overlay='true' + echo "Overlay enabled!" + ;; + 'n'|'nofifo') + nofifo='true' + echo "Named pipes disabled, using files instead!" + ;; + 'd'|'daemon') + daemonize='true' + echo "Daemon mode selected!" + ;; + 'v'|'verbose') + parse_opt_arg verbosity '10' + export verbose=true + # shellcheck disable=SC2154 + echo "Set verbosity to: ${verbosity}" + echo "Set verbose to: ${verbose}" + ;; + 'h'|'help'|'version') # Help + print_usage + exit 0 + ;; + '?') # Invalid option specified + echo "Invalid option '${OPTARG}'" + print_usage + exit 64 + ;; + ':') # Expecting an argument but none provided + echo "Missing option argument for option '${OPTARG}'" + print_usage + exit 64 + ;; + '*') # Anything else + echo "Unknown error while processing options" + print_usage + exit 64 + ;; + esac +} + +# Process arguments/parameters/options +while getopts ":-:p:s:ndotvh" opt; do + parse_arguments "${opt}" +done + +all_arguments=( "${@}" ) +declare -a non_argument_parameters +for (( index=${#@}-1 ; index>=0 ; index-- )) ; do + # shellcheck disable=SC2004 + if ! [[ "${all_arguments[$index]}" =~ -[-:alphanum:]* ]] && ! in_array "${all_arguments[$(($index - 1))]}" '--signal' '--process' '--verbose' '-p' '-s' '-v' ; then + non_argument_parameters[(${index})]="${all_arguments[${index}]}" + else + break + fi +done +echo "Non-argument parameters:" "${non_argument_parameters[*]:-}" + +export signal="${signal:-SIGHUP}" +export process="${process:-}" +export overlay="${overlay:-false}" +export daemonize="${daemonize:-false}" +export nofifo="${nofifo:-false}" + +if [ "${#@}" -lt 2 ] ; then + echo "You need to supply at least one source dir/file and a destination directory" + print_usage + exit 64 +fi + +# Create a named pipe and set up envsubst loop to feed it +function setup_named_pipe { + local destination="${1}" + local file="${2}" + local path="${3}" + echo "Creating named pipe: ${destination}/${file#${path}} with permissions identical to ${file}" + # Create a named pipe for each file with same permissions, then + # set up an inotifywait process to monitor and trigger envsubst + mkfifo -m "$(stat -c '%a' "${file}")" "${destination}/${file#${path}}" + + # Loop envsubst until the destination or source file no longer exist + while [ -d "${destination}" ] && [ -f "${file}" ] ; do + render_file "${destination}" "${file}" "${path}}" + done +} + +# Render configuration template to a file using envsubst +function render_file { + local destination="${1}" + local file="${2}" + local path="${3}" + echo "Rendering file: ${destination}/${file#${path}} from template: ${file}" + envsubst < "${file}" > "${destination}/${file#${path}}" "$(compgen -v | sed -e 's/^/\$/g' | tr '\n' ',')" +} + +# Create a directory to mirror a source +# shellcheck disable=SC2174 +function create_directory_structure { + local destination="${1}" + local dir="${2}" + local path="${3}" + echo "Creating directory ${destination}/${dir#${path}} with permissions identical to ${dir}" + # Create each directory in the mirror with same permissions + mkdir -m "$(stat -c '%a' "${dir}")" -p "${destination}/${dir#${path}}" +} + +# Loops inotify on a given source and makes sure it's mirrored and templates +# rendered to the destination +function inotify_looper { + local destination="${1}" + local full_path="${2}" + # Set up notifications for each path and fork watching + inotifywait --monitor --recursive --format '%w %f %e' "${full_path}" \ + --event 'modify' --event 'close_write' \ + --event 'moved_to' --event 'create' \ + --event 'moved_from' --event 'delete' --event 'move_self' \ + --event 'delete_self' --event 'unmount' \ + | while read -r -a dir_file_events; do + for event in "${dir_file_events[@]:2}"; do + case "${event}" in + 'ACCESS'|'CLOSE_NOWRITE'|'OPEN') #Non events + echo "Non mutable event on: ${dir_file_events[*]}, this should not happen since we don't subscribe to these" + exit 1 + ;; + 'MODIFY'|'CLOSE_WRITE') # File modified events + echo "File modification event on: ${dir_file_events[*]}" + if ${nofifo} ; then + render_file "${destination}" "${dir_file_events[0]}/${dir_file_events[1]}" "${full_path}" + fi + if [ -n "${process}" ] ; then + signal_process "${process}" "${signal}" + fi + ;; + 'MOVED_TO'|'CREATE') # New file events + echo "New file event on: ${dir_file_events[*]} ${event}" + create_directory_structure "${destination}" "${dir_file_events[0]}" "${full_path}" + if ${nofifo} ; then + render_file "${destination}" "${dir_file_events[0]}/${dir_file_events[1]}" "${full_path}" + else + setup_named_pipe "${destination}" "${dir_file_events[0]}/${dir_file_events[1]}" "${full_path}" & + fi + if [ -n "${process}" ] ; then + signal_process "${process}" "${signal}" + fi + ;; + 'MOVED_FROM'|'DELETE'|'MOVE_SELF') # File/Directory deletion events + fs_object="${dir_file_events[0]}/${dir_file_events[1]}" + mirror_object="${destination}/${fs_object#${full_path}}" + echo "Filesystem object removed from source, removing from mirror" + echo "Source: ${fs_object} Pipe: ${mirror_object}" + if [ -f "${fs_object}" ] ; then + rm -f "${mirror_object}" + elif [ -d "${fs_object}" ] ; then + rmdir "${mirror_object}" + fi + if [ -n "${process}" ] ; then + signal_process "${process}" "${signal}" + fi + ;; + 'DELETE_SELF'|'UNMOUNT') # Stop/exit/cleanup events + echo "Received fatal event: ${dir_file_events[0:1]} ${event}, exiting!" + if [ -n "${process}" ] ; then + signal_process "${process}" "${signal}" + fi + exit 1 + ;; + esac + done + done +} + + +# Mirrors given path(s) of directories, files and symlinks to a destination path +# using name pipes or files substituting environment variables found in files in realtime +# Ignores filesystem objects that are not files, directories or symlinks +function mirror_envsubst_paths { + declare -a sources + destination="$(readlink -m "${1}")" + sources=("${@:2}") + if ! [ -d "${destination}" ] ; then + echo "Destination path: ${destination} is not a directory, exiting!" + exit 1 + fi + declare -a looper_pids + # Iterate over each source file/directory, exclude root dir if specified + for path in "${sources[@]}"; do + if ! [ -e "${path}" ] ; then + echo "Source path: ${path} does not exist, exiting!" + exit 1 + fi + full_path="$(readlink -m "${path}")" + + if [ "${full_path#${destination}}" != "${full_path}" ] || [ "${destination#${full_path}}" != "${destination}" ] ; then + echo "Source/Destination directories can't be subdirectories of each other or the same directory" + exit 64 + fi + + mapfile -t directories < <(find "${full_path}" -mindepth 1 -type d -exec readlink -m {} \;) + mapfile -t files < <(find "${full_path}" -type f -exec readlink -m {} \;) + mapfile -t links < <(find "${full_path}" -type l) + + # Create directory structure, check if destination is empty + if [ -n "$(ls -A "${destination}")" ] && ! ${overlay} ; then + echo "Destination directory is not empty, if you still want to overlay into it please use the -o/--overlay option" + print_usage + exit 1 + else + for dir in "${directories[@]}"; do + create_directory_structure "${destination}" "${dir}" "${full_path}" + done + + fi + + # Create named pipes / files and set up cleanup on signals for them + if [ -z "${files[*]}" ] ; then + echo "Destination directory does not contain any files, no pipes created for ${full_path}!" + else + for file in "${files[@]:-}"; do + if ${dev_mode} ; then + add_on_sig "rm -f ${destination}${file#${full_path}}" + fi + if ${nofifo} ; then + render_file "${destination}" "${file}" "${full_path}" + else + setup_named_pipe "${destination}" "${file}" "${full_path}" & + fi + done + fi + + # Create symbolic links as needed and set up cleanup + for link in "${links[@]}" ; do + echo "Processing symbolic link ${link}" + target="${destination}${link#${full_path}}" + ln --symbolic "$(readlink ${link})" "${target}" + add_on_sig "unlink ${target}" + done + + if ${dev_mode} ; then + # Set up safe cleanup for directory structure (needs to be done in + # reverse order to ensure safety of operation without recursive rm + local index + for (( index=${#directories[@]}-1 ; index>=0 ; index-- )) ; do + add_on_sig "rmdir ${destination}${directories[${index}]#${full_path}}" + done + + # Run update loop and detach it + if ${daemonize} ; then + inotify_looper "${destination}" "${full_path}" & + else + inotify_looper "${destination}" "${full_path}" & + fi + looper_pids+=( "${!}" ) + fi + done + if ! ${daemonize} ; then + echo "Waiting for looper pids: ${looper_pids[*]}" + wait "${looper_pids[*]}" + fi +} + +# Call the main mirroring function +if ${daemonize} ; then + mirror_envsubst_paths "${non_argument_parameters[@]:-}" & + wait "${!}" +else + mirror_envsubst_paths "${non_argument_parameters[@]:-}" +fi diff --git a/scripts/run_nginx.sh b/scripts/run_nginx.sh new file mode 100755 index 0000000000000000000000000000000000000000..9ac6af8574e02ddf2ec85613b5f3c27ecb681fbd --- /dev/null +++ b/scripts/run_nginx.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# +# Copyright (c) 2018 SD Elements Inc. +# +# All Rights Reserved. +# +# NOTICE: All information contained herein is, and remains +# the property of SD Elements Incorporated and its suppliers, +# if any. The intellectual and technical concepts contained +# herein are proprietary to SD Elements Incorporated +# and its suppliers and may be covered by U.S., Canadian and other Patents, +# patents in process, and are protected by trade secret or copyright law. +# Dissemination of this information or reproduction of this material +# is strictly forbidden unless prior written permission is obtained +# from SD Elements Inc.. + +# Set strict mode +set -eu + +# Version +# shellcheck disable=2034 +version='0.0.2' + +# Import the shell standard library +source /bin/shtdlib_dccscr.sh + + +# Dynamically figure add resolvers for nginx +export NAMESERVERS="resolver $(grep nameserver /etc/resolv.conf | awk '{print $2}') valid=10s;" + +# Create config files +sg www-data "/bin/rtenvsub.sh --nofifo --overlay --daemon /etc/nginx /run/nginx" + +echo 'Waiting for config to become available ' +until test -e '/etc/nginx/nginx.conf' && test -d '/etc/nginx/sites-enabled'; do + add_on_break 'exit' + echo -n . + sleep 1 +done + +# Run nginx +echo 'Starting nginx' +/usr/sbin/nginx -g 'daemon off;' || exit_on_fail +echo "Nginx exited with return code: ${?}" diff --git a/scripts/shtdlib_dccscr.sh b/scripts/shtdlib_dccscr.sh new file mode 100644 index 0000000000000000000000000000000000000000..c9244fa2d331b7e7921070674b691f449be51053 --- /dev/null +++ b/scripts/shtdlib_dccscr.sh @@ -0,0 +1,222 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2034,SC2174,SC2016,SC2026,SC2206,SC2128 +# +# This is a collection of shared functions used by SD Elements products +# +# Copyright (c) 2018 SD Elements Inc. +# +# All Rights Reserved. +# +# NOTICE: All information contained herein is, and remains +# the property of SD Elements Incorporated and its suppliers, +# if any. The intellectual and technical concepts contained +# herein are proprietary to SD Elements Incorporated +# and its suppliers and may be covered by U.S., Canadian and other Patents, +# patents in process, and are protected by trade secret or copyright law. +# + +# If there is no TTY then it's not interactive +if ! [[ -t 1 ]]; then + interactive=false +fi +# Default is interactive mode unless already set +interactive="${interactive:-true}" + +# Allows checking of exit status, on error print debugging info and exit. +# Takes an optional error message in which case only it will be shown +# This is typically only used when running in non-strict mode but when errors +# should be raised and to help with debugging +function exit_on_fail { + message="${*:-}" + if [ -z "${message}" ] ; then + echo "Last command did not execute successfully but is required!" >&2 + else + echo "${*}" >&2 + fi + echo "[$( caller )] ${*:-}" + echo "BASH_SOURCE: ${BASH_SOURCE[*]}" + echo "BASH_LINENO: ${BASH_LINENO[*]}" + echo "FUNCNAME: ${FUNCNAME[*]}" + exit 1 +} + +# Check if a variable is in array +# First parameter is the variable, rest is the array +function in_array { + local x + for x in "${@:2}"; do [[ "${x}" == "${1}" ]] && return 0; done + return 1 +} + +# Parse for optional arguments (-f vs. -f optional_argument) +# Takes variable name as first arg and default value as optional second +# variable will be initialized in any case for compat with -e +# You need to set or export `parameter_array` in the script that uses `parse_opt_arg`: +# +# # shellcheck disable=2034 +# parameter_array=(${@:-}) # Store all parameters as an array +# +# # Parse command line arguments +# function parse_arguments { +# echo "Parse Arguments got argument: ${1}" +# case ${1} in +# ... +function parse_opt_arg { + # Pick up optional arguments + echo "Parameter Array is: ${parameter_array[*]:-}" + next_arg="${parameter_array[$((OPTIND - 1))]:-}" + echo "Optarg/Option index is: ${OPTIND} and next argument is: ${next_arg}" + if [ "$(echo "${next_arg}" | grep -v '^-')" != "" ]; then + echo "Found optional argument and setting ${1}=\"${next_arg}\"" + eval "${1}=\"${next_arg}\"" + # Skip over the optional value so getopts does not stop processing + (( OPTIND++ )) + else + if [ "${2}" != '' ]; then + echo "Optional argument not found, using default and setting ${1}=\"${2}\"" + eval "${1}=\"${2}\"" + else + echo "Initializing empty variable ${1}" + eval "${1}=" + fi + fi + unset next_arg + echo "Set argument: ${1} to \"${!1}\"" +} + +# Create which -s alias (whichs), same as POSIX: -s +# No output, just return 0 if all of the executables are found, or 1 if some were not found. +function whichs { + # Bash 3.1 does not flush stdout so we use tee to make sure it gets done + command -v "${*}" &> /dev/null | tee /dev/null &> /dev/null + return "${PIPESTATUS}" +} + +# Allows clear assert syntax +function assert { + echo "Assertion made: ${*}" + # shellcheck disable=SC2068 + if ! "${@}" ; then + echo "Assertion failed: '${*}'" + exit 1 + fi +} + +# Signals a process by either exact name or pid +# Accepts name/pid as first parameter and optionally signal as second parameter +function signal_process { +echo "Signaling PID: ${1} with signal: ${2:-SIGTERM}" +if [[ "${1}" =~ ^[0-9]+$ ]] ; then + if [ "${2}" != '' ] ; then + kill -s "${2}" "${1}" + else + kill "${1}" + fi +else + assert whichs pkill + if [ "${2}" != '' ] ; then + pkill --exact --signal "${2}" "${1}" + else + pkill --exact "${1}" + fi +fi +} + +# Traps for cleaning up on exit +# Note that trap definition needs to happen here not inside the add_on_sig as +# shown in the original since this can easily be called in a subshell in which +# case the trap will only apply to that subshell +declare -a on_exit +on_exit=() +declare -a on_break +on_break=() + +function on_exit { + # shellcheck disable=SC2181 + if [ ${?} -ne 0 ]; then + # Prints to stderr to provide an easy way to check if the script + # failed. Because the exit signal gets propagated only the first call to + # this function will know the exit code of the script. All subsequent + # calls will see $? = 0 if the previous signal handler did not fail + echo "Last command did not complete successfully" >&2 + fi + + if [ -n "${on_exit:-}" ] ; then + echo "Received SIGEXIT, ${#on_exit[@]} items to clean up." + if [ ${#on_exit[@]} -gt 0 ]; then + for item in "${on_exit[@]}"; do + if [ -n "${item}" ] ; then + echo "Executing cleanup statement on exit: ${item}" + # shellcheck disable=SC2091 + ${item} + fi + done + fi + fi + echo "Finished cleaning up, de-registering signal trap" + trap - EXIT + if ! $interactive ; then + # Be a nice Unix citizen and propagate the signal + kill -s EXIT "${$}" + fi +} + +function on_break { + if [ -n "${on_break:-}" ] ; then + echo "Break signal received, unexpected exit, ${#on_break[@]} items to clean up." + if [ ${#on_break[@]} -gt 0 ]; then + for item in "${on_break[@]}"; do + if [ -n "${item}" ] ; then + echo "Executing cleanup statement on break: ${item}" + ${item} + fi + done + fi + fi + # Be a nice Unix citizen and propagate the signal + trap - "${1}" + if ! $interactive ; then + # Be a nice Unix citizen and propagate the signal + kill -s "${1}" "${$}" + fi +} + +function add_on_exit { + echo "Registering signal action on exit: \"${*}\"" + if [ -n "${on_exit:-}" ] ; then + local n="${#on_exit[@]}" + else + local n=0 + fi + on_exit[${n}]="${*}" + echo "on_exit content: ${on_exit[*]}, size: ${#on_exit[*]}, keys: ${!on_exit[*]}" +} + +function add_on_break { + echo "Registering signal action on break: \"${*}\"" + if [ -n "${on_break:-}" ] ; then + local n="${#on_break[@]}" + else + local n=0 + fi + on_break[${n}]="${*}" + echo "on_break content: ${on_break[*]}, size: ${#on_break[*]}, keys: ${!on_break[*]}" +} + +function add_on_sig { + add_on_exit "${*}" + add_on_break "${*}" +} + +function clear_sig_registry { + echo "Clearing all registered signal actions" + on_exit=() + on_break=() +} + +echo "Setting up signal traps" +trap on_exit EXIT +trap "on_break INT" INT +trap "on_break QUIT" QUIT +trap "on_break TERM" TERM +echo "Signal trap successfully initialized"