示例#1
0
 def write_config(profile_name, config_values):
     # discard because we're already loading the existing values
     write_values(session,
                  profile_name,
                  config_values,
                  config_file_writer=config_writer,
                  existing_config_action="discard")
示例#2
0
def configure_profile(profile, sso_start_url, sso_region, account, role,
                      region, output, config_default, existing_config_action,
                      interactive, credential_process, verbose):
    """Configure a single profile.

    You can set all the options for a profile, or let it prompt you interactively to select from available accounts and roles.

    \b
    The values required for a complete profile are:
    --sso-start-url
    --sso-region
    --account-id
    --role-name
    --region

    --sso-start-url and --sso-region are not needed if a single value can be found for them in your ~/.aws/config
    or in the environment variables AWS_DEFAULT_SSO_START_URL and AWS_DEFAULT_SSO_REGION.
    """
    configure_logging(LOGGER, verbose)

    try:
        instance = get_instance(
            sso_start_url,
            sso_region,
            sso_start_url_vars=CONFIGURE_DEFAULT_START_URL_VARS,
            sso_region_vars=CONFIGURE_DEFAULT_SSO_REGION_VARS,
        )
    except GetInstanceError as e:
        LOGGER.fatal(str(e))
        sys.exit(1)

    sso_start_url = instance.start_url if instance else None
    sso_region = instance.region if instance else None

    if config_default:
        config_default = dict(v.split("=", 1) for v in config_default)
    else:
        config_default = {}

    session = botocore.session.Session(profile=profile)

    config_values = {}
    existing_profile = False
    existing_config = {}
    if existing_config_action != "discard":
        try:
            existing_config = session.get_scoped_config()
            config_values.update(existing_config)
            existing_profile = True
        except ProfileNotFound:
            pass

    if sso_start_url:
        config_values["sso_start_url"] = sso_start_url

    if sso_region:
        config_values["sso_region"] = sso_region

    if account:
        config_values["sso_account_id"] = account

    if role:
        config_values["sso_role_name"] = role

    if region:
        config_values["region"] = region
    elif "region" not in config_values:
        for var_name in CONFIGURE_DEFAULT_REGION_VARS:
            value = os.environ.get(var_name)
            if value:
                LOGGER.debug(f"Got default region {value} from {var_name}")
                config_values["region"] = value
                break

    if output:
        config_values["output"] = output

    for k, v in config_default.items():
        if k in existing_config and existing_config_action in ["keep"]:
            continue
        config_values[k] = v

    if credential_process is not None:
        set_credential_process = credential_process
    elif os.environ.get(DISABLE_CREDENTIAL_PROCESS_VAR,
                        "").lower() in ["1", "true"]:
        set_credential_process = False
    else:
        set_credential_process = SET_CREDENTIAL_PROCESS_DEFAULT

    if set_credential_process:
        credential_process_name = os.environ.get(
            CREDENTIAL_PROCESS_NAME_VAR) or "aws-sso-util credential-process"
        config_values[
            "credential_process"] = f"{credential_process_name} --profile {shell_quote(profile)}"
    elif set_credential_process is False:
        config_values.pop("credential_process", None)

    required_keys = [
        "sso_start_url", "sso_region", "sso_account_id", "sso_role_name",
        "region"
    ]

    missing_keys = [k for k in required_keys if k not in config_values]

    if missing_keys and not interactive:
        LOGGER.error(f"Missing profile options {', '.join(missing_keys)}")
        sys.exit(1)
    else:
        LOGGER.debug(f"Missing keys: {', '.join(missing_keys)}")

    # discard because we've already loading the existing values
    write_values(session,
                 profile,
                 config_values,
                 existing_config_action="discard")

    if not missing_keys:
        return

    try:
        result = subprocess.run(["aws", "--version"], capture_output=True)
        cli_version = parse_cli_version(result.stdout.decode("utf-8"))
        if cli_version.startswith("1."):
            LOGGER.warn(
                textwrap.dedent(f"""\
            Your profile has been written, but is not complete.
            You have the AWS CLI version {cli_version}, which does not support AWS SSO.
            If you install the AWS CLI v2, aws-sso-util configure profile can interactively
            prompt you for the necessary fields. Details here:
            https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html"""
                                ))
            sys.exit(2)
    except FileNotFoundError:
        LOGGER.warn(
            textwrap.dedent("""\
            Your profile has been written, but is not complete.
            If you install the AWS CLI v2, aws-sso-util configure profile can interactively
            prompt you for the necessary fields. Details here:
            https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html"""
                            ))
        sys.exit(2)

    result = subprocess.run(
        f"aws configure sso --profile {shell_quote(profile)}", shell=True)

    if result.returncode:
        # this doesn't appear to work
        # LOGGER.error(f"Interactive configuration existed without success, restoring previous values")
        # write_values(session, profile, existing_config)
        sys.exit(10 + result.returncode)