برنامه نویسی

نظارت بر انطباق سیاست CloudFormation: استفاده از CloudTrail و آتنا

مقدمه:

این پست جزئیات اجرای را نشان می دهد که نظارت دارد چه کسی یا چه چیزی منابع AWS ایجاد شده توسط CloudFormation را تغییر داده است. با استفاده از AWS Config ، CloudTrail ، Athena و Lambda می توان تغییرات را ردیابی کرد ، می توان گزارش ها را مورد تجزیه و تحلیل قرار داد و گزارش های مربوط به انطباق را می توان خودکار کرد. داده های جمع آوری شده در آمازون S3 ذخیره می شوند و آن را برای حسابرسی ها و تأیید انطباق در دسترس قرار می دهند.

درباره پروژه:

این پست بر اساس مقاله قبلی من در مورد نظارت بر Drift CloudFormation Stack با استفاده از قوانین پیکربندی AWS ساخته شده است. در این نسخه پیشرفته ، قابلیت های نظارت توسط:

پیگیری فعالیت های کاربر بر روی منابع ابری تأثیر می گذارد.
ورود به سیستم جزئیات تغییر آمازون S3 از طریق CloudTrail.
گزارش های پردازش و پرس و جو با استفاده از AWS آتنا.
ترمیم خودکار از طریق مدیر سیستم AWS و لامبدا.

اجزای اصلی:
قانون پیکربندی AWS: مانیتور برای رانش با استفاده از CloudFormation_stack_Drift_Detection_Check.
مدیر سیستم اتوماسیون مدیر سیستم: یک عملکرد لامبدا را برای بررسی های مربوط به انطباق فراخوانی می کند.
اقدام اصلاح: سند اتوماسیون InvokeLambdafromConfig را اجرا می کند.
سطل آمازون S3: فروشگاه ها از نتایج CloudTrail و Athena Query.
میز آتنا: داده های ورود به سیستم خام را سازماندهی و نمایش داده می کند.
مسیر CloudTrail: پرونده های فعالیت AWS API را ضبط می کند.
عملکرد لامبدا: نامهای منابع CloudFormation را برای تغییرات اخیر آتنا استخراج می کند.
زیرساخت Scema:
طرح

