Security

This module is responsible for securing the transfer of result files contained in the docker images that represent PHT Trains. This is done by encrypting the resulting files using envelope encryption.

Additionally the progression of the train, the validity of the image and the results, as well as the identities of the participating stations are validated before a participant executes a train image.

TODO add link to paper

A more detailed description of the steps involved in the Protocol refer [link to paper].

The different stages of this protocol are used in the main DAG used by the pht station [link to station docu, repo] but can also be used independently i.e. to to offer decryption of result to authorized users at a station.

TODO add images showing how the security protocol works

The classes and functions implementing the security protocol are documented in the following sections.

Security Protocol

The following image shows the steps performed by the protocol, the pre-run protocol is performed before a train is executed and after decrypting the files checks the validity of the immutable files, if the hash of the result files corresponds to the hash sent by the previous station and the validity of the digital signature.

After a successful execution of the train container the post-run protocol calculates the hash of the results, signs the hash and the digital signature, encrypts the files using a new symmetric key. This key is encrypted using the public keys provided in the train configuration .json file and stored in the image. Before it is transferred to other stations.

../_images/security-protocol.png
class train_lib.security.SecurityProtocol.SecurityProtocol(station_id: str, config: Union[str, dict], results_dir: Optional[str] = None, train_dir: Optional[str] = None, docker_client=None)[source]

Bases: object

Class that performs the security protocol outlined in the security concept

Parameters
  • station_id (str) – PID used to identify the station and to access the correct security values inside the train_config.json

  • config (Union[str, dict]) – either a string containing a path to the train_config.json or a dictionary containing the values parsed from said json file

  • results_dir – path to the directory containing the results

  • train_dir – path to the directory containing the immutable files defining a train

post_run_protocol(img: Optional[str] = None, private_key_path: Optional[str] = None, mutable_dir: str = '/opt/pht_results')[source]

Updates the necessary values in the train_config.json and encrypts the updated files after a successful train execution.

Parameters
  • img – identifier of the image <repository>:<tag>

  • private_key_path – path to the private key associated with the current station and with the corresponding public key registered in vault under the PID chosen by the station

  • mutable_dir – path to the directory in which the mutable files are stored

Returns

pre_run_protocol(img: Optional[str] = None, private_key_path: Optional[str] = None, immutable_dir: str = '/opt/pht_train', mutable_dir: str = '/opt/pht_results')[source]

Decrypts the files contained in the train. And performs the steps necessary to validate a train before it is being run

Parameters
  • img – identifier of the image from which the security relevant files will be extracted

  • private_key_path

  • immutable_dir

  • mutable_dir

Returns

sign_digital_signature(sk: cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey)[source]

Update the digital signature of the train after successful execution of the train. If there is no previous signature present creates a signature based on the session id, otherwise the signature of the previous station is loaded, signed using the current stations private key and appended to the list of signatures stored in the train.

Parameters

sk – private key of the currently running station

validate_immutable_files(train_dir: Optional[str] = None, files: Optional[list] = None, ordered_file_list: Optional[List[str]] = None, immutable_file_names: Optional[List[str]] = None)[source]

Checks if the hash of the immutable files is the same as the one stored at the creation of the train

Raises

ValidationError – when the files to be executed do not match the agreed upon files

Returns

validate_previous_results(files: Optional[List[BinaryIO]] = None)[source]

Verify that the results from the execution of the previous station did not change, by hashing the stored results from the previous station and comparing it with the decrypted stored hash from the previous station

verify_digital_signature()[source]

Verifies the digital signature of the train by iterating over the list of signatures and verifying each one using the correct public key stored in the train configuration json

Raise

InvalidSignatureError if any of the signed values can not be validated using the provided public keys

Key Manager

class train_lib.security.KeyManager.KeyManager(train_config: Union[str, dict])[source]

Bases: object

Class that creates, stores and if necessary updates all relevant keys for symmetric and asymmetric encryption

encrypt_symmetric_key(sym_key: bytes) dict[source]

Encrypt the symmetric key with all public keys provided in the train configuration file

Parameters

sym_key – byte object containing the the symmetric key used to encrypt the mutable files

Returns

dictionary containing the symmetric key encrypted with all available public keys, keys are the station

ids and values are the symmetric key encrypted with the RSA public key associated with the station id

Return type

dict

generate_encrypted_keys(symmetric_key: bytes)[source]

Generates a dictionary containing the symmetric key used to encrypt files, encrypted with the public keys of all stations on the route :param symmetric_key: byte object containing the symmetric key used to encrypt the mutable files :return: Dictionary consisting of key = Station Id, value = Symmetric key encrypted with public key of station

static generate_symmetric_key()[source]

Create a symmetric fernet key for encrypting sensitive files :return:

get_security_param(param: str)[source]

Returns a parameter from the associated keyfile :param param: :return: value of the specified parameter

get_sym_key(station_id: str, private_key_path: Optional[str] = None)[source]

Decrypts the symmetric key using a stored private key :arg station_id: station identifier used to load the correct public key :return: symmetric fernet key used to encrypt and decrypt files

static load_private_key(env_key: Optional[str] = None, key_path: Optional[str] = None)[source]

Loads the private key from the path provided provided in the environment variables of the currently running image :param key_path: path to a file containing the private key :param env_key: environment variable containing a hex string representing the station private key :return: a private key object either rsa or ec

static load_public_key(key: str)[source]

Loads a public key :param key: string representation of a public key :return: public key object for asymmetric encryption

save_keyfile(path=None, binary_file=False)[source]

Store the updated config file as a json at the same location

Returns

Return type

set_security_param(param: str, value)[source]

Updates a parameter in the keyfile with the given value :param param: the parameter to update :param value: new value for param :return:

Hashing

train_lib.security.Hashing.hash_immutable_files(immutable_files: Union[List[str], List[BinaryIO]], user_id: str, session_id: bytes, binary_files=False, ordered_file_list: Optional[list] = None, immutable_file_names: Optional[List[str]] = None)[source]

Calculates the hash of all immutable files in the train, A, R, Q as well as the :param binary_files: boolean parameter indicating whether the files are binary files or file paths :param user_id: :param session_id: :param immutable_files: :return: byte object representing the hash of all files

train_lib.security.Hashing.hash_results(result_files: Union[List[str], List[BinaryIO]], session_id: bytes, binary_files=False)[source]

Creates a hash of the results of train execution :param result_files: List :param session_id: :return:

Symmetric Encryption

class train_lib.security.SymmetricEncryption.FileEncryptor(key: bytes)[source]

Bases: object

Performs symmetric encryption and decryption of sensitive files belonging to the train cargo

decrypt_files(files: Union[List[str], List[BinaryIO]], binary_files=False) Optional[List[_io.BytesIO]][source]

Decrypt the given files using symmetric encryption :return:

encrypt_files(files: Union[List[str], List[BinaryIO]], binary_files=False) Optional[List[_io.BytesIO]][source]

Decrypt the given files using symmetric encryption :return:

Docker Image Validation

train_lib.docker_util.validate_master_image.validate_train_image(train_img: str, master_image: str)[source]

Validates a train image against an official master image :param train_img: identifier of the docker image defining a train :param master_image: identifier of the master docker image to validate against :return: