diff --git a/Dockerfile b/Dockerfile index 44fce78..06810e5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,9 +18,10 @@ RUN ln -sf /usr/share/zoneinfo/UTC /etc/localtime \ && echo "NETWORKING=yes" > /etc/sysconfig/network RUN rm -fr /var/cache/yum/* && yum clean all && yum -y install --setopt=tsflags=nodocs epel-release && yum -y update && \ - yum -y install net-tools wget curl tar unzip mlocate logrotate strace telnet man vim rsyslog cron httpd mod_ssl dos2unix && \ + yum -y install net-tools wget curl tar unzip mlocate logrotate strace telnet man vim rsyslog cron httpd mod_ssl dos2unix cronie supervisor && \ yum clean all +#install shibboleth, cleanup httpd RUN curl -o /etc/yum.repos.d/security:shibboleth.repo \ http://download.opensuse.org/repositories/security://shibboleth/CentOS_7/security:shibboleth.repo \ && yum -y install shibboleth.x86_64 \ @@ -33,13 +34,10 @@ RUN curl -o /etc/yum.repos.d/security:shibboleth.repo \ RUN LD_LIBRARY_PATH="/opt/shibboleth/lib64" RUN export LD_LIBRARY_PATH -ADD ./container_files/system/httpd-shib-foreground /usr/local/bin/ ADD ./container_files/system/shibboleth_keygen.sh /usr/local/bin/ ADD ./container_files/httpd/ssl.conf /etc/httpd/conf.d/ ADD ./container_files/shibboleth/* /etc/shibboleth/ - -RUN chmod +x /usr/local/bin/httpd-shib-foreground \ - && chmod +x /usr/local/bin/shibboleth_keygen.sh +RUN chmod +x /usr/local/bin/shibboleth_keygen.sh # fix httpd logging to tier format RUN sed -i 's/LogFormat "/LogFormat "httpd;access_log;%{ENV}e;%{USERTOKEN}e;/g' /etc/httpd/conf/httpd.conf \ @@ -51,11 +49,31 @@ RUN sed -i 's/LogFormat "/LogFormat "httpd;access_log;%{ENV}e;%{USERTOKEN}e;/g' && sed -i '/UseCanonicalName/c\UseCanonicalName On' /etc/httpd/conf/httpd.conf # add a basic page to shibb's default protected directory -RUN mkdir -p /var/www/html/secure/ +RUN mkdir -p /var/www/html/secure/; mkdir -p /opt/tier/ ADD container_files/httpd/index.html /var/www/html/secure/ +# setup crond and supervisord +ADD container_files/system/startup.sh /usr/local/bin/ +ADD container_files/system/setupcron.sh /usr/local/bin/ +ADD container_files/system/setenv.sh /opt/tier/ +ADD container_files/system/sendtierbeacon.sh /usr/local/bin/ +ADD container_files/system/supervisord.conf /etc/supervisor/ +RUN mkdir -p /etc/supervisor/conf.d \ + && chmod +x /usr/local/bin/setupcron.sh \ + && chmod +x /usr/local/bin/sendtierbeacon.sh \ +# setup cron + && /usr/local/bin/setupcron.sh + +#set cron to not require a login session +RUN sed -i '/session required pam_loginuid.so/c\#session required pam_loginuid.so' /etc/pam.d/crond + + EXPOSE 80 443 -CMD ["httpd-shib-foreground"] +HEALTHCHECK --interval=1m --timeout=30s \ + CMD curl -k -f https://127.0.0.1:8443/Shibboleth.sso/Status || exit 1 + + +CMD ["/usr/local/bin/startup.sh"] diff --git a/README.md b/README.md index c66928e..3c2eced 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,34 @@ -# shibboleth-sp +# TIER shibboleth-sp [![Build Status](https://jenkins.testbed.tier.internet2.edu/buildStatus/icon?job=docker/shib-sp/master)](https://jenkins.testbed.tier.internet2.edu/job/docker/shib-sp/master) -This is the TIER upstream Shibboleth SP container. - -It is based from CentOS 7 and includes httpd, mod_ssl, and the current shibboleth SP. - -Files you must supply/override in your downstream builds: - -The SP's private key and corresponding certificate (very important!) can be generated in your downstream container like this: - RUN /usr/local/bin/shibboleth_keygen.sh -o /etc/shibboleth -f - - ...that command generates/overwrites the following files: - /etc/shibboleth/sp-key.pem - - /etc/shibboleth/sp-cert.pem - -/etc/httpd/conf.d/ssl.conf - including: - ServerName fqdn:port - UseCanonicalName On - -/etc/shibboleth/shibboleth2.xml - including: - entityID +This is the TIER upstream Shibboleth SP container. + +It is based from CentOS 7 and includes httpd, mod_ssl, and the current shibboleth SP. + +Files you must supply/override in your downstream builds: + +1. The SP's ***private key and corresponding certificate*** (very important!), which can be generated in your downstream container like this: +> RUN /usr/local/bin/shibboleth_keygen.sh -o /etc/shibboleth -f +> +> ...that command generates/overwrites the following files: +> /etc/shibboleth/sp-key.pem +> /etc/shibboleth/sp-cert.pem + +2. ***/etc/httpd/conf.d/ssl.conf*** +> including: +> ServerName fqdn:port +> UseCanonicalName On + +3. ***/etc/shibboleth/shibboleth2.xml*** +> including: +> entityID +

