diff --git a/.ci/docker/Dockerfile.aca b/.ci/docker/Dockerfile.aca new file mode 100644 index 00000000..f11f1d60 --- /dev/null +++ b/.ci/docker/Dockerfile.aca @@ -0,0 +1,10 @@ +FROM hirs/hirs-ci:centos7 + +MAINTAINER apl.dev3@jhuapl.edu + +# Install packages for installing HIRS ACA +RUN yum -y update && yum clean all +RUN yum install -y mariadb-server openssl tomcat java-1.8.0 rpmdevtools coreutils initscripts chkconfig sed grep firewalld policycoreutils && yum clean all + +# Expose ACA Port +EXPOSE 8443 diff --git a/docker/Dockerfile.centos7 b/.ci/docker/Dockerfile.centos7 similarity index 100% rename from docker/Dockerfile.centos7 rename to .ci/docker/Dockerfile.centos7 diff --git a/.ci/docker/Dockerfile.tpm2provisioner b/.ci/docker/Dockerfile.tpm2provisioner new file mode 100644 index 00000000..769653c3 --- /dev/null +++ b/.ci/docker/Dockerfile.tpm2provisioner @@ -0,0 +1,14 @@ +FROM hirs/hirs-ci:centos7 + +MAINTAINER apl.dev3@jhuapl.edu + +# Install packages for installing HIRS TPM2 Provisioner +RUN yum -y update && yum clean all +# TODO: Remove vim-common if/when Paccor updates (Also update Paccor version below) +RUN yum install -y tpm2-tools libcurl procps-ng vim-common wget dbus python-requests && yum clean all + +# Install PACCOR for Device Info Gathering +RUN mkdir paccor && pushd paccor && wget https://github.com/nsacyber/paccor/releases/download/v1.0.6r3/paccor-1.0.6-3.noarch.rpm && yum -y install paccor-*.rpm && popd + +# Install Software TPM for Provisioning +RUN mkdir ibmtpm && pushd ibmtpm && wget https://downloads.sourceforge.net/project/ibmswtpm2/ibmtpm974.tar.gz && tar -zxvf ibmtpm974.tar.gz && cd src && make -j5 && popd diff --git a/docker/Dockerfile.ubuntu18 b/.ci/docker/Dockerfile.ubuntu18 similarity index 100% rename from docker/Dockerfile.ubuntu18 rename to .ci/docker/Dockerfile.ubuntu18 diff --git a/.ci/docker/docker-compose.yml b/.ci/docker/docker-compose.yml new file mode 100644 index 00000000..eec26eec --- /dev/null +++ b/.ci/docker/docker-compose.yml @@ -0,0 +1,17 @@ +version: "3.1" +services: + aca: + image: hirs/hirs-ci:aca + ports: + - "8443:8443" + volumes: + - ../../:/HIRS + command: /HIRS/.ci/integration-tests/setup-aca.sh + tpm2provisioner: + image: hirs/hirs-ci:tpm2provisioner + depends_on: + - "aca" + volumes: + - ../../:/HIRS + network_mode: "host" + command: /HIRS/.ci/integration-tests/setup-tpm2provisioner.sh diff --git a/.ci/integration-tests/certs/ca.crt b/.ci/integration-tests/certs/ca.crt new file mode 100644 index 00000000..6d6d32de Binary files /dev/null and b/.ci/integration-tests/certs/ca.crt differ diff --git a/.ci/integration-tests/certs/ca.key b/.ci/integration-tests/certs/ca.key new file mode 100644 index 00000000..e0bda2dd Binary files /dev/null and b/.ci/integration-tests/certs/ca.key differ diff --git a/.ci/integration-tests/certs/ek_cert.der b/.ci/integration-tests/certs/ek_cert.der new file mode 100644 index 00000000..60ec60c4 Binary files /dev/null and b/.ci/integration-tests/certs/ek_cert.der differ diff --git a/.ci/integration-tests/run-integration-tests.sh b/.ci/integration-tests/run-integration-tests.sh new file mode 100755 index 00000000..2f196fb1 --- /dev/null +++ b/.ci/integration-tests/run-integration-tests.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# Script to run the Integration Tests for HIRS + +set -e + +# Start Integration Testing Docker Environment +docker-compose -f .ci/docker/docker-compose.yml up -d + +# Check to see if Environment Stand-Up is Complete +# TODO: Refine to handle multiple container IDs +container_id_regex='([a-f0-9]{12})\s+hirs\/hirs-ci:tpm2provisioner' +while : ; do + docker_containers=$(docker container ls) + if [[ $docker_containers =~ $container_id_regex ]]; then + container_id=${BASH_REMATCH[1]} + break + fi + echo "Containers not found. Waiting 5 seconds." + sleep 5 +done + +tpm2_provisioner_started_regex='TPM2 Provisioner Loaded!' +while : ; do + docker_logs=$(docker logs $container_id) + if [[ $docker_logs =~ $tpm2_provisioner_started_regex ]]; then + break + fi + echo "Containers not completely booted. Waiting 10 seconds." + sleep 10 +done + +echo "Environment Stand-Up Complete!" diff --git a/.ci/integration-tests/setup-aca.sh b/.ci/integration-tests/setup-aca.sh new file mode 100755 index 00000000..3851018b --- /dev/null +++ b/.ci/integration-tests/setup-aca.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Script to setup the ACA Docker Image for Integration Tests + +set -e + +# Prevent rebuild of packages if they already exist +cd /HIRS +if [ ! -d package/rpm/RPMS ]; then + ./package/package.centos.sh +fi +yum install -y package/rpm/RPMS/noarch/HIRS_AttestationCA*.el7.noarch.rpm + +echo "ACA Loaded!" + +tail -f /dev/null diff --git a/.ci/integration-tests/setup-tpm2provisioner.sh b/.ci/integration-tests/setup-tpm2provisioner.sh new file mode 100755 index 00000000..9b500dcc --- /dev/null +++ b/.ci/integration-tests/setup-tpm2provisioner.sh @@ -0,0 +1,89 @@ +#!/bin/bash + +# Script to setup the TPM2 Provisioner Docker Image for Integration Tests + +set -e + +# Wait for ACA to boot +until [ "`curl --silent --connect-timeout 1 -I -k https://localhost:8443/HIRS_AttestationCAPortal | grep '302 Found'`" != "" ]; do + : +done + +pushd /HIRS +if [ ! -d package/rpm/RPMS ]; then + ./package/package.centos.sh +fi +yum install -y package/rpm/RPMS/x86_64/HIRS_Provisioner_TPM_2_0*.el7.x86_64.rpm +popd + +mkdir -p /var/run/dbus +if [ -e /var/run/dbus/pid ]; then + rm /var/run/dbus/pid +fi + +if [ -e /var/run/dbus/system_bus_socket ]; then + rm /var/run/dbus/system_bus_socket +fi + +# Start the DBus +dbus-daemon --fork --system +echo "DBus started" + +# Give DBus time to start up +sleep 5 + +/ibmtpm/src/./tpm_server & +echo "TPM Emulator started" + +tpm2-abrmd -t socket & +echo "TPM2-Abrmd started" + +# Give ABRMD time to start and register on the DBus +sleep 5 + +# EK and PC Certificate +ek_cert_der="/HIRS/.ci/integration-tests/certs/ek_cert.der" +platform_cert="platformAttributeCertificate.pem" + +echo "Creating Platform Cert for Container" +PC_DIR=/var/hirs/pc_generation +mkdir -p $PC_DIR +/opt/paccor/scripts/allcomponents.sh > $PC_DIR/componentsFile +/opt/paccor/scripts/referenceoptions.sh > $PC_DIR/optionsFile +/opt/paccor/scripts/otherextensions.sh > $PC_DIR/extensionsFile +/opt/paccor/bin/observer -c $PC_DIR/componentsFile -p $PC_DIR/optionsFile -e $ek_cert_der -f $PC_DIR/observerFile +/opt/paccor/bin/signer -o $PC_DIR/observerFile -x $PC_DIR/extensionsFile -b 20180101 -a 20280101 -N $RANDOM -k /HIRS/.ci/integration-tests/certs/ca.key -P /HIRS/.ci/integration-tests/certs/ca.crt --pem -f $PC_DIR/$platform_cert + +# Release EK Cert if one exists +if tpm2_nvlist | grep -q 0x1c00002; then + tpm2_nvrelease -x 0x1c00002 -a 0x40000001 +fi + +# Define nvram space to enable loading of EK cert (-x NV Index, -a handle to +# authorize [0x40000001 = ownerAuth handle], -s size [defaults to 2048], -t +# specifies attribute value in publicInfo struct +# [0x2000A = ownerread|ownerwrite|policywrite]) +size=$(cat $ek_cert_der | wc -c) +echo "Define nvram location for ek cert of size $size" +tpm2_nvdefine -x 0x1c00002 -a 0x40000001 -t 0x2000A -s $size + +# Load EK Cert into TPM nvram +echo "Load ek cert into nvram" +tpm2_nvwrite -x 0x1c00002 -a 0x40000001 $ek_cert_der + +# Release Platform Cert if one exists +if tpm2_nvlist | grep -q 0x1c90000; then + tpm2_nvrelease -x 0x1c90000 -a 0x40000001 +fi + +# Store the platform certificate in the TPM's NVRAM +echo "Load platform cert into nvram" +tpm2_nvdefine -x 0x1c90000 -a 0x40000001 -t 0x2000A -s $(cat $PC_DIR/$platform_cert | wc -c) +tpm2_nvwrite -x 0x1c90000 -a 0x40000001 $PC_DIR/$platform_cert + +# Set Logging to INFO Level +sed -i "s/WARN/INFO/" /etc/hirs/TPM2_Provisioner/log4cplus_config.ini + +echo "TPM2 Provisioner Loaded!" + +tail -f /dev/null diff --git a/.travis.yml b/.travis.yml index 16095c62..6dd75657 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,14 +29,18 @@ cache: install: true script: - - docker run --rm hirs/hirs-ci:centos7 /bin/bash -c "git clone https://github.com/nsacyber/HIRS.git /root/HIRS; cd /root/HIRS; git checkout ${TRAVIS_BRANCH}; ./gradlew :$SUBPROJECT:build" + - docker run --rm -v $(pwd):/HIRS hirs/hirs-ci:centos7 /bin/bash -c "cd /HIRS; ./gradlew :$SUBPROJECT:build" jobs: include: - stage: package - script: docker run --rm hirs/hirs-ci:centos7 /bin/bash -c "git clone https://github.com/nsacyber/HIRS.git /root/HIRS; cd /root/HIRS; git checkout ${TRAVIS_BRANCH}; ./package/package.centos.sh" + script: docker run --rm -v $(pwd):/HIRS hirs/hirs-ci:centos7 /bin/bash -c "cd /HIRS; ./package/package.centos.sh" env: null name: "Package Centos" - - script: docker run --rm hirs/hirs-ci:ubuntu18 /bin/bash -c "git clone https://github.com/nsacyber/HIRS.git /root/HIRS; cd /root/HIRS; git checkout ${TRAVIS_BRANCH}; ./package/package.ubuntu.sh" + - script: docker run --rm -v $(pwd):/HIRS hirs/hirs-ci:ubuntu18 /bin/bash -c "cd /HIRS; ./package/package.ubuntu.sh" env: null name: "Package Ubuntu" + - stage: integration-tests + script: .ci/integration-tests/./run-integration-tests.sh + env: null + name: "Integration Tests" diff --git a/HIRS_ProvisionerTPM2/package/rpm-post-install.sh b/HIRS_ProvisionerTPM2/package/rpm-post-install.sh index 8f7cf31c..a137e8d2 100644 --- a/HIRS_ProvisionerTPM2/package/rpm-post-install.sh +++ b/HIRS_ProvisionerTPM2/package/rpm-post-install.sh @@ -1,9 +1,16 @@ +set -e + +if ! [ $(id -u) = 0 ]; then + echo "Please run this script as root." + exit 1 +fi + HIRS_SITE_CONFIG="/etc/hirs/hirs-site.config" -sudo mkdir -p /var/log/hirs/provisioner -sudo ln /usr/local/lib/libcurl.so /usr/lib64/libcurl.so -sudo ln -s -f /usr/local/bin/hirs-provisioner-tpm2 /usr/sbin/hirs-provisioner-tpm2 -sudo ln -s -f /usr/local/bin/tpm_aca_provision /usr/sbin/tpm_aca_provision +mkdir -p /var/log/hirs/provisioner +ln /usr/local/lib/libcurl.so /usr/lib64/libcurl.so +ln -s -f /usr/local/bin/hirs-provisioner-tpm2 /usr/sbin/hirs-provisioner-tpm2 +ln -s -f /usr/local/bin/tpm_aca_provision /usr/sbin/tpm_aca_provision if [ ! -f $HIRS_SITE_CONFIG ]; then # Create template site config if it does not exist diff --git a/package/scripts/aca/certificate_generate.sh b/package/scripts/aca/certificate_generate.sh index 5be588ab..94b4ef01 100644 --- a/package/scripts/aca/certificate_generate.sh +++ b/package/scripts/aca/certificate_generate.sh @@ -1,5 +1,12 @@ #!/usr/bin/env bash +# Check if we're in a Docker container +if [ -f /.dockerenv ]; then + DOCKER_CONTAINER=true +else + DOCKER_CONTAINER=false +fi + # variables for the CA certificates CA_PATH=/etc/hirs/certificates CA_KEYSTORE=${CA_PATH}/TrustStore.jks @@ -50,7 +57,7 @@ sed -i "s/aca\.keyStore\.password\s*=/aca.keyStore.password=password/" /etc/hirs # copy the trust store to the ACA cp ${CA_KEYSTORE} /etc/hirs/aca/client-files/ -# start up the tomcat6 service +# start up the tomcat service # Guess where Tomcat is installed and what it's called: if [ -d /usr/share/tomcat6 ] ; then @@ -63,4 +70,17 @@ else fi # restart tomcat after updating the trust store. -/sbin/service ${TOMCAT_SERVICE} restart; +if [ $DOCKER_CONTAINER = true ]; then + # If in Docker container, avoid services that invoke the D-Bus + if [[ $(ss -t -l -n | grep -q LISTEN.*:::8009) -eq 0 ]]; then + echo "Tomcat is running, so we restart it." + /usr/libexec/tomcat/server stop + (/usr/libexec/tomcat/server start) & + # Wait for Tomcat to boot completely + until [ "`curl --silent --connect-timeout 1 -I http://localhost:8080 | grep 'Coyote'`" != "" ]; do + : + done + fi +else + /sbin/service ${TOMCAT_SERVICE} restart; +fi diff --git a/package/scripts/common/db_create.sh b/package/scripts/common/db_create.sh index 2c900024..4f1ec285 100644 --- a/package/scripts/common/db_create.sh +++ b/package/scripts/common/db_create.sh @@ -1,10 +1,27 @@ #!/bin/bash -SQL_SERVICE=`/opt/hirs/scripts/common/get_db_service.sh` +# Check if we're in a Docker container +if [ -f /.dockerenv ]; then + DOCKER_CONTAINER=true +else + DOCKER_CONTAINER=false +fi echo "Creating HIRS Database..." -chkconfig $SQL_SERVICE on -service $SQL_SERVICE start + +if [ $DOCKER_CONTAINER = true ]; then + # If in Docker container, avoid services that invoke the D-Bus + if [[ $(pgrep -c -u mysql mysqld) -eq 0 ]]; then + /usr/libexec/mariadb-prepare-db-dir + nohup /usr/bin/mysqld_safe --basedir=/usr &>/dev/null & + MYSQLD_PID=$(pgrep -u mysql mysqld) + /usr/libexec/mariadb-wait-ready $MYSQLD_PID + fi +else + SQL_SERVICE=`/opt/hirs/scripts/common/get_db_service.sh` + chkconfig $SQL_SERVICE on + service $SQL_SERVICE start +fi CENTOS_VER=`/opt/hirs/scripts/common/get_centos_major_version.sh` if [ $CENTOS_VER -eq "6" ] ; then diff --git a/package/scripts/common/firewall_configure_tomcat.sh b/package/scripts/common/firewall_configure_tomcat.sh index 228948c7..ef25af35 100644 --- a/package/scripts/common/firewall_configure_tomcat.sh +++ b/package/scripts/common/firewall_configure_tomcat.sh @@ -1,15 +1,20 @@ +if ! [ $(id -u) = 0 ]; then + echo "Please run this script as root." + exit 1 +fi + CENTOS_VER=`/opt/hirs/scripts/common/get_centos_major_version.sh` if [ $CENTOS_VER -eq "6" ] ; then checkHTTPS=`iptables-save | grep -- "--dport 8443 -j ACCEPT"` if [[ $checkHTTPS == "" ]]; then echo "Tomcat HTTPS firewall rule doesn't exist, adding now" - sudo iptables -I INPUT 1 -p tcp -m tcp --dport 8443 -j ACCEPT + iptables -I INPUT 1 -p tcp -m tcp --dport 8443 -j ACCEPT service iptables save fi elif [ $CENTOS_VER -eq "7" ] ; then - sudo firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 -p tcp --dport 8443 -j ACCEPT - sudo firewall-cmd --reload + firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 -p tcp --dport 8443 -j ACCEPT + firewall-cmd --reload else echo "Unsupported CentOS version: ${CENTOS_VER}" exit 1 diff --git a/package/scripts/common/ssl_configure.sh b/package/scripts/common/ssl_configure.sh old mode 100644 new mode 100755 index a34300fd..22c222ef --- a/package/scripts/common/ssl_configure.sh +++ b/package/scripts/common/ssl_configure.sh @@ -14,6 +14,13 @@ P12_DATA=${CERTIFICATES}/private/p12.data echo 'Checking SSL configuration for HIRS' +# Check if we're in a Docker container +if [ -f /.dockerenv ]; then + DOCKER_CONTAINER=true +else + DOCKER_CONTAINER=false +fi + ################# # Key Generation ################# @@ -115,7 +122,15 @@ if [[ $1 = "server" ]]; then chkconfig ${TOMCAT_SERVICE} on # Configure the server.xml file such that it uses our key store and trust store - service ${TOMCAT_SERVICE} stop + if [ $DOCKER_CONTAINER = true ]; then + # If in Docker container, avoid services that invoke the D-Bus + if [[ $(pgrep -c -f /usr/share/tomcat) -ne 0 ]]; then + echo "Tomcat is running, so we stop it." + /usr/libexec/tomcat/server stop + fi + else + service ${TOMCAT_SERVICE} stop + fi # Configure Tomcat SSL properly. The method for doing this changes from 6.0.38 onward. rpmdev-vercmp 6.0.38 $TOMCAT_VERSION @@ -143,7 +158,16 @@ EOF # (3) set tomcat user as owner of tomcat installation chgrp -R tomcat ${CATALINA_HOME} - service ${TOMCAT_SERVICE} start + if [ $DOCKER_CONTAINER = true ]; then + # If in Docker container, avoid services that invoke the D-Bus + (/usr/libexec/tomcat/server start) & + # Wait for Tomcat to boot completely + until [ "`curl --silent --connect-timeout 1 -I http://localhost:8080 | grep 'Coyote'`" != "" ]; do + : + done + else + service ${TOMCAT_SERVICE} start + fi fi fi @@ -207,7 +231,19 @@ if [[ $1 = "server" ]]; then sed -i "/\[mysqld\]/r $MYSQL_ADDITIONS_FILE" /etc/my.cnf - SQL_SERVICE=`/opt/hirs/scripts/common/get_db_service.sh` - service $SQL_SERVICE restart + if [ $DOCKER_CONTAINER = true ]; then + # If in Docker container, avoid services that invoke the D-Bus + if [[ $(pgrep -c -u mysql mysqld) -ne 0 ]]; then + echo "MariaDB is running, so we'll need to restart it." + mysqladmin shutdown + /usr/libexec/mariadb-prepare-db-dir + nohup /usr/bin/mysqld_safe --basedir=/usr &>/dev/null & + MYSQLD_PID=$(pgrep -u mysql mysqld) + /usr/libexec/mariadb-wait-ready $MYSQLD_PID + fi + else + SQL_SERVICE=`/opt/hirs/scripts/common/get_db_service.sh` + service $SQL_SERVICE restart + fi fi fi \ No newline at end of file