diff --git a/Library/test-helpers/Dockerfile.tenant b/Library/test-helpers/Dockerfile.tenant new file mode 100644 index 00000000..31510a3b --- /dev/null +++ b/Library/test-helpers/Dockerfile.tenant @@ -0,0 +1,7 @@ +FROM quay.io/centos/centos:stream9 +RUN \ + rm -f /etc/yum.repos.d/centos.repo && \ + curl -o /etc/yum.repos.d/c9s.repo 'https://raw.githubusercontent.com/RedHat-SP-Security/keylime-tests/main/tools/c9s.repo' && \ + cat /etc/yum.repos.d/* && \ + dnf install -y keylime-tenant which && \ + dnf clean all diff --git a/Library/test-helpers/lib.sh b/Library/test-helpers/lib.sh index 1cd907b5..afa7d537 100644 --- a/Library/test-helpers/lib.sh +++ b/Library/test-helpers/lib.sh @@ -620,6 +620,38 @@ limeStopAgent() { true <<'=cut' =pod +=head2 limeKeylimeTenant + +Run the keylime tenant on localhost or in container with specified tenant commands. + + limeKeylimeTenant TENANT_CMD + +=over + +=item + + TENANT_CMD - Set of commands which tenant run. + +=back + +Returns 0 when the stop was successful, non-zero otherwise. + +=cut + +limeKeylimeTenant() { + + local TENANT_CMD=$@ + + if [ -n "$limeconKeylimeTenantCmd" ]; then + limeconRunTenant "$limeconKeylimeTenantCmd" "$TENANT_CMD" "$limeconTenantVolume" + else + keylime_tenant $TENANT_CMD + fi +} + +true <<'=cut' +=pod + =head2 limeStartIMAEmulator Start the keylime IMA Emulator. @@ -1187,7 +1219,7 @@ limeWaitForAgentStatus() { local START=$SECONDS for I in `seq $TIMEOUT`; do - timeout $TIMEOUT keylime_tenant -c status -u $UUID &> $OUTPUT + limeTimeoutCommand $TIMEOUT 'limeKeylimeTenant -c status -u $UUID' &> $OUTPUT AGTSTATE=$(cat "$OUTPUT" | grep "^{" | tail -1 | jq -r ".[].operational_state") if echo "$AGTSTATE" | grep -E -q "$STATUS"; then cat $OUTPUT @@ -1204,7 +1236,6 @@ limeWaitForAgentStatus() { return 1 } - true <<'=cut' =pod @@ -1240,7 +1271,7 @@ limeWaitForAgentRegistration() { local START=$SECONDS for I in `seq $TIMEOUT`; do - timeout $TIMEOUT keylime_tenant -c regstatus -u $UUID &> $OUTPUT + limeTimeoutCommand $TIMEOUT 'limeKeylimeTenant -c regstatus -u $UUID' &> $OUTPUT REGSTATE=$(cat $OUTPUT | grep "^{" | jq -r ".[].operational_state") if [ "$REGSTATE" == "Registered" ]; then cat $OUTPUT @@ -1257,6 +1288,45 @@ limeWaitForAgentRegistration() { return 1 } +true <<'=cut' +=pod + +=head2 limeTimeoutCommand + +Function stop command via SIGTERM after specified amount of time. + + limeTimeoutCommand TIMEOUT COMMAND + +=over + +=item + + TIMEOUT - Maximum time in seconds to wait + +=item COMMAND + +Specify command which have timeout. + +=back + +=cut + +limeTimeoutCommand() { + local TIMEOUT="$1"; + local COMMAND="$2"; + grep -qP '^\d+$' <<< $TIMEOUT + + ( + eval "$COMMAND" & + child=$! + trap -- "" SIGTERM + ( + sleep $TIMEOUT + kill $child 2> /dev/null + ) & + wait $child + ) +} # ~~~~~~~~~~~~~~~~~~~~ # Install @@ -2426,6 +2496,50 @@ limeconRunSystemd() { true <<'=cut' =pod +=head2 limeconRunTenant + +Tenant container run via podman with specified parameters. + + limeconRunTenant PODMAN_CMD TENANT_CMD MOUNT_DIR + +=item PODMAC_CMD + +Setup of starting container. + +=item TENANT_CMD + +Keylime tenant command in container + +=item MOUNT_DIR + +Path of mount dir. + +=back + +Returns 0. + +=cut + +limeconRunTenant() { + + local PODMAN_CMD=$1 + local TENANT_CMD=$2 + local MOUNT_DIR=$3 + local MOUNT_TENANT="--volume=/etc/keylime/:/etc/keylime/" + + if [ -d cv_ca ]; then + MOUNT_TENANT="--volume $PWD/cv_ca:/var/lib/keylime/cv_ca/:z $MOUNT_TENANT" + fi + + podman run $MOUNT_DIR $MOUNT_TENANT $PODMAN_CMD keylime_tenant $TENANT_CMD + sleep 3 + limeconStop "tenant_container" + +} + +true <<'=cut' +=pod + =head2 limeconRunVerifier Container run via podman with specified parameters. diff --git a/container/functional/keylime_all_in_container-basic-attestation/main.fmf b/container/functional/keylime_all_in_container-basic-attestation/main.fmf new file mode 100644 index 00000000..770976d1 --- /dev/null +++ b/container/functional/keylime_all_in_container-basic-attestation/main.fmf @@ -0,0 +1,28 @@ +summary: Tests basic keylime attestation scenario for all keylime component in containers +description: | + Running agents,verifier and registrar and tenant in containers. + Every container uses certificates generated by keylime verifier. + Build container image for agent, verifier,registrar and tenant. + Starts verifier, registrar in container. + Setup agent conf for agent. + Run container with agent. + Register agent by verifier. + Verify registration of agent by one shot tenant container. + Verifiers that container passed with agent attestation. + Do changes in scripts monitored by agent and confirm that agent fail attestation accordingly. + All actions are verified by one shot tenant container. +contact: Patrik Koncity +tag: + - container +component: + - keylime +test: ./test.sh +framework: beakerlib +require: + - yum + - podman + - nmap +recommend: + - keylime +duration: 10m +enabled: true \ No newline at end of file diff --git a/container/functional/keylime_all_in_container-basic-attestation/test.sh b/container/functional/keylime_all_in_container-basic-attestation/test.sh new file mode 100755 index 00000000..a4950f5a --- /dev/null +++ b/container/functional/keylime_all_in_container-basic-attestation/test.sh @@ -0,0 +1,159 @@ +#!/bin/bash +# vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k +. /usr/share/beakerlib/beakerlib.sh || exit 1 + +#Machine should have /dev/tpm0 or /dev/tpmrm0 device +AGENT_ID="d432fbb3-d2f1-4a97-9ef7-75bd81c00000" + +[ -n "$DOCKERFILE_VERIFIER" ] || DOCKERFILE_VERIFIER=Dockerfile.upstream.c9s +[ -n "$DOCKERFILE_REGISTRAR" ] || DOCKERFILE_REGISTRAR=Dockerfile.upstream.c9s +[ -n "$DOCKERFILE_AGENT" ] || DOCKERFILE_AGENT=Dockerfile.upstream.c9s +[ -n "$DOCKERFILE_TENANT" ] || DOCKERFILE_TENANT=Dockerfile.upstream.c9s + +[ -n "$REGISTRY" ] || REGISTRY=quay.io + +rlJournalStart + + rlPhaseStartSetup "Do the keylime setup" + rlRun 'rlImport "./test-helpers"' || rlDie "cannot import keylime-tests/test-helpers library" + rlAssertRpm keylime + # update /etc/keylime.conf + limeBackupConfig + CONT_NETWORK_NAME="container_network" + IP_VERIFIER="172.18.0.4" + IP_REGISTRAR="172.18.0.8" + IP_AGENT="172.18.0.12" + IP_TENANT="172.18.0.16" + #create network for containers + rlRun "limeconCreateNetwork ${CONT_NETWORK_NAME} 172.18.0.0/16" + + #prepare verifier container + rlRun "limeUpdateConf verifier ip $IP_VERIFIER" + rlRun "limeUpdateConf verifier registrar_ip $IP_REGISTRAR" + #for log purposes, when agent fail, we need see verifier log, that attestation failed + rlRun "limeUpdateConf verifier log_destination stream" + + # prepare registrar container + rlRun "limeUpdateConf registrar ip $IP_REGISTRAR" + + # tenant + rlRun "limeUpdateConf tenant require_ek_cert False" + rlRun "limeUpdateConf tenant verifier_ip $IP_VERIFIER" + rlRun "limeUpdateConf tenant registrar_ip $IP_REGISTRAR" + + #need to setup configuration files + + # Pull or build verifier container + TAG_VERIFIER="verifier_image" + if [ -n "$VERIFIER_IMAGE" ]; then + rlRun "limeconPullImage $REGISTRY $VERIFIER_IMAGE $TAG_VERIFIER" + else + rlRun "limeconPrepareImage ${VERIFIER_DOCKERFILE} ${TAG_VERIFIER}" + fi + + # Pull or build registrar container + TAG_REGISTRAR="registrar_image" + if [ -n "$REGISTRAR_IMAGE" ]; then + rlRun "limeconPullImage $REGISTRY $REGISTRAR_IMAGE $TAG_REGISTRAR" + else + rlRun "limeconPrepareImage ${REGISTRAR_DOCKERFILE} ${TAG_REGISTRAR}" + fi + + #build tenant container + TAG_TENANT="tenant_image" + rlRun "limeconPrepareImage ${DOCKERFILE_TENANT} ${TAG_TENANT}" + + # if TPM emulator is present + if limeTPMEmulated; then + # start tpm emulator + rlRun "limeStartTPMEmulator" + rlRun "limeWaitForTPMEmulator" + rlRun "limeCondStartAbrmd" + # start ima emulator + rlRun "limeInstallIMAConfig" + rlRun "limeStartIMAEmulator" + fi + sleep 5 + + #mandatory for access agent containers to tpm + rlRun "chmod o+rw /dev/tpmrm0" + + #run verifier container + CONT_VERIFIER="verifier_container" + rlRun "limeconRunVerifier $CONT_VERIFIER $TAG_VERIFIER $IP_VERIFIER $CONT_NETWORK_NAME keylime_verifier /etc/keylime" + rlRun "limeWaitForVerifier 8881 $IP_VERIFIER" + #wait for generating of certs + sleep 5 + rlRun "podman cp $CONT_VERIFIER:/var/lib/keylime/cv_ca/ ." + + #run registrar container + CONT_REGISTRAR="registrar_container" + rlRun "limeconRunRegistrar $CONT_REGISTRAR $TAG_REGISTRAR $IP_REGISTRAR $CONT_NETWORK_NAME keylime_registrar /etc/keylime $(realpath ./cv_ca)" + rlRun "limeWaitForRegistrar 8891 $IP_REGISTRAR" + + CONT_TENANT="tenant_container" + # define limeconKeylimeTenantCmd so that the keylime container can be used by limeWaitForAgentStatus etc. + limeconKeylimeTenantCmd="--name $CONT_TENANT --net $CONT_NETWORK_NAME --ip $IP_TENANT localhost/$TAG_TENANT" + limeconTenantVolume="--volume $PWD/:/workdir/:z" + + #setup of agent + TAG_AGENT="agent_image" + CONT_AGENT="agent_container" + rlRun "limeconPrepareImage ${DOCKERFILE_AGENT} ${TAG_AGENT}" + rlRun "limeUpdateConf agent registrar_ip '\"$IP_REGISTRAR\"'" + rlRun "limeconPrepareAgentConfdir $AGENT_ID $IP_AGENT confdir_$CONT_AGENT" + + # create some scripts + TESTDIR=$(limeCreateTestDir) + rlRun "echo -e '#!/bin/bash\necho This is good-script1' > $TESTDIR/good-script1.sh && chmod a+x $TESTDIR/good-script1.sh" + rlRun "echo -e '#!/bin/bash\necho This is good-script2' > $TESTDIR/good-script2.sh && chmod a+x $TESTDIR/good-script2.sh" + # create allowlist and excludelist + rlRun "limeCreateTestPolicy ${TESTDIR}/*" + + rlRun "limeconRunAgent $CONT_AGENT $TAG_AGENT $IP_AGENT $CONT_NETWORK_NAME $TESTDIR keylime_agent $PWD/confdir_$CONT_AGENT $(realpath ./cv_ca)" + rlRun -s "limeWaitForAgentRegistration $AGENT_ID" + rlPhaseEnd + + rlPhaseStartTest "Add keylime agent" + rlRun "limeKeylimeTenant -v $IP_VERIFIER -t $IP_AGENT -u $AGENT_ID --runtime-policy /workdir/policy.json -f /etc/hosts -c add" + rlRun -s "limeWaitForAgentStatus $AGENT_ID 'Get Quote'" + rlRun -s "limeKeylimeTenant -c cvlist" + rlAssertGrep "{'code': 200, 'status': 'Success', 'results': {'uuids':.*'$AGENT_ID'" "$rlRun_LOG" -E + rlPhaseEnd + + rlPhaseStartTest "Running allowed scripts should not affect attestation" + rlRun "${TESTDIR}/good-script1.sh" + rlRun "${TESTDIR}/good-script2.sh" + rlRun "tail /sys/kernel/security/ima/ascii_runtime_measurements | grep good-script1.sh" + rlRun "tail /sys/kernel/security/ima/ascii_runtime_measurements | grep good-script2.sh" + rlRun "sleep 5" + rlRun -s "limeWaitForAgentStatus $AGENT_ID 'Get Quote'" + rlPhaseEnd + + rlPhaseStartTest "Fail keylime agent" + rlRun "echo -e '#!/bin/bash\necho boom' > $TESTDIR/bad-script.sh && chmod a+x $TESTDIR/bad-script.sh" + rlRun "$TESTDIR/bad-script.sh" + rlRun "sleep 5" + rlRun "podman logs verifier_container | grep \"keylime.verifier - WARNING - Agent d432fbb3-d2f1-4a97-9ef7-75bd81c00000 failed, stopping polling\"" + rlRun -s "limeWaitForAgentStatus $AGENT_ID '(Failed|Invalid Quote)'" + rlPhaseEnd + + rlPhaseStartCleanup "Do the keylime cleanup" + limeconSubmitLogs + rlRun "limeconStop registrar_container verifier_container agent_container" + rlRun "limeconDeleteNetwork $CONT_NETWORK_NAME" + #set tmp resource manager permission to default state + rlRun "chmod o-rw /dev/tpmrm0" + if limeTPMEmulated; then + rlRun "limeStopIMAEmulator" + rlRun "limeStopTPMEmulator" + rlRun "limeCondStopAbrmd" + fi + limeExtendNextExcludelist "$TESTDIR" + limeSubmitCommonLogs + limeClearData + limeRestoreConfig + rlPhaseEnd + +rlJournalEnd +