> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Cloudtrail delivery failing remediation

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Using Console" defaultOpen="true">
        To remediate the misconfiguration "Log files should be delivered without any failures" for AWS using AWS console, follow the below steps:

        1. Open the AWS Management Console and navigate to the CloudWatch service.

        2. Click on "Logs" in the left-hand menu and select the log group that is experiencing the delivery failure.

        3. Click on the "Actions" drop-down menu and select "Stream to Amazon Elasticsearch Service".

        4. In the "Stream to Amazon Elasticsearch Service" dialog box, select the Elasticsearch domain that you want to stream the log data to.

        5. Choose the appropriate IAM role that has permission to stream the log data to the Elasticsearch domain.

        6. Configure the log stream settings as required and click on "Start Streaming".

        7. Once the log stream is successfully started, CloudWatch will begin delivering log data to the Elasticsearch domain without any failures.

        8. You can monitor the log stream status and troubleshoot any issues using the CloudWatch Logs console.

        By following these steps, you can remediate the misconfiguration "Log files should be delivered without any failures" for AWS using AWS console.

        #
      </Accordion>

      <Accordion title="Using CLI">
        To remediate the misconfiguration "Log files Should Be Delivered Without Any Failures" in AWS, you can follow the below steps using AWS CLI:

        1. Open the AWS CLI on your local machine or terminal.

        2. Run the following command to create a new S3 bucket to store the logs:

           ```
           aws s3api create-bucket --bucket <bucket-name> --region <region> --create-bucket-configuration LocationConstraint=<region>
           ```

           Replace `<bucket-name>` with your desired bucket name and `<region>` with the region in which you want to create the bucket.

        3. Run the following command to enable access logging for your S3 bucket:

           ```
           aws s3api put-bucket-acl --bucket <bucket-name> --grant-read uri=http://acs.amazonaws.com/groups/s3/LogDelivery --grant-write uri=http://acs.amazonaws.com/groups/s3/LogDelivery --grant-read-acp uri=http://acs.amazonaws.com/groups/s3/LogDelivery --grant-write-acp uri=http://acs.amazonaws.com/groups/s3/LogDelivery --grant-full-control uri=http://acs.amazonaws.com/groups/s3/LogDelivery
           ```

           Replace `<bucket-name>` with the name of the bucket you created in step 2.

        4. Run the following command to create a new CloudWatch Logs group:

           ```
           aws logs create-log-group --log-group-name <log-group-name>
           ```

           Replace `<log-group-name>` with your desired name for the log group.

        5. Run the following command to create a new CloudWatch Logs stream:

           ```
           aws logs create-log-stream --log-group-name <log-group-name> --log-stream-name <log-stream-name>
           ```

           Replace `<log-group-name>` with the name of the log group you created in step 4 and `<log-stream-name>` with your desired name for the log stream.

        6. Run the following command to create a new CloudWatch Logs subscription filter:

           ```
           aws logs put-subscription-filter --log-group-name <log-group-name> --filter-name <filter-name> --filter-pattern "" --destination-arn arn:aws:s3:::<bucket-name>
           ```

           Replace `<log-group-name>` with the name of the log group you created in step 4, `<filter-name>` with your desired name for the filter, and `<bucket-name>` with the name of the S3 bucket you created in step 2.

        7. Verify that the logs are being delivered to the S3 bucket by checking the contents of the bucket. You should see log files being created and updated in real-time.

        By following these steps, you can remediate the misconfiguration "Log files Should Be Delivered Without Any Failures" in AWS using AWS CLI.
      </Accordion>

      <Accordion title="Using Python">
        To remediate the misconfiguration "Log files Should Be Delivered Without Any Failures" for AWS using Python, you can follow these steps:

        Step 1: Create an S3 bucket to store the log files.

        ```
        import boto3

        s3 = boto3.client('s3')

        bucket_name = 'your-bucket-name'

        s3.create_bucket(Bucket=bucket_name)
        ```

        Step 2: Create an IAM role with permissions to write to the S3 bucket.

        ```
        import boto3

        iam = boto3.client('iam')

        role_name = 'your-role-name'

        assume_role_policy_document = {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Principal": {
                        "Service": "logs.amazonaws.com"
                    },
                    "Action": "sts:AssumeRole"
                }
            ]
        }

        response = iam.create_role(
            RoleName=role_name,
            AssumeRolePolicyDocument=json.dumps(assume_role_policy_document)
        )

        policy_document = {
            "Version": "2012-10-17",
            "Statement": [
                {
                    "Effect": "Allow",
                    "Action": [
                        "s3:PutObject"
                    ],
                    "Resource": [
                        "arn:aws:s3:::your-bucket-name/*"
                    ]
                }
            ]
        }

        iam.put_role_policy(
            RoleName=role_name,
            PolicyName='your-policy-name',
            PolicyDocument=json.dumps(policy_document)
        )
        ```

        Step 3: Create a CloudWatch Logs subscription filter to deliver the log files to the S3 bucket.

        ```
        import boto3

        logs = boto3.client('logs')

        log_group_name = 'your-log-group-name'
        filter_name = 'your-filter-name'
        destination_arn = 'arn:aws:s3:::your-bucket-name'

        response = logs.put_subscription_filter(
            logGroupName=log_group_name,
            filterName=filter_name,
            filterPattern='',
            destinationArn=destination_arn,
            roleArn='arn:aws:iam::your-account-id:role/your-role-name'
        )
        ```

        Note: Replace the placeholders (your-bucket-name, your-role-name, your-policy-name, your-log-group-name, your-filter-name, and your-account-id) with your own values.

        These steps will remediate the misconfiguration "Log files Should Be Delivered Without Any Failures" for AWS using Python.
      </Accordion>

      <Accordion title="Using Terraform">
        ```hcl theme={null}
        # S3 bucket policy allowing CloudTrail to deliver logs
        resource "aws_s3_bucket_policy" "cloudtrail_logs" {
          bucket = aws_s3_bucket.cloudtrail_logs_bucket.id  # replace with your bucket

          policy = jsonencode({
            Version = "2012-10-17"
            Statement = [
              {
                Sid    = "AWSCloudTrailAclCheck"
                Effect = "Allow"
                Principal = {
                  Service = "cloudtrail.amazonaws.com"
                }
                Action   = "s3:GetBucketAcl"
                Resource = "arn:aws:s3:::${aws_s3_bucket.cloudtrail_logs_bucket.bucket}"
              },
              {
                Sid    = "AWSCloudTrailWrite"
                Effect = "Allow"
                Principal = {
                  Service = "cloudtrail.amazonaws.com"
                }
                Action   = "s3:PutObject"
                Resource = "arn:aws:s3:::${aws_s3_bucket.cloudtrail_logs_bucket.bucket}/AWSLogs/${data.aws_caller_identity.current.account_id}/*"
                Condition = {
                  StringEquals = {
                    "s3:x-amz-acl" = "bucket-owner-full-control"
                  }
                }
              }
            ]
          })
        }

        # Example bucket used above
        resource "aws_s3_bucket" "cloudtrail_logs_bucket" {
          bucket = "CLOUDTRAIL_LOGS_BUCKET_NAME" # replace with your CloudTrail S3 bucket name
        }

        data "aws_caller_identity" "current" {}

        # KMS key policy allowing CloudTrail to encrypt logs (only if your trail uses SSE-KMS)
        resource "aws_kms_key" "cloudtrail_logs_key" {
          description             = "KMS key for CloudTrail log encryption"
          deletion_window_in_days = 30

          policy = jsonencode({
            Version = "2012-10-17"
            Statement = [
              {
                Sid    = "Enable IAM User Permissions"
                Effect = "Allow"
                Principal = {
                  AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
                }
                Action   = "kms:*"
                Resource = "*"
              },
              {
                Sid    = "Allow CloudTrail to encrypt logs"
                Effect = "Allow"
                Principal = {
                  Service = "cloudtrail.amazonaws.com"
                }
                Action = [
                  "kms:GenerateDataKey*",
                  "kms:DescribeKey",
                ]
                Resource = "*"
              }
            ]
          })
        }

        # Attach this KMS key to your CloudTrail trail (no replacement of the trail)
        resource "aws_cloudtrail" "trail" {
          name                          = "CLOUDTRAIL_TRAIL_NAME"          # replace
          s3_bucket_name                = aws_s3_bucket.cloudtrail_logs_bucket.bucket
          kms_key_id                    = aws_kms_key.cloudtrail_logs_key.arn
          include_global_service_events = true
          is_multi_region_trail         = true
          enable_log_file_validation    = true

          cloud_watch_logs_group_arn  = aws_cloudwatch_log_group.cloudtrail_logs.arn
          cloud_watch_logs_role_arn   = aws_iam_role.cloudtrail_to_cw.arn
        }

        # CloudWatch Logs log group for the trail (only if using CloudWatch Logs)
        resource "aws_cloudwatch_log_group" "cloudtrail_logs" {
          name              = "CLOUDTRAIL_LOG_GROUP_NAME" # replace
          retention_in_days = 90
        }

        # CloudWatch Logs resource policy allowing CloudTrail to create streams and put events
        resource "aws_cloudwatch_log_resource_policy" "cloudtrail_delivery" {
          policy_name = "CloudTrail-Delivery-Policy-${aws_cloudtrail.trail.name}"

          # WARNING: This resource creates or overwrites a CloudWatch Logs resource policy
          policy_document = jsonencode({
            Version = "2012-10-17"
            Statement = [
              {
                Sid    = "AWSCloudTrailCreateLogStream"
                Effect = "Allow"
                Principal = {
                  Service = "cloudtrail.amazonaws.com"
                }
                Action   = "logs:CreateLogStream"
                Resource = aws_cloudwatch_log_group.cloudtrail_logs.arn
              },
              {
                Sid    = "AWSCloudTrailPutLogEvents"
                Effect = "Allow"
                Principal = {
                  Service = "cloudtrail.amazonaws.com"
                }
                Action   = "logs:PutLogEvents"
                Resource = aws_cloudwatch_log_group.cloudtrail_logs.arn
              }
            ]
          })
        }

        # IAM role CloudTrail uses to write to CloudWatch Logs (already required by CloudTrail)
        resource "aws_iam_role" "cloudtrail_to_cw" {
          name = "CLOUDTRAIL_CW_ROLE_NAME" # replace

          assume_role_policy = jsonencode({
            Version = "2012-10-17"
            Statement = [
              {
                Effect = "Allow"
                Principal = {
                  Service = "cloudtrail.amazonaws.com"
                }
                Action = "sts:AssumeRole"
              }
            ]
          })
        }

        resource "aws_iam_role_policy" "cloudtrail_to_cw_policy" {
          role = aws_iam_role.cloudtrail_to_cw.id

          policy = jsonencode({
            Version = "2012-10-17"
            Statement = [
              {
                Effect   = "Allow"
                Action   = ["logs:CreateLogStream", "logs:PutLogEvents"]
                Resource = aws_cloudwatch_log_group.cloudtrail_logs.arn
              }
            ]
          })
        }
        ```

        None of these changes force replacement of the S3 bucket, KMS key, CloudTrail trail, or CloudWatch Logs log group; they update policies in place, though the `aws_cloudwatch_log_resource_policy` will overwrite any existing CloudWatch Logs resource policy with the same `policy_name`.

        After applying, `terraform plan` should show:

        * creation or in-place update of `aws_s3_bucket_policy.cloudtrail_logs` with the two CloudTrail statements,
        * the KMS key (or only its `policy` change if it already exists) containing the CloudTrail statement,
        * creation or update of `aws_cloudwatch_log_resource_policy.cloudtrail_delivery` with the two CloudTrail statements,
          and no planned resource replacements.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
