def add_profile(args): if args.external_id and not args.role_to_assume: _print_error("Error: Cannot use --external-id without --role.") sys.exit(1) keyring = Keyring() if keyring.get_profile(args.profile): _print_error(f"Error: Profile \"{args.profile}\" already exists. If you want to modify " "the profile, remove the profile and add it again.") sys.exit(1) jumpcloud_url = args.url or input(f"Enter the JumpCloud SSO URL for \"{args.profile}\": ") jumpcloud_url = jumpcloud_url.strip() if not jumpcloud_url.startswith("https://sso.jumpcloud.com/saml2/"): _print_error("Error: That's not a valid JumpCloud SSO URL. SSO URLs must " "start with \"https://sso.jumpcloud.com/saml2/\".") sys.exit(1) if args.role_to_assume: if is_arn(args.role_to_assume): arn_parts = parse_arn(args.role_to_assume) assumed_role = AssumedRole(aws_account_id=arn_parts.aws_account_id, aws_role=arn_parts.aws_role, external_id=args.external_id) else: assumed_role = AssumedRole(aws_account_id=None, aws_role=args.role_to_assume, external_id=args.external_id) else: assumed_role = None profile = Profile(args.profile, jumpcloud_url, assumed_role) keyring.store_profile(profile) print(f"Profile \"{args.profile}\" added.")
def _login_to_aws(keyring, profile): # Returns an AWSSession with temporary credentials for the given profile. session = _login_to_jumpcloud(profile.name) sys.stderr.write("Attempting SSO authentication to Amazon Web Services...\n") try: saml_assertion = session.get_aws_saml_assertion(profile) except JumpCloudError as e: sys.stderr.write("\n") _print_error(f"Error: {e.message}") if isinstance(e, JumpCloudServerError): _print_error(f"- JumpCloud error message: {e.jumpcloud_error_message or e.response.text}") elif isinstance(e, JumpCloudMissingSAMLResponse): sys.stderr.write("\n") _print_error("You may have been removed from the Single-Sign On Application for the profile " f"\"{profile.name}\", or its URL may be be incorrect. You can check the URL by " "visiting the JumpCloud Console in your web browser and confirming that one of " f"the Single Sign-On Applications has the URL \"{profile.jumpcloud_url}\". If " "the URL is correct, aws-jumpcloud may need to be updated.") sys.exit(1) roles = get_assertion_roles(saml_assertion) # Warning: It's a valid JumpCloud configuration to present more than one # role in the assertion, but we don't use that feature right now. We # should handle that situation properly at some point. assert(len(roles) == 1) role = roles[0] # Update the AWS account ID and role name if they've changed r = parse_arn(role.role_arn) if profile.aws_account_id != r.aws_account_id: profile.aws_account_id = r.aws_account_id keyring.store_profile(profile) if profile.aws_role != r.aws_role: profile.aws_role = r.aws_role keyring.store_profile(profile) session = assume_role_with_saml(role, saml_assertion, profile.override_session_duration) # Update the AWS account alias on each login. The alias refers to the # account used to login, not any assumed role (which happens below). alias = get_account_alias(session) if alias != profile.aws_account_alias: profile.aws_account_alias = alias keyring.store_profile(profile) if profile.role_to_assume: if not profile.role_to_assume.aws_account_id: profile.role_to_assume.aws_account_id = profile.aws_account_id keyring.store_profile(profile) sys.stderr.write(f"Assuming role {profile.role_to_assume.arn}...\n") email = keyring.get_jumpcloud_email() role_session_name = get_role_session_name(email) session = assume_role(session, profile.role_to_assume, role_session_name) keyring.store_session(profile.name, session) sys.stderr.write("\n") return session