def send_email_invites(new_users, settings):
    msg_template = '''
You have been invited to join the {} AWS account!
Below you will find credentials for the first sign in.
You will be requested to change your password.

The password is encrypted with your public gpg key. To decrypt the password:

echo <password> | base64 -d | gpg -d - && echo
(you will be asked to provide your passphrase to unlock the secret)

Details:

Console URL: {}
Username: {}
Encrypted password: {}

'''
    mails = []
    for account, console_url, user_name, enc_password in new_users:
        to = user_name
        subject = 'Invitation to join the {} AWS account'.format(account)
        body = msg_template.format(account, console_url, user_name,
                                   enc_password)
        mails.append((to, subject, body))
    smtp_client = SmtpClient(settings=settings)
    smtp_client.send_mails(mails)
Exemple #2
0
def send_email_notification(user, settings):
    msg_template = '''
Hello,

This is an automated message coming from App-Interface.

The App SRE team adheres to the OpenShift GitHub policy:
https://mojo.redhat.com/docs/DOC-1200784

Your GitHub profile does not comply with the following requirements:

- Company field should contain "Red Hat".


For any questions, please ping @app-sre-ic on #sd-app-sre in CoreOS Slack,
or mail us at [email protected].

App-Interface repository: https://gitlab.cee.redhat.com/service/app-interface

'''
    to = user['username']
    subject = 'App-Interface compliance - GitHub profile'
    body = msg_template
    smtp_client = SmtpClient(settings=settings)
    smtp_client.send_mail([to], subject, body)
Exemple #3
0
def run(dry_run):
    settings = queries.get_app_interface_settings()
    accounts = queries.get_aws_accounts()
    users = queries.get_users()
    state = State(
        integration=QONTRACT_INTEGRATION,
        accounts=accounts,
        settings=settings
    )
    smtp_client = SmtpClient(settings=settings)
    mails = smtp_client.get_mails(
        criteria='SUBJECT "Sentry Access Request"',
        folder='[Gmail]/Sent Mail'
    )
    user_names = get_sentry_users_from_mails(mails)
    if not dry_run:
        slack = init_slack_workspace(QONTRACT_INTEGRATION,
                                     init_usergroups=False)
    for user_name in user_names:
        guesses = guess_user(user_name, users)
        if not guesses:
            logging.debug(f'no users guessed for {user_name}')
            continue
        slack_username = \
            guesses[0].get('slack_username') or guesses[0]['org_username']
        if state.exists(slack_username):
            continue
        logging.info(['help_user', slack_username])
        if not dry_run:
            state.add(slack_username)
            slack.chat_post_message(
                f'yo <@{slack_username}>! it appears that you have ' +
                'requested access to a project in Sentry. ' +
                'access is managed automatically via app-interface. '
                'checkout https://url.corp.redhat.com/sentry-help')
Exemple #4
0
def run(dry_run):
    settings = queries.get_app_interface_settings()
    accounts = queries.get_aws_accounts()
    smtp_client = SmtpClient(settings=settings)
    state = State(integration=QONTRACT_INTEGRATION,
                  accounts=accounts,
                  settings=settings)
    credentials_requests = queries.get_credentials_requests()

    # validate no 2 requests have the same name
    credentials_requests_names = \
        set([r['name'] for r in credentials_requests])
    if len(credentials_requests) != len(credentials_requests_names):
        logging.error('request names must be unique.')
        sys.exit(1)

    error = False

    credentials_requests_to_send = \
        [r for r in credentials_requests if not state.exists(r['name'])]
    for credentials_request_to_send in credentials_requests_to_send:
        user = credentials_request_to_send['user']
        org_username = user['org_username']
        public_gpg_key = user.get('public_gpg_key')
        credentials_name = credentials_request_to_send['credentials']
        if not public_gpg_key:
            error = True
            logging.error(
                f"user {org_username} does not have a public gpg key")
            continue
        logging.info(['send_credentials', org_username, credentials_name])

        if not dry_run:
            request_name = credentials_request_to_send['name']
            names = [org_username]
            subject = request_name
            ecrypted_credentials = get_ecrypted_credentials(
                credentials_name, user, settings, smtp_client)
            if not ecrypted_credentials:
                error = True
                logging.error(
                    f"could not get encrypted credentials {credentials_name}")
                continue
            body = MESSAGE_TEMPLATE.format(request_name, credentials_name,
                                           ecrypted_credentials)
            smtp_client.send_mail(names, subject, body)
            state.add(request_name)

    if error:
        sys.exit(1)
Exemple #5
0
def run(dry_run):
    settings = queries.get_app_interface_settings()
    accounts = queries.get_state_aws_accounts()
    smtp_client = SmtpClient(settings=settings)
    state = State(integration=QONTRACT_INTEGRATION,
                  accounts=accounts,
                  settings=settings)
    credentials_requests = queries.get_credentials_requests()

    # validate no 2 requests have the same name
    credentials_requests_names = {r["name"] for r in credentials_requests}
    if len(credentials_requests) != len(credentials_requests_names):
        logging.error("request names must be unique.")
        sys.exit(1)

    error = False

    credentials_requests_to_send = [
        r for r in credentials_requests if not state.exists(r["name"])
    ]
    for credentials_request_to_send in credentials_requests_to_send:
        try:
            user = credentials_request_to_send["user"]
            credentials_name = credentials_request_to_send["credentials"]
            org_username = user["org_username"]
            logging.info(["send_credentials", org_username, credentials_name])

            request_name = credentials_request_to_send["name"]
            names = [org_username]
            subject = request_name
            encrypted_credentials = get_encrypted_credentials(
                credentials_name, user, settings)
            if not dry_run:
                body = MESSAGE_TEMPLATE.format(request_name, credentials_name,
                                               encrypted_credentials)
                smtp_client.send_mail(names, subject, body)
                state.add(request_name)
        except KeyError:
            logging.exception(
                f"Bad user details for {org_username} - {credentials_name}")
            error = True
        except CalledProcessError as e:
            logging.exception(f"Failed to handle GPG key for {org_username} "
                              f"({credentials_name}): {e.stdout}")
            error = True

    if error:
        sys.exit(1)