+ ***New in the 3.0 release:*** +>The image is based from the public CentOS7 image +>The TIER logging format has been implemented for shibd and httpd +>Everything now runs under supervisord +>The TIER Beacon has been implemented +>The file */etc/httpd/conf.d/ssl.conf* is now the default CentOS7 file diff --git a/container_files/system/httpd-shib-foreground b/container_files/system/httpd-shib-foreground deleted file mode 100755 index 60a415f..0000000 --- a/container_files/system/httpd-shib-foreground +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -set -e - -# Apache gets grumpy about PID files pre-existing -rm -f /etc/httpd/logs/httpd.pid - -(/usr/sbin/shibd) & httpd -DFOREGROUND diff --git a/container_files/system/sendtierbeacon.sh b/container_files/system/sendtierbeacon.sh new file mode 100755 index 0000000..7496968 --- /dev/null +++ b/container_files/system/sendtierbeacon.sh @@ -0,0 +1,28 @@ +#!/bin/bash +LOGHOST="collector.testbed.tier.internet2.edu" +LOGPORT="5001" +if [ -s /opt/tier/env.bash ]; then + . /opt/tier/env.bash +fi + +#JSON/REST style +LOGTEXT="{ \"msgType\" : \"TIERBEACON\", \"msgName\" : \"TIER\", \"msgVersion\" : \"1.0\", \"tbProduct\" : \"$IMAGENAME\", \"tbProductVersion\" : \"$VERSION\", \"tbTIERRelease\" : \"$TIERVERSION\", \"tbMaintainer\" : \"$MAINTAINER\" }" + + +if [ -z "$TIER_BEACON_OPT_OUT" ]; then + #send JSON + echo $LOGTEXT > msgjson.txt + curl -s -XPOST "${LOGHOST}:${LOGPORT}/" -H 'Content-Type: application/json' -T msgjson.txt 1>/dev/null + if [ $? -eq 0 ]; then + echo "tier_beacon;none;$ENV;$USERTOKEN;"`date`"; TIER beacon sent" + else + echo "tier_beacon;none;$ENV;$USERTOKEN;"`date`"; Failed to send TIER beacon" + fi + + rm -f msgjson.txt + + #below is for syslog, F-TICKS style + #`logger -n $LOGHOST -P $LOGPORT -t TIERBEACON $LOGTEXT` + +fi + diff --git a/container_files/system/setenv.sh b/container_files/system/setenv.sh new file mode 100755 index 0000000..55c8c89 --- /dev/null +++ b/container_files/system/setenv.sh @@ -0,0 +1,6 @@ +#!/bin/bash +printenv | sed 's/^\(.*\)$/\1/g' | grep -E "^VERSION" > /opt/tier/env.bash +printenv | sed 's/^\(.*\)$/\1/g' | grep -E "^TIERVERSION" >> /opt/tier/env.bash +printenv | sed 's/^\(.*\)$/\1/g' | grep -E "^IMAGE" >> /opt/tier/env.bash +printenv | sed 's/^\(.*\)$/\1/g' | grep -E "^MAINTAINER" >> /opt/tier/env.bash + diff --git a/container_files/system/setupcron.sh b/container_files/system/setupcron.sh new file mode 100755 index 0000000..3cabd35 --- /dev/null +++ b/container_files/system/setupcron.sh @@ -0,0 +1,18 @@ +#!/bin/bash +CRONFILE=/opt/tier/tier-cron + +#set env vars for cron job +# this script creates /opt/tier/env.bash which is sourced by the cron job's script, which was not seeing the environment set by the Dockerfile +/opt/tier/setenv.sh + +#build crontab file with random start time between midnight and 3:59am +echo "#send daily beacon to TIER Central" > ${CRONFILE} +echo $(expr $RANDOM % 59) $(expr $RANDOM % 3) "* * * /usr/local/bin/sendtierbeacon.sh >> /var/log/cron.log 2>&1" >> ${CRONFILE} +chmod 644 ${CRONFILE} + +#install crontab +crontab ${CRONFILE} + +#create cron logfile +touch /var/log/cron.log + diff --git a/container_files/system/startup.sh b/container_files/system/startup.sh new file mode 100755 index 0000000..b5f0d3a --- /dev/null +++ b/container_files/system/startup.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +#for passed-in env vars, remove spaces and replace any ; with : in usertoken env var since we will use ; as a delimiter +export USERTOKEN="${USERTOKEN//;/:}" +export USERTOKEN="${USERTOKEN// /}" +export ENV="${ENV//;/:}" +export ENV="${ENV// /}" + +# generic console logging pipe for anyone +mkfifo -m 666 /tmp/logpipe +cat <> /tmp/logpipe 1>&2 & + +mkfifo -m 666 /tmp/logcrond +(cat <> /tmp/logcrond | awk -v ENV="$ENV" -v UT="$USERTOKEN" '{printf "crond;console;%s;%s;%s\n", ENV, UT, $0; fflush()}' 1>/tmp/logpipe) & + +mkfifo -m 666 /tmp/loghttpd +(cat <> /tmp/loghttpd | awk -v ENV="$ENV" -v UT="$USERTOKEN" '{printf "httpd;console;%s;%s;%s\n", ENV, UT, $0; fflush()}' 1>/tmp/logpipe) & + +mkfifo -m 666 /tmp/logsuperd +(cat <> /tmp/logsuperd | awk -v ENV="$ENV" -v UT="$USERTOKEN" '{printf "supervisord;console;%s;%s;%s\n", ENV, UT, $0; fflush()}' 1>/tmp/logpipe) & + +mkfifo -m 666 /tmp/logshibd +(cat <> /tmp/logshibd | awk -v ENV="$ENV" -v UT="$USERTOKEN" '{printf "shibd;console;%s;%s;%s\n", ENV, UT, $0; fflush()}' 1>/tmp/logpipe) & + +#launch supervisord +/usr/bin/supervisord -c /etc/supervisor/supervisord.conf + diff --git a/container_files/system/supervisord.conf b/container_files/system/supervisord.conf new file mode 100644 index 0000000..e25dd78 --- /dev/null +++ b/container_files/system/supervisord.conf @@ -0,0 +1,37 @@ +[supervisord] +logfile=/tmp/logsuperd +logfile_maxbytes=0 +loglevel=error +nodaemon=true +user=root + +[program:cron] +command=/usr/sbin/crond -n +autostart=true +autorestart=true +stdout_logfile=/tmp/logcrond +stdout_logfile_maxbytes=0 +stderr_logfile=/tmp/logcrond +stderr_logfile_maxbytes=0 +directory=/usr/bin + +[program:httpd] +command=httpd -DFOREGROUND +autostart=true +autorestart=true +stdout_logfile=/tmp/loghttpd +stdout_logfile_maxbytes=0 +stderr_logfile=/tmp/loghttpd +stderr_logfile_maxbytes=0 + +[program:shibd] +command=/usr/sbin/shibd +autostart=true +autorestart=true +stdout_logfile=/tmp/logshibd +stdout_logfile_maxbytes=0 +stderr_logfile=/tmp/logshibd +stderr_logfile_maxbytes=0 + +[include] +files=/etc/supervisor/conf.d/* diff --git a/tests/clairscan.sh b/tests/clairscan.sh new file mode 100755 index 0000000..a06ea78 --- /dev/null +++ b/tests/clairscan.sh @@ -0,0 +1,73 @@ +#!/bin/bash + +startsecs=$(date +'%s') +starttime=$(date +%H:%M:%S) + +echo 'starting:' ${starttime} + +#ensure clair-scanner +if [ ! -s ./clair-scanner ]; then + echo 'downloading curl-scanner...' + curl -s -L -o ./clair-scanner https://github.com/arminc/clair-scanner/releases/download/v8/clair-scanner_linux_amd64 + chmod 755 clair-scanner +else + echo 'using existing clair-scanner...' +fi + +#ensure DB container +echo 'ensuring a fresh clair-db container...' +docker ps | grep clair-db &>/dev/null +if [ $? == "0" ]; then + echo 'removing existing clair-db container...' + docker kill db &>/dev/null + docker rm db &>/dev/null + docker run -p 5432:5432 -d --name db arminc/clair-db:latest &>/dev/null +else + docker run -p 5432:5432 -d --name db arminc/clair-db:latest &>/dev/null +fi +sleep 30 + +#ensure clair-scan container +echo 'ensuring a fresh clair-scan container...' +docker ps | grep clair-local-scan &>/dev/null +if [ $? == "0" ]; then + echo 'removing existing clair-scan container...' + docker kill clair &>/dev/null + docker rm clair &>/dev/null + docker run -p 6060:6060 --link db:postgres -d --name clair arminc/clair-local-scan:v2.0.5 &>/dev/null +else + docker run -p 6060:6060 --link db:postgres -d --name clair arminc/clair-local-scan:v2.0.5 &>/dev/null +fi +sleep 30 + +#get ip where clair-scanner will listen +clairip=$(/sbin/ifconfig docker0 | grep 'inet ' | sed 's/^[[:space:]]*//g' | cut -f 2 -d ' ' | sed 's/^[[:space:]]*//g') +echo 'sending ip addr' ${clairip} 'to clair-scan server...' + +#run scan +echo 'running scan...' +./clair-scanner --ip ${clairip} $1 +retcode=$? + +#eval results +if [ $retcode == '0' ]; then + echo 'scan found nothing.' +else + echo 'scan found issues.' +fi + +#cleanup +echo 'removing temporary containers...' +docker kill clair &>/dev/null +docker rm clair &>/dev/null +docker kill db &>/dev/null +docker rm db &>/dev/null + +endsecs=$(date +'%s') +endtime=$(date +%H:%M:%S) +echo 'finished:' $endtime ' ('$((endsecs - startsecs)) 'seconds)' +echo "" + +#pass along return code from scan +exit $retcode + diff --git a/tests/image.bats b/tests/image.bats index 3d9fb5e..2ab8f4b 100644 --- a/tests/image.bats +++ b/tests/image.bats @@ -26,3 +26,6 @@ load ../common docker run -i $maintainer/$imagename find /usr/local/bin/httpd-shib-foreground } +@test "070 There are no known security vulnerabilities" { + ./tests/clairscan.sh ${maintainer}/${imagename}:latest +}