Skip to content

Commit

Permalink
Added an AWS Logging module to set up basic logging. (#3)
Browse files Browse the repository at this point in the history
* Switch to trivy for security scans.
  • Loading branch information
jamesiarmes authored May 17, 2024
1 parent b237b98 commit 2f99f72
Show file tree
Hide file tree
Showing 12 changed files with 276 additions and 8 deletions.
21 changes: 16 additions & 5 deletions .github/workflows/branch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,24 @@ jobs:
exit $exit_code
tfsec:
name: tfsec
trivy:
name: trivy
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Runs tfsec
uses: aquasecurity/tfsec-action@v1.0.0
- name: Run Trivy vulnarability scanner
uses: aquasecurity/trivy-action@master
with:
additional_args: --config-file tfsec.yml
scan-type: config
ignore-unfixed: true
skip-dirs: '"**/*/.terraform"'
exit-code: 1
format: sarif
output: 'trivy-results.sarif'

- name: Parse SARIF file
if: always()
uses: Ayrx/[email protected]
with:
sarif_file: 'trivy-results.sarif'
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ terraform.
|----------|--------------------------------------|--------------------------------------------------------------------------|
| AWS | [backend][aws-backend] | S3 storage backend for tfstate. |
| AWS | [cloudfront_waf][aws-cloudfront-waf] | CloudFront distribution that passes traffic through WAF without caching. |
| AWS | [logging][aws-logging] | CloudFront distribution that passes traffic through WAF without caching. |

[aws-backend]: ./aws/backend/README.md
[aws-cloudfront-waf]: ./aws/cloudfront_waf/README.md
[aws-logging]: ./aws/logging/README.md
[opentofu]: https://opentofu.org/
[terraform]: https://www.terraform.io/
6 changes: 3 additions & 3 deletions aws/cloudfront_waf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ Web Application Firewall (WAF) _without_ caching.
Add this module to your `main.tf` (or appropriate) file:

```hcl
module "backend" {
source = "github.com/codeforamerica/tofu-modules/aws/backend"
module "cloudfront_waf" {
source = "github.com/codeforamerica/tofu-modules/aws/cloudfront_waf"
project = "my-project"
environment = "dev"
domain = "my-project.org"
log_bucket = module.log_bucket.s3_bucket_bucket_domain_name
log_bucket = module.logging.bucket
}
```

Expand Down
51 changes: 51 additions & 0 deletions aws/logging/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# AWS Logging Module

This module created an S3 bucket for logging, as well as a KMS for CloudWatch
logs.

_Note: The bucket created by this module uses AES256 encryption. CMKs (Customer
Managed Keys) are [not supported] for access logging._

## Usage

Add this module to your `main.tf` (or appropriate) file:

```hcl
module "cloudfront_waf" {
source = "github.com/codeforamerica/tofu-modules/aws/logging"
project = "my-project"
environment = "dev"
}
```

Make sure you re-run `tofu init` after adding the module to your configuration.

```bash
tofu init
tofu plan
```

To update the source for this module, pass `-upgrade` to `tofu init`:

```bash
tofu init -upgrade
```

## Inputs

| Name | Description | Type | Default | Required |
|---------------------|-------------------------------------------------------|----------|---------|----------|
| project | Name of the project. | `string` | n/a | yes |
| environment | Environment for the project. | `string` | `"dev"` | no |
| key_recovery_period | Number of days to recover the KMS key after deletion. | `number` | 30 | yes |

## Outputs

| Name | Description | Type |
|---------------|------------------------------------|----------|
| bucket | Name of the S3 bucket for logging. | `string` |
| kms_key_alias | Alias of the KMS encryption key. | `string` |
| kms_key_arn | ARN of the KMS encryption key. | `string` |

[not supported]: https://repost.aws/knowledge-center/s3-server-access-log-not-delivered
7 changes: 7 additions & 0 deletions aws/logging/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
data "aws_caller_identity" "identity" {}

data "aws_partition" "current" {}

data "aws_region" "current" {}

data "aws_elb_service_account" "current" {}
3 changes: 3 additions & 0 deletions aws/logging/local.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
locals {
prefix = "${var.project}-${var.environment}"
}
71 changes: 71 additions & 0 deletions aws/logging/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# We don't want to log access to this bucket, as that would cause an infinite
# loop of logging.
#trivy:ignore:avd-aws-0089
resource "aws_s3_bucket" "logs" {
bucket = "${local.prefix}-logs"

lifecycle {
prevent_destroy = true
}
}

resource "aws_s3_bucket_public_access_block" "good_example" {
bucket = aws_s3_bucket.logs.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}

#tfsec:ignore:aws-s3-encryption-customer-key
resource "aws_s3_bucket_server_side_encryption_configuration" "logs" {
bucket = aws_s3_bucket.logs.id

rule {
bucket_key_enabled = true

apply_server_side_encryption_by_default {
# S3 access logs don't support encryption with a customer managed key
# (CMK).
# See https://repost.aws/knowledge-center/s3-server-access-log-not-delivered
sse_algorithm = "AES256"
}
}
}

resource "aws_s3_bucket_versioning" "logs" {
bucket = aws_s3_bucket.logs.id

versioning_configuration {
status = "Enabled"
}
}

resource "aws_s3_bucket_policy" "logs" {
bucket = aws_s3_bucket.logs.id
policy = jsonencode(yamldecode(templatefile("${path.module}/templates/bucket-policy.yaml.tftpl", {
account_id : data.aws_caller_identity.identity.account_id,
partition : data.aws_partition.current.partition,
bucket_arn : aws_s3_bucket.logs.arn,
elb_account_arn : data.aws_elb_service_account.current.arn
})))
}

resource "aws_kms_key" "logs" {
description = "Logging encryption key for ${var.project} ${var.environment}"
deletion_window_in_days = var.key_recovery_period
enable_key_rotation = true
policy = jsonencode(yamldecode(templatefile("${path.module}/templates/key-policy.yaml.tftpl", {
account_id : data.aws_caller_identity.identity.account_id
partition : data.aws_partition.current.partition
region : data.aws_region.current.name
bucket_arn : aws_s3_bucket.logs.arn
project : var.project
environment : var.environment
})))
}

resource "aws_kms_alias" "logs" {
name = "alias/${var.project}/${var.environment}/logs"
target_key_id = aws_kms_key.logs.id
}
11 changes: 11 additions & 0 deletions aws/logging/output.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
output "bucket" {
value = aws_s3_bucket.logs.bucket
}

output "kms_key_arn" {
value = aws_kms_key.logs.arn
}

output "kms_key_alias" {
value = aws_kms_alias.logs.name
}
41 changes: 41 additions & 0 deletions aws/logging/templates/bucket-policy.yaml.tftpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Version: '2012-10-17'
Statement:
- Sid: AllowSSLRequestsOnly
Effect: Deny
Principal:
Service: config.amazonaws.com
Action:
- s3:*
Resource:
- "${bucket_arn}"
- "${bucket_arn}/*"
Condition:
Bool:
aws:SecureTransport: false
- Sid: AllowLBAccessLogsFromAWS
Effect: Allow
Principal:
AWS: "${elb_account_arn}"
Action: s3:PutObject
Resource: "${bucket_arn}/AWSLogs/${account_id}/*"
- Sid: AWSLogDeliveryWrite
Effect: Allow
Principal:
Service: delivery.logs.amazonaws.com
Action: s3:PutObject
Resource: "${bucket_arn}/AWSLogs/${account_id}/*"
Condition:
StringEquals:
s3:x-amz-acl: bucket-owner-full-control
- Sid: AWSLogDeliveryAclCheck
Effect: Allow
Principal:
Service: delivery.logs.amazonaws.com
Action: s3:GetBucketAcl
Resource: "${bucket_arn}"
- Sid: AllowS3AccessLogs
Effect: Allow
Principal:
Service: logging.s3.amazonaws.com
Action: s3:PutObject
Resource: "${bucket_arn}/*"
40 changes: 40 additions & 0 deletions aws/logging/templates/key-policy.yaml.tftpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Version: '2012-10-17'
Id: key-default-1
Statement:
- Sid: Enable IAM User Permissions
Effect: Allow
Principal:
AWS: arn:${partition}:iam::${account_id}:root
Action: kms:*
Resource: "*"
- Sid: Allow CloudWatch to encrypt logs
Effect: Allow
Principal:
Service: logs.${region}.amazonaws.com
Action:
- kms:Encrypt*
- kms:Decrypt*
- kms:ReEncrypt*
- kms:GenerateDataKey*
- kms:Describe*
Resource: "*"
Condition:
ArnLike:
kms:EncryptionContext:aws:logs:arn: arn:${partition}:logs:${region}:${account_id}:log-group:*
- Sid: Allow RDS Performance Insights
Effect: Allow
Principal:
AWS:
- arn:${partition}:iam::${account_id}:root
Action:
- kms:Decrypt
- kms:GenerateDataKey
Resource: "*"
Condition:
StringEquals:
kms:ViaService: rds.${region}.amazonaws.com
aws:RequestTag/project: ${project}
aws:RequestTag/environment: ${environment}
ForAnyValue:StringLike:
kms:EncryptionContext:aws:pi:service: rds
kms:EncryptionContext:service: pi
21 changes: 21 additions & 0 deletions aws/logging/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
variable "environment" {
type = string
description = "Environment for the deployment."
default = "dev"
}

variable "key_recovery_period" {
type = number
default = 30
description = "Recovery period for deleted KMS keys in days. Must be between 7 and 30."

validation {
condition = var.key_recovery_period > 6 && var.key_recovery_period < 31
error_message = "Recovery period must be between 7 and 30."
}
}

variable "project" {
type = string
description = "Project that these resources are supporting."
}
10 changes: 10 additions & 0 deletions aws/logging/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
terraform {
required_version = ">= 1.6"

required_providers {
aws = {
version = ">= 5.44"
source = "hashicorp/aws"
}
}
}

0 comments on commit 2f99f72

Please sign in to comment.