forked from gruntwork-io/terratest
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for a custom aws endpoint
Fixes gruntwork-io#494. This makes it possible to run terratest against a custom aws endpoint. This allows it to be used woth [Moto's standalone server mode](http://docs.getmoto.org/en/latest/docs/server_mode.html) for example, to test AWS modules locally without needing an AWS account or any access to AWS. Unfortunately these tests don't pass as is, because they would require setting up the moto server, and I'm not sure where that setup should be added. They do pass if the moto server is running.
- Loading branch information
Shaun Verch
committed
Mar 18, 2023
1 parent
5409026
commit 41bf74c
Showing
6 changed files
with
320 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Terraform AWS S3 Example | ||
|
||
This folder contains a simple Terraform module to demonstrate using custom | ||
endpoints. It's deploying some AWS resources to `http://localhost:5000`, which | ||
is the default port for [moto running in server | ||
mode](http://docs.getmoto.org/en/latest/docs/server_mode.html). This allows for | ||
testing terraform modules locally with no connection to AWS. | ||
|
||
Check out | ||
[test/terraform_aws_endpoint_example_test.go](/test/terraform_aws_endpoint_example_test.go) | ||
to see how you can write automated tests for this module. | ||
|
||
## Running this module manually | ||
|
||
1. Run [Moto locally in server mode](http://docs.getmoto.org/en/latest/docs/server_mode.html) | ||
1. Install [Terraform](https://www.terraform.io/) and make sure it's on your `PATH`. | ||
1. Run `terraform init`. | ||
1. Run `terraform apply`. | ||
1. When you're done, run `terraform destroy`. | ||
|
||
## Running automated tests against this module | ||
|
||
1. Run [Moto locally in server mode](http://docs.getmoto.org/en/latest/docs/server_mode.html) | ||
1. Install [Terraform](https://www.terraform.io/) and make sure it's on your `PATH`. | ||
1. Install [Golang](https://golang.org/) and make sure this code is checked out into your `GOPATH`. | ||
1. `cd test` | ||
1. `dep ensure` | ||
1. `go test -v -run TestTerraformAwsEndpointExample` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
# --------------------------------------------------------------------------------------------------------------------- | ||
# PIN TERRAFORM VERSION TO >= 0.12 | ||
# The examples have been upgraded to 0.12 syntax | ||
# --------------------------------------------------------------------------------------------------------------------- | ||
provider "aws" { | ||
region = var.region | ||
access_key = "dummy" | ||
secret_key = "dummy" | ||
|
||
endpoints { | ||
sts = "http://localhost:5000" | ||
s3 = "http://localhost:5000" | ||
} | ||
} | ||
|
||
terraform { | ||
# This module is now only being tested with Terraform 0.13.x. However, to make upgrading easier, we are setting | ||
# 0.12.26 as the minimum version, as that version added support for required_providers with source URLs, making it | ||
# forwards compatible with 0.13.x code. | ||
required_version = ">= 0.12.26" | ||
} | ||
|
||
# --------------------------------------------------------------------------------------------------------------------- | ||
# DEPLOY A S3 BUCKET WITH VERSIONING ENABLED INCLUDING TAGS TO A LOCAL ENDPOINT | ||
# See test/terraform_aws_endpoint_example_test.go for how to write automated tests for this code. | ||
# --------------------------------------------------------------------------------------------------------------------- | ||
|
||
# Deploy and configure test S3 bucket with versioning and access log | ||
resource "aws_s3_bucket" "test_bucket" { | ||
bucket = "${local.aws_account_id}-${var.tag_bucket_name}" | ||
|
||
tags = { | ||
Name = var.tag_bucket_name | ||
Environment = var.tag_bucket_environment | ||
} | ||
} | ||
|
||
resource "aws_s3_bucket_logging" "test_bucket" { | ||
bucket = aws_s3_bucket.test_bucket.id | ||
target_bucket = aws_s3_bucket.test_bucket_logs.id | ||
target_prefix = "TFStateLogs/" | ||
} | ||
|
||
resource "aws_s3_bucket_versioning" "test_bucket" { | ||
bucket = aws_s3_bucket.test_bucket.id | ||
versioning_configuration { | ||
status = "Enabled" | ||
} | ||
} | ||
|
||
resource "aws_s3_bucket_acl" "test_bucket" { | ||
bucket = aws_s3_bucket.test_bucket.id | ||
acl = "private" | ||
} | ||
|
||
|
||
# Deploy S3 bucket to collect access logs for test bucket | ||
resource "aws_s3_bucket" "test_bucket_logs" { | ||
bucket = "${local.aws_account_id}-${var.tag_bucket_name}-logs" | ||
|
||
tags = { | ||
Name = "${local.aws_account_id}-${var.tag_bucket_name}-logs" | ||
Environment = var.tag_bucket_environment | ||
} | ||
|
||
force_destroy = true | ||
} | ||
|
||
resource "aws_s3_bucket_acl" "test_bucket_logs" { | ||
bucket = aws_s3_bucket.test_bucket_logs.id | ||
acl = "log-delivery-write" | ||
} | ||
|
||
# Configure bucket access policies | ||
|
||
resource "aws_s3_bucket_policy" "bucket_access_policy" { | ||
count = var.with_policy ? 1 : 0 | ||
bucket = aws_s3_bucket.test_bucket.id | ||
policy = data.aws_iam_policy_document.s3_bucket_policy.json | ||
} | ||
|
||
data "aws_iam_policy_document" "s3_bucket_policy" { | ||
statement { | ||
effect = "Allow" | ||
principals { | ||
# TF-UPGRADE-TODO: In Terraform v0.10 and earlier, it was sometimes necessary to | ||
# force an interpolation expression to be interpreted as a list by wrapping it | ||
# in an extra set of list brackets. That form was supported for compatibility in | ||
# v0.11, but is no longer supported in Terraform v0.12. | ||
# | ||
# If the expression in the following list itself returns a list, remove the | ||
# brackets to avoid interpretation as a list of lists. If the expression | ||
# returns a single list item then leave it as-is and remove this TODO comment. | ||
identifiers = [local.aws_account_id] | ||
type = "AWS" | ||
} | ||
actions = ["*"] | ||
resources = ["${aws_s3_bucket.test_bucket.arn}/*"] | ||
} | ||
|
||
statement { | ||
effect = "Deny" | ||
principals { | ||
identifiers = ["*"] | ||
type = "AWS" | ||
} | ||
actions = ["*"] | ||
resources = ["${aws_s3_bucket.test_bucket.arn}/*"] | ||
|
||
condition { | ||
test = "Bool" | ||
variable = "aws:SecureTransport" | ||
values = [ | ||
"false", | ||
] | ||
} | ||
} | ||
} | ||
|
||
# --------------------------------------------------------------------------------------------------------------------- | ||
# LOCALS | ||
# Used to represent any data that requires complex expressions/interpolations | ||
# --------------------------------------------------------------------------------------------------------------------- | ||
|
||
data "aws_caller_identity" "current" { | ||
} | ||
|
||
locals { | ||
aws_account_id = data.aws_caller_identity.current.account_id | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
output "bucket_id" { | ||
value = aws_s3_bucket.test_bucket.id | ||
} | ||
|
||
output "bucket_arn" { | ||
value = aws_s3_bucket.test_bucket.arn | ||
} | ||
|
||
output "logging_target_bucket" { | ||
value = aws_s3_bucket_logging.test_bucket.target_bucket | ||
} | ||
|
||
output "logging_target_prefix" { | ||
value = aws_s3_bucket_logging.test_bucket.target_prefix | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# --------------------------------------------------------------------------------------------------------------------- | ||
# ENVIRONMENT VARIABLES | ||
# Define these secrets as environment variables | ||
# --------------------------------------------------------------------------------------------------------------------- | ||
|
||
# AWS_ACCESS_KEY_ID | ||
# AWS_SECRET_ACCESS_KEY | ||
|
||
# --------------------------------------------------------------------------------------------------------------------- | ||
# REQUIRED PARAMETERS | ||
# You must provide a value for each of these parameters. | ||
# --------------------------------------------------------------------------------------------------------------------- | ||
variable "region" { | ||
description = "The AWS region to deploy to" | ||
type = string | ||
} | ||
|
||
# --------------------------------------------------------------------------------------------------------------------- | ||
# OPTIONAL PARAMETERS | ||
# These parameters have reasonable defaults. | ||
# --------------------------------------------------------------------------------------------------------------------- | ||
|
||
variable "with_policy" { | ||
description = "If set to `true`, the bucket will be created with a bucket policy." | ||
type = bool | ||
default = false | ||
} | ||
|
||
variable "tag_bucket_name" { | ||
description = "The Name tag to set for the S3 Bucket." | ||
type = string | ||
default = "Test Bucket" | ||
} | ||
|
||
variable "tag_bucket_environment" { | ||
description = "The Environment tag to set for the S3 Bucket." | ||
type = string | ||
default = "Test" | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package test | ||
|
||
import ( | ||
"os" | ||
"fmt" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/gruntwork-io/terratest/modules/aws" | ||
"github.com/gruntwork-io/terratest/modules/random" | ||
"github.com/gruntwork-io/terratest/modules/terraform" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
// An example of how to test the Terraform module in examples/terraform-aws-endpoint-example using Terratest. | ||
func TestTerraformAwsEndpointExample(t *testing.T) { | ||
t.Parallel() | ||
|
||
// Set a custom endpoint for AWS, and set the keys to dummy keys to | ||
// pass that check | ||
os.Setenv("TERRATEST_CUSTOM_AWS_ENDPOINT", "http://localhost:5000") | ||
os.Setenv("AWS_ACCESS_KEY_ID", "dummy") | ||
os.Setenv("AWS_SECRET_ACCESS_KEY", "dummy") | ||
|
||
// Give this S3 Bucket a unique ID for a name tag so we can distinguish it from any other Buckets provisioned | ||
// in your AWS account | ||
expectedName := fmt.Sprintf("terratest-aws-endpoint-example-%s", strings.ToLower(random.UniqueId())) | ||
|
||
// Give this S3 Bucket an environment to operate as a part of for the purposes of resource tagging | ||
expectedEnvironment := "Automated Testing" | ||
|
||
// Pick a random AWS region to test in. This helps ensure your code works in all regions. | ||
awsRegion := aws.GetRandomStableRegion(t, nil, nil) | ||
|
||
// Construct the terraform options with default retryable errors to handle the most common retryable errors in | ||
// terraform testing. | ||
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ | ||
// The path to where our Terraform code is located | ||
TerraformDir: "../examples/terraform-aws-endpoint-example", | ||
|
||
// Variables to pass to our Terraform code using -var options | ||
Vars: map[string]interface{}{ | ||
"tag_bucket_name": expectedName, | ||
"tag_bucket_environment": expectedEnvironment, | ||
"with_policy": "true", | ||
"region": awsRegion, | ||
}, | ||
}) | ||
|
||
// At the end of the test, run `terraform destroy` to clean up any resources that were created | ||
defer terraform.Destroy(t, terraformOptions) | ||
|
||
// This will run `terraform init` and `terraform apply` and fail the test if there are any errors | ||
terraform.InitAndApply(t, terraformOptions) | ||
|
||
// Run `terraform output` to get the value of an output variable | ||
bucketID := terraform.Output(t, terraformOptions, "bucket_id") | ||
|
||
// Verify that our Bucket has versioning enabled | ||
actualStatus := aws.GetS3BucketVersioning(t, awsRegion, bucketID) | ||
expectedStatus := "Enabled" | ||
assert.Equal(t, expectedStatus, actualStatus) | ||
|
||
// Verify that our Bucket has a policy attached | ||
aws.AssertS3BucketPolicyExists(t, awsRegion, bucketID) | ||
|
||
// Verify that our bucket has server access logging TargetBucket set to what's expected | ||
loggingTargetBucket := aws.GetS3BucketLoggingTarget(t, awsRegion, bucketID) | ||
expectedLogsTargetBucket := fmt.Sprintf("%s-logs", bucketID) | ||
loggingObjectTargetPrefix := aws.GetS3BucketLoggingTargetPrefix(t, awsRegion, bucketID) | ||
expectedLogsTargetPrefix := "TFStateLogs/" | ||
|
||
assert.Equal(t, expectedLogsTargetBucket, loggingTargetBucket) | ||
assert.Equal(t, expectedLogsTargetPrefix, loggingObjectTargetPrefix) | ||
} |