پیکربندی در infrastructure/monitoring_stack_cloudtrail.yaml الگوی ابری:

    AWSTemplateFormatVersion: '2010-09-09'
    Description: CloudTrail setup for monitoring CFN stack modifications

    Parameters:
      AthenaDatabaseName:
        Type: String
        Description: Athena database name for running queries
        Default: 'cloudtrail_logs'
      StackNameToMonitor:
        Type: String
        Description: CloudFormation stack name to monitor
        Default: 'base-infrastructure'
      MaximumExecutionFrequency:
        Type: String
        Description: The maximum frequency with which drift in CloudFormation stacks need to be evaluated
        Default: 'One_Hour'

    Resources:
    #################################
    # CloudTrail and Athena
    #################################
      CloudTrailLogsBucket:
        Type: AWS::S3::Bucket
        Properties:
          BucketName: !Sub "aws-cloudtrail-logs-${AWS::AccountId}"
          VersioningConfiguration:
            Status: Enabled
          LifecycleConfiguration:
            Rules:
              - Id: ExpireLogs
                Status: Enabled
                ExpirationInDays: 365

      CloudTrailLogsBucketPolicy:
        Type: AWS::S3::BucketPolicy
        Properties:
          Bucket: !Ref CloudTrailLogsBucket
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Sid: "AWSCloudTrailAclCheck"
                Effect: Allow
                Principal:
                  Service: cloudtrail.amazonaws.com
                Action: s3:GetBucketAcl
                Resource: !Sub "arn:${AWS::Partition}:s3:::aws-cloudtrail-logs-${AWS::AccountId}"
                Condition:
                  StringEquals:
                    AWS:SourceArn: !Sub "arn:${AWS::Partition}:cloudtrail:${AWS::Region}:${AWS::AccountId}:trail/monitoring-cfn-policy-compliance"
              - Sid: "AWSCloudTrailWrite"
                Effect: Allow
                Principal:
                  Service: cloudtrail.amazonaws.com
                Action: s3:PutObject
                Resource: !Sub "arn:${AWS::Partition}:s3:::aws-cloudtrail-logs-${AWS::AccountId}/AWSLogs/${AWS::AccountId}/*"
                Condition:
                  StringEquals:
                    AWS:SourceArn: !Sub "arn:${AWS::Partition}:cloudtrail:${AWS::Region}:${AWS::AccountId}:trail/monitoring-cfn-policy-compliance"
                    s3:x-amz-acl: "bucket-owner-full-control"
              - Sid: "AthenaQueryResultPutObject"
                Effect: Allow
                Principal:
                  Service: athena.amazonaws.com
                Action: s3:PutObject
                Resource: !Sub "arn:${AWS::Partition}:s3:::aws-cloudtrail-logs-${AWS::AccountId}/athena-results/*"
                Condition:
                  StringEquals:
                    aws:SourceArn: !Sub "arn:${AWS::Partition}:athena:${AWS::Region}:${AWS::AccountId}:workgroup/primary"

      CloudTrail:
        Type: AWS::CloudTrail::Trail
        Properties:
          TrailName: monitoring-cfn-policy-compliance
          S3BucketName: !Ref CloudTrailLogsBucket
          IncludeGlobalServiceEvents: true
          IsMultiRegionTrail: true
          EnableLogFileValidation: false
          IsOrganizationTrail: false
          IsLogging: true

      AthenaDatabase:
        Type: AWS::Glue::Database
        Properties:
          CatalogId: !Ref AWS::AccountId
          DatabaseInput:
            Name: !Ref AthenaDatabaseName

      AthenaTable:
        Type: AWS::Glue::Table
        Properties:
          CatalogId: !Ref AWS::AccountId
          DatabaseName: !Ref AthenaDatabase
          TableInput:
            Name: !Sub "aws_cloudtrail_logs_${AWS::AccountId}"
            TableType: EXTERNAL_TABLE
            Parameters:
              classification: cloudtrail
            StorageDescriptor:
              Columns:
                - Name: eventVersion
                  Type: string
                - Name: userIdentity
                  Type: struct,sessionIssuer:struct,ec2RoleDelivery:string,webIdFederationData:struct>>>
                - Name: eventTime
                  Type: string
                - Name: eventSource
                  Type: string
                - Name: eventName
                  Type: string
                - Name: awsRegion
                  Type: string
                - Name: sourceIpAddress
                  Type: string
                - Name: userAgent
                  Type: string
                - Name: errorCode
                  Type: string
                - Name: errorMessage
                  Type: string
                - Name: requestParameters
                  Type: string
                - Name: responseElements
                  Type: string
                - Name: additionalEventData
                  Type: string
                - Name: requestId
                  Type: string
                - Name: eventId
                  Type: string
                - Name: resources
                  Type: array>
                - Name: eventType
                  Type: string
                - Name: apiVersion
                  Type: string
                - Name: readOnly
                  Type: string
                - Name: recipientAccountId
                  Type: string
                - Name: serviceEventDetails
                  Type: string
                - Name: sharedEventID
                  Type: string
                - Name: vpcEndpointId
                  Type: string
                - Name: tlsDetails
                  Type: struct
              Location: !Sub "s3://aws-cloudtrail-logs-${AWS::AccountId}/AWSLogs/${AWS::AccountId}/CloudTrail/"
              InputFormat: com.amazon.emr.cloudtrail.CloudTrailInputFormat
              OutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat
              SerdeInfo:
                SerializationLibrary: org.apache.hive.hcatalog.data.JsonSerDe

    #################################
    # Lambda function
    #################################
      LambdaExecutionRole:
        Type: AWS::IAM::Role
        Properties:
          RoleName: LambdaAthenaQueryExecutionRole
          AssumeRolePolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Principal:
                  Service: 
                    - lambda.amazonaws.com
                    - athena.amazonaws.com
                Action:
                  - sts:AssumeRole
          Policies:
            - PolicyName: CloudFormationDescribe
              PolicyDocument:
                Version: "2012-10-17"
                Statement:
                  - Effect: Allow
                    Action:
                      - cloudformation:DescribeStackResources
                    Resource: "arn:aws:cloudformation:*"
            - PolicyName: AthenaQueryPolicy
              PolicyDocument:
                Version: "2012-10-17"
                Statement:
                  - Effect: Allow
                    Action:
                    - athena:StartQueryExecution
                    - athena:GetQueryExecution
                    - athena:GetQueryResults
                    - athena:GetWorkGroup
                    - athena:GetDataCatalog
                    - athena:GetTableMetadata
                    - glue:GetDatabase
                    - glue:GetTable
                    - glue:GetPartitions
                    Resource: "*"
                  - Effect: Allow
                    Action:
                    - s3:PutObject
                    - s3:GetObject
                    - s3:ListBucket
                    - s3:GetBucketLocation
                    - s3:PutObjectAcl
                    Resource: 
                      - !Sub "arn:${AWS::Partition}:s3:::${CloudTrailLogsBucket}"
                      - !Sub "arn:${AWS::Partition}:s3:::${CloudTrailLogsBucket}/*"
                  - Effect: Allow
                    Action:
                      - lambda:AddPermission
                    Resource: "*"
                  - Effect: Allow
                    Action:
                      - logs:CreateLogGroup
                      - logs:CreateLogStream
                      - logs:PutLogEvents
                    Resource: "*"

      CheckCloudTrailLogsLambda:
        Type: AWS::Lambda::Function
        Properties:
          FunctionName: CheckCloudTrailLogsLambda
          Runtime: nodejs22.x
          Handler: index.handler
          Role: !GetAtt LambdaExecutionRole.Arn
          Timeout: 120
          MemorySize: 256
          Environment:
            Variables:
              STACKS_TO_MONITOR: !Ref StackNameToMonitor
              ATHENA_DATABASE: !Ref AthenaDatabase
              ATHENA_TABLE: !Ref AthenaTable
              S3_OUTPUT_BUCKET: !Ref CloudTrailLogsBucket
          Code:
            ZipFile: |
              const { AthenaClient, StartQueryExecutionCommand } = require("@aws-sdk/client-athena");
              const { CloudFormationClient, DescribeStackResourcesCommand } = require("@aws-sdk/client-cloudformation");

              const athena = new AthenaClient({});
              const cloudformation = new CloudFormationClient({});

              exports.handler = async (event) => {
                  console.log("Event received:", JSON.stringify(event, null, 2));

                  const stacks = process.env.STACKS_TO_MONITOR.split(",");
                  const tableName = process.env.ATHENA_TABLE;
                  const databaseName = process.env.ATHENA_DATABASE;
                  const s3Bucket = process.env.S3_OUTPUT_BUCKET;

                  let resourceNames = [];

                  // Extract resource names from the CloudFormation stacks
                  for (const stack of stacks) {
                      const stackResources = await cloudformation.send(
                          new DescribeStackResourcesCommand({ StackName: stack })
                      );

                      stackResources.StackResources.forEach(resource => {
                          if (resource.PhysicalResourceId) {
                              resourceNames.push(resource.PhysicalResourceId);
                          }
                      });
                  }

                  // Construct Athena query
                  let whereClause = resourceNames.map(name => `resource.arn LIKE '%${name}%'`).join(" OR ");
                  let queryString = `
                      SELECT 
                          userIdentity.userName AS username,
                          eventName AS action,
                          eventTime AS timestamp,
                          resource.arn AS resource_arn,
                          sourceIPAddress AS request_source,
                          userAgent AS user_agent
                      FROM ${tableName}
                      CROSS JOIN UNNEST(resources) AS t(resource)
                      WHERE (${whereClause})
                      AND eventName IS NOT NULL
                      AND userIdentity.userName IS NOT NULL
                      AND from_iso8601_timestamp(eventTime) >= current_timestamp - INTERVAL '1' HOUR
                      ORDER BY from_iso8601_timestamp(eventTime) DESC;
                  `;

                  // Run the Athena query
                  const params = {
                      QueryString: queryString,
                      QueryExecutionContext: { Database: databaseName },
                      ResultConfiguration: { OutputLocation: `s3://${s3Bucket}/athena-results/` }
                  };

                  try {
                      const command = new StartQueryExecutionCommand(params);
                      const queryExecution = await athena.send(command);
                      console.log("Query started:", queryExecution.QueryExecutionId);
                      return { status: "Query started successfully", queryExecutionId: queryExecution.QueryExecutionId };
                  } catch (error) {
                      console.error("Error running query:", error);
                      throw error;
                  }
              };

      LambdaPermissionForConfig:
        Type: AWS::Lambda::Permission
        Properties:
          FunctionName: !Ref CheckCloudTrailLogsLambda
          Action: lambda:InvokeFunction
          Principal: config.amazonaws.com

    #################################
    # Config Rule
    #################################
      IamRoleForConfig2:
        Type: AWS::IAM::Role
        Properties:
          RoleName: CfnDriftDetectionForCloudTrail
          Description: IAM role for AWS Config to access CloudFormation drift detection
          AssumeRolePolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Principal:
                  Service: config.amazonaws.com
                Action:
                  - sts:AssumeRole
          ManagedPolicyArns:
            - arn:aws:iam::aws:policy/ReadOnlyAccess
          Policies:
            - PolicyName: CloudFormationDriftDetectionpolicy
              PolicyDocument:
                Version: "2012-10-17"
                Statement:
                  - Effect: Allow
                    Action:
                      - cloudformation:DetectStackResourceDrift
                      - cloudformation:DetectStackDrift
                      - cloudformation:DescribeStacks
                      - cloudformation:DescribeStackResources
                      - cloudformation:BatchDescribeTypeConfigurations
                      - cloudformation:DescribeStackResourceDrifts
                      - cloudformation:DescribeStackDriftDetectionStatus
                    Resource: !Sub "arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:*"

      ConfigRuleCheckCloudTralLogs:
        DependsOn:
        - LambdaPermissionForConfig
        Type: AWS::Config::ConfigRule
        Properties:
          ConfigRuleName: ConfigRuleCheckCloudTrailLogs
          Description: AWS Config rule to detect drift in CFN stacks and check CloudTrail logs
          Scope:
            TagKey: stack-name
            TagValue: !Ref StackNameToMonitor
          Source:
            Owner: AWS
            SourceIdentifier: CLOUDFORMATION_STACK_DRIFT_DETECTION_CHECK
          MaximumExecutionFrequency: !Ref MaximumExecutionFrequency
          InputParameters:
            cloudformationRoleArn: !GetAtt IamRoleForConfig2.Arn

      IamRoleForRemediation:
        Type: AWS::IAM::Role
        Properties:
          RoleName: AwsConfigRemediationActionInvokeLambda
          Description: IAM role for AWS Config remediation action to invoke Lambda function
          AssumeRolePolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Principal:
                  Service:
                    - config.amazonaws.com
                    - ssm.amazonaws.com
                Action:
                  - sts:AssumeRole
          Policies:
            - PolicyName: InvokeLambdaPolicy
              PolicyDocument:
                Version: '2012-10-17'
                Statement:
                  - Effect: Allow
                    Action:
                      - lambda:InvokeFunction
                    Resource: !GetAtt CheckCloudTrailLogsLambda.Arn

      SsmDocumentInvokeLambda:
        Type: AWS::SSM::Document
        Properties:
          DocumentType: Automation
          Name: InvokeLambdaFromConfig
          Content:
            schemaVersion: "0.3"
            description: "SSM Automation document to invoke a Lambda function"
            parameters:
              AutomationAssumeRole:
                type: String
                description: (Optional) The ARN of the role that allows Automation to perform the actions
                default: !GetAtt IamRoleForRemediation.Arn
            mainSteps:
              - name: InvokeLambda
                action: aws:invokeLambdaFunction
                inputs:
                  FunctionName: !Ref CheckCloudTrailLogsLambda
                  Payload: '{}'
                  InvocationType: Event
                  LogType: None
                maxAttempts: 2
                timeoutSeconds: 30
                onFailure: Abort
                isCritical: true
            assumeRole: !GetAtt IamRoleForRemediation.Arn

      RemediationActionInvokeLambda:
        Type: AWS::Config::RemediationConfiguration
        Properties:
          ConfigRuleName: !Ref ConfigRuleCheckCloudTralLogs
          TargetType: SSM_DOCUMENT
          TargetId: !Ref SsmDocumentInvokeLambda
          Automatic: true
          MaximumAutomaticAttempts: 2
          RetryAttemptSeconds: 30
          Parameters:
            AutomationAssumeRole:
              StaticValue:
                Values:
                  - !GetAtt IamRoleForRemediation.Arn
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

