Systems Manager를 사용하여 애플리케이션 인벤토리 가져오기

8637 단어 inventoryssmawsglue
배경

클라우드에 배포된 "소프트웨어 버전"에 대해 보고할 방법이 필요합니다.

목적

각 EC2 인스턴스에서 애플리케이션 인벤토리를 가져와 중앙 집중식 계정 S3 버킷에 저장합니다. s3 버킷에서 정보를 쿼리하기 위해 Glue, Athena(다른 계정에서)를 통합하고 있습니다.

제안된 아키텍처



시행절차
  • 각 계정(일회성 활동)(PROD/NONPROD)에서 시스템 관리자 인벤토리 활성화
  • 시스템 관리자로부터 로그를 수신하기 위해 중앙 집중식 계정에 S3 버킷 생성(일회성 활동)
  • 각 계정(PROD/NONPROD)에서 리소스 데이터 동기화를 생성하여 로그를 중앙 집중식 버킷으로 전송(일회성 활동)
  • 분석 서비스가 다른 계정에서 실행 중인 경우 객체 수준 권한을 업데이트해야 하므로 중앙 집중식 계정에 Lambda 함수를 생성하여 각 객체에 객체 수준 권한을 할당합니다(AWS에서 제공하는 해결 방법)
  • S3 버킷(s3://ssm-application-inventory-logs)을 쿼리하기 위해 필요한 계정에서 Glue 및 Athena를 구성합니다.

  • 각 계정에서 System Manager 인벤토리 활성화

    각 계정에서 일회성 활동이므로 AWS 콘솔을 사용하여 이 기능을 활성화해야 합니다.

    [ https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-inventory-configuring.html ]

    접착제 세부 정보

    ssm 인벤토리 출력과 일치하도록 필요한 계정에 Glue 크롤러, Glue 데이터베이스 및 테이블을 생성합니다.



    아테나 쿼리
  • 이 서비스는 다른 계정에서 활성화되어 있습니다.

  • 최신 보고서를 위해 크롤러 실행
  • 최신 보고서를 얻으려면 Glue 크롤러를 수동으로 실행해야 합니다. 성공적인 실행 후 Athena 예제를 따릅니다.



  • 예 1:
  • 모든 계정에서 전체 인벤토리 세부 정보를 가져오려면 아래 쿼리를 사용하십시오.

  • SELECT * from aws_application
    




    예 2:
  • 응용 프로그램별 인스턴스 세부 정보를 가져오려면 아래 쿼리를 사용하여 'java%'를 응용 프로그램 이름으로 바꿉니다.

  • SELECT java.name, java.version, a.resourceid, accountid 
    FROM “ssm-inventory-crawler-db”.”aws_application” a, (select distinct (resourceid), version, name from “ssm-inventory-crawler-db”.”aws_application” where name like ‘java%’) java
    where a.resourceid = java.resourceid
    order by a.resourceid
    


    예 3:
  • Athena를 사용하여 "python"과 같은 사용자 정의 인벤토리 라이브러리를 가져오려면

  • SELECT * FROM “ssm-inventory-crawler-db”.”custom_python2libraries”;
    


    예 4:

    Athena를 사용하여 "npm"과 같은 사용자 지정 인벤토리 라이브러리를 가져오려면

    SELECT * FROM “ssm-inventory-crawler-db”.”custom_nodejsnpm”;
    


    Lambda를 사용하여 자동화된 방식으로 쿼리 실행
  • 아래 Python 스크립트를 사용하여 CloudWatch 이벤트 규칙 및 Lambda를 사용하여 매월 1일 Athena를 쿼리할 수 있습니다.

  • #!/usr/bin/python3
    import boto3
    import datetime
    import os
    import json
    import logging
    # boto3.setup_default_session(profile_name='saml',region_name='ap-southeast-1')
    logger = logging.getLogger()
    logger.setLevel(logging.DEBUG)
    def poll_status(_id, message):
        athena= boto3.client('athena',region_name='ap-southeast-1')
        result = athena.get_query_execution( QueryExecutionId = _id )
        state  = result['QueryExecution']['Status']['State']
    
        while state == "QUEUED":
            result = athena.get_query_execution( QueryExecutionId = _id )
            state  = result['QueryExecution']['Status']['State']
            while state == "RUNNING":
                result = athena.get_query_execution( QueryExecutionId = _id )
                state  = result['QueryExecution']['Status']['State']
                if state == "FAILED":
                    logger.info("FAILED-LOG: {} ".format(result))
            # return result
        else:
            logger.info("SUCCESS-LOG : {} ".format(result))
            sns_arn = os.environ["SNS_ARN"] #"arn:aws:sns:ap-southeast-1:928167378288:application-inventory-logs" 
            notification= _sns_notification(sns_arn,message)
            return result
    def run_query(query, database, s3_output):
        client = boto3.client('athena',region_name='ap-southeast-1')
        response = client.start_query_execution(
            QueryString=query,
            QueryExecutionContext={
                'Database': database
                },
            ResultConfiguration={
                'OutputLocation': s3_output,
                }
            )
        print('Execution ID: ' + response['QueryExecutionId'])
        QueryExecutionId = response['QueryExecutionId']
        return QueryExecutionId
    
            # local_filename = QueryExecutionId + '.csv'
    def _sns_notification(snsarn,message):
        client = boto3.client('sns')
        response = client.publish(TargetArn=snsarn,Message=json.dumps({'default': json.dumps(message)}),MessageStructure='json')
        logger.warning("SNS-NOTIFICATION : {} ".format(response))
        return response
    def lambda_handler(event, context):
        #Athena configuration
        s3_output = os.environ['ATHENA_OUTPUT_BUCKET'] #'s3://athena-query-result-logs/result/' 
        database =   os.environ['GLUE_DB'] #'ssminventorycrawlerdb'
        table = os.environ["GLUE_TABLE"] #'aws_application' #
        app_search = os.environ["APPLICATION_LIST"] # "java% python% node%" #
        app_list= app_search.split(' ')
        sns_arn = "arn:aws:sns:ap-southeast-1:928167378288:application-inventory-logs" #os.environ["SNS-ARN"]
        #Athena database and table definition
    
        #Query definitions & Execute all queries
        python_library = "SELECT * FROM "'"%s"'"."'"%s"'" ;" % (database, "custom_python2libraries")
        npm_librarary = "SELECT * FROM "'"%s"'"."'"%s"'" ;" % (database, "custom_nodejsnpm")
        all_app = "SELECT * FROM "'"%s"'"."'"%s"'" ;" % (database, table)
        queries = [ python_library, npm_librarary, all_app ]
        for qa in queries:
            print("Executing query: %s" % (qa))
            resp = run_query(qa, database, s3_output)
            logger.info("QUERY-ID: {} ".format(resp))
            s3_key = resp + '.csv'
            message= {"Application-Inventory": s3_key,"Bucket-Details": s3_output,"App-name":qa}
            logger.info("MESSAGE-DETAILS : {} ".format(message))
            result = poll_status(resp, message)
        for app in app_list:
            specific_app = ("""SELECT java.name, java.version, a.resourceid, accountid 
                        FROM "%s"."%s" a, (select distinct (resourceid), version, name from "%s"."%s" where name like '%s') java
                        where a.resourceid = java.resourceid
                        order by a.resourceid """) % (database, table,database, table,app)
            # queries = [ python_library, npm_librarary, all_app, specific_app ]
            # for q in queries:
            print("Executing query: %s" % (specific_app))
            res = run_query(specific_app, database, s3_output)
            logger.info("QUERY-ID: {} ".format(res))
            s3_key = res + '.csv'
            messages= {"Application-Inventory": s3_key,"Bucket-Details": s3_output,"App-name":specific_app}
            logger.info("MESSAGE-DETAILS : {} ".format(messages))
            results = poll_status(res, messages)
    
    if __name__ == '__main__':
        lambda_handler("event", "context")
    


    자원
  • 맞춤 인벤토리:

  • [ https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-inventory-custom.html ]
  • CFN 리소스 데이터 동기화:

  • [ https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ssm-resourcedatasync.html ]

    좋은 웹페이지 즐겨찾기