From 91208ab50b6e55718e8e844be790daba4280d957 Mon Sep 17 00:00:00 2001 From: "shimoda.m@nds-tyo.co.jp" Date: Wed, 6 Jul 2022 09:42:41 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20DB=E6=8E=A5=E7=B6=9A=E3=81=A8View?= =?UTF-8?q?=E3=81=AE=E5=8F=96=E5=BE=97=E5=87=A6=E7=90=86=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../check-view-option/constants.py | 6 +++ .../check-view-option/database.py | 40 +++++++++++++++ .../check-view-option/exceptions.py | 5 ++ .../check-view-option/main.py | 50 +++++++++++++++++-- 4 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 lambda/check-view-secutiry-option/check-view-option/database.py diff --git a/lambda/check-view-secutiry-option/check-view-option/constants.py b/lambda/check-view-secutiry-option/check-view-option/constants.py index 3336997b..a0f93a3a 100644 --- a/lambda/check-view-secutiry-option/check-view-option/constants.py +++ b/lambda/check-view-secutiry-option/check-view-option/constants.py @@ -28,6 +28,12 @@ RESPONSE_ERROR_CODE = 'Code' RESPONSE_CODE_NO_SUCH_KEY = 'NoSuchKey' RESPONSE_CODE_PARAMETER_NOT_FOUND = 'ParameterNotFound' +# sql + +DEFAULT_SCHEMA = 'INFORMATION_SCHEMA' +INFORMATION_SCHEMA_SECURITY_TYPE_INVOKER = 'INVOKER' +CONNECTION_TIMEOUT = 5 + # system var UTF8 = 'utf-8' LAUNCH_ON_LOCAL = 'local' diff --git a/lambda/check-view-secutiry-option/check-view-option/database.py b/lambda/check-view-secutiry-option/check-view-option/database.py new file mode 100644 index 00000000..133ebbb4 --- /dev/null +++ b/lambda/check-view-secutiry-option/check-view-option/database.py @@ -0,0 +1,40 @@ +import contextlib + +import pymysql +from pymysql.constants import CLIENT + +from constants import CONNECTION_TIMEOUT, DEFAULT_SCHEMA + + +class Database: + + __connection: pymysql.Connection = None + __host: str = None + __user: str = None + __password: str = None + __database: str = None + + def __init__(self, host: str, user: str, password: str) -> None: + self.__host = host + self.__user = user + self.__password = password + self.__database = DEFAULT_SCHEMA + + def connect(self): + connection = pymysql.connect(host=self.__host, user=self.__user, passwd=self.__password, + database=self.__database, connect_timeout=CONNECTION_TIMEOUT, + client_flag=CLIENT.MULTI_STATEMENTS) + self.__connection = connection + + @contextlib.contextmanager + def query(self, query: str): + if self.__connection is None: + raise Exception('データベースに接続されていません') + + with self.__connection.cursor() as cursor: + cursor.execute(query) + yield cursor + + def close(self): + self.__connection.close() + self.__connection = None diff --git a/lambda/check-view-secutiry-option/check-view-option/exceptions.py b/lambda/check-view-secutiry-option/check-view-option/exceptions.py index df870583..fc00a279 100644 --- a/lambda/check-view-secutiry-option/check-view-option/exceptions.py +++ b/lambda/check-view-secutiry-option/check-view-option/exceptions.py @@ -17,3 +17,8 @@ class FileNotFoundException(MeDaCaException): class ParameterNotFoundException(MeDaCaException): """パラメータストアのキーが見つからない場合の例外""" pass + + +class DatabaseConnectionException(MeDaCaException): + """データベース接続に失敗した場合の例外""" + pass diff --git a/lambda/check-view-secutiry-option/check-view-option/main.py b/lambda/check-view-secutiry-option/check-view-option/main.py index 51586e65..cd41aaa4 100644 --- a/lambda/check-view-secutiry-option/check-view-option/main.py +++ b/lambda/check-view-secutiry-option/check-view-option/main.py @@ -8,11 +8,14 @@ import botocore from aws.s3 import ConfigBucket from aws.ssm import SSMParameterStore -from constants import (CHECK_TARGET_SCHEMAS, RESPONSE_CODE_NO_SUCH_KEY, +from constants import (CHECK_TARGET_SCHEMAS, + INFORMATION_SCHEMA_SECURITY_TYPE_INVOKER, + RESPONSE_CODE_NO_SUCH_KEY, RESPONSE_CODE_PARAMETER_NOT_FOUND, RESPONSE_ERROR, RESPONSE_ERROR_CODE) -from exceptions import (FileNotFoundException, MeDaCaException, - ParameterNotFoundException) +from database import Database +from exceptions import (DatabaseConnectionException, FileNotFoundException, + MeDaCaException, ParameterNotFoundException) from medaca_logger import MeDaCaLogger @@ -27,8 +30,16 @@ def handler(event, context): logger.info('I-03-01', 'データベースへの接続開始 開始') # DB接続のためのパラメータ取得 db_host, db_user_name, db_user_password = read_db_param_from_parameter_store() - # print(db_host, db_user_name, db_user_password) + connection = connection_database(db_host, db_user_name, db_user_password) logger.info('I-03-01', 'データベースへの接続開始 終了') + logger.info('I-04-01', 'Viewセキュリティオプション チェック開始') + check_result = check_view_security_option(connection, check_target_schemas) + + if len(check_result) == 0: + logger.info('I-04-02', 'Viewセキュリティオプション 未設定のViewはありません。処理を終了します。') + return + + logger.info('I-04-01', 'Viewセキュリティオプション 未設定のViewがあるため、メール送信処理を開始します。') except MeDaCaException as e: logger.exception(e.error_id, e) @@ -84,6 +95,37 @@ def read_db_param_from_parameter_store() -> tuple: raise Exception(e) +def connection_database(host: str, user_name: str, password: str) -> Database: + try: + database = Database(host, user_name, password) + database.connect() + return database + except Exception as e: + raise DatabaseConnectionException('E-03-02', f'データベースへの接続に失敗しました エラー内容:{e}') + + +def check_view_security_option(connection: Database, check_target_schemas: list) -> list: + select_view_security_option_sql = f""" + SELECT + TABLE_SCHEMA, + TABLE_NAME + FROM + INFORMATION_SCHEMA.VIEWS + WHERE + TABLE_SCHEMA IN ( + {','.join([f"'{schema_name}'" for schema_name in check_target_schemas])} + ) + AND SECURITY_TYPE <> '{INFORMATION_SCHEMA_SECURITY_TYPE_INVOKER}' + """ + print(select_view_security_option_sql) + try: + with connection.query(select_view_security_option_sql) as cursor: + result = cursor.fetchall() + return result + except Exception as e: + raise DatabaseConnectionException('E-03-02', f'Viewセキュリティオプションチェックに失敗しました エラー内容:{e}') + + # ローカル実行用 if __name__ == '__main__': handler({}, {})