skip to Main Content

I’m trying to get my s3 bucket working to store access logs. Below is how I’m deploying the required policy for it using terraform.

resource "aws_s3_bucket_policy" "bucket_logging_policy" {
  bucket = aws_s3_bucket.s3_access_logs_bucket.id
  policy = jsonencode({
    "Version" : "2012-10-17",
    "Statement" : [
      {
        "Effect" : "Allow",
        "Principal" : {
          "Service" : "logging.s3.amazonaws.com"
        },
        "Action" : "s3:PutObject",
        "Resource" : "arn:aws:s3:::${aws_s3_bucket.s3_access_logs_bucket.id}/*"
      }
    ]
  })
}

While building however, Sonarqube is throwing errors in below lines:
"Effect" : "Allow" -> Non-conforming requests should be denied.
"Action" : "s3:PutObject", -> All S3 actions should be restricted.

Tried with general suggestions given by Sonarqube(below) and aws, but no luck. I’m new to this, so having trouble figuring out. Any idea where the policy is not adhering to standards?

resource "aws_s3_bucket_policy" "bucket_logging_policy" {
  bucket = aws_s3_bucket.s3_access_logs_bucket.id
 
  policy = jsonencode({
    "Version" = "2012-10-17",
    "Statement" = [
      {
        "Effect": "Allow",
        "Principal": {
          "Service": "logging.s3.amazonaws.com"
        },
        "Action": "s3:PutObject",
        "Resource": "arn:aws:s3:::${aws_s3_bucket.s3_access_logs_bucket.id}/*"
      },
      {
        "Effect": "Deny",
        "Principal": "*",
        "Action": "s3:*",
        "Resource": "arn:aws:s3:::${aws_s3_bucket.s3_access_logs_bucket.id}/*",
        "Condition": {
          "Bool": {
            "aws:SecureTransport": "false"
          }
        }
      }
    ]
  })
}

Also made sure I’m compliant with conditions given here https://docs.aws.amazon.com/AmazonS3/latest/userguide/enable-server-access-logging.html

2

Answers


  1. Chosen as BEST ANSWER

    All the changes by Marko above helped with the actions = "s3:PutObject" issue as it's replaced by a list actions = ["s3:PutObject"].

    For the "Effect" : "Allow" problem, I used variable to assign that value:

    data "aws_caller_identity" "current" {}
    
    data "aws_iam_policy_document" "s3_policy" {
      statement {
        sid    = "S3ServerAccessLogsPolicy"
        effect = var.permission_for_logs
        principals {
          type = "Service"
          identifiers = [
            "logging.s3.amazonaws.com"
          ]
        }
        actions = [
          "s3:PutObject"
        ]
        resources = [
          "${aws_s3_bucket.s3_access_logs_bucket.arn}/<example logging prefix>/*"
        ]
        condition {
          variable = "aws:SourceArn"
          test     = "ArnLike"
          values = [
            aws_s3_bucket.s3_access_logs_bucket.arn
          ]
        }
        condition {
          variable = "aws:SourceAccount"
          test     = "StringEquals"
          values = [
            data.aws_caller_identity.current.account_id
          ]
        }
      }
    }
    
    resource "aws_s3_bucket_policy" "bucket_logging_policy" {
      bucket = aws_s3_bucket.s3_access_logs_bucket.id
     
      policy = data.aws_iam_policy_document.s3_policy.json
    }
    

    While I added below in variables.tf:

    variable "permission_for_logs" {
      description = "Permission to store logs"
      type        = string
    }
    

    I added this allow permission in module for this bucket:

    module "s3_access_logs_bucket" {
      ...
      permission_for_logs = "Allow"
      ...
    }
    

    It solved the issue for me.


  2. Based on the link you sent, there is the condition which seems to be missing in your policy, i.e:

    resource "aws_s3_bucket_policy" "bucket_logging_policy" {
      bucket = aws_s3_bucket.s3_access_logs_bucket.id
      policy = jsonencode({
        "Version" : "2012-10-17",
        "Statement" : [
          {
            "Effect" : "Allow",
            "Principal" : {
              "Service" : "logging.s3.amazonaws.com"
            },
            "Action" : ["s3:PutObject"],
            "Resource" : "${aws_s3_bucket.s3_access_logs_bucket.arn}/<example logging prefix>/*",
            "Condition": {
               "ArnLike": {
                   "aws:SourceArn": aws_s3_bucket.s3_access_logs_bucket.arn
               },
               "StringEquals": {
                   "aws:SourceAccount": "<source account id>"
              }
            }
          }
        ]
      })
    }
    

    As you can see, the bucket resource also exports the ARN attribute, so you don’t have to construct the entire ARN using the ID. Also, I would always suggest using the data source for building any kind of a policy in terraform, since it’s easier to work with it and avoid errors. Additionally, to avoid hardcoding the account ID, the data source for getting the ID should be used:

    data "aws_caller_identity" "current" {}
    
    data "aws_iam_policy_document" "s3_policy" {
      statement {
        sid    = "S3ServerAccessLogsPolicy"
        effect = "Allow"
        principals {
          type = "Service"
          identifiers = [
            "logging.s3.amazonaws.com"
          ]
        }
        actions = [
          "s3:PutObject"
        ]
        resources = [
          "${aws_s3_bucket.s3_access_logs_bucket.arn}/<example logging prefix>/*"
        ]
        condition {
          variable = "aws:SourceArn"
          test     = "ArnLike"
          values = [
            aws_s3_bucket.s3_access_logs_bucket.arn
          ]
        }
        condition {
          variable = "aws:SourceAccount"
          test     = "StringEquals"
          values = [
            data.aws_caller_identity.current.account_id
          ]
        }
      }
    }
    
    resource "aws_s3_bucket_policy" "bucket_logging_policy" {
      bucket = aws_s3_bucket.s3_access_logs_bucket.id
     
      policy = data.aws_iam_policy_document.s3_policy.json
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search