Skip to content

Commit

Permalink
Add awspec tests and supporting components (#6)
Browse files Browse the repository at this point in the history
* Tests and fixtures for ALB components using awspec and test kitchen
* S3 log bucket and policy rendering for logging now in place
* root_principle_id added and referenced through a map for s3 bucket policy
* string lists moved to native list types
* default region removed
* Restructured project templates to alb dir to add testing. This is a breaking change so upping major version.
* Redundant examples dir removed
* Updated documentation
* All PR feedback addressed
  • Loading branch information
brandonjbjelland authored Mar 16, 2017
1 parent a2fbc68 commit 7842de9
Show file tree
Hide file tree
Showing 19 changed files with 343 additions and 256 deletions.
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
*.tfvars*
*.tfvars
*.tfstate*
.terraform
**/Gemfile.lock
**/inspec.lock
*.gem
.kitchen/
.kitchen.local.yml
Gemfile.lock
28 changes: 28 additions & 0 deletions .kitchen.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
driver:
name: terraform

provisioner:
name: terraform
directory: test/fixtures
variable_files:
- test/fixtures/terraform.tfvars

platforms:
- name: aws

verifier:
name: awspec
# - name: terraform
# format: doc
# groups:
# - name: local_tests
# controls:
# - local_alb

suites:
- name: default
verifier:
name: awspec
patterns:
- test/integration/default/local_alb.rb
14 changes: 10 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]
## [1.0.0] - 2017-03-16
### Added
* Tests and fixtures for ALB components using awspec and test kitchen
* S3 log bucket and policy rendering for logging now in place
* root_principle_id added and referenced through a map for s3 bucket policy
* string lists moved to native list types
* default region removed

### Changed
* Restructured project templates to alb dir to add testing. This is a breaking change so upping major version.
* Redundant examples dir removed
* Updated documentation

## [0.1.0] - 2017-03-09
### Added
- Initial release

### Changed
* Initial release
8 changes: 7 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
ruby '2.4.0'

