diff --git a/.env.example b/.env.example index bbb9617..476d3ad 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,8 @@ PARTY_1_PROJECT=pprl-party-1 +PARTY_1_KEY_VERSION=1 + PARTY_2_PROJECT=pprl-party-2 +PARTY_2_KEY_VERSION=1 WORKLOAD_AUTHOR_PROJECT=pprl-party-1 WORKLOAD_AUTHOR_PROJECT_REGION=europe-west2 diff --git a/scripts/06-tear-down-operator.sh b/scripts/06-tear-down-operator.sh new file mode 100644 index 0000000..61e44f6 --- /dev/null +++ b/scripts/06-tear-down-operator.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# +# Tears down all billable resources for the workload operator. + +echo "Loading functions and environment variables..." +source common.sh + +set_gcp_project $WORKLOAD_OPERATOR_PROJECT + +echo "Deleting workload virtual machine..." +gcloud compute instances delete \ + projects/$WORKLOAD_OPERATOR_PROJECT/zones/$WORKLOAD_OPERATOR_PROJECT_ZONE/instances/pprl-cvm + +delete_storage_bucket $ATTESTATION_BUCKET + +delete_service_account $WORKLOAD_SERVICE_ACCOUNT_EMAIL diff --git a/scripts/06-tear-down.sh b/scripts/06-tear-down.sh deleted file mode 100644 index 2992bed..0000000 --- a/scripts/06-tear-down.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -set -e -set -o pipefail - -# This script sets up the server architecture for linkage on GCP - -## Load in our environment variables -echo "Loading environment variables..." -export $(grep "^PROJECT" .env.admin | xargs -0) -export PROJECT_PARTIES=($PROJECT_PARTY_1 $PROJECT_PARTY_2) -export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_NAME --format "value(projectNumber)") -export SERVICE_DOMAIN=$PROJECT_NAME.iam.gserviceaccount.com -export KEYRINGS_LOCATION=projects/$PROJECT_NAME/locations/$PROJECT_REGION/keyRings - -# Delete compute instance -echo "Y" | gcloud compute instances delete projects/$PROJECT_NAME/zones/$PROJECT_REGION/instances/pprl-tee - -# (option) Delete docker repo and any images -echo "Y" | gcloud artifacts repositories delete pprl-repo --location=$PROJECT_REGION - -# Delete service accounts - -# Delete keys - -# (option) Delete storage buckets - - -# Delete workload identity pools and any attestation verifiers diff --git a/scripts/07-tear-down-author.sh b/scripts/07-tear-down-author.sh new file mode 100644 index 0000000..622263a --- /dev/null +++ b/scripts/07-tear-down-author.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# +# Tears down all billable resources for the workload author. + +echo "Loading functions and environment variables..." +source common.sh + +set_gcp_project $WORKLOAD_AUTHOR_PROJECT + +delete_artifact_repository $ARTIFACT_REPOSITORY $WORKLOAD_AUTHOR_PROJECT_REGION diff --git a/scripts/08-tear-down-party.sh b/scripts/08-tear-down-party.sh new file mode 100644 index 0000000..7694d41 --- /dev/null +++ b/scripts/08-tear-down-party.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# +# Tears down all billable resources for the data-owning party. + +echo "Loading functions and environment variables..." +source common.sh + +export PROJECT_NAME=${1} +export PROJECT_KEY_VERSION=${2} +if [ ! $PROJECT_KEY_VERSION ]; then +do + export PROJECT_KEY_VERSION=1 +done + +set_gcp_project $PROJECT_NAME + +delete_storage_bucket $PROJECT_NAME-bucket + +destroy_kms_key_version \ + $PROJECT_NAME-akek $PROJECT_NAME-akek-kr $PROJECT_LOCATION $PROJECT_KEY_VERSION + +delete_workload_identity_pool $PROJECT_NAME-wip $PROJECT_LOCATION + +delete_service_account $PROJECT_NAME-sa@$PROJECT_NAME.iam.gserviceaccount.com diff --git a/scripts/common.sh b/scripts/common.sh index 2b12235..0522ff9 100644 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -152,18 +152,19 @@ create_kms_encryption_key() { # Key name # Keyring name # Location +# Key version ####################################### -destroy_kms_key() { +destroy_kms_key_version() { gcloud kms keys list --keyring=${2} --location=${3} --filter="PRIMARY_STATE=(ENABLED)" | grep ${1} if [[ $? -eq 0 ]]; then - gcloud kms keys versions destroy 1 --key ${1} --keyring ${2} --location ${3} + gcloud kms keys versions destroy ${4} --key ${1} --keyring ${2} --location ${3} if [[ $? -eq 0 ]]; then - echo "Key ${1} is deleted successfully." + echo "Key ${1} version ${4} deleted successfully." else - err "Failed to delete a key ${1}." + err "Failed to delete key ${1} version ${4}." fi else - echo "Key ${1} doesn't exist. Skipping the deletion of the key ${1}..." + echo "Key ${1} version ${4} doesn't exist. Skipping deletion..." fi } diff --git a/scripts/server.py b/scripts/server.py index 8424988..8a4416f 100644 --- a/scripts/server.py +++ b/scripts/server.py @@ -30,8 +30,10 @@ def load_environment_variables(path: None | str = None) -> tuple[str, str, str, Name of the second party. location : str Location of the workload identity pools and keyrings. - version : str - Version of the key encryption keys. + version_1 : str + Version of the key encryption key for the first party. + version_2 : str + Version of the key encryption key for the second party. """ environ = config.load_environment(path) @@ -40,9 +42,10 @@ def load_environment_variables(path: None | str = None) -> tuple[str, str, str, party_1 = environ.get("PARTY_1_PROJECT") party_2 = environ.get("PARTY_2_PROJECT") location = environ.get("PROJECT_LOCATION", "global") - version = environ.get("PROJECT_KEY_VERSION", 1) + version_1 = environ.get("PARTY_1_KEY_VERSION", 1) + version_2 = environ.get("PARTY_2_KEY_VERSION", 1) - return operator, party_1, party_2, location, version + return operator, party_1, party_2, location, version_1, version_2 def main(): @@ -53,15 +56,17 @@ def main(): logger.setup_logging() logging.info("Logging set up.") - operator, party_1, party_2, location, version = load_environment_variables(".env") + operator, party_1, party_2, location, version_1, version_2 = load_environment_variables( + ".env" + ) parties = (party_1, party_2) logging.info("Downloading embedder...") embedder = cloud.download_embedder(parties, operator) logging.info("Preparing assets...") - data_1, dek_1 = cloud.prepare_party_assets(party_1, operator, location, version) - data_2, dek_2 = cloud.prepare_party_assets(party_2, operator, location, version) + data_1, dek_1 = prepare_party_assets(party_1, operator, location, version_1) + data_2, dek_2 = prepare_party_assets(party_2, operator, location, version_2) logging.info("Performing matching...") outputs = perform_matching(data_1, data_2, embedder) @@ -74,12 +79,13 @@ def main(): else: logging.basicConfig(encoding="utf-8", level=logging.INFO) - operator, party_1, party_2, location, version = load_environment_variables() - inpath_1, outpath_1 = local.build_local_file_paths(party_1) - inpath_2, outpath_2 = local.build_local_file_paths(party_2) - embedder = local.load_embedder() + logging.info("Setting up environment and file paths...") + operator, party_1, party_2, *_ = load_environment_variables() + inpath_1, outpath_1 = build_local_file_paths(party_1) + inpath_2, outpath_2 = build_local_file_paths(party_2) logging.info("Loading files...") + embedder = load_embedder() data_1 = pd.read_json(inpath_1) data_2 = pd.read_json(inpath_2) diff --git a/src/pprl/app/__init__.py b/src/pprl/app/__init__.py index 2db8696..0956eb1 100644 --- a/src/pprl/app/__init__.py +++ b/src/pprl/app/__init__.py @@ -29,6 +29,7 @@ def home(): environ = config.load_environment() parties = (environ.get("PARTY_1_PROJECT"), environ.get("PARTY_2_PROJECT")) app.config["env"] = environ + app.config["parties"] = parties return flask.render_template("home.html", parties=parties) @@ -109,11 +110,16 @@ def upload_to_gcp(data, embedder): """Encrypt and upload the data to GCP, then wait for results.""" app.config["submission_time"] = datetime.now(timezone.utc) - party_config = app.config.get("config") party = app.config.get("party") + environ = app.config.get("env") + + location = environ.get("PROJECT_LOCATION", "global") + + party_num = next(i + 1 for i, part in enumerate(app.config["parties"]) if party == part) + version = environ.get(f"PARTY_{party_num}_KEY_VERSION", 1) data_encrypted, dek = encryption.encrypt_data(data) - dek_encrypted = encryption.encrypt_dek(dek, party, party_config) + dek_encrypted = encryption.encrypt_dek(dek, party, location, version) app.config["dek"] = dek store = app.config.get("store") diff --git a/src/pprl/encryption.py b/src/pprl/encryption.py index 223f322..d45c3f9 100644 --- a/src/pprl/encryption.py +++ b/src/pprl/encryption.py @@ -64,7 +64,7 @@ def decrypt_data(encrypted: bytes, key: bytes) -> pd.DataFrame: def _build_key_version_path( - party: str, location: str, version: int, client: kms.KeyManagementServiceClient + party: str, location: str, version: int | str, client: kms.KeyManagementServiceClient ) -> str: """ Build a full key version path for retrieval from KMS. @@ -75,7 +75,7 @@ def _build_key_version_path( Name of the party whose key to retrieve. location : str Location of the keyring on which the key lives. - version : int + version : int | str Version of the key to retrieve. client : google.cloud.kms.KeyManagementServiceClient Connection to KMS. @@ -92,7 +92,7 @@ def _build_key_version_path( return path -def _get_public_key(party: str, location: str, version: int, **kwargs: dict) -> bytes: +def _get_public_key(party: str, location: str, version: int | str, **kwargs: dict) -> bytes: """ Get the public key from the GCP Key Management Service (KMS). @@ -102,7 +102,7 @@ def _get_public_key(party: str, location: str, version: int, **kwargs: dict) -> Name of the party. location : str Location of the keyring on which the key lives. - version : int + version : int | str Key version to use. **kwargs : dict Keyword arguments to pass when creating an instance of @@ -123,7 +123,7 @@ def _get_public_key(party: str, location: str, version: int, **kwargs: dict) -> def encrypt_dek( - dek: bytes, party: str, location: str = "global", version: int = 1, **kwargs: dict + dek: bytes, party: str, location: str = "global", version: int | str = 1, **kwargs ) -> bytes: """ Encrypt the data encryption key. @@ -139,8 +139,8 @@ def encrypt_dek( Name of the party. location : str Location of the keyring on which the key lives. - version : int - Version of the assymetric key to get from GCP. Default is 1. + version : int | str + Version of the asymmetric key to get from GCP. Default is 1. **kwargs : dict Keyword arguments to pass when creating an instance of `google.cloud.kms.KeyManagementServiceClient`. @@ -166,7 +166,7 @@ def encrypt_dek( def decrypt_dek( - encrypted: bytes, party: str, location: str = "global", version: int = 1, **kwargs + encrypted: bytes, party: str, location: str = "global", version: int | str = 1, **kwargs ) -> bytes: """ Decrypt a data encryption key using an asymmetric key held on KMS. @@ -183,8 +183,8 @@ def decrypt_dek( Name of the party whose key we are decrypting. location : str Location of the keyring on which the key lives. - version : int - Version of the assymetric key to get from GCP. Default is 1. + version : int | str + Version of the asymmetric key to get from GCP. Default is 1. **kwargs : dict Keyword arguments to pass when creating an instance of `google.cloud.kms.KeyManagementServiceClient`.