پیش نیازها:

اطمینان حاصل کنید که پیش نیازهای زیر وجود دارد:

  • یک حساب AWS با مجوزهای کافی برای ایجاد و مدیریت منابع.
  • AWS CLI روی دستگاه محلی نصب شده است.
  • زیرساخت های CloudFormation از پست قبلی من (در صورت وجود) مستقر شده است.

استقرار:

  1. پشته CloudFormation را مستقر کنید.
    aws cloudformation create-stack \
        --stack-name monitoring-policy-compliance \
        --template-body file://infrastructure/monitoring_stack_cloudtrail.yaml \
        --capabilities CAPABILITY_NAMED_IAM \
        --disable-rollback
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

2. منابع مستقر شده با پشته. مقدار منبع را از پشته زیرساخت پایه تغییر داده و قانون تشخیص رانش را برای تأیید عملکرد ارزیابی کنید.

    aws ssm put-parameter --name "ConnectionToken" --value "secret_token_value_2" --type "String" --overwrite

    aws configservice start-config-rules-evaluation --config-rule-names ConfigRuleCheckCloudTrailLogs
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

3. بعد از اجرای تشخیص رانش ، نتایج پرس و جو آتنا را که در S3 تحت /و نتایج آتنا در پرونده .csv ذخیره شده است ، بررسی کنید.

    aws s3 ls s3:///athena-results/ --recursive

    aws s3 cp s3:///.csv ./
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

