diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 71da442..02bf72e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/antonbabenko/pre-commit-terraform - rev: v1.103.0 + rev: v1.104.0 hooks: - id: terraform_fmt - id: terraform_wrapper_module_for_each diff --git a/README.md b/README.md index c93a9a1..3f400d3 100644 --- a/README.md +++ b/README.md @@ -357,13 +357,13 @@ See [patterns.md](https://github.com/terraform-aws-modules/terraform-aws-alb/blo | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.5.7 | -| [aws](#requirement\_aws) | >= 6.19 | +| [aws](#requirement\_aws) | >= 6.22 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 6.19 | +| [aws](#provider\_aws) | >= 6.22 | ## Modules @@ -417,7 +417,7 @@ No modules. | [internal](#input\_internal) | If true, the LB will be internal. Defaults to `false` | `bool` | `null` | no | | [ip\_address\_type](#input\_ip\_address\_type) | The type of IP addresses used by the subnets for your load balancer. The possible values are `ipv4` and `dualstack` | `string` | `null` | no | | [ipam\_pools](#input\_ipam\_pools) | The IPAM pools to use with the load balancer |
object({
ipv4_ipam_pool_id = string
})
| `null` | no | -| [listeners](#input\_listeners) | Map of listener configurations to create |
map(object({
alpn_policy = optional(string)
certificate_arn = optional(string)
additional_certificate_arns = optional(list(string), [])
authenticate_cognito = optional(object({
authentication_request_extra_params = optional(map(string))
on_unauthenticated_request = optional(string)
scope = optional(string)
session_cookie_name = optional(string)
session_timeout = optional(number)
user_pool_arn = optional(string)
user_pool_client_id = optional(string)
user_pool_domain = optional(string)
}))
authenticate_oidc = optional(object({
authentication_request_extra_params = optional(map(string))
authorization_endpoint = string
client_id = string
client_secret = string
issuer = string
on_unauthenticated_request = optional(string)
scope = optional(string)
session_cookie_name = optional(string)
session_timeout = optional(number)
token_endpoint = string
user_info_endpoint = string
}))
fixed_response = optional(object({
content_type = string
message_body = optional(string)
status_code = optional(string)
}))
forward = optional(object({
target_group_arn = optional(string)
target_group_key = optional(string)
}))
weighted_forward = optional(object({
target_groups = optional(list(object({
target_group_arn = optional(string)
target_group_key = optional(string)
weight = optional(number)
})))
stickiness = optional(object({
duration = optional(number)
enabled = optional(bool)
}))
}))
redirect = optional(object({
host = optional(string)
path = optional(string)
port = optional(string)
protocol = optional(string)
query = optional(string)
status_code = string
}))
mutual_authentication = optional(object({
advertise_trust_store_ca_names = optional(string)
ignore_client_certificate_expiry = optional(bool)
mode = string
trust_store_arn = optional(string)
}))
order = optional(number)
port = optional(number)
protocol = optional(string)
routing_http_request_x_amzn_mtls_clientcert_header_name = optional(string)
routing_http_request_x_amzn_mtls_clientcert_issuer_header_name = optional(string)
routing_http_request_x_amzn_mtls_clientcert_leaf_header_name = optional(string)
routing_http_request_x_amzn_mtls_clientcert_serial_number_header_name = optional(string)
routing_http_request_x_amzn_mtls_clientcert_subject_header_name = optional(string)
routing_http_request_x_amzn_mtls_clientcert_validity_header_name = optional(string)
routing_http_request_x_amzn_tls_cipher_suite_header_name = optional(string)
routing_http_request_x_amzn_tls_version_header_name = optional(string)
routing_http_response_access_control_allow_credentials_header_value = optional(string)
routing_http_response_access_control_allow_headers_header_value = optional(string)
routing_http_response_access_control_allow_methods_header_value = optional(string)
routing_http_response_access_control_allow_origin_header_value = optional(string)
routing_http_response_access_control_expose_headers_header_value = optional(string)
routing_http_response_access_control_max_age_header_value = optional(string)
routing_http_response_content_security_policy_header_value = optional(string)
routing_http_response_server_enabled = optional(bool)
routing_http_response_strict_transport_security_header_value = optional(string)
routing_http_response_x_content_type_options_header_value = optional(string)
routing_http_response_x_frame_options_header_value = optional(string)
ssl_policy = optional(string)
tcp_idle_timeout_seconds = optional(number)
tags = optional(map(string), {})

# Listener rules
rules = optional(map(object({
actions = list(object({
authenticate_cognito = optional(object({
authentication_request_extra_params = optional(map(string))
on_unauthenticated_request = optional(string)
scope = optional(string)
session_cookie_name = optional(string)
session_timeout = optional(number)
user_pool_arn = string
user_pool_client_id = string
user_pool_domain = string
}))
authenticate_oidc = optional(object({
authentication_request_extra_params = optional(map(string))
authorization_endpoint = string
client_id = string
client_secret = string
issuer = string
on_unauthenticated_request = optional(string)
scope = optional(string)
session_cookie_name = optional(string)
session_timeout = optional(number)
token_endpoint = string
user_info_endpoint = string
}))
fixed_response = optional(object({
content_type = string
message_body = optional(string)
status_code = optional(string)
}))
forward = optional(object({
target_group_arn = optional(string)
target_group_key = optional(string)
}))
order = optional(number)
redirect = optional(object({
host = optional(string)
path = optional(string)
port = optional(string)
protocol = optional(string)
query = optional(string)
status_code = string
}))
weighted_forward = optional(object({
stickiness = optional(object({
duration = optional(number)
enabled = optional(bool)
}))
target_groups = optional(list(object({
target_group_arn = optional(string)
target_group_key = optional(string)
weight = optional(number)
})))
}))
}))
conditions = list(object({
host_header = optional(object({
values = optional(list(string))
regex_values = optional(list(string))
}))
http_header = optional(object({
http_header_name = string
values = optional(list(string))
regex_values = optional(list(string))
}))
http_request_method = optional(object({
values = list(string)
}))
path_pattern = optional(object({
values = optional(list(string))
regex_values = optional(list(string))
}))
query_string = optional(list(object({
key = optional(string)
value = string
})))
source_ip = optional(object({
values = list(string)
}))
}))
listener_arn = optional(string)
listener_key = optional(string)
priority = optional(number)
transform = optional(map(object({
type = optional(string)
host_header_rewrite_config = optional(object({
rewrite = optional(object({
regex = string
replace = string
}))
}))
url_rewrite_config = optional(object({
rewrite = optional(object({
regex = string
replace = string
}))
}))
})))
tags = optional(map(string), {})
})), {})
}))
| `{}` | no | +| [listeners](#input\_listeners) | Map of listener configurations to create |
map(object({
alpn_policy = optional(string)
certificate_arn = optional(string)
additional_certificate_arns = optional(list(string), [])
authenticate_cognito = optional(object({
authentication_request_extra_params = optional(map(string))
on_unauthenticated_request = optional(string)
scope = optional(string)
session_cookie_name = optional(string)
session_timeout = optional(number)
user_pool_arn = optional(string)
user_pool_client_id = optional(string)
user_pool_domain = optional(string)
}))
authenticate_oidc = optional(object({
authentication_request_extra_params = optional(map(string))
authorization_endpoint = string
client_id = string
client_secret = string
issuer = string
on_unauthenticated_request = optional(string)
scope = optional(string)
session_cookie_name = optional(string)
session_timeout = optional(number)
token_endpoint = string
user_info_endpoint = string
}))
fixed_response = optional(object({
content_type = string
message_body = optional(string)
status_code = optional(string)
}))
forward = optional(object({
target_group_arn = optional(string)
target_group_key = optional(string)
}))
jwt_validation = optional(object({
issuer = string
jwks_endpoint = string
additional_claim = optional(list(object({
format = string
name = string
values = list(string)
})))
}))
weighted_forward = optional(object({
target_groups = optional(list(object({
target_group_arn = optional(string)
target_group_key = optional(string)
weight = optional(number)
})))
stickiness = optional(object({
duration = optional(number)
enabled = optional(bool)
}))
}))
redirect = optional(object({
host = optional(string)
path = optional(string)
port = optional(string)
protocol = optional(string)
query = optional(string)
status_code = string
}))
mutual_authentication = optional(object({
advertise_trust_store_ca_names = optional(string)
ignore_client_certificate_expiry = optional(bool)
mode = string
trust_store_arn = optional(string)
}))
order = optional(number)
port = optional(number)
protocol = optional(string)
routing_http_request_x_amzn_mtls_clientcert_header_name = optional(string)
routing_http_request_x_amzn_mtls_clientcert_issuer_header_name = optional(string)
routing_http_request_x_amzn_mtls_clientcert_leaf_header_name = optional(string)
routing_http_request_x_amzn_mtls_clientcert_serial_number_header_name = optional(string)
routing_http_request_x_amzn_mtls_clientcert_subject_header_name = optional(string)
routing_http_request_x_amzn_mtls_clientcert_validity_header_name = optional(string)
routing_http_request_x_amzn_tls_cipher_suite_header_name = optional(string)
routing_http_request_x_amzn_tls_version_header_name = optional(string)
routing_http_response_access_control_allow_credentials_header_value = optional(string)
routing_http_response_access_control_allow_headers_header_value = optional(string)
routing_http_response_access_control_allow_methods_header_value = optional(string)
routing_http_response_access_control_allow_origin_header_value = optional(string)
routing_http_response_access_control_expose_headers_header_value = optional(string)
routing_http_response_access_control_max_age_header_value = optional(string)
routing_http_response_content_security_policy_header_value = optional(string)
routing_http_response_server_enabled = optional(bool)
routing_http_response_strict_transport_security_header_value = optional(string)
routing_http_response_x_content_type_options_header_value = optional(string)
routing_http_response_x_frame_options_header_value = optional(string)
ssl_policy = optional(string)
tcp_idle_timeout_seconds = optional(number)
tags = optional(map(string), {})

# Listener rules
rules = optional(map(object({
actions = list(object({
authenticate_cognito = optional(object({
authentication_request_extra_params = optional(map(string))
on_unauthenticated_request = optional(string)
scope = optional(string)
session_cookie_name = optional(string)
session_timeout = optional(number)
user_pool_arn = string
user_pool_client_id = string
user_pool_domain = string
}))
authenticate_oidc = optional(object({
authentication_request_extra_params = optional(map(string))
authorization_endpoint = string
client_id = string
client_secret = string
issuer = string
on_unauthenticated_request = optional(string)
scope = optional(string)
session_cookie_name = optional(string)
session_timeout = optional(number)
token_endpoint = string
user_info_endpoint = string
}))
jwt_validation = optional(object({
issuer = string
jwks_endpoint = string
additional_claim = optional(list(object({
format = string
name = string
values = list(string)
})))
}))
fixed_response = optional(object({
content_type = string
message_body = optional(string)
status_code = optional(string)
}))
forward = optional(object({
target_group_arn = optional(string)
target_group_key = optional(string)
}))
order = optional(number)
redirect = optional(object({
host = optional(string)
path = optional(string)
port = optional(string)
protocol = optional(string)
query = optional(string)
status_code = string
}))
weighted_forward = optional(object({
stickiness = optional(object({
duration = optional(number)
enabled = optional(bool)
}))
target_groups = optional(list(object({
target_group_arn = optional(string)
target_group_key = optional(string)
weight = optional(number)
})))
}))
}))
conditions = list(object({
host_header = optional(object({
values = optional(list(string))
regex_values = optional(list(string))
}))
http_header = optional(object({
http_header_name = string
values = optional(list(string))
regex_values = optional(list(string))
}))
http_request_method = optional(object({
values = list(string)
}))
path_pattern = optional(object({
values = optional(list(string))
regex_values = optional(list(string))
}))
query_string = optional(list(object({
key = optional(string)
value = string
})))
source_ip = optional(object({
values = list(string)
}))
}))
listener_arn = optional(string)
listener_key = optional(string)
priority = optional(number)
transform = optional(map(object({
type = optional(string)
host_header_rewrite_config = optional(object({
rewrite = optional(object({
regex = string
replace = string
}))
}))
url_rewrite_config = optional(object({
rewrite = optional(object({
regex = string
replace = string
}))
}))
})))
tags = optional(map(string), {})
})), {})
}))
| `{}` | no | | [load\_balancer\_type](#input\_load\_balancer\_type) | The type of load balancer to create. Possible values are `application`, `gateway`, or `network`. The default value is `application` | `string` | `"application"` | no | | [minimum\_load\_balancer\_capacity](#input\_minimum\_load\_balancer\_capacity) | Minimum capacity for a load balancer. Only valid for Load Balancers of type `application` or `network` |
object({
capacity_units = number
})
| `null` | no | | [name](#input\_name) | The name of the LB. This name must be unique within your AWS account, can have a maximum of 32 characters, must contain only alphanumeric characters or hyphens, and must not begin or end with a hyphen | `string` | `null` | no | diff --git a/examples/complete-alb/README.md b/examples/complete-alb/README.md index 94581e3..db20f4b 100644 --- a/examples/complete-alb/README.md +++ b/examples/complete-alb/README.md @@ -20,7 +20,7 @@ Note that this example may create resources which cost money. Run `terraform des | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.5.7 | -| [aws](#requirement\_aws) | >= 6.19 | +| [aws](#requirement\_aws) | >= 6.22 | | [null](#requirement\_null) | >= 2.0 | | [random](#requirement\_random) | >= 3.6 | @@ -28,7 +28,7 @@ Note that this example may create resources which cost money. Run `terraform des | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 6.19 | +| [aws](#provider\_aws) | >= 6.22 | | [null](#provider\_null) | >= 2.0 | | [random](#provider\_random) | >= 3.6 | diff --git a/examples/complete-alb/main.tf b/examples/complete-alb/main.tf index 29f1a12..5410edb 100644 --- a/examples/complete-alb/main.tf +++ b/examples/complete-alb/main.tf @@ -395,6 +395,45 @@ module "alb" { target_group_key = "ex-instance" } } + + ex-jwt = { + port = 445 + protocol = "HTTPS" + certificate_arn = module.acm.acm_certificate_arn + + forward = { + target_group_key = "ex-instance" + } + + rules = { + ex-jwt = { + priority = 5 + + actions = [ + { + jwt_validation = { + issuer = "https://${var.domain_name}" + jwks_endpoint = "https://${var.domain_name}/jwks.json" + additional_claim = [ + { format = "space-separated-values", name = "scp", values = ["read", "write"] } + ] + } + }, + { + forward = { + target_group_key = "ex-lambda-with-trigger" + } + } + ] + + conditions = [{ + host_header = { + values = ["foobar.com"] + } + }] + } + } + } } target_groups = { diff --git a/examples/complete-alb/versions.tf b/examples/complete-alb/versions.tf index 93f5ac5..fa6fd38 100644 --- a/examples/complete-alb/versions.tf +++ b/examples/complete-alb/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 6.19" + version = ">= 6.22" } null = { source = "hashicorp/null" diff --git a/examples/complete-nlb/README.md b/examples/complete-nlb/README.md index c3ef6ff..339987a 100644 --- a/examples/complete-nlb/README.md +++ b/examples/complete-nlb/README.md @@ -20,13 +20,13 @@ Note that this example may create resources which cost money. Run `terraform des | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.5.7 | -| [aws](#requirement\_aws) | >= 6.19 | +| [aws](#requirement\_aws) | >= 6.22 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 6.19 | +| [aws](#provider\_aws) | >= 6.22 | ## Modules diff --git a/examples/complete-nlb/versions.tf b/examples/complete-nlb/versions.tf index 0d5ee58..0cf1cd7 100644 --- a/examples/complete-nlb/versions.tf +++ b/examples/complete-nlb/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 6.19" + version = ">= 6.22" } } } diff --git a/examples/mutual-auth-alb/README.md b/examples/mutual-auth-alb/README.md index 3c59669..c7f807a 100644 --- a/examples/mutual-auth-alb/README.md +++ b/examples/mutual-auth-alb/README.md @@ -21,7 +21,7 @@ Note that this example may create resources which cost money. Run `terraform des | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.5.7 | -| [aws](#requirement\_aws) | >= 6.19 | +| [aws](#requirement\_aws) | >= 6.22 | | [null](#requirement\_null) | >= 2.0 | | [tls](#requirement\_tls) | >= 4.0 | @@ -29,7 +29,7 @@ Note that this example may create resources which cost money. Run `terraform des | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 6.19 | +| [aws](#provider\_aws) | >= 6.22 | | [null](#provider\_null) | >= 2.0 | | [tls](#provider\_tls) | >= 4.0 | diff --git a/examples/mutual-auth-alb/versions.tf b/examples/mutual-auth-alb/versions.tf index 0fd680a..e422bce 100644 --- a/examples/mutual-auth-alb/versions.tf +++ b/examples/mutual-auth-alb/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 6.19" + version = ">= 6.22" } null = { source = "hashicorp/null" diff --git a/main.tf b/main.tf index 2593cec..7538187 100644 --- a/main.tf +++ b/main.tf @@ -164,6 +164,30 @@ resource "aws_lb_listener" "this" { } } + dynamic "default_action" { + for_each = each.value.jwt_validation != null ? [each.value.jwt_validation] : [] + + content { + jwt_validation { + issuer = default_action.value.issuer + jwks_endpoint = default_action.value.jwks_endpoint + + dynamic "additional_claim" { + for_each = default_action.value.additional_claim != null ? default_action.value.additional_claim : [] + + content { + format = additional_claim.value.format + name = additional_claim.value.name + values = additional_claim.value.values + } + } + } + + order = each.value.order + type = "jwt-validation" + } + } + dynamic "default_action" { for_each = each.value.fixed_response != null ? [each.value.fixed_response] : [] @@ -354,6 +378,35 @@ resource "aws_lb_listener_rule" "this" { } } + # JWT validation + dynamic "action" { + for_each = [for action in each.value.actions : action if action.jwt_validation != null] + + content { + dynamic "jwt_validation" { + for_each = [action.value.jwt_validation] + + content { + issuer = jwt_validation.value.issuer + jwks_endpoint = jwt_validation.value.jwks_endpoint + + dynamic "additional_claim" { + for_each = jwt_validation.value.additional_claim != null ? jwt_validation.value.additional_claim : [] + + content { + format = additional_claim.value.format + name = additional_claim.value.name + values = additional_claim.value.values + } + } + } + } + + order = action.value.order + type = "jwt-validation" + } + } + # Fixed response dynamic "action" { for_each = [for action in each.value.actions : action if action.fixed_response != null] diff --git a/modules/lb_trust_store/README.md b/modules/lb_trust_store/README.md index 7ef4d78..bc3ebae 100644 --- a/modules/lb_trust_store/README.md +++ b/modules/lb_trust_store/README.md @@ -30,13 +30,13 @@ module "trust_store" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.5.7 | -| [aws](#requirement\_aws) | >= 6.19 | +| [aws](#requirement\_aws) | >= 6.22 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | >= 6.19 | +| [aws](#provider\_aws) | >= 6.22 | ## Modules diff --git a/modules/lb_trust_store/versions.tf b/modules/lb_trust_store/versions.tf index 0d5ee58..0cf1cd7 100644 --- a/modules/lb_trust_store/versions.tf +++ b/modules/lb_trust_store/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 6.19" + version = ">= 6.22" } } } diff --git a/variables.tf b/variables.tf index 5d5401b..849c7f0 100644 --- a/variables.tf +++ b/variables.tf @@ -269,6 +269,15 @@ variable "listeners" { target_group_arn = optional(string) target_group_key = optional(string) })) + jwt_validation = optional(object({ + issuer = string + jwks_endpoint = string + additional_claim = optional(list(object({ + format = string + name = string + values = list(string) + }))) + })) weighted_forward = optional(object({ target_groups = optional(list(object({ target_group_arn = optional(string) @@ -346,6 +355,15 @@ variable "listeners" { token_endpoint = string user_info_endpoint = string })) + jwt_validation = optional(object({ + issuer = string + jwks_endpoint = string + additional_claim = optional(list(object({ + format = string + name = string + values = list(string) + }))) + })) fixed_response = optional(object({ content_type = string message_body = optional(string) diff --git a/versions.tf b/versions.tf index 0d5ee58..0cf1cd7 100644 --- a/versions.tf +++ b/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 6.19" + version = ">= 6.22" } } } diff --git a/wrappers/lb_trust_store/versions.tf b/wrappers/lb_trust_store/versions.tf index 0d5ee58..0cf1cd7 100644 --- a/wrappers/lb_trust_store/versions.tf +++ b/wrappers/lb_trust_store/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 6.19" + version = ">= 6.22" } } } diff --git a/wrappers/versions.tf b/wrappers/versions.tf index 0d5ee58..0cf1cd7 100644 --- a/wrappers/versions.tf +++ b/wrappers/versions.tf @@ -4,7 +4,7 @@ terraform { required_providers { aws = { source = "hashicorp/aws" - version = ">= 6.19" + version = ">= 6.22" } } }