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)
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)
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')
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)
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