From fa23ff57e884eb8a5f02be35f24dab85a8313b3e Mon Sep 17 00:00:00 2001 From: Muhammad Attallah Date: Thu, 28 Nov 2024 11:33:17 +0100 Subject: [PATCH 01/28] fix: get correct(updated) aws account info --- mpqp/execution/connection/aws_connection.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index 01d16956..89963e18 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -38,7 +38,9 @@ def setup_aws_braket_account() -> tuple[str, list[Any]]: try: os.system("aws configure") save_env_variable("BRAKET_CONFIGURED", "True") + session = AwsSession() + save_env_variable("AWS_DEFAULT_REGION", session.region) return "Amazon Braket account correctly configured", [] @@ -68,19 +70,26 @@ def get_aws_braket_account_info() -> str: raise AWSBraketRemoteExecutionError( "Error when trying to get AWS credentials. No AWS Braket account configured." ) + import boto3 from braket.aws import AwsSession try: - session = AwsSession() + # TODO getting outdated credentials without passing profile name, investigate? + boto3_session = boto3.Session(profile_name="752542621531_quant_team") + session = AwsSession(boto_session=boto3_session) # get the AWS Braket user access key, secret key and region credentials = session.boto_session.get_credentials() + + print(credentials.token) + print(credentials.method) + if credentials is None: raise AWSBraketRemoteExecutionError("Could not retrieve AWS' credentials") + access_key_id = credentials.access_key secret_access_key = credentials.secret_key obfuscate_key = secret_access_key[:5] + "*" * (len(secret_access_key) - 5) - region_name = session.boto_session.region_name except Exception as e: raise AWSBraketRemoteExecutionError( @@ -129,11 +138,15 @@ def get_braket_device(device: AWSDevice, is_noisy: bool = False) -> "BraketDevic try: braket_client = boto3.client("braket", region_name=device.get_region()) + print("client", braket_client) aws_session = AwsSession(braket_client=braket_client) + print("session", aws_session.boto_session) mpqp_version = pkg_resources.get_distribution("mpqp").version[:3] aws_session.add_braket_user_agent( user_agent="APN/1.0 ColibriTD/1.0 MPQP/" + mpqp_version ) + print("second_session", aws_session) + print("device", AwsDevice(device.get_arn(), aws_session=aws_session)) return AwsDevice(device.get_arn(), aws_session=aws_session) except ValueError as ve: raise AWSBraketRemoteExecutionError( From 6ad217f4b60c273eb35fbf64587ab1c6a6f67627 Mon Sep 17 00:00:00 2001 From: Muhammad Attallah Date: Mon, 2 Dec 2024 11:18:02 +0100 Subject: [PATCH 02/28] chore: remove debug prints --- mpqp/execution/connection/aws_connection.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index 89963e18..b5fabbf7 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -74,16 +74,10 @@ def get_aws_braket_account_info() -> str: from braket.aws import AwsSession try: - # TODO getting outdated credentials without passing profile name, investigate? - boto3_session = boto3.Session(profile_name="752542621531_quant_team") + boto3_session = boto3.Session(profile_name="default") session = AwsSession(boto_session=boto3_session) - # get the AWS Braket user access key, secret key and region credentials = session.boto_session.get_credentials() - - print(credentials.token) - print(credentials.method) - if credentials is None: raise AWSBraketRemoteExecutionError("Could not retrieve AWS' credentials") @@ -138,15 +132,11 @@ def get_braket_device(device: AWSDevice, is_noisy: bool = False) -> "BraketDevic try: braket_client = boto3.client("braket", region_name=device.get_region()) - print("client", braket_client) aws_session = AwsSession(braket_client=braket_client) - print("session", aws_session.boto_session) mpqp_version = pkg_resources.get_distribution("mpqp").version[:3] aws_session.add_braket_user_agent( user_agent="APN/1.0 ColibriTD/1.0 MPQP/" + mpqp_version ) - print("second_session", aws_session) - print("device", AwsDevice(device.get_arn(), aws_session=aws_session)) return AwsDevice(device.get_arn(), aws_session=aws_session) except ValueError as ve: raise AWSBraketRemoteExecutionError( From 6f62c64b45abcd0c5e3b9893893d131d18d34b17 Mon Sep 17 00:00:00 2001 From: Muhammad Attallah Date: Tue, 3 Dec 2024 17:07:55 +0100 Subject: [PATCH 03/28] fix: update Dockerfile, awscli works --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index f3a579a4..989e2ebc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,6 +28,7 @@ COPY .. /usr/src/app/mpqp/ COPY requirements.txt requirements-dev.txt /usr/src/app/ RUN pip install --upgrade pip && \ pip install --no-cache-dir -r /usr/src/app/requirements.txt && \ + pip install awscli && \ pip install . RUN echo "alias pytest='python -m pytest'" >> ~/.bashrc \ No newline at end of file From 5991c3cb626257f23a371c61ccf38ed380d05e51 Mon Sep 17 00:00:00 2001 From: Hamsatz Date: Thu, 5 Dec 2024 16:20:22 +0100 Subject: [PATCH 04/28] feat: setting up TODOs for SSO auth --- mpqp/execution/connection/aws_connection.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index b5fabbf7..5c4b08c1 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -21,6 +21,8 @@ def setup_aws_braket_account() -> tuple[str, list[Any]]: Braket. The function attempts to configure the Amazon Braket account using the provided credentials. + # TODO: update the description and add SSO elements + Returns: A tuple containing a message indicating the result of the setup (e.g., success, cancelled, or error, ...) and an empty list. The list is @@ -35,10 +37,14 @@ def setup_aws_braket_account() -> tuple[str, list[Any]]: if decision.lower().strip() != "y": return "Canceled.", [] + # TODO: add here another user choice to login with IAM or SSO + try: os.system("aws configure") save_env_variable("BRAKET_CONFIGURED", "True") + # TODO add an environment variable to know if it is IAM or SSO auth ? + session = AwsSession() save_env_variable("AWS_DEFAULT_REGION", session.region) @@ -51,6 +57,11 @@ def setup_aws_braket_account() -> tuple[str, list[Any]]: return "", [] +def setup_account_sso(): + # TODO: add here the additional inputs and file manipulations specific to SSO + pass + + def get_aws_braket_account_info() -> str: """Get AWS Braket credentials information including access key ID, obfuscated secret access key, and region. @@ -73,6 +84,8 @@ def get_aws_braket_account_info() -> str: import boto3 from braket.aws import AwsSession + # TODO: modify this function to get the rest of SSO crendentials when it is the case + try: boto3_session = boto3.Session(profile_name="default") session = AwsSession(boto_session=boto3_session) @@ -141,7 +154,7 @@ def get_braket_device(device: AWSDevice, is_noisy: bool = False) -> "BraketDevic except ValueError as ve: raise AWSBraketRemoteExecutionError( "Failed to retrieve remote AWS device. Please check the arn, or if the " - "device is accessible from your region..\nTrace: " + str(ve) + "device is accessible from your region.\nTrace: " + str(ve) ) except NoRegionError as err: raise AWSBraketRemoteExecutionError( From 2af5f28f7763270420fd82c56bae8287d02a55a2 Mon Sep 17 00:00:00 2001 From: Muhammad Attallah Date: Sun, 8 Dec 2024 23:38:38 +0100 Subject: [PATCH 05/28] chore: update amazon braket account setup, add sso authentication --- mpqp/execution/connection/aws_connection.py | 47 ++++++++++++++++----- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index 5c4b08c1..e28ceb3f 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -30,6 +30,8 @@ def setup_aws_braket_account() -> tuple[str, list[Any]]: """ from braket.aws import AwsSession + from mpqp.tools.choice_tree import AnswerNode, QuestionNode, run_choice_tree + if get_env_variable("BRAKET_CONFIGURED") == "True": decision = input( "An Amazon Braket account is already configured. Do you want to update it? [y/N] " @@ -37,17 +39,19 @@ def setup_aws_braket_account() -> tuple[str, list[Any]]: if decision.lower().strip() != "y": return "Canceled.", [] - # TODO: add here another user choice to login with IAM or SSO + braket_auth_choices = QuestionNode( + "Choose your Amazon Braket authentication method: ", + [ + AnswerNode("IAM (Identity and Access Management)", configure_account_iam), + AnswerNode("SSO (Single Sign-On)", configure_account_sso), + ], + ) + run_choice_tree(braket_auth_choices) try: - os.system("aws configure") - save_env_variable("BRAKET_CONFIGURED", "True") - - # TODO add an environment variable to know if it is IAM or SSO auth ? - session = AwsSession() - save_env_variable("AWS_DEFAULT_REGION", session.region) + return "Amazon Braket account correctly configured", [] except Exception as e: @@ -57,9 +61,32 @@ def setup_aws_braket_account() -> tuple[str, list[Any]]: return "", [] -def setup_account_sso(): - # TODO: add here the additional inputs and file manipulations specific to SSO - pass +def configure_account_iam() -> tuple[str, list[Any]]: + """Configure IAM authentication for Amazon Braket. + This function guides the user through the Amazon Braket IAM configuration process. + """ + print("Configuring IAM authentication for Amazon Braket...") + os.system("aws configure") + + print("IAM authentication configured successfully.") + save_env_variable("BRAKET_AUTH_METHOD", "IAM") + save_env_variable("BRAKET_CONFIGURED", "True") + + return "IAM configuration successful.", [] + + +def configure_account_sso() -> tuple[str, list[Any]]: + """Configure SSO authentication for Amazon Braket. + This function guides the user through the Amazon Braket SSO configuration process. + """ + print("Configuring SSO authentication for Amazon Braket...") + os.system("aws configure sso") + + print("SSO authentication configured successfully.") + save_env_variable("BRAKET_AUTH_METHOD", "SSO") + save_env_variable("BRAKET_CONFIGURED", "True") + + return "SSO configuration successful.", [] def get_aws_braket_account_info() -> str: From ce94ec334c39fbfdb096c7615a2561e42d8e2055 Mon Sep 17 00:00:00 2001 From: Hamsatz Date: Wed, 11 Dec 2024 03:45:59 +0100 Subject: [PATCH 06/28] feat: adding awscli to the requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 3570cb28..04bad30c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,6 +2,7 @@ numpy>=1.26.4 scipy>=1.11.4 amazon-braket-sdk==1.79.1 aws-configure==2.1.8 +awscli==1.36.19 amazon-braket-default-simulator==1.23.2 boto3==1.34.124 myqlm==1.10.6 From 6a3e06c5487349a566f29372ec563c0a0bec9660 Mon Sep 17 00:00:00 2001 From: Hamsatz Date: Wed, 11 Dec 2024 10:56:08 +0100 Subject: [PATCH 07/28] feat: upgrade boto3 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 04bad30c..f964faf4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,7 +4,7 @@ amazon-braket-sdk==1.79.1 aws-configure==2.1.8 awscli==1.36.19 amazon-braket-default-simulator==1.23.2 -boto3==1.34.124 +boto3==1.35.78 myqlm==1.10.6 myqlm-interop cvxpy==1.4.3 From 50f4ef994aeae00ee1babe42a934ca34ae896405 Mon Sep 17 00:00:00 2001 From: Muhammad Attallah Date: Fri, 13 Dec 2024 14:49:07 +0100 Subject: [PATCH 08/28] chore: update SSO configuration, prompt user for credentials instead of using cached on es --- mpqp/execution/connection/aws_connection.py | 74 ++++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index e28ceb3f..3ecefb66 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -1,5 +1,5 @@ import os -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Union from termcolor import colored from typeguard import typechecked @@ -7,6 +7,8 @@ if TYPE_CHECKING: from braket.devices.device import Device as BraketDevice +from getpass import getpass + from mpqp.execution.connection.env_manager import get_env_variable, save_env_variable from mpqp.execution.devices import AWSDevice from mpqp.tools.errors import AWSBraketRemoteExecutionError @@ -75,14 +77,82 @@ def configure_account_iam() -> tuple[str, list[Any]]: return "IAM configuration successful.", [] +def get_user_sso_credentials() -> Union[dict[str, str], None]: + + print("Please enter your AWS SSO credentials (inputs are hidden):") + + try: + access_key_id = input("Enter AWS access key ID: ").strip() + secret_access_key = getpass("Enter AWS secret access key: ").strip() + session_token = getpass( + "Enter AWS session token (if applicable, press Enter to skip): " + ).strip() + region = input("Enter AWS region: ").strip() + + return { + "access_key_id": access_key_id, + "secret_access_key": secret_access_key, + "session_token": session_token, + "region": region, + } + + except Exception as e: + print(f"An error occurred while getting credentials: {e}") + return None + + +def update_aws_credentials_file( + profile_name: str, + access_key_id: str, + secret_access_key: str, + session_token: str, + region: str, +): + """Update .aws/credentials file with the latest SSO credentials.""" + + from configparser import ConfigParser + from pathlib import Path + + credentials_file = Path.home() / ".aws" / "credentials" + config = ConfigParser() + + if credentials_file.exists(): + config.read(credentials_file) + + for section in config.sections(): + config.remove_section(section) + + config.add_section(profile_name) + config[profile_name]["aws_access_key_id"] = access_key_id + config[profile_name]["aws_secret_access_key"] = secret_access_key + if session_token: + config[profile_name]["aws_session_token"] = session_token + config[profile_name]["region"] = region + + with open(credentials_file, "w") as f: + config.write(f) + + def configure_account_sso() -> tuple[str, list[Any]]: """Configure SSO authentication for Amazon Braket. This function guides the user through the Amazon Braket SSO configuration process. """ print("Configuring SSO authentication for Amazon Braket...") - os.system("aws configure sso") + sso_credentials = get_user_sso_credentials() print("SSO authentication configured successfully.") + + if not sso_credentials: + raise Exception("Failed to retrieve SSO credentials after configuration.") + + update_aws_credentials_file( + profile_name="default", + access_key_id=sso_credentials["access_key_id"], + secret_access_key=sso_credentials["secret_access_key"], + session_token=sso_credentials.get("session_token", ""), + region=sso_credentials["region"], + ) + save_env_variable("BRAKET_AUTH_METHOD", "SSO") save_env_variable("BRAKET_CONFIGURED", "True") From d8ae9426d5875ed69b1776cf4a9af9b04f1037e5 Mon Sep 17 00:00:00 2001 From: Muhammad Attallah Date: Fri, 13 Dec 2024 15:28:06 +0100 Subject: [PATCH 09/28] fix: credentials overwritten correctly when configuring either IAM or SSO --- mpqp/execution/connection/aws_connection.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index 3ecefb66..fa52ec0d 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -119,8 +119,8 @@ def update_aws_credentials_file( if credentials_file.exists(): config.read(credentials_file) - for section in config.sections(): - config.remove_section(section) + if config.has_section(profile_name): + config.remove_section(profile_name) config.add_section(profile_name) config[profile_name]["aws_access_key_id"] = access_key_id From 38d9b5c200789d6a835a681a134bc56ff47ccc76 Mon Sep 17 00:00:00 2001 From: Muhammad Attallah Date: Fri, 13 Dec 2024 16:33:22 +0100 Subject: [PATCH 10/28] fix: ensure aws directory is created before updating --- mpqp/execution/connection/aws_connection.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index fa52ec0d..bf74f158 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -114,6 +114,11 @@ def update_aws_credentials_file( from pathlib import Path credentials_file = Path.home() / ".aws" / "credentials" + + credentials_dir = credentials_file.parent + if not credentials_dir.exists(): + credentials_dir.mkdir(parents=True, exist_ok=True) + config = ConfigParser() if credentials_file.exists(): From cfd665bf806ac74d6ec394baa9d07fe5b3c6cb32 Mon Sep 17 00:00:00 2001 From: Muhammad Attallah Date: Mon, 16 Dec 2024 01:17:25 +0100 Subject: [PATCH 11/28] fix: correct credentials for both IAM and SSO --- mpqp/execution/connection/aws_connection.py | 105 +++++++++++--------- 1 file changed, 60 insertions(+), 45 deletions(-) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index bf74f158..f68aceb7 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -1,5 +1,5 @@ import os -from typing import TYPE_CHECKING, Any, Union +from typing import TYPE_CHECKING, Any, Optional, Union from termcolor import colored from typeguard import typechecked @@ -7,7 +7,9 @@ if TYPE_CHECKING: from braket.devices.device import Device as BraketDevice +from configparser import ConfigParser from getpass import getpass +from pathlib import Path from mpqp.execution.connection.env_manager import get_env_variable, save_env_variable from mpqp.execution.devices import AWSDevice @@ -63,56 +65,15 @@ def setup_aws_braket_account() -> tuple[str, list[Any]]: return "", [] -def configure_account_iam() -> tuple[str, list[Any]]: - """Configure IAM authentication for Amazon Braket. - This function guides the user through the Amazon Braket IAM configuration process. - """ - print("Configuring IAM authentication for Amazon Braket...") - os.system("aws configure") - - print("IAM authentication configured successfully.") - save_env_variable("BRAKET_AUTH_METHOD", "IAM") - save_env_variable("BRAKET_CONFIGURED", "True") - - return "IAM configuration successful.", [] - - -def get_user_sso_credentials() -> Union[dict[str, str], None]: - - print("Please enter your AWS SSO credentials (inputs are hidden):") - - try: - access_key_id = input("Enter AWS access key ID: ").strip() - secret_access_key = getpass("Enter AWS secret access key: ").strip() - session_token = getpass( - "Enter AWS session token (if applicable, press Enter to skip): " - ).strip() - region = input("Enter AWS region: ").strip() - - return { - "access_key_id": access_key_id, - "secret_access_key": secret_access_key, - "session_token": session_token, - "region": region, - } - - except Exception as e: - print(f"An error occurred while getting credentials: {e}") - return None - - def update_aws_credentials_file( profile_name: str, access_key_id: str, secret_access_key: str, - session_token: str, + session_token: Optional[str], region: str, ): """Update .aws/credentials file with the latest SSO credentials.""" - from configparser import ConfigParser - from pathlib import Path - credentials_file = Path.home() / ".aws" / "credentials" credentials_dir = credentials_file.parent @@ -120,7 +81,6 @@ def update_aws_credentials_file( credentials_dir.mkdir(parents=True, exist_ok=True) config = ConfigParser() - if credentials_file.exists(): config.read(credentials_file) @@ -130,14 +90,68 @@ def update_aws_credentials_file( config.add_section(profile_name) config[profile_name]["aws_access_key_id"] = access_key_id config[profile_name]["aws_secret_access_key"] = secret_access_key + if session_token: config[profile_name]["aws_session_token"] = session_token + config[profile_name]["region"] = region with open(credentials_file, "w") as f: config.write(f) +def configure_account_iam() -> tuple[str, list[Any]]: + """Configure IAM authentication for Amazon Braket.""" + + print("Configuring IAM authentication for Amazon Braket...") + os.system("aws configure") + + print("IAM authentication configured successfully.") + save_env_variable("BRAKET_AUTH_METHOD", "IAM") + save_env_variable("BRAKET_CONFIGURED", "True") + + credentials_file = Path.home() / ".aws" / "credentials" + + config = ConfigParser() + config.read(credentials_file) + + access_key_id = config.get("default", "aws_access_key_id", fallback="") + secret_access_key = config.get("default", "aws_secret_access_key", fallback="") + region = config.get("default", "region", fallback="us-east-1") + + update_aws_credentials_file( + profile_name="default", + access_key_id=access_key_id, + secret_access_key=secret_access_key, + session_token=None, + region=region, + ) + + return "IAM configuration successful.", [] + + +def get_user_sso_credentials() -> Union[dict[str, str], None]: + + print("Please enter your AWS SSO credentials (inputs are hidden):") + + try: + access_key_id = input("Enter AWS access key ID: ").strip() + secret_access_key = getpass("Enter AWS secret access key: ").strip() + session_token = getpass("Enter AWS session token: ").strip() + region = input("Enter AWS region: ").strip() + + return { + "access_key_id": access_key_id, + "secret_access_key": secret_access_key, + "session_token": session_token, + "region": region, + } + + except Exception as e: + print(f"An error occurred while getting credentials: {e}") + return None + + def configure_account_sso() -> tuple[str, list[Any]]: """Configure SSO authentication for Amazon Braket. This function guides the user through the Amazon Braket SSO configuration process. @@ -154,7 +168,7 @@ def configure_account_sso() -> tuple[str, list[Any]]: profile_name="default", access_key_id=sso_credentials["access_key_id"], secret_access_key=sso_credentials["secret_access_key"], - session_token=sso_credentials.get("session_token", ""), + session_token=sso_credentials["session_token"], region=sso_credentials["region"], ) @@ -199,6 +213,7 @@ def get_aws_braket_account_info() -> str: access_key_id = credentials.access_key secret_access_key = credentials.secret_key obfuscate_key = secret_access_key[:5] + "*" * (len(secret_access_key) - 5) + region_name = session.boto_session.region_name except Exception as e: raise AWSBraketRemoteExecutionError( From f91cff411bc79242b7514ebf4c993c55954fec9c Mon Sep 17 00:00:00 2001 From: Muhammad Attallah Date: Mon, 16 Dec 2024 01:35:42 +0100 Subject: [PATCH 12/28] chore: update get_aws_braket_account_info, to handle token info --- mpqp/execution/connection/aws_connection.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index f68aceb7..0ee42ccc 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -200,8 +200,6 @@ def get_aws_braket_account_info() -> str: import boto3 from braket.aws import AwsSession - # TODO: modify this function to get the rest of SSO crendentials when it is the case - try: boto3_session = boto3.Session(profile_name="default") session = AwsSession(boto_session=boto3_session) @@ -214,6 +212,12 @@ def get_aws_braket_account_info() -> str: secret_access_key = credentials.secret_key obfuscate_key = secret_access_key[:5] + "*" * (len(secret_access_key) - 5) + session_token = credentials.token + if session_token: + obfuscate_token = session_token[:10] + "*" * (len(session_token) - 10) + else: + obfuscate_token = "N/A" + region_name = session.boto_session.region_name except Exception as e: raise AWSBraketRemoteExecutionError( @@ -221,9 +225,13 @@ def get_aws_braket_account_info() -> str: + str(e) ) - return f""" access_key_id: '{access_key_id}' - secret_access_key: '{obfuscate_key}' - region: '{region_name}'""" + result = f""" access_key_id: '{access_key_id}' + secret_access_key: '{obfuscate_key}'""" + if session_token: + result += f"\n session_token: '{obfuscate_token}'" + + result += f"\n region: '{region_name}'" + return result @typechecked From 44c382b2ed4b4281d41ded3fb1669bcba20a2aa7 Mon Sep 17 00:00:00 2001 From: Muhammad Attallah Date: Mon, 16 Dec 2024 15:44:12 +0100 Subject: [PATCH 13/28] doc: update docs, examples --- docs/getting-started.rst | 2 +- mpqp/execution/connection/aws_connection.py | 44 ++++++++++++++++----- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 34b4d49c..0cd1e952 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -91,7 +91,7 @@ with a list of :class:`~mpqp.core.instruction.instruction.Instruction` .. _Remote setup: Set up remote accesses ---------------------- +---------------------- Installing MPQP gives you access to ``setup_connections``, a script facilitating the setup of remote QPU connections. The supported providers (Qiskit, diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index 0ee42ccc..3cb46d68 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -20,12 +20,19 @@ def setup_aws_braket_account() -> tuple[str, list[Any]]: """Setups the connection to an Amazon Braket account using user input. This function checks whether an Amazon Braket account is already configured - and prompts the user to update it if needed. It then collects the user's AWS - access key, AWS secret key (hidden input), and the AWS region for Amazon - Braket. The function attempts to configure the Amazon Braket account using - the provided credentials. + and prompts the user to update it if needed. The function attempts to configure + the Amazon Braket account using two authentication methods: - # TODO: update the description and add SSO elements + IAM (Identity and Access Management): + - The user is guided to enter their AWS access key, secret access key, and region. + - Credentials are stored in the default AWS credentials file. + + SSO (Single Sign-On): + - The user is guided through the process of configuring SSO authentication. + - SSO credentials are automatically retrieved, including the session token. + + It then collects the user's AWS access key, AWS secret key (hidden input), + AWS session token (hidden input) in case of SSO auth and the AWS region for Amazon Braket. Returns: A tuple containing a message indicating the result of the setup (e.g., @@ -72,7 +79,9 @@ def update_aws_credentials_file( session_token: Optional[str], region: str, ): - """Update .aws/credentials file with the latest SSO credentials.""" + """Create or update .aws/credentials file with the provided credentials. + It ensures the directory and file exist before making changes. + """ credentials_file = Path.home() / ".aws" / "credentials" @@ -187,9 +196,18 @@ def get_aws_braket_account_info() -> str: obfuscated secret access key. Example: + + 1. **IAM Authentication:** >>> get_aws_braket_account_info() - access_key_id: 'AKIA26NYJ***********' - secret_access_key: 'sMDad***********************************' + access_key_id: 'AKIA26NYJD5N33FDLFFA' + secret_access_key: 'qoNEp***********************************' + region: 'us-east-1' + + 2. **SSO Authentication (With Session Token):** + >>> get_aws_braket_account_info() + access_key_id: 'ASIA26NYJD5NW4PMX45W' + secret_access_key: 'LDZYi***********************************' + session_token: 'IQoJb3JpZ2luX2V...deJmFtexse33g==' region: 'us-east-1' """ @@ -214,11 +232,17 @@ def get_aws_braket_account_info() -> str: session_token = credentials.token if session_token: - obfuscate_token = session_token[:10] + "*" * (len(session_token) - 10) + token_length = len(session_token) + obfuscate_token = ( + f"{session_token[:15]}...{session_token[-15:]}" + if token_length > 30 + else session_token + ) else: - obfuscate_token = "N/A" + obfuscate_token = "" region_name = session.boto_session.region_name + except Exception as e: raise AWSBraketRemoteExecutionError( "Error when trying to get AWS credentials. No AWS Braket account configured.\n Trace:" From 5e22fd5b04b54792486e27fbe91e4b92769eb0a5 Mon Sep 17 00:00:00 2001 From: Hamsatz Date: Tue, 17 Dec 2024 10:47:00 +0100 Subject: [PATCH 14/28] feat: introduce scripts for aws-cli installation --- Dockerfile | 5 ++++- .../awscli_installation/linux_awscli_install.sh | 10 ++++++++++ mpqp_scripts/awscli_installation/mac_awscli_install.sh | 6 ++++++ .../awscli_installation/windows_awscli_install.bat | 1 + requirements.txt | 3 +-- 5 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 mpqp_scripts/awscli_installation/linux_awscli_install.sh create mode 100644 mpqp_scripts/awscli_installation/mac_awscli_install.sh create mode 100644 mpqp_scripts/awscli_installation/windows_awscli_install.bat diff --git a/Dockerfile b/Dockerfile index 989e2ebc..a9d8f2cc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,6 +20,10 @@ RUN apt update && \ apt clean && \ rm -rf /var/lib/apt/lists/* + +COPY mpqp_scripts/awscli_installation/linux_awscli_install.sh ./ +RUN ./linux_awscli_install.sh + WORKDIR /usr/src/app/mpqp COPY --from=builder /usr/local/lib/python3.9/site-packages /usr/local/lib/python3.9/site-packages @@ -28,7 +32,6 @@ COPY .. /usr/src/app/mpqp/ COPY requirements.txt requirements-dev.txt /usr/src/app/ RUN pip install --upgrade pip && \ pip install --no-cache-dir -r /usr/src/app/requirements.txt && \ - pip install awscli && \ pip install . RUN echo "alias pytest='python -m pytest'" >> ~/.bashrc \ No newline at end of file diff --git a/mpqp_scripts/awscli_installation/linux_awscli_install.sh b/mpqp_scripts/awscli_installation/linux_awscli_install.sh new file mode 100644 index 00000000..2bc988a3 --- /dev/null +++ b/mpqp_scripts/awscli_installation/linux_awscli_install.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" +unzip awscliv2.zip +./aws/install +rm -rf awscliv2.zip aws + +echo "AWS CLI V2 installed. Version: " +aws --version + diff --git a/mpqp_scripts/awscli_installation/mac_awscli_install.sh b/mpqp_scripts/awscli_installation/mac_awscli_install.sh new file mode 100644 index 00000000..bee3af4f --- /dev/null +++ b/mpqp_scripts/awscli_installation/mac_awscli_install.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg" +sudo installer -pkg ./AWSCLIV2.pkg -target / +echo "AWS CLI V2 installed. Version: " +aws --version \ No newline at end of file diff --git a/mpqp_scripts/awscli_installation/windows_awscli_install.bat b/mpqp_scripts/awscli_installation/windows_awscli_install.bat new file mode 100644 index 00000000..5c18dd97 --- /dev/null +++ b/mpqp_scripts/awscli_installation/windows_awscli_install.bat @@ -0,0 +1 @@ +msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index f964faf4..a702e04e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,9 +2,8 @@ numpy>=1.26.4 scipy>=1.11.4 amazon-braket-sdk==1.79.1 aws-configure==2.1.8 -awscli==1.36.19 +boto3==1.35.82 amazon-braket-default-simulator==1.23.2 -boto3==1.35.78 myqlm==1.10.6 myqlm-interop cvxpy==1.4.3 From 45c3c805f791ae85f704130d8f8746a98e1b1425 Mon Sep 17 00:00:00 2001 From: Muhammad Attallah Date: Tue, 17 Dec 2024 15:13:50 +0100 Subject: [PATCH 15/28] fix: update Dockerfile --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index a9d8f2cc..42a9cad0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,7 +22,7 @@ RUN apt update && \ COPY mpqp_scripts/awscli_installation/linux_awscli_install.sh ./ -RUN ./linux_awscli_install.sh +RUN chmod +x linux_awscli_install.sh && ./linux_awscli_install.sh WORKDIR /usr/src/app/mpqp @@ -34,4 +34,4 @@ RUN pip install --upgrade pip && \ pip install --no-cache-dir -r /usr/src/app/requirements.txt && \ pip install . -RUN echo "alias pytest='python -m pytest'" >> ~/.bashrc \ No newline at end of file +RUN echo "alias pytest='python -m pytest'" >> ~/.bashrc From 83b00585143850df49b1c0eeea53c35e81ba6dd0 Mon Sep 17 00:00:00 2001 From: Muhammad Attallah Date: Tue, 17 Dec 2024 17:23:37 +0100 Subject: [PATCH 16/28] doc: fix docs --- mpqp/execution/connection/aws_connection.py | 20 ++++++++++---------- mpqp/execution/providers/ibm.py | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index 3cb46d68..65cd7588 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -195,20 +195,20 @@ def get_aws_braket_account_info() -> str: A formatted string containing AWS credentials information with an obfuscated secret access key. - Example: + Examples: 1. **IAM Authentication:** - >>> get_aws_braket_account_info() - access_key_id: 'AKIA26NYJD5N33FDLFFA' - secret_access_key: 'qoNEp***********************************' - region: 'us-east-1' + >>> get_aws_braket_account_info() + access_key_id: 'AKIA26NYJD5N33FDLFFA' + secret_access_key: 'qoNEp***********************************' + region: 'us-east-1' 2. **SSO Authentication (With Session Token):** - >>> get_aws_braket_account_info() - access_key_id: 'ASIA26NYJD5NW4PMX45W' - secret_access_key: 'LDZYi***********************************' - session_token: 'IQoJb3JpZ2luX2V...deJmFtexse33g==' - region: 'us-east-1' + >>> get_aws_braket_account_info() + access_key_id: 'ASIA26NYJD5NW4PMX45W' + secret_access_key: 'LDZYi***********************************' + session_token: 'IQoJb3JpZ2luX2V...deJmFtexse33g==' + region: 'us-east-1' """ if get_env_variable("BRAKET_CONFIGURED") == "False": diff --git a/mpqp/execution/providers/ibm.py b/mpqp/execution/providers/ibm.py index 81815996..eb93a7e9 100644 --- a/mpqp/execution/providers/ibm.py +++ b/mpqp/execution/providers/ibm.py @@ -212,7 +212,7 @@ def generate_qiskit_noise_model( circuit: QCircuit, ) -> tuple["Qiskit_NoiseModel", QCircuit]: """Generate a ``qiskit`` noise model packing all the - class:`~mpqp.noise.noise_model.NoiseModel`s attached to the given QCircuit. + :class:`~mpqp.noise.noise_model.NoiseModel` attached to the given QCircuit. In ``qiskit``, the noise cannot be applied to qubits unaffected by any operations. For this reason, this function also returns a copy of the From 20fd589e7dad98da4fb37567c0983c8e51723134 Mon Sep 17 00:00:00 2001 From: Hamsatz Date: Wed, 18 Dec 2024 09:51:38 +0100 Subject: [PATCH 17/28] doc: intermediate commit, aws braket configuration doc --- docs/execution-extras.rst | 2 +- docs/getting-started.rst | 115 ++++++++++++++++++++++++++++++-------- 2 files changed, 93 insertions(+), 24 deletions(-) diff --git a/docs/execution-extras.rst b/docs/execution-extras.rst index 34d2a7a4..f6ed8226 100644 --- a/docs/execution-extras.rst +++ b/docs/execution-extras.rst @@ -22,7 +22,7 @@ Provider specifics Even though most of our interfaces use abstractions such that you do not need to know on which provider's QPU your code is running, we need at some point to tackle the specifics of each providers. Most (hopefully all soon) of it is -tackle in these modules. +tackled in these modules. To see which devices are available, see :ref:`Devices`. diff --git a/docs/getting-started.rst b/docs/getting-started.rst index 0cd1e952..e5e4385f 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -104,27 +104,93 @@ To run the script, simply run the following command in your terminal: $ setup_connections Each of these providers has their own set of data needed to set up the connection, -summed up here: - -- IBM Quantum (Qiskit): For this provider, you only need your account ``API - token``, which you can find on your `account page `_. -- Atos/Eviden (Qaptiva/QLM): For this provider, several connection methods - exist. For now, we only support the username/password method. You should have - received you username and password by email. -- AWS (Braket): For this provider, you will need more information. All of it can - be found in your - `AWS console `_. - In the console, go to ``IAM service``. In the ``Users`` tab, click on your - username. In the ``Security credential`` tab, you'll find an ``Access keys`` - section. In this section, you can create a new access key for ``MPQP``. You - should save this because you will not be able to recover it later. - This will give you your key and your secret, but for the configuration, you - also need a region (for example ``us-east-1``). In short, one needs: - - + ``AWS Access Key ID``, - + ``AWS Secret Access Key`` and - + ``Default region name``. -- Azure (Azure): For this provider, you need to have an Azure account and create an +detailed up in subsections below. + +To see which devices are available, checkout the :ref:`Devices` section. + +IBM Quantum (Qiskit) +^^^^^^^^^^^^^^^^^^^^ + +For this provider, you only need your account ``API token``, which you can find on your +`account page `_. The token will be configured once for all users. + + +Atos/Eviden (QLM/Qaptiva) +^^^^^^^^^^^^^^^^^^^^^^^^^ + +For this provider, several connection methods exist. For now, we only support the username/password method. +You should have received you username and password by email. + + +AWS Braket +^^^^^^^^^^ + +For configuring access to AWS Braket, you first need to have ``awscli`` installed on your machine. To check if it is +already installed, you can run this command: + +.. code-block:: console + + $ aws --version + +- For ``Windows``, installing ``mpqp`` can be sufficient since the Python package ``aws-configure`` (in the +requirements) also installs ``awscli`` locally. If it is not the case, you can execute the following command +(in a terminal where you have admin access) to install ``awscliV2``: + +.. code-block:: console + + > msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi + +- For ``MacOS``, on some versions, the installation of ``aws-configure`` can be sufficient. If it is not the case, you +can install it using ``brew``: + +.. code-block:: console + + $ brew install awscli + +or execute the script we prepared for installing ``awscliv2``: + +.. code-block:: console + + $ ./mpqp/mpqp_scripts/awscli_installation/mac_awscli_install.sh + +- For ``Linux``, one can use the dedicated script for installing ``awscliv2``: + +.. code-block:: console + + $ ./mpqp/mpqp_scripts/awscli_installation/linux_awscli_install.sh + + +Amazon Web Services propose two different ways to authenticate yourself to access remote services, including remote +simulators and QPUs via Braket: the ``IAM`` authentication, and the ``SSO`` one. + +.. TODO: finish this section + + +- IAM: All of it can be found in your +`AWS console `_. +In the console, go to ``IAM service``. In the ``Users`` tab, click on your +username. In the ``Security credential`` tab, you'll find an ``Access keys`` +section. In this section, you can create a new access key for ``MPQP``. You +should save this because you will not be able to recover it later. +This will give you your key and your secret, but for the configuration, you +also need a region (for example ``us-east-1``). In short, one needs: + ++ ``AWS Access Key ID``, ++ ``AWS Secret Access Key`` and ++ ``Default region name``. + +- SSO: + ++ ``AWS Access Key ID``, ++ ``AWS Secret Access Key``, ++ ``AWS Session Token`` and ++ ``Default region name``. + + +Microsoft Azure +^^^^^^^^^^^^^^^ + +For this provider, you need to have an Azure account and create an Azure Quantum workspace. To create an Azure Quantum workspace, follow the steps on: `Azure Quantum workspace `_. @@ -156,11 +222,14 @@ summed up here: For additional details and options, see the documentation of `az login `_. -- IonQ (Cirq): For this provider, you need to have an IonQ account and create an +IonQ (Cirq) +^^^^^^^^^^^ + +For this provider, you need to have an IonQ account and create an ``API token``. You can obtain it from the IonQ Console under `IonQ setting keys `_. -To see which devices are available, checkout the :ref:`Devices` section. + Execute examples ---------------- From 9a3f75a974ee2577995fc154a0a6ab9026db1fd8 Mon Sep 17 00:00:00 2001 From: Hamsatz Date: Wed, 18 Dec 2024 14:49:54 +0100 Subject: [PATCH 18/28] doc: finalizing the doc --- docs/getting-started.rst | 110 +++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 52 deletions(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index e5e4385f..b4923430 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -132,95 +132,101 @@ already installed, you can run this command: $ aws --version -- For ``Windows``, installing ``mpqp`` can be sufficient since the Python package ``aws-configure`` (in the -requirements) also installs ``awscli`` locally. If it is not the case, you can execute the following command -(in a terminal where you have admin access) to install ``awscliV2``: +- For ``Windows``, installing ``mpqp`` can be sufficient since the Python package ``aws-configure`` (in the requirements) also installs ``awscli`` locally. If it is not the case, you can execute the following command (in a terminal where you have admin access) to install ``awscliV2``: -.. code-block:: console + .. code-block:: console - > msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi + > msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi -- For ``MacOS``, on some versions, the installation of ``aws-configure`` can be sufficient. If it is not the case, you -can install it using ``brew``: +- For ``MacOS``, on some versions, the installation of ``aws-configure`` can be sufficient. If it is not the case, you can install it using ``brew``: -.. code-block:: console + .. code-block:: console - $ brew install awscli + $ brew install awscli -or execute the script we prepared for installing ``awscliv2``: + or execute the script we prepared for installing ``awscliv2``: -.. code-block:: console + .. code-block:: console - $ ./mpqp/mpqp_scripts/awscli_installation/mac_awscli_install.sh + $ ./mpqp/mpqp_scripts/awscli_installation/mac_awscli_install.sh - For ``Linux``, one can use the dedicated script for installing ``awscliv2``: -.. code-block:: console + .. code-block:: console - $ ./mpqp/mpqp_scripts/awscli_installation/linux_awscli_install.sh + $ ./mpqp/mpqp_scripts/awscli_installation/linux_awscli_install.sh -Amazon Web Services propose two different ways to authenticate yourself to access remote services, including remote -simulators and QPUs via Braket: the ``IAM`` authentication, and the ``SSO`` one. +Amazon Web Services propose two different ways to authenticate for access remote services (including remote +simulators and QPUs via Braket): the ``IAM`` authentication, and the ``SSO`` one. When you run the ``setup_connections`` +script and select AWS configuration, you will have to choose between one of the two above. .. TODO: finish this section -- IAM: All of it can be found in your -`AWS console `_. -In the console, go to ``IAM service``. In the ``Users`` tab, click on your -username. In the ``Security credential`` tab, you'll find an ``Access keys`` -section. In this section, you can create a new access key for ``MPQP``. You -should save this because you will not be able to recover it later. -This will give you your key and your secret, but for the configuration, you -also need a region (for example ``us-east-1``). In short, one needs: +- IAM: All the necessary credentials can be found in your `AWS console `_. + In the console, go to ``IAM``. In the ``Users`` tab, click on your + username. In the ``Security credential`` tab, you'll find an ``Access keys`` + section. In this section, you can create a new access key for ``MPQP/Braket``, or use an existing one. You + should save the secret access key because you will not be able to recover it later. + This will give you your key and your secret, but for the configuration, you + also need to input a region (for example ``us-east-1``). In short, when running ``setup_connections``, + it will execute the ``aws configure`` command that will ask you the following credentials: + + + ``AWS Access Key ID``, + + ``AWS Secret Access Key``, + + ``Default region name``. -+ ``AWS Access Key ID``, -+ ``AWS Secret Access Key`` and -+ ``Default region name``. +- SSO: Standing for "Single-Sign-On", SSO enables organizations to simplify and strengthen password security by giving + access to all connected services with a signe login. It is the recommended way to authenticate to Amazon Web Services. + To recover your SSO credentials, you have to follow the ``SSO start url`` provided by your AWS administrator, (for + example https://d-4859u1689s.awsapps.com/start ). -- SSO: + You will need you username and password attached (and potentially MFA) to login. Then, in the ``AWS Access Portal``, + you can find the different sso sessions and profile associated with your company account. Click on the + ``Access key`` (with the key symbol) to retrieve your SSO credentials. When running ``setup_connections``, + you will be asked for: -+ ``AWS Access Key ID``, -+ ``AWS Secret Access Key``, -+ ``AWS Session Token`` and -+ ``Default region name``. + + ``AWS Access Key ID``, + + ``AWS Secret Access Key``, + + ``AWS Session Token``, + + ``Default region name``. Microsoft Azure ^^^^^^^^^^^^^^^ For this provider, you need to have an Azure account and create an - Azure Quantum workspace. To create an Azure Quantum workspace, follow the - steps on: - `Azure Quantum workspace `_. - Once you have your Quantum workspace, you can go to the ``Overview`` section, - where you will find your ``Resource ID`` and ``Location``. +Azure Quantum workspace. To create an Azure Quantum workspace, follow the +steps on: +`Azure Quantum workspace `_. +Once you have your Quantum workspace, you can go to the ``Overview`` section, +where you will find your ``Resource ID`` and ``Location``. - You might encounter a pop-up requesting Azure authentication for each Azure - job submission. This occurs because your security token is reset at the end of - each session. In order to avoid this, you can use the Azure CLI. +You might encounter a pop-up requesting Azure authentication for each Azure +job submission. This occurs because your security token is reset at the end of +each session. In order to avoid this, you can use the Azure CLI. - First, install the Azure CLI: refer to the guide on their website - `How to install the Azure CLI `_. +First, install the Azure CLI: refer to the guide on their website +`How to install the Azure CLI `_. - Next, log in to Azure: +Next, log in to Azure: - - Using interactive login: +- Using interactive login: - .. code-block:: console +.. code-block:: console - $ az login + $ az login - - For username and password authentication (note that this method doesn't work - with Microsoft accounts or accounts with two-factor authentication): +- For username and password authentication (note that this method doesn't work +with Microsoft accounts or accounts with two-factor authentication): - .. code-block:: console +.. code-block:: console - $ az login -u johndoe@contoso.com -p=VerySecret + $ az login -u johndoe@contoso.com -p=VerySecret - For additional details and options, see the documentation of - `az login `_. +For additional details and options, see the documentation of +`az login `_. IonQ (Cirq) ^^^^^^^^^^^ From 8eee4c5b63846e57c9fce1b2f8421ccf177286d0 Mon Sep 17 00:00:00 2001 From: Muhammad Attallah Date: Thu, 19 Dec 2024 11:25:32 +0100 Subject: [PATCH 19/28] doc: update docs --- mpqp/execution/connection/aws_connection.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index 65cd7588..681ca955 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -17,7 +17,7 @@ def setup_aws_braket_account() -> tuple[str, list[Any]]: - """Setups the connection to an Amazon Braket account using user input. + """Set-up the connection to an Amazon Braket account using user input. This function checks whether an Amazon Braket account is already configured and prompts the user to update it if needed. The function attempts to configure @@ -188,8 +188,8 @@ def configure_account_sso() -> tuple[str, list[Any]]: def get_aws_braket_account_info() -> str: - """Get AWS Braket credentials information including access key ID, - obfuscated secret access key, and region. + """Retrieves AWS Braket credentials information including access key ID, secret access key, + and region. For SSO authentication, the session token is also included. Returns: A formatted string containing AWS credentials information with an @@ -210,6 +210,10 @@ def get_aws_braket_account_info() -> str: session_token: 'IQoJb3JpZ2luX2V...deJmFtexse33g==' region: 'us-east-1' + Note: + This function assumes that the AWS credentials are already configured + in the AWS credentials/config file ``~/.aws/credentials``. + """ if get_env_variable("BRAKET_CONFIGURED") == "False": raise AWSBraketRemoteExecutionError( From 30493559d1c8642a3c133ddcdb0a297c2e338f17 Mon Sep 17 00:00:00 2001 From: Hamsatz Date: Sun, 22 Dec 2024 11:59:51 +0100 Subject: [PATCH 20/28] feat: uniformization of outputs when accounts not configured --- mpqp/execution/connection/azure_connection.py | 2 +- mpqp/execution/connection/ibm_connection.py | 4 ++-- mpqp/execution/connection/ionq_connection.py | 2 +- mpqp_scripts/setup_connections.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mpqp/execution/connection/azure_connection.py b/mpqp/execution/connection/azure_connection.py index 561e8f4c..e70fe565 100644 --- a/mpqp/execution/connection/azure_connection.py +++ b/mpqp/execution/connection/azure_connection.py @@ -73,7 +73,7 @@ def get_azure_account_info() -> str: """ azure_resource_id = get_env_variable("AZURE_RESOURCE_ID") if azure_resource_id == "": - display = "Not configured" + return "Account not configured" else: display = azure_resource_id[:5] + "*****" azure_location = get_env_variable("AZURE_LOCATION") diff --git a/mpqp/execution/connection/ibm_connection.py b/mpqp/execution/connection/ibm_connection.py index 29874246..543f2c33 100644 --- a/mpqp/execution/connection/ibm_connection.py +++ b/mpqp/execution/connection/ibm_connection.py @@ -146,8 +146,8 @@ def get_active_account_info() -> str: """ service = get_QiskitRuntimeService() account = service.active_account() - if TYPE_CHECKING: - assert account is not None + if account is None: + return "Account not configured" return f""" Channel: {account["channel"]} Token: {account["token"][:5]}***** URL: {account["url"]} diff --git a/mpqp/execution/connection/ionq_connection.py b/mpqp/execution/connection/ionq_connection.py index 888139e2..e781842a 100644 --- a/mpqp/execution/connection/ionq_connection.py +++ b/mpqp/execution/connection/ionq_connection.py @@ -45,7 +45,7 @@ def get_ionq_account_info() -> str: """ ionq_api_key = get_env_variable("IONQ_API_KEY") if ionq_api_key == "": - display = "Not configured" + return "Account not configured" else: display = ionq_api_key[:5] + "*****" diff --git a/mpqp_scripts/setup_connections.py b/mpqp_scripts/setup_connections.py index fabc0010..7d6fd9bc 100644 --- a/mpqp_scripts/setup_connections.py +++ b/mpqp_scripts/setup_connections.py @@ -26,7 +26,7 @@ def print_config_info(): try: print(ibmqc.get_active_account_info()) except IBMRemoteExecutionError as err: - if "No IBM Q account configured" in str(err): + if "Unable to find account" in str(err): print("Account not configured") print("===== Qaptiva QLMaaS info : ===== ") From 9efad881bec5f0fa86461290de4face41c5c25d6 Mon Sep 17 00:00:00 2001 From: Hamsatz Date: Sun, 22 Dec 2024 12:04:42 +0100 Subject: [PATCH 21/28] feat: add "hidden" whe using getpass --- mpqp/execution/connection/aws_connection.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index 681ca955..3e7b7ada 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -145,8 +145,8 @@ def get_user_sso_credentials() -> Union[dict[str, str], None]: try: access_key_id = input("Enter AWS access key ID: ").strip() - secret_access_key = getpass("Enter AWS secret access key: ").strip() - session_token = getpass("Enter AWS session token: ").strip() + secret_access_key = getpass("Enter AWS secret access key (hidden): ").strip() + session_token = getpass("Enter AWS session token (hidden): ").strip() region = input("Enter AWS region: ").strip() return { From aba4daee132336d564b8bcd42e65399008162d88 Mon Sep 17 00:00:00 2001 From: Hamsatz Date: Mon, 23 Dec 2024 14:53:08 +0100 Subject: [PATCH 22/28] feat: update AWS info printing and inputs --- mpqp/execution/connection/aws_connection.py | 47 +++++++++++---------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index 3e7b7ada..b7e1523c 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -141,13 +141,13 @@ def configure_account_iam() -> tuple[str, list[Any]]: def get_user_sso_credentials() -> Union[dict[str, str], None]: - print("Please enter your AWS SSO credentials (inputs are hidden):") + print("Please enter your AWS SSO credentials:") try: access_key_id = input("Enter AWS access key ID: ").strip() secret_access_key = getpass("Enter AWS secret access key (hidden): ").strip() - session_token = getpass("Enter AWS session token (hidden): ").strip() - region = input("Enter AWS region: ").strip() + session_token = getpass("Enter SSO session token (hidden): ").strip() + region = input("Enter SSO region: ").strip() return { "access_key_id": access_key_id, @@ -196,19 +196,18 @@ def get_aws_braket_account_info() -> str: obfuscated secret access key. Examples: - - 1. **IAM Authentication:** - >>> get_aws_braket_account_info() - access_key_id: 'AKIA26NYJD5N33FDLFFA' - secret_access_key: 'qoNEp***********************************' - region: 'us-east-1' - - 2. **SSO Authentication (With Session Token):** - >>> get_aws_braket_account_info() - access_key_id: 'ASIA26NYJD5NW4PMX45W' - secret_access_key: 'LDZYi***********************************' - session_token: 'IQoJb3JpZ2luX2V...deJmFtexse33g==' - region: 'us-east-1' + >>> print(get_aws_braket_account_info()) + Authentication method: IAM + Access Key ID: 'AKIA26JFZI8JFZ18FI4N' + Secret Access Key: 'E9oF9*********************************' + Region: 'us-east-1' + + >>> print(get_aws_braket_account_info()) + Authentication method: SSO + Access Key ID: 'ASIA26JFEZ6JEOZ9JC7K' + Secret Access Key: 'FiZp3***********************************' + SSO Session Token: 'EfGkf2kbI3nfC5V...IIZUf79jofZNF==' + Region: 'us-east-1' Note: This function assumes that the AWS credentials are already configured @@ -228,7 +227,7 @@ def get_aws_braket_account_info() -> str: credentials = session.boto_session.get_credentials() if credentials is None: - raise AWSBraketRemoteExecutionError("Could not retrieve AWS' credentials") + raise AWSBraketRemoteExecutionError("Could not retrieve AWS credentials") access_key_id = credentials.access_key secret_access_key = credentials.secret_key @@ -236,29 +235,33 @@ def get_aws_braket_account_info() -> str: session_token = credentials.token if session_token: + auth_method = "SSO" token_length = len(session_token) obfuscate_token = ( f"{session_token[:15]}...{session_token[-15:]}" if token_length > 30 else session_token ) + else: obfuscate_token = "" + auth_method = "IAM" region_name = session.boto_session.region_name except Exception as e: raise AWSBraketRemoteExecutionError( - "Error when trying to get AWS credentials. No AWS Braket account configured.\n Trace:" + "Error when trying to get AWS credentials. Possibly no AWS Braket account configured.\n Trace:" + str(e) ) - result = f""" access_key_id: '{access_key_id}' - secret_access_key: '{obfuscate_key}'""" + result = f""" Authentication method: {auth_method} + Access Key ID: '{access_key_id}' + Secret Access Key: '{obfuscate_key}'""" if session_token: - result += f"\n session_token: '{obfuscate_token}'" + result += f"\n SSO Session Token: '{obfuscate_token}'" - result += f"\n region: '{region_name}'" + result += f"\n Region: '{region_name}'" return result From 7cbe8a5cf0bbd13c68d6c1a84cb4c67c815b4a1a Mon Sep 17 00:00:00 2001 From: Hamsatz Date: Mon, 23 Dec 2024 16:53:13 +0100 Subject: [PATCH 23/28] doc: advice for creating IAM key --- docs/getting-started.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index b4923430..b781836d 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -161,13 +161,12 @@ Amazon Web Services propose two different ways to authenticate for access remote simulators and QPUs via Braket): the ``IAM`` authentication, and the ``SSO`` one. When you run the ``setup_connections`` script and select AWS configuration, you will have to choose between one of the two above. -.. TODO: finish this section - - IAM: All the necessary credentials can be found in your `AWS console `_. In the console, go to ``IAM``. In the ``Users`` tab, click on your username. In the ``Security credential`` tab, you'll find an ``Access keys`` - section. In this section, you can create a new access key for ``MPQP/Braket``, or use an existing one. You + section. In this section, you can create a new access key for ``MPQP/Braket`` (with "Local code" or + "Third-party service" as usecase), or use an existing one. You should save the secret access key because you will not be able to recover it later. This will give you your key and your secret, but for the configuration, you also need to input a region (for example ``us-east-1``). In short, when running ``setup_connections``, From 928241cae6a2da73b7e4697141129ba70e0e50ed Mon Sep 17 00:00:00 2001 From: Muhammad Attallah Date: Tue, 24 Dec 2024 10:55:35 +0100 Subject: [PATCH 24/28] doc: fix and update docs --- docs/getting-started.rst | 2 +- mpqp/execution/connection/aws_connection.py | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/getting-started.rst b/docs/getting-started.rst index b781836d..aa140608 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started.rst @@ -218,7 +218,7 @@ Next, log in to Azure: $ az login - For username and password authentication (note that this method doesn't work -with Microsoft accounts or accounts with two-factor authentication): + with Microsoft accounts or accounts with two-factor authentication): .. code-block:: console diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index b7e1523c..dd606a48 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -29,7 +29,8 @@ def setup_aws_braket_account() -> tuple[str, list[Any]]: SSO (Single Sign-On): - The user is guided through the process of configuring SSO authentication. - - SSO credentials are automatically retrieved, including the session token. + - SSO credentials, including the session token, are retrieved and provided by the user + to complete the authentication process. It then collects the user's AWS access key, AWS secret key (hidden input), AWS session token (hidden input) in case of SSO auth and the AWS region for Amazon Braket. @@ -79,8 +80,8 @@ def update_aws_credentials_file( session_token: Optional[str], region: str, ): - """Create or update .aws/credentials file with the provided credentials. - It ensures the directory and file exist before making changes. + """Create or update the ``~/.aws/credentials`` file with the provided credentials. + Ensure that the directory and file exist before making changes. """ credentials_file = Path.home() / ".aws" / "credentials" From d5666dd78f7b8142039ba0c8614b86d9bbf2bcbd Mon Sep 17 00:00:00 2001 From: Muhammad Attallah Date: Tue, 24 Dec 2024 11:08:42 +0100 Subject: [PATCH 25/28] chore: update 'configure_account_sso' flow --- mpqp/execution/connection/aws_connection.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index dd606a48..09a7aa39 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -167,13 +167,13 @@ def configure_account_sso() -> tuple[str, list[Any]]: This function guides the user through the Amazon Braket SSO configuration process. """ print("Configuring SSO authentication for Amazon Braket...") - sso_credentials = get_user_sso_credentials() - - print("SSO authentication configured successfully.") + sso_credentials = get_user_sso_credentials() if not sso_credentials: raise Exception("Failed to retrieve SSO credentials after configuration.") + print("SSO authentication configured successfully.") + update_aws_credentials_file( profile_name="default", access_key_id=sso_credentials["access_key_id"], From 35a93df83b010454294a2ca33eaac3367ca2d11c Mon Sep 17 00:00:00 2001 From: Muhammad Attallah Date: Thu, 26 Dec 2024 15:12:45 +0100 Subject: [PATCH 26/28] fix: section removal logic --- mpqp/execution/connection/aws_connection.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index 09a7aa39..84c21e20 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -94,8 +94,8 @@ def update_aws_credentials_file( if credentials_file.exists(): config.read(credentials_file) - if config.has_section(profile_name): - config.remove_section(profile_name) + if config.has_section(profile_name): + config.remove_section(profile_name) config.add_section(profile_name) config[profile_name]["aws_access_key_id"] = access_key_id From f42e526e9aa77585323c4580fb28ff788dffbe39 Mon Sep 17 00:00:00 2001 From: hJaffaliColibritd <133856040+hJaffaliColibritd@users.noreply.github.com> Date: Fri, 3 Jan 2025 10:19:14 +0100 Subject: [PATCH 27/28] Update mpqp/execution/connection/aws_connection.py Co-authored-by: Henri-ColibrITD <133855265+Henri-ColibrITD@users.noreply.github.com> --- mpqp/execution/connection/aws_connection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index 84c21e20..ae4974af 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -238,7 +238,7 @@ def get_aws_braket_account_info() -> str: if session_token: auth_method = "SSO" token_length = len(session_token) - obfuscate_token = ( + obfuscated_token = ( f"{session_token[:15]}...{session_token[-15:]}" if token_length > 30 else session_token From 9d5bc3611b64a49292acc4561a8435331a52c607 Mon Sep 17 00:00:00 2001 From: Hamsatz Date: Fri, 3 Jan 2025 10:22:45 +0100 Subject: [PATCH 28/28] chore: pdate variable names --- mpqp/execution/connection/aws_connection.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mpqp/execution/connection/aws_connection.py b/mpqp/execution/connection/aws_connection.py index ae4974af..a2cf9c99 100644 --- a/mpqp/execution/connection/aws_connection.py +++ b/mpqp/execution/connection/aws_connection.py @@ -232,7 +232,7 @@ def get_aws_braket_account_info() -> str: access_key_id = credentials.access_key secret_access_key = credentials.secret_key - obfuscate_key = secret_access_key[:5] + "*" * (len(secret_access_key) - 5) + obfuscated_key = secret_access_key[:5] + "*" * (len(secret_access_key) - 5) session_token = credentials.token if session_token: @@ -245,7 +245,7 @@ def get_aws_braket_account_info() -> str: ) else: - obfuscate_token = "" + obfuscated_token = "" auth_method = "IAM" region_name = session.boto_session.region_name @@ -258,9 +258,9 @@ def get_aws_braket_account_info() -> str: result = f""" Authentication method: {auth_method} Access Key ID: '{access_key_id}' - Secret Access Key: '{obfuscate_key}'""" + Secret Access Key: '{obfuscated_key}'""" if session_token: - result += f"\n SSO Session Token: '{obfuscate_token}'" + result += f"\n SSO Session Token: '{obfuscated_token}'" result += f"\n Region: '{region_name}'" return result