source 'https://rubygems.org/' do
gem 'kitchen-terraform', '~> 0.6'
gem 'test-kitchen'
gem 'kitchen-terraform'
gem 'awspec'
gem 'kitchen-verifier-awspec'
gem 'parseconfig'
end
33 changes: 25 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,19 @@ For an example of using ALB with ECS look no further than the [hashicorp example

## Input Variables
* `alb_is_internal` - Determines if the ALB is externally facing or internal. (Optional; default: false)
* `alb_name` - Name of the ALB as it appears in the AWS console. (Optional; default: my_alb)
* `alb_name` - Name of the ALB as it appears in the AWS console. (Optional; default: my-alb)
* `alb_protocols` - A comma delimited list of protocols the ALB will accept for incoming connections. Only HTTP and HTTPS are supported. (Optional; default: HTTPS)
* `alb_security_groups` - A comma delimited list of security groups to attach to the ALB. (Required)
* `aws_region` - Region to deploy our resources. (Required)
* `aws_account_id` - The AWS account ID. (Required)
* `backend_port` - Port on which the backing instances serve traffic. (Optional; default: 80)
* `backend_protocol` - Protocol the backing instances use. (Optional; default: HTTP)
* `certificate_arn` - . (Required if using HTTPS in `alb_protocols`)
* `cookie_duration` - If sticky sessions via cookies are desired, set this variable to a value from 2 - 604800 seconds. (Optional)
* `health_check_path` - Path for the load balancer to health check instances. (Optional; default: /)
* `log_bucket` - S3 bucket where access logs should land. (Required)
* `log_prefix` - S3 prefix within the `log_bucket` where logs should land. (Optional)
* `principle_account_id` - A mapping of regions to principle account IDs used to send LB logs. (Should only change as regions are added)
* `subnets` - ALB will be created in the subnets in this list. (Required)
* `vpc_id` - Resources will be created in the VPC with this `id`. (Required)

Expand All @@ -43,25 +46,39 @@ For an example of using ALB with ECS look no further than the [hashicorp example
* `alb_dns_name` - DNS CNAME of the ALB created.
* `alb_zone_id` - Route53 `zone_id` of the newly minted ALB.
* `target_group_arn` - `arn` of the target group. Useful for passing to your Auto Scaling group module.
* `principle_account_id` - the id of the AWS root user within this region. See [docs here]('http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-access-logs.html#attach-bucket-policy').

## Usage example:
A full example set is contained in the [example directory](example/). Here's the gist:
1. Set the input variables from above in [variables.tf](example/variables.tf).
2. Define the ALB module using the following in your [main.tf](example/main.tf):
A full example leveraging other community modules is contained in the [test/fixtures directory](test/fixtures). Here's the gist if you're using this module without:
1. Set the input variables from above in [variables.tf](test/fixtures/variables.tf).
2. Define the ALB module using the following in your [main.tf](test/fixtures/main.tf):
```
module "alb" {
source = "github.com/brandoconnor/tf_aws_alb"
alb_security_groups = "${var.security_group_id_list}"
source = "github.com/terraform-community-modules/tf_aws_alb//alb"
alb_security_groups = "${var.alb_security_groups}"
aws_account_id = "${var.aws_account_id}"
certificate_arn = "${var.certificate_arn}"
log_bucket = "${var.log_bucket}"
subnets = "${var.subnet_id_list}"
log_prefix = "${var.log_prefix}"
subnets = "${var.public_subnets}"
vpc_id = "${var.vpc_id}"
}
```
3. Always `terraform plan` to see your change before running `terraform apply`.
4. Win the day!

## Testing
This module has been packaged with [awspec]('https://github.com/k1LoW/awspec') tests through test kitchen. To run them:
1. Install the prerequisites of rvm and ruby 2.4.0 via homebrew.
2. Install bundler and the gems from our Gemfile:
```
gem install bundler; bundle install
```
3. Configure variables in `test/fixtures/terraform.tfvars`. An example of how this should look is in [terraform.tfvars.example](test/fixtures/terraform.tfvars.example).
4. Test using `kitchen test` from the root of the repo.

## Contributing
Report issues/questions/feature requests on in the [Issues](https://github.com/brandoconnor/tf_aws_alb/issues) section.
Report issues/questions/feature requests on in the [Issues](https://github.com/terraform-community-modules/tf_aws_alb/issues) section.

Pull requests are welcome! Ideally create a feature branch and issue for every
individual change you make. These are the steps:
Expand Down
19 changes: 19 additions & 0 deletions alb/bucket_policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"Id": "Policy1429136655940",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1429136633762",
"Action": [
"s3:PutObject"
],
"Effect": "Allow",
"Resource": "arn:aws:s3:::${log_bucket}/${log_prefix}/AWSLogs/${account_id}/*",
"Principal": {
"AWS": [
"${principle_account_id}"
]
}
}
]
}
82 changes: 71 additions & 11 deletions alb/main.tf
Original file line number Diff line number Diff line change
@@ -1,24 +1,84 @@
### ALB resources with a switch - logging enabled/disabled
### ALB resources

resource "aws_alb" "alb_loging" {
# TODO:
# support not logging

data "template_file" "bucket_policy" {
template = "${file("${path.module}/bucket_policy.json")}"

vars {
log_bucket = "${var.log_bucket}"
log_prefix = "${var.log_prefix}"
account_id = "${var.aws_account_id}"
principle_account_id = "${lookup(var.principle_account_id, var.aws_region)}"
}
}

resource "aws_alb" "main" {
name = "${var.alb_name}"
subnets = ["${split(",", var.subnets)}"]
security_groups = ["${split(",", var.alb_security_groups)}"]
subnets = ["${var.subnets}"]
security_groups = ["${var.alb_security_groups}"]
internal = "${var.alb_is_internal}"

access_logs {
bucket = "${var.log_bucket}"
prefix = "${var.log_prefix}"
}
}

count = "${var.log_bucket != "" && var.log_prefix != "" ? 1 : 0}"
resource "aws_s3_bucket" "log_bucket" {
bucket = "${var.log_bucket}"
policy = "${data.template_file.bucket_policy.rendered}"
force_destroy = true
}

resource "aws_alb" "alb_nologing" {
name = "${var.alb_name}"
subnets = ["${split(",", var.subnets)}"]
security_groups = ["${split(",", var.alb_security_groups)}"]
internal = "${var.alb_is_internal}"
resource "aws_alb_target_group" "target_group" {
name = "${var.alb_name}-tg"
port = "${var.backend_port}"
protocol = "${upper(var.backend_protocol)}"
vpc_id = "${var.vpc_id}"

health_check {
interval = 30
path = "${var.health_check_path}"
port = "traffic-port"
healthy_threshold = 3
unhealthy_threshold = 3
timeout = 5
protocol = "${var.backend_protocol}"
}

stickiness {
type = "lb_cookie"
cookie_duration = "${var.cookie_duration}"
enabled = "${ var.cookie_duration == 1 ? false : true}"
}
}

resource "aws_alb_listener" "front_end_http" {
load_balancer_arn = "${aws_alb.main.arn}"
port = "80"
protocol = "HTTP"

default_action {
target_group_arn = "${aws_alb_target_group.target_group.id}"
type = "forward"
}

count = "${trimspace(element(split(",", var.alb_protocols), 1)) == "HTTP" || trimspace(element(split(",", var.alb_protocols), 2)) == "HTTP" ? 1 : 0}"
}

resource "aws_alb_listener" "front_end_https" {
load_balancer_arn = "${aws_alb.main.arn}"
port = "443"
protocol = "HTTPS"
certificate_arn = "${var.certificate_arn}"
ssl_policy = "ELBSecurityPolicy-2015-05"

default_action {
target_group_arn = "${aws_alb_target_group.target_group.id}"
type = "forward"
}

count = "${(var.log_bucket == "" || var.log_prefix == "") ? 1 : 0}"
count = "${trimspace(element(split(",", var.alb_protocols), 1)) == "HTTPS" || trimspace(element(split(",", var.alb_protocols), 2)) == "HTTPS" ? 1 : 0}"
}
27 changes: 11 additions & 16 deletions alb/outputs.tf
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
# this approach is not working just yet
output "arn" {
value = "${coalesce(aws_alb.alb_loging.arn, aws_alb.alb_nologing.arn) }"

/*value = "${aws_alb.alb_loging.arn}"*/
output "alb_id" {
value = "${aws_alb.main.id}"
}

output "dns_name" {
value = "${aws_alb.alb_loging.dns_name}"

/*value = "${coalesce(list("aws_alb.alb_loging.dns_name", "aws_alb.alb_nologing.dns_name")) }"*/
output "alb_dns_name" {
value = "${aws_alb.main.dns_name}"
}

output "id" {
value = "${aws_alb.alb_loging.id}"

/*value = "${coalesce(list("aws_alb.alb_loging.dns_name", "aws_alb.alb_nologing.dns_name")) }"*/
output "alb_zone_id" {
value = "${aws_alb.main.zone_id}"
}

output "zone_id" {
value = "${aws_alb.alb_loging.zone_id}"
output "target_group_arn" {
value = "${aws_alb_target_group.target_group.arn}"
}

/*value = "${coalesce(list("aws_alb.alb_loging.dns_name", "aws_alb.alb_nologing.dns_name")) }"*/
output "principle_account_id" {
value = "${lookup(var.principle_account_id, var.aws_region)}"
}
69 changes: 68 additions & 1 deletion alb/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,49 @@ variable "alb_is_internal" {

variable "alb_name" {
description = "The name of the ALB as will show in the AWS EC2 ELB console."
default = "my-alb"
}

variable "alb_protocols" {
description = "A comma delimited list of the protocols the ALB accepts. e.g.: HTTPS"
default = "HTTPS"
}

variable "alb_security_groups" {
description = "A comma separated string of security groups with which we associate the ALB. e.g. 'sg-edcd9784,sg-edcd9785'"
type = "list"
}

variable "aws_region" {
description = "AWS region to use."
}

variable "aws_account_id" {
description = "AWS account ID."
}

variable "backend_port" {
description = "The port the service on the EC2 instances listen on."
default = 80
}

variable "backend_protocol" {
description = "The protocol the backend service speaks. Options: HTTP, HTTPS, TCP, SSL (secure tcp)."
default = "HTTP"
}

variable "certificate_arn" {
description = "The ARN of the SSL Certificate. e.g. 'arn:aws:iam::123456789012:server-certificate/ProdServerCert'"
}

variable "cookie_duration" {
description = "If load balancer connection stickiness is desired, set this to the duration that cookie should be valid. If no stickiness is wanted, leave it blank. e.g.: 300"
default = "1"
}

variable "health_check_path" {
description = "The URL the ELB should use for health checks. e.g. /health"
default = "/"
}

variable "log_bucket" {
Expand All @@ -23,6 +62,34 @@ variable "log_prefix" {
description = "S3 prefix within the log_bucket under which logs are stored."
}

variable "principle_account_id" {
description = "A map of ELB/ALB root account numbers used to set up logging."

default = {
us-east-1 = "127311923021"
us-east-2 = "033677994240"
us-west-1 = "027434742980"
us-west-2 = "797873946194"
ca-central-1 = "985666609251"
eu-west-1 = "156460612806"
eu-central-1 = "054676820928"
eu-west-2 = "652711504416"
ap-northeast-1 = "582318560864"
ap-northeast-2 = "600734575887"
ap-southeast-1 = "114774131450"
ap-southeast-2 = "783225319266"
ap-south-1 = "718504428378"
sa-east-1 = "507241528517"
us-gov-west-1 = "048591011584"
cn-north-1 = "638102146993"
}
}

variable "subnets" {
description = "A comma delimited list of subnets to associate with the ALB. e.g. 'subnet-1a2b3c4d,subnet-1a2b3c4e,subnet-1a2b3c4f'"
description = "A list of subnets to associate with the ALB. e.g. ['subnet-1a2b3c4d','subnet-1a2b3c4e','subnet-1a2b3c4f']"
type = "list"
}

variable "vpc_id" {
description = "VPC id where the ALB and other resources will be deployed."
}
15 changes: 0 additions & 15 deletions example/main.tf

This file was deleted.

Loading

0 comments on commit 7842de9

Please sign in to comment.