Skip to content

Commit fbbf392

Browse files
committed
feat: move route53 dns BBs to meshstack-hub
1 parent 192830d commit fbbf392

File tree

26 files changed

+852
-0
lines changed

26 files changed

+852
-0
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
name: AWS Route53 DNS Alias Record Buildingblock Backplane
3+
summary: |
4+
Deploys an IAM user with Route53 access for managing DNS alias records
5+
---
6+
7+
# AWS Route53 DNS Alias Record Backplane
8+
9+
This will deploy an IAM user (or role only in case of using `workload_identity_federation`) with Route53 access for managing DNS alias records.
10+
11+
## Usage
12+
13+
```hcl
14+
provider "aws" {
15+
region = "eu-central-1" # or any other region
16+
}
17+
18+
module "aws_route53_dns_alias_record_backplane" {
19+
source = "git::https://github.com/meshcloud/meshstack-hub.git//modules/aws/route53-dns-alias-record/backplane"
20+
21+
# List of Route53 hosted zone IDs that the building block can manage
22+
hosted_zone_ids = [
23+
"Z07734711DJ9F80W7IUV9",
24+
"ZVJQRTFA77CTX",
25+
"Z24AXR0TAO4HY4"
26+
]
27+
28+
workload_identity_federation = {
29+
issuer = "https://your-oidc-issuer"
30+
audience = "your-audience"
31+
subjects = [
32+
"system:serviceaccount:your-namespace:your-service-account-name", # Exact match
33+
"system:serviceaccount:your-namespace:*", # Wildcard match
34+
]
35+
} # Optional, if not provided, IAM access keys will be created instead
36+
}
37+
38+
output "aws_route53_dns_alias_record_backplane" {
39+
value = module.aws_route53_dns_alias_record_backplane
40+
}
41+
```
42+
43+
<!-- BEGIN_TF_DOCS -->
44+
## Requirements
45+
46+
| Name | Version |
47+
|------|---------|
48+
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3.0 |
49+
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | ~> 5.0 |
50+
51+
## Modules
52+
53+
No modules.
54+
55+
## Resources
56+
57+
| Name | Type |
58+
|------|------|
59+
| [aws_iam_access_key.buildingblock_route53_alias_record_access_key](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_access_key) | resource |
60+
| [aws_iam_openid_connect_provider.buildingblock_oidc_provider](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_openid_connect_provider) | resource |
61+
| [aws_iam_policy.buildingblock_route53_alias_record_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
62+
| [aws_iam_role.assume_federated_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
63+
| [aws_iam_role_policy_attachment.buildingblock_route53_alias_record](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
64+
| [aws_iam_user.buildingblock_route53_alias_record_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user) | resource |
65+
| [aws_iam_user_policy_attachment.buildingblock_route53_alias_record_user_policy_attachment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user_policy_attachment) | resource |
66+
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
67+
| [aws_iam_policy_document.route53_alias_record_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
68+
| [aws_iam_policy_document.workload_identity_federation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
69+
70+
## Inputs
71+
72+
| Name | Description | Type | Default | Required |
73+
|------|-------------|------|---------|:--------:|
74+
| <a name="input_workload_identity_federation"></a> [workload\_identity\_federation](#input\_workload\_identity\_federation) | Set these options to add a trusted identity provider from meshStack to allow workload identity federation for authentication which can be used instead of access keys. Supports multiple subjects and wildcard patterns (e.g., 'system:serviceaccount:namespace:*'). | <pre>object({<br> issuer = string,<br> audience = string,<br> subjects = list(string)<br> })</pre> | `null` | no |
75+
76+
## Outputs
77+
78+
| Name | Description |
79+
|------|-------------|
80+
| <a name="output_credentials"></a> [credentials](#output\_credentials) | n/a |
81+
| <a name="output_workload_identity_federation_role"></a> [workload\_identity\_federation\_role](#output\_workload\_identity\_federation\_role) | n/a |
82+
<!-- END_TF_DOCS -->
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
data "aws_caller_identity" "current" {}
2+
3+
resource "aws_iam_user" "buildingblock_route53_alias_record_user" {
4+
count = var.workload_identity_federation == null ? 1 : 0
5+
6+
name = "buildingblock-route53-alias-record-user"
7+
}
8+
9+
data "aws_iam_policy_document" "route53_alias_record_access" {
10+
# Global Route53 actions that don't support resource-level permissions
11+
statement {
12+
effect = "Allow"
13+
actions = [
14+
"route53:GetChange",
15+
"route53:ListHostedZones"
16+
]
17+
resources = ["*"]
18+
}
19+
20+
# Zone-specific actions scoped to specific hosted zones
21+
statement {
22+
effect = "Allow"
23+
actions = [
24+
"route53:ListTagsForResource",
25+
"route53:GetHostedZone",
26+
"route53:ChangeResourceRecordSets",
27+
"route53:ListResourceRecordSets"
28+
]
29+
resources = [
30+
for zone_id in var.hosted_zone_ids : "arn:aws:route53:::hostedzone/${zone_id}"
31+
]
32+
}
33+
}
34+
35+
resource "aws_iam_policy" "buildingblock_route53_alias_record_policy" {
36+
name = var.workload_identity_federation == null ? "Route53AliasRecordBuildingBlockPolicy" : "Route53AliasRecordBuildingBlockFederatedPolicy"
37+
description = "Policy for the Route53 DNS Alias Record Building Block"
38+
policy = data.aws_iam_policy_document.route53_alias_record_access.json
39+
}
40+
41+
resource "aws_iam_user_policy_attachment" "buildingblock_route53_alias_record_user_policy_attachment" {
42+
count = var.workload_identity_federation == null ? 1 : 0
43+
44+
user = aws_iam_user.buildingblock_route53_alias_record_user[0].name
45+
policy_arn = aws_iam_policy.buildingblock_route53_alias_record_policy.arn
46+
}
47+
48+
resource "aws_iam_access_key" "buildingblock_route53_alias_record_access_key" {
49+
count = var.workload_identity_federation == null ? 1 : 0
50+
51+
user = aws_iam_user.buildingblock_route53_alias_record_user[0].name
52+
}
53+
54+
# Workload Identity Federation
55+
56+
resource "aws_iam_openid_connect_provider" "buildingblock_oidc_provider" {
57+
count = var.workload_identity_federation != null ? 1 : 0
58+
59+
url = var.workload_identity_federation.issuer
60+
client_id_list = [var.workload_identity_federation.audience]
61+
}
62+
63+
data "aws_iam_policy_document" "workload_identity_federation" {
64+
count = var.workload_identity_federation != null ? 1 : 0
65+
version = "2012-10-17"
66+
67+
statement {
68+
effect = "Allow"
69+
principals {
70+
type = "Federated"
71+
identifiers = [aws_iam_openid_connect_provider.buildingblock_oidc_provider[0].arn]
72+
}
73+
actions = ["sts:AssumeRoleWithWebIdentity"]
74+
75+
condition {
76+
test = "StringEquals"
77+
variable = "${trimprefix(var.workload_identity_federation.issuer, "https://")}:aud"
78+
79+
values = [var.workload_identity_federation.audience]
80+
}
81+
82+
condition {
83+
test = "StringLike"
84+
variable = "${trimprefix(var.workload_identity_federation.issuer, "https://")}:sub"
85+
86+
values = var.workload_identity_federation.subjects
87+
}
88+
}
89+
}
90+
91+
resource "aws_iam_role" "assume_federated_role" {
92+
count = var.workload_identity_federation != null ? 1 : 0
93+
94+
name = "BuildingBlockRoute53AliasRecordIdentityFederation"
95+
assume_role_policy = data.aws_iam_policy_document.workload_identity_federation[0].json
96+
}
97+
98+
resource "aws_iam_role_policy_attachment" "buildingblock_route53_alias_record" {
99+
count = var.workload_identity_federation != null ? 1 : 0
100+
101+
role = aws_iam_role.assume_federated_role[0].name
102+
policy_arn = aws_iam_policy.buildingblock_route53_alias_record_policy.arn
103+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
output "credentials" {
2+
sensitive = true
3+
value = {
4+
AWS_ACCESS_KEY_ID = var.workload_identity_federation == null ? aws_iam_access_key.buildingblock_route53_alias_record_access_key[0].id : "N/A; workload identity federation in use"
5+
AWS_SECRET_ACCESS_KEY = var.workload_identity_federation == null ? aws_iam_access_key.buildingblock_route53_alias_record_access_key[0].secret : "N/A; workload identity federation in use"
6+
}
7+
}
8+
9+
output "workload_identity_federation_role" {
10+
value = var.workload_identity_federation == null ? null : aws_iam_role.assume_federated_role[0].arn
11+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
variable "hosted_zone_ids" {
2+
type = list(string)
3+
description = "List of Route53 hosted zone IDs that the building block can manage. Example: ['Z07734711DJ9F80W7IUV9', 'ZVJQRTFA77CTX']"
4+
}
5+
6+
variable "workload_identity_federation" {
7+
type = object({
8+
issuer = string,
9+
audience = string,
10+
subjects = list(string)
11+
})
12+
default = null
13+
description = "Set these options to add a trusted identity provider from meshStack to allow workload identity federation for authentication which can be used instead of access keys. Supports multiple subjects and wildcard patterns (e.g., 'system:serviceaccount:namespace:*')."
14+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
terraform {
2+
required_version = ">= 1.3.0"
3+
required_providers {
4+
aws = {
5+
source = "hashicorp/aws"
6+
version = "~> 5.0"
7+
}
8+
}
9+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# AWS Route53 DNS Alias Record
2+
3+
## Description
4+
This building block creates Route53 alias records, which are AWS-specific DNS records that can only route traffic to AWS resources (load balancers, CloudFront distributions, S3 websites, etc.).
5+
6+
## When to Use
7+
- Point custom domains to AWS load balancers (ALB/NLB)
8+
- Route traffic to CloudFront distributions
9+
- Create apex/root domain records (e.g., example.com)
10+
11+
## Shared Responsibility
12+
13+
| Responsibility | Platform Team | Application Team |
14+
|----------------|---------------|------------------|
15+
| Managing Route53 hosted zones |||
16+
| Provisioning DNS alias records |||
17+
| Managing record names and target resources |||
18+
19+
## Key Recommendations
20+
- Use descriptive DNS names (e.g., `api.example.com`, `www.example.com`)
21+
- Enable health checks for automatic failover when appropriate
22+
- Coordinate with your platform team before modifying production DNS records
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
name: AWS Route53 DNS Alias Record
3+
description: Provides AWS Route53 DNS alias records
4+
---
5+
6+
# AWS Route53 DNS Alias Record
7+
8+
This Terraform module provisions AWS Route53 DNS alias records.
9+
10+
## Requirements
11+
- Terraform `>= 1.3.0`
12+
- AWS Provider `~> 5.0`
13+
14+
## Providers
15+
16+
```hcl
17+
terraform {
18+
required_providers {
19+
aws = {
20+
source = "hashicorp/aws"
21+
version = "~> 5.0"
22+
}
23+
}
24+
}
25+
26+
provider "aws" {
27+
region = var.region
28+
allowed_account_ids = var.allowed_account_ids # Optional
29+
}
30+
```
31+
32+
<!-- BEGIN_TF_DOCS -->
33+
34+
## Backend configuration
35+
Here you can find an example of how to create a backend.tf file on this [Wiki Page](https://github.com/meshcloud/building-blocks/wiki/%5BUser-Guide%5D-Setting-up-the-Backend-for-terraform-state#how-to-configure-backendtf-file-for-these-providers)
22 KB
Loading
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
data "aws_route53_zone" "zone" {
2+
name = var.zone_name
3+
private_zone = var.private_zone
4+
}
5+
6+
locals {
7+
# meshStack doesn't support empty strings as inputs right now, so we treat @ (which is common to denote apex records
8+
# in zonefiles) as a special value to indicate "empty"
9+
record_name = var.sub == "@" ? "" : var.sub
10+
}
11+
12+
resource "aws_route53_record" "record" {
13+
zone_id = data.aws_route53_zone.zone.zone_id
14+
name = join(".", compact([local.record_name, data.aws_route53_zone.zone.name]))
15+
type = var.type
16+
17+
alias {
18+
name = var.alias_name
19+
evaluate_target_health = var.alias_evaluate_target_health
20+
zone_id = var.alias_zone_id
21+
}
22+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
output "record_name" {
2+
description = "The FQDN of the DNS record"
3+
value = aws_route53_record.record.name
4+
}
5+
6+
output "record_type" {
7+
description = "The type of the DNS record"
8+
value = aws_route53_record.record.type
9+
}
10+
11+
output "alias_target" {
12+
description = "The alias target"
13+
value = var.alias_name
14+
}
15+
16+
output "summary" {
17+
description = "Summary of the created DNS alias record"
18+
value = <<-EOT
19+
# Route53 DNS Alias Record Created
20+
21+
✅ **Your DNS alias record is ready!**
22+
23+
## Record Details
24+
25+
| Property | Value |
26+
|----------|-------|
27+
| **DNS Name** | `${aws_route53_record.record.name}` |
28+
| **Type** | `${var.type}` |
29+
| **Alias Target** | `${var.alias_name}` |
30+
| **Health Check** | ${var.alias_evaluate_target_health ? "✅ Enabled" : "⚠️ Disabled"} |
31+
| **Zone** | `${var.zone_name}` |
32+
33+
---
34+
35+
## Resolution
36+
37+
```
38+
${aws_route53_record.record.name}${var.alias_name}
39+
```
40+
41+
${var.private_zone ? "⚠️ **Note:** This is a private hosted zone record, only resolvable within your VPC." : "🌐 **Note:** This is a public DNS record, resolvable globally."}
42+
EOT
43+
}

0 commit comments

Comments
 (0)