Skip to content

Commit

Permalink
Merge pull request #1 from sudoblark/feature/initial-setup
Browse files Browse the repository at this point in the history
Initial module setup
  • Loading branch information
benjaminlukeclark authored Sep 18, 2024
2 parents 86de852 + 4ed88d5 commit f3f4d28
Show file tree
Hide file tree
Showing 15 changed files with 370 additions and 4 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/commit-to-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
validation:
strategy:
matrix:
folder: ["add", "folders", "here"]
folder: ["./", "examples/step_function"]
name: Terraform validate for ${{ matrix.folder }}
runs-on: ubuntu-20.04
steps:
Expand All @@ -41,7 +41,7 @@ jobs:
linting:
strategy:
matrix:
folder: ["add", "folders", "here"]
folder: ["./", "examples/step_function"]
name: Terraform lint for ${{ matrix.folder }}
runs-on: ubuntu-20.04
steps:
Expand All @@ -59,7 +59,7 @@ jobs:
plan:
strategy:
matrix:
folder: ["add", "folders", "here"]
folder: ["examples/step_function"]
name: Terraform plan for ${{ matrix.folder }}
runs-on: ubuntu-20.04
needs: [validation, linting]
Expand Down
1 change: 1 addition & 0 deletions .terraform-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.5.1
63 changes: 62 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,72 @@ The below documentation is intended to assist users in utilising the module, the
the module itself, and the [examples](#examples) section which has examples of how to utilise the module.

<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | ~> 1.5.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.61.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | 5.67.0 |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_step_function_state_machine"></a> [step\_function\_state\_machine](#module\_step\_function\_state\_machine) | terraform-aws-modules/step-functions/aws | 4.2.0 |

## Resources

| Name | Type |
|------|------|
| [aws_caller_identity.current_account](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_iam_policy_document.attached_policies](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_region.current_region](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_application_name"></a> [application\_name](#input\_application\_name) | Name of the application utilising resource. | `string` | n/a | yes |
| <a name="input_environment"></a> [environment](#input\_environment) | Which environment this is being instantiated in. | `string` | n/a | yes |
| <a name="input_raw_state_machines"></a> [raw\_state\_machines](#input\_raw\_state\_machines) | Data structure<br>---------------<br>A list of dictionaries, where each dictionary has the following attributes:<br><br>REQUIRED<br>---------<br>- template\_file : File path which this machine corresponds to<br>- template\_input : A dictionary of key/value pairs, outlining in detail the inputs needed for a template to be instantiated<br>- suffix : Friendly name for the state function<br>- iam\_policy\_statements : A list of dictionaries where each dictionary is an IAM statement defining glue job permissions<br>-- Each dictionary in this list must define the following attributes:<br>--- sid: Friendly name for the policy, no spaces or special characters allowed<br>--- actions: A list of IAM actions the state machine is allowed to perform<br>--- resources: Which resource(s) the state machine may perform the above actions against<br>--- conditions : An OPTIONAL list of dictionaries, which each defines:<br>---- test : Test condition for limiting the action<br>---- variable : Value to test<br>---- values : A list of strings, denoting what to test for<br><br><br>OPTIONAL<br>---------<br>- cloudwatch\_retention : How many days logs should be retained for in Cloudwatch, defaults to 90 | <pre>list(<br> object({<br> template_file = string,<br> template_input = map(string),<br> suffix = string,<br> iam_policy_statements = list(<br> object({<br> sid = string,<br> actions = list(string),<br> resources = list(string),<br> conditions = optional(list(<br> object({<br> test : string,<br> variable : string,<br> values = list(string)<br> })<br> ), [])<br> })<br> ),<br> cloudwatch_retention = optional(number, 90)<br> })<br> )</pre> | n/a | yes |

## Outputs

No outputs.
<!-- END_TF_DOCS -->

## Data structure
<POPULATE WITH YOUR DATA STRUCTURE>
```
Data structure
---------------
A list of dictionaries, where each dictionary has the following attributes:
REQUIRED
---------
- template_file : File path which this machine corresponds to
- template_input : A dictionary of key/value pairs, outlining in detail the inputs needed for a template to be instantiated
- suffix : Friendly name for the state function
- iam_policy_statements : A list of dictionaries where each dictionary is an IAM statement defining glue job permissions
-- Each dictionary in this list must define the following attributes:
--- sid: Friendly name for the policy, no spaces or special characters allowed
--- actions: A list of IAM actions the state machine is allowed to perform
--- resources: Which resource(s) the state machine may perform the above actions against
--- conditions : An OPTIONAL list of dictionaries, which each defines:
---- test : Test condition for limiting the action
---- variable : Value to test
---- values : A list of strings, denoting what to test for
OPTIONAL
---------
- cloudwatch_retention : How many days logs should be retained for in Cloudwatch, defaults to 90gi
```

## Examples
See `examples` folder for an example setup.
79 changes: 79 additions & 0 deletions aws_iam_policy_document.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
locals {
actual_iam_policy_documents = {
for state_machine in var.raw_state_machines :
state_machine.suffix => {
statements = concat(state_machine.iam_policy_statements, local.barebones_statemachine_statements,
[
{
sid = "ListOwnExecutions",
actions = [
"states:ListExecutions"
]
resources = [
format(
"arn:aws:states:%s:%s:stateMachine:%s-%s-%s-stepfunction",
lower(data.aws_region.current_region.name),
lower(data.aws_caller_identity.current_account.id),
lower(var.environment),
lower(var.application_name),
lower(state_machine.suffix)
)
]
conditions = []
},
{
sid = "AllowCloudwatchStreamAccess",
actions = [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
resources = [
"arn:aws:logs:${data.aws_region.current_region.name}:${data.aws_caller_identity.current_account.account_id}:log-group:/aws/stepfunction/${format("%s-%s-%s-stepfunction", var.environment, var.application_name, state_machine.suffix)}",
"arn:aws:logs:${data.aws_region.current_region.name}:${data.aws_caller_identity.current_account.account_id}:log-group:/aws/stepfunction/${format("%s-%s-%s-stepfunction", var.environment, var.application_name, state_machine.suffix)}:*"
]
conditions = []
},
{
sid = "AllowCloudwatchLogDelivery",
actions = [
"logs:CreateLogDelivery",
"logs:PutResourcePolicy",
"logs:UpdateLogDelivery",
"logs:DeleteLogDelivery",
"logs:DescribeResourcePolicies",
"logs:GetLogDelivery",
"logs:ListLogDeliveries",
"logs:DescribeLogGroups"
],
resources = ["*"]
conditions = []
}
]
)
}
}
}

data "aws_iam_policy_document" "attached_policies" {
for_each = local.actual_iam_policy_documents

dynamic "statement" {
for_each = each.value["statements"]

content {
sid = statement.value["sid"]
actions = statement.value["actions"]
resources = statement.value["resources"]

dynamic "condition" {
for_each = statement.value["conditions"]

content {
test = condition.value["test"]
variable = condition.value["variable"]
values = condition.value["values"]
}
}
}
}
}
19 changes: 19 additions & 0 deletions common_iam_policies.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
locals {
barebones_statemachine_statements = [
{
sid = "BarebonesEventActionsForStatemachine"
actions = [
"events:PutEvents",
"events:DescribeRule",
"events:PutRule",
"events:PutTargets"
]
resources = [
"arn:aws:events:${data.aws_region.current_region.name}:${data.aws_caller_identity.current_account.account_id}:rule/default/StepFunctionsGetEventsForECSTaskRule",
"arn:aws:events:${data.aws_region.current_region.name}:${data.aws_caller_identity.current_account.account_id}:rule/StepFunctionsGetEventsForECSTaskRule",
"arn:aws:events:${data.aws_region.current_region.name}:${data.aws_caller_identity.current_account.account_id}:event-bus/default"
]
conditions = []
}
]
}
5 changes: 5 additions & 0 deletions data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Get current region
data "aws_region" "current_region" {}

# Retrieve the current AWS Account info
data "aws_caller_identity" "current_account" {}
1 change: 1 addition & 0 deletions examples/step_function/.terraform-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1.5.1
5 changes: 5 additions & 0 deletions examples/step_function/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Get current region
data "aws_region" "current_region" {}

# Retrieve the current AWS Account info
data "aws_caller_identity" "current_account" {}
11 changes: 11 additions & 0 deletions examples/step_function/files/step-function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"Comment": "A Hello World example of the Amazon States Language using an AWS Lambda Function",
"StartAt": "HelloWorld",
"States": {
"HelloWorld": {
"Type": "Task",
"Resource": "${lambda-arn}",
"End": true
}
}
}
23 changes: 23 additions & 0 deletions examples/step_function/locals.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
locals {
raw_state_machines = [
{
suffix : "hello-world",
template_file : "${path.module}/files/step-function.json",
template_input : {
"lambda-arn" : "arn:aws:lambda:${data.aws_region.current_region.name}:${data.aws_caller_identity.current_account.account_id}:function:hello-world-function"
},
iam_policy_statements : [
{
sid : "AllowLambdaExecution",
actions : [
"lambda:InvokeFunction",
"lambda:InvokeAsync",
],
resources : [
"arn:aws:lambda:${data.aws_region.current_region.name}:${data.aws_caller_identity.current_account.account_id}:function:hello-world-function"
]
}
]
}
]
}
21 changes: 21 additions & 0 deletions examples/step_function/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.61.0"
}
}
required_version = "~> 1.5.0"
}

provider "aws" {
region = "eu-west-2"
}

module "step_function" {
source = "github.com/sudoblark/sudoblark.terraform.module.aws.state_machine?ref=1.0.0"

application_name = var.application_name
environment = var.environment
raw_state_machines = local.raw_state_machines
}
15 changes: 15 additions & 0 deletions examples/step_function/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
variable "environment" {
description = "Which environment this is being instantiated in."
type = string
validation {
condition = contains(["dev", "test", "prod"], var.environment)
error_message = "Must be either dev, test or prod"
}
default = "prod"
}

variable "application_name" {
description = "Name of the application utilising the resource resource."
type = string
default = "demo-app"
}
9 changes: 9 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.61.0"
}
}
required_version = "~> 1.5.0"
}
45 changes: 45 additions & 0 deletions state_machine.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
locals {
actual_state_machines = {
for state_machine in var.raw_state_machines :
state_machine.suffix => merge(state_machine, {
state_machine_definition = templatefile(state_machine.template_file, state_machine.template_input)
policy_json = data.aws_iam_policy_document.attached_policies[state_machine.suffix].json
state_machine_name = format("%s-%s-%s-stepfunction", var.environment, var.application_name, state_machine.suffix)
})
}
}

module "step_function_state_machine" {
for_each = local.actual_state_machines

depends_on = [
data.aws_iam_policy_document.attached_policies
]


source = "terraform-aws-modules/step-functions/aws"
version = "4.2.0"

name = each.value["state_machine_name"]
create_role = true
policy_jsons = [each.value["policy_json"]]

definition = each.value["state_machine_definition"]

logging_configuration = {
"include_execution_data" = true
"level" = "ALL"
}
cloudwatch_log_group_name = "/aws/vendedlogs/states/${each.value["state_machine_name"]}"
cloudwatch_log_group_retention_in_days = each.value["cloudwatch_retention"]

service_integrations = {
stepfunction_Sync = {
# Set to true to use the default events (otherwise, set this to a list of ARNs; see the docs linked in locals.tf
# for more information). Without events permissions, you will get an error similar to this:
# Error: AccessDeniedException: 'arn:aws:iam::xxxx:role/step-functions-role' is not authorized to
# create managed-rule
events = true
}
}
}
Loading

0 comments on commit f3f4d28

Please sign in to comment.