در اینجا نمونه ای از سیاهههای مربوط به این پرونده آورده شده است:

سیاهههای مربوط به

)

منابع 4.Cleanup. پس از آزمایش ، ورود به سیستم CloudTrail Trail را متوقف کنید ، تمام داده ها را از سطل S3 حذف کنید و پشته CloudFormation را حذف کنید.

    aws cloudtrail stop-logging --name monitor-cfn-policy-compliance

    aws s3 rm s3:// --recursive

    aws cloudformation delete-stack --stack-name monitoring-policy-compliance
حالت تمام صفحه را وارد کنید

از حالت تمام صفحه خارج شوید

نتیجه گیری:

اجرای این راه حل ، دید در تغییرات تأثیرگذار بر منابع مدیریت ابر را فراهم می کند. این امر باعث افزایش امنیت ، پیگیری انطباق و آمادگی حسابرسی می شود. امکان ورود و پرس و جو از اقدامات کاربر ، پاسخ به درخواست های مربوط به پیروی از مشتریان ، تنظیم کننده ها یا تیم های امنیتی را ساده می کند.

اگر این پست را مفید و جالب دیدید ، لطفاً روی دکمه واکنش زیر کلیک کنید تا پشتیبانی خود را نشان دهید. در صورت تمایل به استفاده و به اشتراک گذاشتن این پست. 🙂

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا