11
votes

I created CodeBuild project in a custom VPC and in private subnet. Private subnet has internet access, also AWS console confirms that internet connection is for this code build project. I keep getting VPC_CLIENT_ERROR: Unexpected EC2 error: UnauthorizedOperation error in "Provisioning" phase of the build. There must be something missing in my service role policy but cant figure out what.

Here is CodeBuild project (terraform):

resource "aws_codebuild_project" "frontend" {
  name          = "frontend"
  build_timeout = "5"
  service_role  = "${aws_iam_role.frontend_build.arn}"

  artifacts {
    type = "S3"
    location = "frontend.myapp.com"
    namespace_type = "NONE"
    packaging = "NONE"
    path = "public"
  }

  environment {
    compute_type                = "BUILD_GENERAL1_SMALL"
    image                       = "aws/codebuild/standard:1.0"
    type                        = "LINUX_CONTAINER"
    image_pull_credentials_type = "CODEBUILD"

    environment_variable {
      name  = "SOME_KEY1"
      value = "SOME_VALUE1"
    }
  }

  logs_config {
    cloudwatch_logs {
      group_name = "build"
      stream_name = "frontend-build"
    }
  }

  source {
    type            = "GITHUB"
    location        = "https://github.com/MyOrg/my-repo.git"
    git_clone_depth = 1
    report_build_status = true
    auth {
      type = "OAUTH"
    }
  }

  vpc_config {
    vpc_id = module.vpc.vpc_id
    subnets = module.vpc.private_subnets
    security_group_ids = [aws_security_group.build.id]
  }
}

Here is service_role for this CodeBuild project:

resource "aws_iam_role" "frontend_build" {
  name = "frontend-build"

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

And here is policy for that role:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "ec2:CreateNetworkInterfacePermission",
            "Resource": "arn:aws:ec2:us-east-1:371508653482:network-interface/*",
            "Condition": {
                "StringEquals": {
                    "ec2:AuthorizedService": "codebuild.amazonaws.com",
                    "ec2:Subnet": "subnet-124641af7a83bf872"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:CreateNetworkInterface",
                "ec2:DescribeDhcpOptions",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DeleteNetworkInterface",
                "ec2:DescribeSubnets",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeVpcs",
                "ecr:BatchCheckLayerAvailability",
                "ecr:CompleteLayerUpload",
                "ecr:GetAuthorizationToken",
                "ecr:InitiateLayerUpload",
                "ecr:PutImage",
                "ecr:UploadLayerPart",
                "ecs:RunTask",
                "iam:PassRole",
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "ssm:GetParameters"
            ],
            "Resource": "*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:GetAuthorizationToken",
                "s3:GetBucketAcl",
                "s3:GetBucketLocation",
                "logs:CreateLogGroup",
                "logs:PutLogEvents",
                "ecr:BatchCheckLayerAvailability"
            ],
            "Resource": "*"
        },
        {
            "Sid": "VisualEditor2",
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::xxx-frontend-build-logs",
                "arn:aws:s3:::xxx-frontend-build-logs/*"
            ]
        }
    ]
}

Here is security group for CodeBuild project:

resource "aws_security_group" "build" {
  name   = "build"
  vpc_id = module.vpc.vpc_id
}

resource "aws_security_group_rule" "build_egress" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.build.id
}
2

2 Answers

16
votes

It looks to me that CodeBuild service role is unable to create the ENI in VPC. The problem seems to be with this line in the CodeBuild role policy:

{
    "Sid": "VisualEditor0",
    "Effect": "Allow",
    "Action": "ec2:CreateNetworkInterfacePermission",
    "Resource": "arn:aws:ec2:us-east-1:371508653482:network-interface/*",
    "Condition": {
        "StringEquals": {
            "ec2:AuthorizedService": "codebuild.amazonaws.com",
            "ec2:Subnet": "subnet-124641af7a83bf872"     <================= Need full ARN here
        }
    }
},

Instead of:

"Condition": {
        "StringEquals": {
            "ec2:AuthorizedService": "codebuild.amazonaws.com",
            "ec2:Subnet": "subnet-124641af7a83bf872"
        }
}

try...

"Condition": {
    "StringEquals": {
    "ec2:Subnet": [
        "arn:aws:ec2:region:account-id:subnet/subnet-124641af7a83bf872"
    ],
    "ec2:AuthorizedService": "codebuild.amazonaws.com"
}

Details here: [1]

Ref: [1] Using Identity-Based Policies for CodeBuild - Allow CodeBuild Access to AWS Services Required to Create a VPC Network Interface - https://docs.aws.amazon.com/codebuild/latest/userguide/auth-and-access-control-iam-identity-based-access-control.html#customer-managed-policies-example-create-vpc-network-interface

2
votes

You can also use StringLike in case it's not convenient for you to provide subnet id within the policy

{
  "Effect": "Allow",
  "Action": [
    "ec2:CreateNetworkInterfacePermission"
  ],
  "Resource": "arn:aws:ec2:*:*:network-interface/*",
  "Condition": {
    "StringLike": {
      "ec2:Subnet": [
        "arn:aws:ec2:*:*:subnet/*"
      ],
      "ec2:AuthorizedService": "codebuild.amazonaws.com"
    }
  }
}