diff --git a/BUILD.md b/BUILD.md index 70e235e5b..2a73ce751 100644 --- a/BUILD.md +++ b/BUILD.md @@ -117,7 +117,8 @@ These docker compose files can be further customized to run multiple worker pool 3. When submitting work orders using any of the sample client applications, `--worker_id` argument needs to be mentioned explicitly to choose one of the workers in the system (Note : Each pool represents a single worker). For example: ```bash ./generic_client.py -o --uri "http://avalon-listener:1947" \ - --workload_id "echo-result" --in_data "Hello" --worker_id worker-pool-2 + --workload_id "echo-result" --in_data "Hello" --worker_id worker-pool-2 \ + -avs "http://avalon-avs:6090" ``` # Standalone Build diff --git a/avs/Dockerfile b/avs/Dockerfile new file mode 100644 index 000000000..d0d345bf7 --- /dev/null +++ b/avs/Dockerfile @@ -0,0 +1,220 @@ +# Copyright 2020 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ------------------------------------------------------------------------------ + +# Description: +# Builds Avalon attestaion verification service +# verification service +# +# Configuration (build) parameters +# - proxy configuration: https_proxy http_proxy ftp_proxy +# +# Build: +# $ docker build docker -f avs/Dockerfile -t avalon-avs-dev +# if behind a proxy, you might want to add also below options +# --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy --build-arg ftp_proxy=$ftp_proxy + +# -------------=== build avalon attestation verification service image ===------------- +FROM ubuntu:bionic as base_image + +# Ignore timezone prompt in apt +ENV DEBIAN_FRONTEND=noninteractive + +# Add necessary packages +RUN apt-get update \ + && apt-get install -y -q \ + software-properties-common \ + python3-requests \ + python3-colorlog \ + python3-twisted \ + && apt-get clean + +# Make Python3 default +RUN ln -sf /usr/bin/python3 /usr/bin/python + + +# -------------=== python build ===------------- + +#Build python intermediate docker image +FROM ubuntu:bionic as python_image + + +# Add necessary packages +RUN apt-get update \ + && apt-get install -y -q \ + ca-certificates \ + pkg-config \ + python3-pip \ + python3-dev \ + make \ + && apt-get clean + +# Install setuptools packages using pip because +# these are not available in apt repository. +RUN pip3 install setuptools + +# Make Python3 default +RUN ln -sf /usr/bin/python3 /usr/bin/python + +# -------------=== Build openssl_image ===------------- + +#Build openssl intermediate docker image +FROM ubuntu:bionic as openssl_image + +RUN apt-get update \ + && apt-get install -y -q \ + ca-certificates \ + pkg-config \ + make \ + wget \ + tar \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /tmp + +# Build ("Untrusted") OpenSSL +RUN OPENSSL_VER=1.1.1g \ + && wget https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz \ + && tar -zxf openssl-$OPENSSL_VER.tar.gz \ + && cd openssl-$OPENSSL_VER/ \ + && ./config \ + && THREADS=8 \ + && make -j$THREADS \ + && make test \ + && make install -j$THREADS + + +# -------------=== common/cpp build ===------------- + +#Build common/cpp intermediate docker image +FROM ubuntu:bionic as common_cpp_image + +RUN apt-get update \ + && apt-get install -y -q \ + pkg-config \ + cmake \ + make + + +# Copy openssl build artifacts from openssl_image +COPY --from=openssl_image /usr/local/ssl /usr/local/ssl +COPY --from=openssl_image /usr/local/bin /usr/local/bin +COPY --from=openssl_image /usr/local/include /usr/local/include +COPY --from=openssl_image /usr/local/lib /usr/local/lib + +RUN ldconfig \ + && ln -s /etc/ssl/certs/* /usr/local/ssl/certs/ + +ENV TCF_HOME=/project/avalon + +COPY ./common/cpp /project/avalon/common/cpp + +WORKDIR /project/avalon/common/cpp + +RUN mkdir -p build \ + && cd build \ + && cmake .. -DUNTRUSTED_ONLY=1 \ + && make + + +# -------------=== common/python build ===------------- + +#Build common/python intermediate docker image +FROM python_image as common_python_image + +COPY VERSION /project/avalon/ +COPY ./bin /project/avalon/bin + +ENV TCF_HOME=/project/avalon + +COPY ./common/python /project/avalon/common/python + +WORKDIR /project/avalon/common/python + +RUN echo "Building Avalon Common Python\n" \ + && make + + +# -------------=== common/verify_report_utils build ===------------- + +#Build common/verify_report_utils intermediate docker image +FROM python_image as verify_report_utils + +RUN apt-get update \ + && apt-get install -y -q \ + swig + +# Copy openssl build artifacts from openssl_image +COPY --from=openssl_image /usr/local/ssl /usr/local/ssl +COPY --from=openssl_image /usr/local/bin /usr/local/bin +COPY --from=openssl_image /usr/local/include /usr/local/include +COPY --from=openssl_image /usr/local/lib /usr/local/lib + +RUN ldconfig \ + && ln -s /etc/ssl/certs/* /usr/local/ssl/certs/ + +COPY --from=common_cpp_image /project/avalon/common/cpp/build /project/avalon/common/cpp/build +COPY VERSION /project/avalon/ +COPY ./bin /project/avalon/bin +COPY ./common/cpp /project/avalon/common/cpp + +ENV TCF_HOME=/project/avalon + +COPY ./common/verify_report_utils/ias /project/avalon/common/verify_report_utils/ias + +WORKDIR /project/avalon/common/verify_report_utils/ias + +RUN echo "Building Avalon Verify Report Utils\n" \ + && make + + +# Build image for attestation version service +FROM python_image as build_avs + +#Environment setup +ENV TCF_HOME=/project/avalon + +WORKDIR /project/avalon/ + +COPY ./avs /project/avalon/avs +COPY VERSION /project/avalon/ +COPY ./bin /project/avalon/bin + +WORKDIR /project/avalon/avs + +RUN echo "Building Avalon Attestation Verification service\n" \ + && make + + +# Build Final image and install dependent modules +FROM base_image as final_image + +COPY --from=common_python_image /project/avalon/common/python/dist/*.whl dist/ +COPY --from=verify_report_utils /project/avalon/common/verify_report_utils/ias/dist/*.whl dist/ +COPY --from=build_avs /project/avalon/avs/dist/*.whl dist/ + +# Installing wheel file requires python3-pip package. +# But python3-pip package will increase size of final docker image. +# So remove python3-pip package and dependencies after installing wheel file. +RUN apt-get update \ + && apt-get install -y -q python3-pip \ + && echo "Install Attestation verification service \n" \ + && pip3 install dist/*.whl \ + && pip3 install json-rpc \ + && echo "Remove unused packages from image\n" \ + && apt-get autoremove --purge -y -q python3-pip \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + diff --git a/avs/Makefile b/avs/Makefile new file mode 100644 index 000000000..9a4bf3e10 --- /dev/null +++ b/avs/Makefile @@ -0,0 +1,47 @@ +# Copyright 2020 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +PY_VERSION=${shell python3 --version | sed 's/Python \(3\.[0-9]\).*/\1/' | cut -b 1} +MOD_VERSION=${shell ../bin/get_version} + +WHEEL_FILE=dist/attestation_verification_service-${MOD_VERSION}-py${PY_VERSION}-none-any.whl + +all : $(WHEEL_FILE) + +$(WHEEL_FILE): build_ext + @echo Build Distribution + python3 setup.py bdist_wheel + +build_ext: + @echo Build build_ext + python3 setup.py build_ext + +build : + mkdir $@ + +install: + @echo INSTALLING WHEEL FILE ================= + pip3 install $(WHEEL_FILE) + +clean: + if pip3 uninstall --yes $(WHEEL_FILE); then \ + echo UNINSTALLED $(WHEEL_FILE); fi + rm -rf build deps dist *.egg-info + find . -iname '*.pyc' -delete + find . -iname '__pycache__' -delete + + +.PHONY : all +.PHONY : clean +.PHONY : install diff --git a/avs/attestation_verification_service/__init__.py b/avs/attestation_verification_service/__init__.py new file mode 100644 index 000000000..f046bc81c --- /dev/null +++ b/avs/attestation_verification_service/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2020 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +all = [] diff --git a/avs/attestation_verification_service/verification_service.py b/avs/attestation_verification_service/verification_service.py new file mode 100644 index 000000000..2b94427aa --- /dev/null +++ b/avs/attestation_verification_service/verification_service.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 + +# Copyright 2020 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging +import json +import sys +import argparse +from listener.base_jrpc_listener import BaseJRPCListener, parse_bind_url +import verify_report.verify_attestation_report as attestation_util +from jsonrpc.exceptions import JSONRPCDispatchException + +logging.basicConfig(format="%(asctime)s - %(levelname)s - %(message)s", + level=logging.INFO) + + +class VerificationService(BaseJRPCListener): + """ + Listener to handle requests from Clients to verify + attestion verification request to verify report/quote + """ + + # The isLeaf instance variable describes whether a resource will have + # children and only leaf resources get rendered. VerificationService + # Listeneris a leaf. + # node in the derivation tree and hence isLeaf is required. + isLeaf = True + + def __init__(self): + """ + Pass through the rpc methods to the + constructor of the BaseJRPCListener. + Parameters : + rpc_methods - An array of RPC methods to which requests will + be dispatched. + """ + self.VERIFICATION_SUCCESS = 0 + self.VERIFICATION_FAILED = 1 + rpc_methods = [ + self.VerifyIASAttestationReport, + self.VerifyDCAPQuote + ] + super().__init__(rpc_methods) + + def VerifyIASAttestationReport(self, **params): + """ + RPC handler method registered with attestation + verification service to verify IAS AVR. + Parameters : + @param params - variable-length argument list + Returns : + @returns response - A jrpc response + """ + try: + input_json_str = params["raw"] + input_value_json = json.loads(input_json_str) + status = attestation_util.verify_ias_attestation_report( + input_value_json["params"]) + if status: + msg = "IAS attestation report verification success" + logging.info(msg) + code = self.VERIFICATION_SUCCESS + else: + msg = "IAS attestation report verification failed" + logging.error(msg) + code = self.VERIFICATION_FAILED + except Exception as ex: + msg = "Verifying attestation report FAILED with " + \ + str(ex) + logging.error(msg) + code = self.VERIFICATION_FAILED + + if code: + raise JSONRPCDispatchException( + code, + msg + ) + else: + return { + "code": code, + "message": msg + } + + def VerifyDCAPQuote(self, **params): + """ + RPC handler method registered with attestation + verification service to verify DCAP quote. + Parameters : + @param params - variable-length argument list + Returns : + @returns response - A jrpc response + """ + #TODO: To be implemented + return None + + +def main(args=None): + parser = argparse.ArgumentParser() + parser.add_argument( '-b', + '--bind', help='URI to listen for requests ', type=str) + options = parser.parse_args(args) + if options.bind: + host_name, port = parse_bind_url(options.bind) + else: + logging.error("Missing bind parameter!") + sys.exit(-1) + listener = VerificationService() + listener.start(host_name, port) + logging.info("Started attestation verification service listener") + +main() diff --git a/avs/setup.py b/avs/setup.py new file mode 100644 index 000000000..ba212128b --- /dev/null +++ b/avs/setup.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# Copyright 2018-2020 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import sys +import subprocess + +# This should only be run with python3 +import sys +if sys.version_info[0] < 3: + print('ERROR: must run with python3') + sys.exit(1) + +from setuptools import setup, find_packages + +tcf_root_dir = os.environ.get('TCF_HOME', '../') +version = subprocess.check_output( + os.path.join(tcf_root_dir, 'bin/get_version')).decode('ascii').strip() + +setup(name='attestation_verification_service', + version = version, + description = 'Avalon SGX Attestation Verification service', + author = 'Hyperledger Avalon', + url = 'https://github.com/hyperledger/avalon', + packages = find_packages(), + install_requires = [ + 'requests' + ], + ext_modules = [], + data_files = [], + entry_points = { + 'console_scripts': + ['attestation_verification_service = attestation_verification_service.verification_service:main'] + } +) diff --git a/ci/docker-compose-direct-model.yaml b/ci/docker-compose-direct-model.yaml index 98fdd89e4..ebe1e15a7 100644 --- a/ci/docker-compose-direct-model.yaml +++ b/ci/docker-compose-direct-model.yaml @@ -28,10 +28,11 @@ services: - DISTRO=$DISTRO working_dir: "/project/avalon/" entrypoint: "bash -c \"\ - ./tools/run_tests.sh -l avalon-listener \"" + ./tools/run_tests.sh -l avalon-listener -a avalon-avs \"" depends_on: - avalon-enclave-manager - avalon-listener + - avalon-avs avalon-enclave-manager: image: avalon-enclave-manager:${ISOLATION_ID} @@ -95,3 +96,20 @@ services: depends_on: - avalon-lmdb + avalon-avs: + image: avalon-avs:${ISOLATION_ID} + build: + context: .. + dockerfile: ./avs/Dockerfile + args: + - http_proxy + - https_proxy + - no_proxy + expose: + - 6090 + command: | + bash -c " + attestation_verification_service --bind http://avalon-avs:6090 + tail -f /dev/null + " + diff --git a/common/crypto_utils/avalon_crypto_utils/verify_attestation_report.py b/common/crypto_utils/avalon_crypto_utils/verify_attestation_report.py new file mode 100644 index 000000000..0ec23bcdb --- /dev/null +++ b/common/crypto_utils/avalon_crypto_utils/verify_attestation_report.py @@ -0,0 +1,54 @@ +# Copyright 2020 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import uuid +import logging +from http_client.http_jrpc_client import HttpJrpcClient +logger = logging.getLogger(__name__) + + +def verify_attestation_report(enclave_info, uri): + ''' + Function to verify quote status, signature of IAS attestation report + @params enclave_info - dict containing attestation report + @params uri is end point of avalon attestation service + ''' + + uri_client = HttpJrpcClient(uri) + # uuid4 generates random uuid and fetching + # field time_hi_version which is 16bits length + verify_report_req = { + "jsonrpc": "2.0", + "id": uuid.uuid4().fields[2], + "params": enclave_info, + "method": "VerifyIASAttestationReport" + } + json_request_str = json.dumps(verify_report_req) + try: + response = uri_client._postmsg(json_request_str) + except Exception as err: + logger.error( + "Exception occurred in communication with Attestation Service") + raise err + logger.info("Response from Attestation service %s", response) + + if "result" in response: + # Response has jrpc code is 0 on success and 1 on failure + if response["result"]["code"]: + return False + else: + return True + else: + return False diff --git a/common/crypto_utils/tests/run_test.sh b/common/crypto_utils/tests/run_test.sh index cd468b1d2..62757f270 100755 --- a/common/crypto_utils/tests/run_test.sh +++ b/common/crypto_utils/tests/run_test.sh @@ -64,7 +64,7 @@ elif [ $1 == "clean" ]; then cd $TCF_HOME//common/crypto_utils make clean - cd $TCF_HOME/common/verify_report_utils/ + cd $TCF_HOME/common/verify_report_utils/ias make clean cd $TCF_HOME/sdk diff --git a/common/verify_report_utils/ias/verify_report/verify_attestation_report.py b/common/verify_report_utils/ias/verify_report/verify_attestation_report.py index a9f4fba36..b967c5759 100644 --- a/common/verify_report_utils/ias/verify_report/verify_attestation_report.py +++ b/common/verify_report_utils/ias/verify_report/verify_attestation_report.py @@ -20,7 +20,7 @@ logger = logging.getLogger(__name__) -def verify_attestation_report(enclave_info): +def verify_ias_attestation_report(enclave_info): ''' Function to verify quote status, signature of IAS attestation report ''' diff --git a/docker-compose.yaml b/docker-compose.yaml index 6fb249512..86f36c48c 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -44,6 +44,7 @@ services: depends_on: - avalon-enclave-manager - avalon-listener + - avalon-avs avalon-enclave-manager: container_name: avalon-enclave-manager @@ -130,3 +131,26 @@ services: " depends_on: - avalon-lmdb + + avalon-avs: + container_name: avalon-avs + image: avalon-avs-dev + build: + context: . + dockerfile: ./avs/Dockerfile + args: + - http_proxy + - https_proxy + - no_proxy + environment: + - http_proxy + - https_proxy + - no_proxy + expose: + - 6090 + command: | + bash -c " + attestation_verification_service --bind http://avalon-avs:6090 + tail -f /dev/null + " + diff --git a/docker/Dockerfile b/docker/Dockerfile index 001489b61..9ddddef1b 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -65,78 +65,6 @@ RUN packages="ca-certificates pkg-config python3-pip make" \ fi; \ /project/avalon/scripts/install_packages -c install -q "$packages" -p "$pip_packages" -# -------------=== Build openssl_image ===------------- - -FROM $IMAGE as openssl_image -ARG DISTRO - -COPY ./scripts/install_packages /project/avalon/scripts/ - -RUN packages="ca-certificates pkg-config make wget tar"; \ - if [ "$DISTRO" = "centos" ] ; then \ - packages="$packages perl gcc"; \ - fi; \ - /project/avalon/scripts/install_packages -c install -q "$packages" - -WORKDIR /tmp - -# Build ("Untrusted") OpenSSL -RUN OPENSSL_VER=1.1.1g \ - && wget https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz \ - && tar -zxf openssl-$OPENSSL_VER.tar.gz \ - && cd openssl-$OPENSSL_VER/ \ - && ./config \ - && THREADS=8 \ - && make -j$THREADS \ - && make test \ - && make install -j$THREADS - -# Created an empty /usr/local/lib64 dir for bionic, because in case of centos -# we need to COPY /usr/local/lib64 for openssl artifacts which will fail for bionic -# as bionic doesn't have this directory. -RUN if [ "$DISTRO" = "bionic" ] ; then \ - mkdir /usr/local/lib64; \ - fi - -# -------------=== common/cpp build ===------------- - -#Build common/cpp intermediate docker image -FROM $IMAGE as common_cpp_image -ARG DISTRO -COPY ./scripts/install_packages /project/avalon/scripts/ - -RUN packages="pkg-config make cmake "; \ - if [ "$DISTRO" = "centos" ] ; then \ - packages="$packages gcc gcc-c++"; \ - fi; \ - /project/avalon/scripts/install_packages -c install -q "$packages" - -# Copy openssl build artifacts from openssl_image -COPY --from=openssl_image /usr/local/ssl /usr/local/ssl -COPY --from=openssl_image /usr/local/bin /usr/local/bin -COPY --from=openssl_image /usr/local/include /usr/local/include -COPY --from=openssl_image /usr/local/lib /usr/local/lib -# In case of openssl, artifacts are installed at /usr/local/lib64 -COPY --from=openssl_image /usr/local/lib64 /usr/local/lib64 - -RUN ldconfig \ - && ln -s /etc/ssl/certs/* /usr/local/ssl/certs/ - -ENV TCF_HOME=/project/avalon - -# For centos, /usr/local/lib64/pkgconfig/ path be included in PKG_CONFIG_PATH -ENV PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib64/pkgconfig/ - -COPY ./common/cpp /project/avalon/common/cpp - -WORKDIR /project/avalon/common/cpp - -RUN mkdir -p build \ - && cd build \ - && cmake .. -DUNTRUSTED_ONLY=1 \ - && make - - # -------------=== common/python build ===------------- #Build common/python intermediate docker image @@ -168,18 +96,6 @@ RUN packages="swig"; \ fi; \ /project/avalon/scripts/install_packages -c install -q "$packages" -# Copy openssl build artifacts from openssl_image -COPY --from=openssl_image /usr/local/ssl /usr/local/ssl -COPY --from=openssl_image /usr/local/bin /usr/local/bin -COPY --from=openssl_image /usr/local/include /usr/local/include -COPY --from=openssl_image /usr/local/lib /usr/local/lib -# In case of openssl, artifacts are installed at /usr/local/lib64 -COPY --from=openssl_image /usr/local/lib64 /usr/local/lib64 - -RUN ldconfig \ - && ln -s /etc/ssl/certs/* /usr/local/ssl/certs/ - -COPY --from=common_cpp_image /project/avalon/common/cpp/build /project/avalon/common/cpp/build COPY VERSION /project/avalon/ COPY ./bin /project/avalon/bin COPY ./common/cpp /project/avalon/common/cpp @@ -196,13 +112,6 @@ WORKDIR /project/avalon/common/crypto_utils RUN echo "Building Avalon Common Crypto Python\n" \ && make -COPY ./common/verify_report_utils/ias /project/avalon/common/verify_report_utils/ias - -WORKDIR /project/avalon/common/verify_report_utils/ias - -RUN echo "Building Avalon Verify IAS Report Utils\n" \ - && make - # -------------=== Avalon SDK build ===------------- #Build Avalon SDK intermediate docker image @@ -276,7 +185,6 @@ COPY ./sdk/avalon_sdk/connector/blockchains/ethereum/contracts /project/avalon/s # Copy Python build artifacts COPY --from=common_python_image /project/avalon/common/python/dist/*.whl dist/ COPY --from=common_crypto_utils_image /project/avalon/common/crypto_utils/dist/*.whl dist/ -COPY --from=common_crypto_utils_image /project/avalon/common/verify_report_utils/ias/dist/*.whl dist/ COPY --from=avalon_sdk_image /project/avalon/sdk/dist/*.whl dist/ # Installing wheel file requires python3-pip package. diff --git a/docker/k8s/fabric/README.md b/docker/k8s/fabric/README.md index d86a466dd..736f23cd8 100644 --- a/docker/k8s/fabric/README.md +++ b/docker/k8s/fabric/README.md @@ -62,7 +62,7 @@ This serves as a playground to setup k8s cluster for Avalon Fabric proxy model. ```bash cd examples/apps/generic_client ./generic_client.py -b fabric --workload_id "echo-result" --in_data "Hello" \ - --worker_id "singleton-worker-1" + --worker_id "singleton-worker-1" -avs "http://avalon-avs:6090" ``` NOTE: `worker_id` should match with worker id of singleton enclave manager. diff --git a/docker/lb/README.md b/docker/lb/README.md index 97f106623..7016cee57 100644 --- a/docker/lb/README.md +++ b/docker/lb/README.md @@ -24,7 +24,8 @@ coming from clients to one of the many avalon-listeners running in backend. # run the transaction cd examples/apps/generic_client - ./generic_client.py --uri "http://avalon-lb-nginx:9947" --workload_id "echo-result" --in_data "Hello" --worker_id "singleton-worker-1" + ./generic_client.py --uri "http://avalon-lb-nginx:9947" --workload_id "echo-result" --in_data "Hello" --worker_id "singleton-worker-1" \ + -avs "http://avalon-avs:6090" ``` @@ -54,5 +55,6 @@ coming from clients to one of the many avalon-listeners running in backend. # run the transaction cd examples/apps/generic_client - ./generic_client.py --uri "http://avalon-lb-haproxy:9947" --workload_id "echo-result" --in_data "Hello" --worker_id "singleton-worker-1" + ./generic_client.py --uri "http://avalon-lb-haproxy:9947" --workload_id "echo-result" --in_data "Hello" --worker_id "singleton-worker-1" \ + -avs "http://avalon-avs:6090" ``` diff --git a/docs/TestingBesuProxyModel.rst b/docs/TestingBesuProxyModel.rst index 41d00469d..48f188237 100644 --- a/docs/TestingBesuProxyModel.rst +++ b/docs/TestingBesuProxyModel.rst @@ -110,7 +110,7 @@ To run Besu with Hyperledger Avalon, follow these steps: docker exec -it avalon-shell bash cd examples/apps/generic_client/ ./generic_client.py -b ethereum --workload_id "echo-result" -o --in_data "Hello" \ - --worker_id "singleton-worker-1" + --worker_id "singleton-worker-1" -avs "http://avalon-avs:6090" NOTE: ``worker_id`` should match with worker id of singleton enclave manager or target worker pool. This ``worker_id`` can either be the command line argument passed in to the enclave manager (Singleton or KME) diff --git a/docs/TestingFabricProxyModel.rst b/docs/TestingFabricProxyModel.rst index 7b189af4e..50bed5513 100644 --- a/docs/TestingFabricProxyModel.rst +++ b/docs/TestingFabricProxyModel.rst @@ -81,7 +81,7 @@ follow these steps: docker exec -it avalon-shell bash cd examples/apps/generic_client/ ./generic_client.py -b fabric --workload_id "echo-result" --in_data "Hello" -o \ - --worker_id "singleton-worker-1" + --worker_id "singleton-worker-1" -avs "http://avalon-avs:6090" NOTE: ``worker_id`` should match with worker id of singleton enclave manager or target worker pool. This ``worker_id`` can either be the command line argument passed in to the enclave manager (Singleton or KME) @@ -146,7 +146,7 @@ requires below changes. docker exec -it avalon-shell bash cd examples/apps/generic_client/ ./generic_client.py -b fabric --workload_id "echo-result" --in_data "Hello" -o \ - --worker_id "singleton-worker-1" + --worker_id "singleton-worker-1" -avs "http://avalon-avs:6090" Troubleshooting diff --git a/docs/TestingGanacheProxyModel.rst b/docs/TestingGanacheProxyModel.rst index d45ccba18..570e84a1c 100644 --- a/docs/TestingGanacheProxyModel.rst +++ b/docs/TestingGanacheProxyModel.rst @@ -111,7 +111,7 @@ To run Ganache with Hyperledger Avalon, follow these steps: docker exec -it avalon-shell bash cd examples/apps/generic_client/ ./generic_client.py -b ethereum --workload_id "echo-result" -o --in_data "Hello" \ - --worker_id "singleton-worker-1" + --worker_id "singleton-worker-1" -avs "http://avalon-avs:6090" NOTE: ``worker_id`` should match with worker id of singleton enclave manager or target worker pool. This ``worker_id`` can either be the command line argument passed in to the enclave manager (Singleton or KME) diff --git a/docs/graphene-workload-tutorial/README.md b/docs/graphene-workload-tutorial/README.md index 7353d9bd9..4996d606e 100644 --- a/docs/graphene-workload-tutorial/README.md +++ b/docs/graphene-workload-tutorial/README.md @@ -39,7 +39,7 @@ docker-compose -f docker-compose.yaml -f docker/compose/avalon-graphene.yaml up You could then test it by getting into the `avalon-shell` container and invoking the generic client. For example, run the generic client from `/project/avalon/examples/app/generic_client` as - ``` ./generic_client.py --uri "http://avalon-listener:1947" -w "graphene-worker-1" --workload_id \ -"python-palindrome" --in_data "God save Eva s dog" -o +"python-palindrome" --in_data "God save Eva s dog" -o -avs "http://avalon-avs:6090" ``` ### Running with Graphene SGX diff --git a/docs/workload-tutorial/README.md b/docs/workload-tutorial/README.md index 235dae2c2..8d645a44a 100644 --- a/docs/workload-tutorial/README.md +++ b/docs/workload-tutorial/README.md @@ -208,7 +208,7 @@ will be created next in [Phase 2](#phase2). ```bash examples/apps/generic_client/generic_client.py -o \ --workload_id "hello-world" --in_data "Dan" \ - --worker_id "kme-worker-1" + --worker_id "kme-worker-1" -avs "http://localhost:6090" ``` @@ -220,7 +220,7 @@ will be created next in [Phase 2](#phase2). examples/apps/generic_client/generic_client.py -o \ --uri "http://avalon-listener:1947" \ --workload_id "hello-world" --in_data "Dan" \ - --worker_id "kme-worker-1" + --worker_id "kme-worker-1" -avs "http://avalon-avs:6090" ``` @@ -307,7 +307,7 @@ In this example we name the worker-specific function `ProcessHelloWorld()`. ```bash examples/apps/generic_client/generic_client.py -o \ --workload_id "hello-world" --in_data "Jane" "Dan" \ - --worker_id "kme-worker-1" + --worker_id "kme-worker-1" -avs "http://localhost:6090" ``` If you are running Docker, run the utility from a Docker shell @@ -318,7 +318,7 @@ In this example we name the worker-specific function `ProcessHelloWorld()`. examples/apps/generic_client/generic_client.py -o \ --uri "http://avalon-listener:1947" \ --workload_id "hello-world" --in_data "Jane" "Dan" \ - --worker_id "kme-worker-1" + --worker_id "kme-worker-1" -avs "http://avalon-avs:6090" ``` * The Hello World worker should return a string @@ -494,7 +494,7 @@ to ```bash examples/apps/generic_client/generic_client.py -o \ --workload_id "hello-world" --in_data "jack" \ - --worker_id "kme-worker-1" + --worker_id "kme-worker-1" -avs "http:localhostt:6090" ``` If you are running Docker, run the utility from the Docker shell @@ -505,7 +505,7 @@ to examples/apps/generic_client/generic_client.py -o \ --uri "http://avalon-listener:1947" \ --workload_id "hello-world" --in_data "jack" \ - --worker_id "kme-worker-1" + --worker_id "kme-worker-1" -avs "http://avalon-avs:6090" ``` * The Hello World worker should return the string @@ -551,7 +551,7 @@ to examples/apps/generic_client/generic_client.py -o \ --workload_id "hello-world" --in_data \ "jack:8342EFBE7C379231A4E03C80E5BA1AC9E8ACBC5338976CE6146431D8CBF2318D" \ - --worker_id "kme-worker-1" + --worker_id "kme-worker-1" -avs "http://localhost:6090" ``` For Docker: ```bash @@ -560,7 +560,7 @@ to --uri "http://avalon-listener:1947" \ --workload_id "hello-world" --in_data \ "jack:8342EFBE7C379231A4E03C80E5BA1AC9E8ACBC5338976CE6146431D8CBF2318D" \ - --worker_id "kme-worker-1" + --worker_id "kme-worker-1" -avs "http://avalon-avs:6090" ``` * The Hello World worker should return the string `Hello , your result is ` diff --git a/examples/apps/generic_client/README.md b/examples/apps/generic_client/README.md index 1cff35f1f..b4c98cc46 100644 --- a/examples/apps/generic_client/README.md +++ b/examples/apps/generic_client/README.md @@ -93,7 +93,8 @@ worker requests on the command line. ### Echo workload using a URI ```bash ./generic_client.py -o --uri "http://localhost:1947" \ - --workload_id "echo-result" --in_data "Hello" --worker_id "singleton-worker-1" + --workload_id "echo-result" --in_data "Hello" --worker_id "singleton-worker-1" \ + -avs "http://localhost:6090" ``` NOTE: `worker_id` should match with worker id of singleton enclave manager. @@ -104,13 +105,14 @@ in the absence of command line argument, worker_id in Add or change the `--uri` parameter if using Docker: ```bash ./generic_client.py -o --uri "http://avalon-listener:1947" \ - --workload_id "echo-result" --in_data "Hello" --worker_id "singleton-worker-1" + --workload_id "echo-result" --in_data "Hello" --worker_id "singleton-worker-1" \ + -avs "http://avalon-avs:6090" ``` Or omit the URI if you use the default URI (standalone mode) : ```bash ./generic_client.py -o --workload_id "echo-result" --in_data "Hello" \ - --worker_id "singleton-worker-1" + --worker_id "singleton-worker-1" -avs "http://localhost:6090" ``` ### Heart disease eval workload using a URI @@ -119,7 +121,7 @@ Standalone mode (no Docker): ./generic_client.py -o --uri "http://localhost:1947" \ --workload_id "heart-disease-eval" \ --in_data "Data: 25 10 1 67 102 125 1 95 5 10 1 11 36 1" \ - --worker_id "singleton-worker-1" + --worker_id "singleton-worker-1" -avs "http://localhost:6090" ``` With Docker: @@ -127,7 +129,7 @@ With Docker: ./generic_client.py -o --uri "http://avalon-listener:1947" \ --workload_id "heart-disease-eval" \ --in_data "Data: 25 10 1 67 102 125 1 95 5 10 1 11 36 1" \ - --worker_id "singleton-worker-1" + --worker_id "singleton-worker-1" -avs "http://avalon-attestation-service:6090" ``` ### Echo workload using registry listing smart contract address @@ -135,13 +137,13 @@ With Docker: ./generic_client.py -o \ --address "0x9Be28B132aeE1b2c5A1C50529a636cEd807842cd" --mode "listing" \ --workload_id "echo-result" --in_data "Hello" \ - --worker_id "singleton-worker-1" + --worker_id "singleton-worker-1" -avs "http://localhost:6090" ``` ### Echo workload with input data as unencrypted plain text ```bash ./generic_client.py -o --uri "http://localhost:1947" \ --workload_id "echo-result" --in_data "Hello" -p \ - --worker_id "singleton-worker-1" + --worker_id "singleton-worker-1" -avs "http://localhost:6090" ``` diff --git a/examples/apps/generic_client/base_generic_client.py b/examples/apps/generic_client/base_generic_client.py index 7529cf6c5..4a8d9b91e 100644 --- a/examples/apps/generic_client/base_generic_client.py +++ b/examples/apps/generic_client/base_generic_client.py @@ -18,7 +18,7 @@ from avalon_sdk.work_order.work_order_params import WorkOrderParams import avalon_crypto_utils.worker_encryption as worker_encryption import avalon_crypto_utils.worker_signing as worker_signing -import verify_report.verify_attestation_report as attestation_util +import avalon_crypto_utils.verify_attestation_report as attestation_util from error_code.error_status import SignatureStatus logging.basicConfig( @@ -41,10 +41,14 @@ def __init__(self): self.encrypt = worker_encryption.WorkerEncrypt() self.signer = worker_signing.WorkerSign() - def do_worker_verification(self, worker_obj): + def do_worker_verification(self, worker_obj, uri): """ Do worker verification on proof data if it exists Proof data exists in SGX hardware mode. + @params worker_obj worker object with attestation report + @params uri end point of avalon attestation verification service + @returns True on verification success + False on verification failed """ encryption_key_signature = worker_obj.encryption_key_signature if encryption_key_signature is not None: @@ -76,7 +80,7 @@ def do_worker_verification(self, worker_obj): logging.info("Perform verification of attestation report") verify_report_status = attestation_util.verify_attestation_report( - enclave_info) + enclave_info, uri) if verify_report_status is False: logging.error("Verification of enclave sign-up info failed") return False diff --git a/examples/apps/generic_client/generic_client.py b/examples/apps/generic_client/generic_client.py index 06aa7b2ae..c770a48be 100755 --- a/examples/apps/generic_client/generic_client.py +++ b/examples/apps/generic_client/generic_client.py @@ -110,6 +110,9 @@ def __init__(self, args): # requester signature for work order requests self._requester_signature = options.requester_signature + # Avalon attestation verification service uri + self._avs_uri = options.attestation_verification_service + logging.info("******* Hyperledger Avalon Generic client *******") # mode should be one of listing or registry (default) @@ -182,6 +185,10 @@ def _parse_command_line(self, args): "-rs", "--requester_signature", help="Enable requester signature for work order requests", action="store_true") + parser.add_argument( + "-avs", "--attestation_verification_service", + help="Uri of avalon attestation verification service", + type=str) options = parser.parse_args(args) return options @@ -238,6 +245,9 @@ def uri(self): def mode(self): return self._mode + def avs(self): + return self._avs_uri + def Main(args=None): parser = GenericClient(args) @@ -280,7 +290,10 @@ def Main(args=None): session_iv = encrypt.generate_iv() # Do worker verification - generic_client_obj.do_worker_verification(worker_obj) + if generic_client_obj.do_worker_verification( + worker_obj, parser.avs()) is False: + logging.error("Worker verification failed\n") + sys.exit(-1) logging.info("**********Worker details Updated with Worker ID" + "*********\n%s\n", worker_id) diff --git a/examples/apps/heart_disease_eval/README.md b/examples/apps/heart_disease_eval/README.md index 0789fe415..dff309ef0 100644 --- a/examples/apps/heart_disease_eval/README.md +++ b/examples/apps/heart_disease_eval/README.md @@ -46,14 +46,14 @@ requests on the command line. 5. If you are running with Docker, then run this in Terminal 2: ``` bash ./generic_client.py --workload_id "heart-disease-eval" \ - --in_data "Data: 25 10 1 67 102 125 1 95 5 10 1 11 36 1" -o + --in_data "Data: 25 10 1 67 102 125 1 95 5 10 1 11 36 1" -o -avs "http://avalon-avs:6090" ``` If you are running standalone, then run this in Terminal 2: ``` bash ./generic_client.py --workload_id "heart-disease-eval" \ --uri "http://localhost:1947/" \ - --in_data "Data: 25 10 1 67 102 125 1 95 5 10 1 11 36 1" -o + --in_data "Data: 25 10 1 67 102 125 1 95 5 10 1 11 36 1" -o -avs "http://localhost:6090" ``` 6. The data will be submitted to the worker and the results will appear diff --git a/sdk/TestingContracts.md b/sdk/TestingContracts.md index 8d4fa0516..23944a2fe 100644 --- a/sdk/TestingContracts.md +++ b/sdk/TestingContracts.md @@ -85,5 +85,5 @@ ```bash cd $TCF_HOME/examples/apps/generic_client/ ./generic_client.py -o --uri "http://localhost:1947" \ - --workload_id "echo-result" --in_data "Hello" --worker_id "singleton-worker-1" + --workload_id "echo-result" --in_data "Hello" --worker_id "singleton-worker-1" -avs "http://localhost:6090" ``` diff --git a/tests/Demo.py b/tests/Demo.py index 2bd2bb90c..1fa62b56c 100644 --- a/tests/Demo.py +++ b/tests/Demo.py @@ -27,6 +27,7 @@ import avalon_crypto_utils.worker_signing as worker_signing import avalon_crypto_utils.worker_hash as worker_hash import avalon_crypto_utils.crypto_utility as crypto_utility +import avalon_crypto_utils.verify_attestation_report as attestation_util import avalon_sdk.worker.worker_details as worker import utility.file_utils as futils @@ -165,6 +166,24 @@ def local_main(config): # Worker details are loaded into Worker_Obj if "WorkerRetrieve" in input_json_str and "result" in response: worker_obj.load_worker(response["result"]["details"]) + if not worker_obj.proof_data: + LOGGER.info("Proof data is empty. " + + "Skipping verification of attestation report") + else: + # Construct enclave sign-up info json + enclave_info = { + 'verifying_key': worker_obj.verification_key, + 'encryption_key': worker_obj.encryption_key, + 'proof_data': worker_obj.proof_data, + 'enclave_persistent_id': '' + } + + if attestation_util.verify_attestation_report( + enclave_info, avs_uri): + LOGGER.info("Worker verification success") + else: + LOGGER.error("Worker verification failed") + exit(1) # ----------------------------------------------------------------- # Poll for "WorkOrderGetResult" and break when you get the result @@ -225,6 +244,7 @@ def parse_command_line(config, args): global encrypted_session_key global session_iv global requester_nonce + global avs_uri parser = argparse.ArgumentParser() parser.add_argument("--logfile", help="Name of the log file. " + @@ -239,6 +259,8 @@ def parse_command_line(config, args): default=[]) parser.add_argument("-c", "--connect_uri", help="URI to send requests to", type=str, default=[]) + parser.add_argument("-a", "--avs_uri", + help="URI to send requests to", type=str, default=[]) parser.add_argument( "output_file", help="JSON output file name", @@ -266,6 +288,13 @@ def parse_command_line(config, args): else: LOGGER.error("ERROR: Please enter the server URI") + if options.avs_uri: + avs_uri = options.avs_uri + else: + LOGGER.error("ERROR: Please enter the " + "attestation verification service URI") + exit(1) + if options.input_dir: LOGGER.info("Load Json Directory from %s", options.input_dir) input_json_dir = options.input_dir diff --git a/tests/test_ias_attestation.py b/tests/test_ias_attestation.py index a210c7f41..b6fd50685 100755 --- a/tests/test_ias_attestation.py +++ b/tests/test_ias_attestation.py @@ -29,7 +29,7 @@ import avalon_sdk.worker.worker_details as worker from avalon_sdk.work_order.work_order_params import WorkOrderParams from avalon_sdk.connector.direct.avalon_direct_client import AvalonDirectClient -import verify_report.verify_attestation_report as attestation_util +import avalon_crypto_utils.verify_attestation_report as attestation_util from error_code.error_status import WorkOrderStatus # Remove duplicate loggers diff --git a/tools/clean.sh b/tools/clean.sh index 6cad95b5f..27633ff81 100755 --- a/tools/clean.sh +++ b/tools/clean.sh @@ -78,7 +78,7 @@ cd $SRCDIR/common/crypto_utils make clean # --------------- VERIFY REPORT UTILS --------------- -cd $SRCDIR/common/verify_report_utils/ +cd $SRCDIR/common/verify_report_utils/ias make clean # --------------- SDK --------------- diff --git a/tools/rebuild.sh b/tools/rebuild.sh index cff2ac790..4fc3ed52e 100755 --- a/tools/rebuild.sh +++ b/tools/rebuild.sh @@ -214,7 +214,7 @@ try make "-j$NUM_CORES" try make install yell --------------- COMMON VERIFY REPORT UTILS PYTHON --------------- -cd $TCF_HOME/common/verify_report_utils/ || error_exit "Failed to change to the directory" +cd $TCF_HOME/common/verify_report_utils/ias || error_exit "Failed to change to the directory" try make "-j$NUM_CORES" try make install diff --git a/tools/run_proxy_model_tests.sh b/tools/run_proxy_model_tests.sh index 794b4f862..015935b96 100755 --- a/tools/run_proxy_model_tests.sh +++ b/tools/run_proxy_model_tests.sh @@ -43,14 +43,15 @@ yell "Start testing fabric generic client for echo result workload ............. yell "#------------------------------------------------------------------------------------------------" try $generic_client_path/generic_client.py --blockchain fabric \ --workload_id "echo-result" \ - --in_data "Hello Fabric proxy model" -o --worker_id $WORKER_ID + --in_data "Hello Fabric proxy model" -o --worker_id $WORKER_ID \ + -avs "http://avalon-avs:6090" yell "Start testing fabric generic client for heart disease eval workload ................" yell "#------------------------------------------------------------------------------------------------" try $generic_client_path/generic_client.py --blockchain fabric \ --workload_id "heart-disease-eval" \ --in_data "Data: 25 10 1 67 102 125 1 95 5 10 1 11 36 1" -o \ - --worker_id $WORKER_ID + --worker_id $WORKER_ID -avs "http://avalon-avs:6090" yell "#------------------------------------------------------------------------------------------------" yell "#------------------------------------------------------------------------------------------------" diff --git a/tools/run_tests.sh b/tools/run_tests.sh index 783f1642d..d49b2a7fe 100755 --- a/tools/run_tests.sh +++ b/tools/run_tests.sh @@ -27,28 +27,36 @@ generic_client_path="${TCF_HOME}/examples/apps/generic_client" # Read Listener port from config file listener_port=`grep listener_port ${TCF_HOME}/config/tcs_config.toml | awk {'print $3'}` LISTENER_URL="localhost" +ATTESTATION_VERIFICATION_SERVICE="localhost" # worker id should match with worker id of singleton enclave manager WORKER_ID="singleton-worker-1" -while getopts "l:lh" OPTCHAR ; do - case $OPTCHAR in - l ) - LISTENER_URL=$OPTARG +while getopts ":l:a:h" OPTCHAR ; do + echo "Processing $OPTCHAR : OPTIND is $OPTIND" + case "$OPTCHAR" in + l) + LISTENER_URL="$OPTARG" ;; - \?|h ) + a) + ATTESTATION_VERIFICATION_SERVICE="$OPTARG" + ;; + \?|h) BN=$(basename $0) echo "$BN: Run tests for Hyperledger Avalon" 1>&2 - echo "Usage: $BN [-l|-h|-?]" 1>&2 + echo "Usage: $BN [-l|-a|-h|-?]" 1>&2 echo "Where:" 1>&2 echo " -l specify the Listener service name" 1>&2 + echo " -a specify the attestation verification service name" 1>&2 echo " -? or -h print usage information" 1>&2 echo "Examples:" 1>&2 - echo " $BN -l avalon-listener" 1>&2 + echo " $BN -l avalon-listener -a avalon-avs" 1>&2 exit 2 ;; esac done -shift `expr $OPTIND - 1` +echo "Out of the getopts loop. OPTIND is now $OPTIND" +echo "LISTENER_URL $LISTENER_URL" +shift $OPTIND-1 yell() { echo "$0: $*" >&2; @@ -90,7 +98,8 @@ do try python3 ${TCF_HOME}/tests/Demo.py \ --logfile __screen__ --loglevel warn \ --input_dir ${TCF_HOME}/tests/$folder/ \ - --connect_uri "http://$LISTENER_URL:$listener_port" work_orders/output.json > /dev/null + --connect_uri "http://$LISTENER_URL:$listener_port" \ + --avs_uri "http://$ATTESTATION_VERIFICATION_SERVICE:6090" work_orders/output.json > /dev/null yell "#------------------------------------------------------------------------------------------------" yell "#------------------------------------------------------------------------------------------------" @@ -99,18 +108,20 @@ done yell "Start testing generic client for echo workload ................" yell "#------------------------------------------------------------------------------------------------" try $generic_client_path/generic_client.py --uri "http://$LISTENER_URL:1947" \ - --workload_id "echo-result" --in_data "Hello" --worker_id $WORKER_ID + --workload_id "echo-result" --in_data "Hello" --worker_id $WORKER_ID \ + -avs "http://$ATTESTATION_VERIFICATION_SERVICE:6090" yell "Start testing generic client for heart disease eval workload ................" yell "#------------------------------------------------------------------------------------------------" try $generic_client_path/generic_client.py --uri "http://$LISTENER_URL:1947" \ --workload_id "heart-disease-eval" \ - --in_data "Data: 25 10 1 67 102 125 1 95 5 10 1 11 36 1" --worker_id $WORKER_ID - + --in_data "Data: 25 10 1 67 102 125 1 95 5 10 1 11 36 1" --worker_id $WORKER_ID \ + -avs "http://$ATTESTATION_VERIFICATION_SERVICE:6090" yell "Start testing generic client with input data as plain text................" yell "#------------------------------------------------------------------------------------------------" try $generic_client_path/generic_client.py --uri "http://$LISTENER_URL:1947" \ - --workload_id "echo-result" --in_data "Hello" -p --worker_id $WORKER_ID + --workload_id "echo-result" --in_data "Hello" -p --worker_id $WORKER_ID \ + -avs "http://$ATTESTATION_VERIFICATION_SERVICE:6090" yell "#------------------------------------------------------------------------------------------------" yell "#------------------------------------------------------------------------------------------------"