Skip to content

Commit

Permalink
Enable logging with private s3 bucket (#210)
Browse files Browse the repository at this point in the history
  • Loading branch information
alldoami authored Jul 8, 2020
1 parent 90a9ec4 commit d87b007
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
aws-aurora,
aws-aurora-mysql,
aws-aurora-postgres,
aws-cloudfront-logs-bucket,
aws-cloudwatch-log-group,
aws-default-vpc-security,
aws-ecs-job,
Expand Down
64 changes: 64 additions & 0 deletions aws-cloudfront-logs-bucket/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# aws-cloudfront-logs-bucket

This module uses the `aws-s3-private-bucket` module as its source and enables logging for Cloudfront to the specified S3 bucket. We include the grant to `aws-logs-delivery` whose canonical id is `c4c1ede66af53448b93c283ce9448c4ba468c9432aa01d700d3878632f77d2d0`, documentation for this can be found [here](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/AccessLogs.html#AccessLogsBucketAndFileOwnership). The suggestion is found here:

```
Restoring the ACL for the bucket
If you remove permissions for the awslogsdelivery account, CloudFront won't be able to save logs to the S3 bucket. To enable CloudFront to start saving logs for your distribution again, restore the ACL permission by doing one of the following:
...
Add the ACL permission for awslogsdelivery manually by navigating to the S3 bucket in the Amazon S3 console and adding permission. To add the ACL for awslogsdelivery, you must provide the canonical ID for the account, which is the following:
c4c1ede66af53448b93c283ce9448c4ba468c9432aa01d700d3878632f77d2d0
```

## Example

```hcl
module "s3-bucket" {
source = "github.com/chanzuckerberg/cztack/aws-cloudfront-logs-bucket?ref=v0.33.1"
bucket_name = "..."
env = var.env
owner = var.owner
project = var.project
service = var.component
}
```

<!-- START -->
## Requirements

No requirements.

## Providers

| Name | Version |
|------|---------|
| aws | n/a |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| abort\_incomplete\_multipart\_upload\_days | Number of days after which an incomplete multipart upload is canceled. | `number` | `14` | no |
| bucket\_name | n/a | `string` | n/a | yes |
| bucket\_policy | n/a | `string` | `""` | no |
| enable\_versioning | Keep old versions of overwritten S3 objects. | `bool` | `true` | no |
| env | n/a | `string` | n/a | yes |
| lifecycle\_rules | List of maps containing configuration of object lifecycle management. | `any` | <pre>[<br> {<br> "enabled": true,<br> "expiration": {<br> "expired_object_delete_marker": true<br> },<br> "noncurrent_version_expiration": {<br> "days": 365<br> },<br> "noncurrent_version_transition": {<br> "days": 30,<br> "storage_class": "STANDARD_IA"<br> }<br> }<br>]</pre> | no |
| owner | n/a | `string` | n/a | yes |
| project | n/a | `string` | n/a | yes |
| public\_access\_block | n/a | `bool` | `true` | no |
| service | n/a | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| arn | n/a |
| domain\_name | n/a |
| id | n/a |
| name | HACK(el): we do this to hint TF dependency graph since modules can't depend\_on |

<!-- END -->
34 changes: 34 additions & 0 deletions aws-cloudfront-logs-bucket/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
locals {
# Define the grant ACL for the Cloudfront logging S3 bucket,
# In order for the awslogsdelivery account to write log files to the bucket,
# we need to grant the AWS log delivery group the FULL_CONTROL access to the logging bucket
grants = [
{
canonical_user_id : data.aws_canonical_user_id.current_user.id
permissions : ["FULL_CONTROL"]

},
{
canonical_user_id : "c4c1ede66af53448b93c283ce9448c4ba468c9432aa01d700d3878632f77d2d0" # AWS log delivery group's canonical user id
permissions : ["FULL_CONTROL"]

}
]
}

data "aws_canonical_user_id" "current_user" {}

module "aws-cloudfront-logs-bucket" {
source = "../aws-s3-private-bucket"
grants = local.grants
env = var.env
owner = var.owner
project = var.project
service = var.service
bucket_name = var.bucket_name
bucket_policy = var.bucket_policy
enable_versioning = var.enable_versioning
abort_incomplete_multipart_upload_days = var.abort_incomplete_multipart_upload_days
public_access_block = var.public_access_block
lifecycle_rules = var.lifecycle_rules
}
59 changes: 59 additions & 0 deletions aws-cloudfront-logs-bucket/module_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package test

import (
"testing"

"github.com/aws/aws-sdk-go/service/s3"
"github.com/chanzuckerberg/cztack/testutil"
"github.com/gruntwork-io/terratest/modules/aws"
"github.com/gruntwork-io/terratest/modules/terraform"
"github.com/stretchr/testify/require"
)

func TestPrivateBucketDefaults(t *testing.T) {

test := &testutil.Test{
Options: func(t *testing.T) *terraform.Options {
project := testutil.UniqueId()
env := testutil.UniqueId()
service := testutil.UniqueId()
owner := testutil.UniqueId()

bucketName := testutil.UniqueId()

return testutil.Options(
testutil.DefaultRegion,
map[string]interface{}{
"project": project,
"env": env,
"service": service,
"owner": owner,

"bucket_name": bucketName,
},
)
},

Validate: func(t *testing.T, options *terraform.Options) {
r := require.New(t)
region := options.EnvVars["AWS_DEFAULT_REGION"]
bucket := options.Vars["bucket_name"].(string)

// get a client to query for other assertions
s3Client := aws.NewS3Client(t, region)

acl, err := s3Client.GetBucketAcl(&s3.GetBucketAclInput{
Bucket: &bucket,
})

r.NoError(err)
r.Len(acl.Grants, 2)

r.Equal("CanonicalUser", *acl.Grants[0].Grantee.Type)
r.Equal("FULL_CONTROL", *acl.Grants[0].Permission)
r.Equal("c4c1ede66af53448b93c283ce9448c4ba468c9432aa01d700d3878632f77d2d0", *acl.Grants[1].Grantee.ID)
r.Equal("FULL_CONTROL", *acl.Grants[1].Permission)
},
}
test.Run(t)
}
16 changes: 16 additions & 0 deletions aws-cloudfront-logs-bucket/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// HACK(el): we do this to hint TF dependency graph since modules can't depend_on
output "name" {
value = module.aws-cloudfront-logs-bucket.name
}

output "domain_name" {
value = module.aws-cloudfront-logs-bucket.domain_name
}

output "arn" {
value = module.aws-cloudfront-logs-bucket.arn
}

output "id" {
value = module.aws-cloudfront-logs-bucket.id
}
64 changes: 64 additions & 0 deletions aws-cloudfront-logs-bucket/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
variable "bucket_name" {
type = string
}

variable "bucket_policy" {
type = string
default = ""
}

variable "project" {
type = string
}

variable "env" {
type = string
}

variable "service" {
type = string
}

variable "owner" {
type = string
}

variable "enable_versioning" {
type = bool
description = "Keep old versions of overwritten S3 objects."
default = true
}

variable "abort_incomplete_multipart_upload_days" {
type = number
description = "Number of days after which an incomplete multipart upload is canceled."
default = 14
}

variable "lifecycle_rules" {
description = "List of maps containing configuration of object lifecycle management."
type = any
default = [
{
enabled = true

expiration = {
expired_object_delete_marker = true
}

noncurrent_version_transition = {
days = 30
storage_class = "STANDARD_IA"
}

noncurrent_version_expiration = {
days = 365
}
}
]
}

variable public_access_block {
type = bool
default = true
}

0 comments on commit d87b007

Please sign in to comment.