Sonarqube not allowing me to set policy for S3 bucket

29 Views Asked by At

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

There are 2 best solutions below

3
Marko E On

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
}
0
Rohit Patil On

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.