def validate_users_gpg_key(users):
    ok = True
    settings = queries.get_app_interface_settings()
    smtp_client = SmtpClient(settings=settings)
    for user in users:
        public_gpg_key = user.get('public_gpg_key')
        if public_gpg_key:
            recipient = smtp_client.get_recipient(user['org_username'])
            try:
                gpg_key_valid(public_gpg_key, recipient)
            except ValueError as e:
                msg = \
                    'invalid public gpg key for user {}: {}'.format(
                        user['org_username'], str(e))
                logging.error(msg)
                ok = False

    return ok
def run(dry_run):
    settings = queries.get_app_interface_settings()
    accounts = queries.get_aws_accounts()
    state = State(integration=QONTRACT_INTEGRATION,
                  accounts=accounts,
                  settings=settings)
    emails = queries.get_app_interface_emails()
    smtp_client = SmtpClient(settings=settings)
    # validate no 2 emails have the same name
    email_names = {e['name'] for e in emails}
    if len(emails) != len(email_names):
        logging.error('email names must be unique.')
        sys.exit(1)

    emails_to_send = [e for e in emails if not state.exists(e['name'])]
    for email in emails_to_send:
        logging.info(['send_email', email['name'], email['subject']])

        if not dry_run:
            names = collect_to(email['to'])
            subject = email['subject']
            body = email['body']
            smtp_client.send_mail(names, subject, body)
            state.add(email['name'])
def collect_queries(query_name=None, settings=None):
    """
    Consults the app-interface and constructs the list of queries
    to be executed.

    :param query_name: (optional) query to look for
    :param settings: App Interface settings

    :return: List of queries dictionaries
    """
    queries_list = []

    # Items to be either overridden ot taken from the k8s secret
    db_conn_items = {
        "db.host": None,
        "db.name": None,
        "db.password": None,
        "db.port": None,
        "db.user": None,
    }

    sql_queries = queries.get_app_interface_sql_queries()

    for sql_query in sql_queries:
        name = sql_query["name"]

        for existing in queries_list:
            if existing["name"] == name:
                logging.error(["SQL-Query %s defined more than once"], name)
                sys.exit(ExitCodes.ERROR)

        # Looking for a specific query
        if query_name is not None:
            if name != query_name:
                continue

        namespace = sql_query["namespace"]
        identifier = sql_query["identifier"]

        # Due to an API limitation, the keys are coming with underscore
        # instead of period, so we are using this unpacking routine
        # to also replace "_" by "." in the keys
        if sql_query["overrides"] is not None:
            overrides = {
                key.replace("_", "."): value
                for key, value in sql_query["overrides"].items()
                if value is not None
            }
        else:
            overrides = {}

        # Merging the overrides. Values that are still None after this
        # will be taken from the k8s secret on template rendering
        db_conn = {**db_conn_items, **overrides}

        # Output can be:
        # - stdout
        # - filesystem
        # - encrypted
        output = sql_query["output"]
        if output is None:
            output = "stdout"
        elif output == "encrypted":
            requestor = sql_query.get("requestor")
            if requestor is None:
                logging.error(
                    "a requestor is required to get encrypted output")
                sys.exit(ExitCodes.ERROR)
            public_gpg_key = requestor.get("public_gpg_key")
            user_name = requestor.get("org_username")
            if public_gpg_key is None:
                logging.error(["user %s does not have a public gpg key"],
                              user_name)
                sys.exit(ExitCodes.ERROR)

        # Extracting the terraformResources information from the namespace
        # fo the given identifier
        tf_resource_info = get_tf_resource_info(namespace, identifier)
        if tf_resource_info is None:
            logging.error(
                ["Could not find rds identifier %s in namespace %s"],
                identifier,
                namespace["name"],
            )
            sys.exit(ExitCodes.ERROR)

        sql_queries = []
        if sql_query["query"] is not None:
            sql_queries.append(sql_query["query"])

        if sql_query["queries"] is not None:
            sql_queries.extend(sql_query["queries"])

        sql_queries = [item.replace("'", "''") for item in sql_queries]

        # building up the final query dictionary
        item = {
            "name": name,
            "namespace": namespace,
            "identifier": sql_query["identifier"],
            "db_conn": db_conn,
            "output": output,
            "queries": sql_queries,
            **tf_resource_info,
        }

        if output == "encrypted":
            smtp_client = SmtpClient(settings=settings)
            item["recipient"] = smtp_client.get_recipient(
                sql_query["requestor"]["org_username"])
            item["public_gpg_key"] = sql_query["requestor"][
                "public_gpg_key"].replace("\n", "")

        # If schedule is defined
        # this should be a CronJob
        schedule = sql_query.get("schedule")
        if schedule:
            item["schedule"] = schedule

        queries_list.append(item)

    return queries_list