Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,13 @@ terraform.rc
*.log

# Ignore any IDE files
.vscode/
.idea/
*.swp
*.swo

# Ignore any OS generated files
.DS_Store
Thumbs.db

# Ignore Lambda deployment packages
lambda_function.zip
3 changes: 3 additions & 0 deletions .vscode/cspell.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"words": []
}
19 changes: 19 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"recommendations": [
"davidanson.vscode-markdownlint",
"eamodio.gitlens",
"esbenp.prettier-vscode",
"foxundermoon.shell-format",
"Gruntfuggly.todo-tree",
"hashicorp.terraform",
"mhutchie.git-graph",
"ms-python.autopep8",
"ms-python.debugpy",
"ms-python.python",
"ms-python.black-formatter",
"ms-python.flake8",
"streetsidesoftware.code-spell-checker",
"usernamehw.errorlens",
"vscode-icons-team.vscode-icons"
]
}
208 changes: 208 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
{
"files.associations": {
"*.dockerfile": "dockerfile",
"*.sh.tpl": "shellscript",
"docker-compose*.yml": "yaml",
"Dockerfile*": "dockerfile",
"*.py.tpl": "python",
"*.yaml.tpl": "yaml",
"*.yml.tpl": "yaml",
"*.tf": "terraform",
"*.tfvars": "terraform"
},
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"__debug_bin": true,
"vendor/": true,
"go.sum": true,
"**/__pycache__": true,
"**/*.pyc": true,
"**/.pytest_cache": true,
"**/.mypy_cache": true,
"**/node_modules": true,
"**/.terraform": true,
"**/.terragrunt-cache": true,
"**/Thumbs.db": true,
"**/.ruff_cache": true,
"**/.coverage": true,
"**/htmlcov": true,
"**/*.tfstate": true,
"**/*.tfstate.*": true
},
"files.trimTrailingWhitespace": true,
"files.trimFinalNewlines": true,
"files.insertFinalNewline": true,
"files.eol": "\n",
"remote.extensionKind": {
"ms-azuretools.vscode-docker": "ui",
"ms-vscode-remote.remote-containers": "ui"
},
"editor.formatOnSave": true,
"editor.formatOnPaste": true,
"editor.rulers": [79],
"editor.wordWrap": "wordWrapColumn",
"editor.wordWrapColumn": 79,
"editor.tabSize": 4,
"editor.insertSpaces": true,
"editor.detectIndentation": false,
"editor.trimAutoWhitespace": true,
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "explicit",
"source.fixAll.ruff": "explicit"
},
"prettier.requireConfig": true,
"workbench.iconTheme": "vscode-icons",
"workbench.colorTheme": "Visual Studio Dark",
"[css]": {
"editor.defaultFormatter": "vscode.css-language-features",
"editor.foldingStrategy": "indentation"
},
"[dockerfile]": {
"editor.defaultFormatter": "ms-azuretools.vscode-docker"
},
"[html]": {
"editor.defaultFormatter": "vscode.html-language-features"
},
"[json]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[jsonc]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[shellscript]": {
"editor.defaultFormatter": "foxundermoon.shell-format"
},
"[terraform]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "hashicorp.terraform",
"editor.insertSpaces": true,
"editor.tabSize": 2
},
"[yaml]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.insertSpaces": true,
"editor.tabSize": 2
},
"[yml]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.insertSpaces": true,
"editor.tabSize": 2
},
"[python]": {
"editor.formatOnSave": true,
"editor.formatOnPaste": true,
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "explicit",
"source.fixAll.ruff": "explicit"
},
"editor.rulers": [79],
"editor.wordWrapColumn": 79,
"editor.tabSize": 4,
"editor.insertSpaces": true
},
"python.formatting.provider": "none",
"python.formatting.blackArgs": [
"--line-length=79",
"--target-version=py39",
"--skip-string-normalization",
"--config=lambdas/pyproject.toml"
],
"python.linting.enabled": true,
"python.linting.lintOnSave": true,
"python.linting.flake8Enabled": true,
"python.linting.flake8Args": [
"--max-line-length=79",
"--extend-ignore=E203,W503,E501",
"--max-complexity=10"
],
"ruff.enable": true,
"ruff.fixAll": true,
"ruff.organizeImports": true,
"ruff.lint.enable": true,
"ruff.format.enable": true,
"ruff.codeAction.fixViolation": {
"enable": true
},
"ruff.codeAction.disableRuleComment": {
"enable": true
},
"python.linting.mypyEnabled": true,
"python.linting.mypyArgs": [
"--config-file=lambdas/pyproject.toml"
],
"python.linting.pylintEnabled": false,
"isort.args": [
"--settings-path=lambdas/pyproject.toml"
],
"isort.check": true,
"python.analysis.typeCheckingMode": "off",
"python.analysis.autoImportCompletions": true,
"python.analysis.autoSearchPaths": true,
"python.analysis.diagnosticMode": "workspace",
"python.analysis.completeFunctionParens": true,
"python.analysis.autoFormatStrings": true,
"python.testing.pytestEnabled": true,
"python.testing.unittestEnabled": false,
"python.testing.pytestArgs": [
"lambdas"
],
"python.testing.autoTestDiscoverOnSaveEnabled": true,
"python.defaultInterpreterPath": "/usr/local/bin/python",
"python.terminal.activateEnvironment": false,
"autoDocstring.docstringFormat": "google",
"autoDocstring.startOnNewLine": false,
"autoDocstring.includeExtendedSummary": true,
"git.autofetch": true,
"git.confirmSync": false,
"git.enableSmartCommit": true,
"terminal.integrated.defaultProfile.linux": "bash",
"terminal.integrated.copyOnSelection": true,
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true,
"**/*.code-search": true,
"**/__pycache__": true,
"**/.pytest_cache": true,
"**/.mypy_cache": true,
"**/.ruff_cache": true
},
"markdown.extension.toc.levels": "2..6",
"markdown.extension.print.absoluteImgPath": false,
"yaml.format.enable": true,
"yaml.format.singleQuote": false,
"yaml.format.bracketSpacing": true,
"python.analysis.indexing": true,
"python.analysis.packageIndexDepths": [
{
"name": "boto3",
"depth": 2
},
{
"name": "botocore",
"depth": 2
}
],
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/node_modules/*/**": true,
"**/__pycache__/**": true,
"**/.pytest_cache/**": true,
"**/.mypy_cache/**": true,
"**/.terraform/**": true,
"**/.terragrunt-cache/**": true
},
"terraform.format.enable": true,
"terraform.lint.enable": true
}
72 changes: 71 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# terraform-aws-cloudmap

Terraform module to manage Amazon Cloud Map namespaces and services for DNS-based discovery.
Terraform module to manage Amazon Cloud Map namespaces and services for DNS-based discovery, including support for Lambda Function URL registration.

<!-- BEGIN_TF_DOCS -->
## Requirements
Expand All @@ -27,6 +27,7 @@ No modules.
| [aws_iam_role.ecs_service_discovery](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy.ecs_service_discovery](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
| [aws_service_discovery_http_namespace.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/service_discovery_http_namespace) | resource |
| [aws_service_discovery_instance.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/service_discovery_instance) | resource |
| [aws_service_discovery_private_dns_namespace.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/service_discovery_private_dns_namespace) | resource |
| [aws_service_discovery_public_dns_namespace.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/service_discovery_public_dns_namespace) | resource |
| [aws_service_discovery_service.services](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/service_discovery_service) | resource |
Expand All @@ -44,6 +45,11 @@ No modules.
| <a name="input_enable_dns_config"></a> [enable\_dns\_config](#input\_enable\_dns\_config) | Enable DNS configuration for the service. Set to false for HTTP namespaces or when using existing HTTP namespaces. | `bool` | `true` | no |
| <a name="input_enable_health_checks"></a> [enable\_health\_checks](#input\_enable\_health\_checks) | Enable health checks for the service. Set to false when using private IPs or unsupported instance types. | `bool` | `true` | no |
| <a name="input_existing_namespace_id"></a> [existing\_namespace\_id](#input\_existing\_namespace\_id) | ID of an existing namespace to use | `string` | `null` | no |
| <a name="input_lambda_attributes"></a> [lambda\_attributes](#input\_lambda\_attributes) | Additional attributes for the Lambda instance in CloudMap | `map(string)` | `{}` | no |
| <a name="input_lambda_instance_id"></a> [lambda\_instance\_id](#input\_lambda\_instance\_id) | Unique identifier for the Lambda instance in CloudMap | `string` | `"lambda-function"` | no |
| <a name="input_lambda_service_name"></a> [lambda\_service\_name](#input\_lambda\_service\_name) | Name of the CloudMap service for Lambda registration. If not specified, uses the first service name from var.services | `string` | `null` | no |
| <a name="input_lambda_url"></a> [lambda\_url](#input\_lambda\_url) | Lambda Function URL or API Gateway endpoint to register in CloudMap | `string` | `null` | no |
| <a name="input_enable_lambda_registration"></a> [enable\_lambda\_registration](#input\_enable\_lambda\_registration) | Enable registration of Lambda Function URL in CloudMap service discovery | `bool` | `false` | no |
| <a name="input_namespace_description"></a> [namespace\_description](#input\_namespace\_description) | Description of the CloudMap namespace | `string` | `null` | no |
| <a name="input_namespace_name"></a> [namespace\_name](#input\_namespace\_name) | Name of the CloudMap namespace | `string` | `null` | no |
| <a name="input_routing_policy"></a> [routing\_policy](#input\_routing\_policy) | Routing policy for the service | `string` | `"MULTIVALUE"` | no |
Expand All @@ -58,9 +64,73 @@ No modules.
| <a name="output_ecs_service_discovery_role_arn"></a> [ecs\_service\_discovery\_role\_arn](#output\_ecs\_service\_discovery\_role\_arn) | ARN of the ECS service discovery IAM role |
| <a name="output_ecs_service_discovery_role_name"></a> [ecs\_service\_discovery\_role\_name](#output\_ecs\_service\_discovery\_role\_name) | Name of the ECS service discovery IAM role |
| <a name="output_health_check_debug"></a> [health\_check\_debug](#output\_health\_check\_debug) | Debug information for health check configuration - use for troubleshooting |
| <a name="output_lambda_discovery_url"></a> [lambda\_discovery\_url](#output\_lambda\_discovery\_url) | CloudMap discovery URL for the Lambda function |
| <a name="output_lambda_instance_id"></a> [lambda\_instance\_id](#output\_lambda\_instance\_id) | ID of the registered Lambda instance in CloudMap |
| <a name="output_lambda_registration_debug"></a> [lambda\_registration\_debug](#output\_lambda\_registration\_debug) | Debug information for Lambda registration - use for troubleshooting |
| <a name="output_lambda_service_id"></a> [lambda\_service\_id](#output\_lambda\_service\_id) | ID of the CloudMap service where Lambda is registered |
| <a name="output_namespace_arn"></a> [namespace\_arn](#output\_namespace\_arn) | ARN of the created namespace |
| <a name="output_namespace_id"></a> [namespace\_id](#output\_namespace\_id) | ID of the created namespace |
| <a name="output_namespace_name"></a> [namespace\_name](#output\_namespace\_name) | Name of the created namespace |
| <a name="output_service_arns"></a> [service\_arns](#output\_service\_arns) | Map of service names to their ARNs for ECS integration |
| <a name="output_services"></a> [services](#output\_services) | Map of created services with their details |
<!-- END_TF_DOCS -->

## Features

- **Multiple Namespace Types**: Support for HTTP, Private DNS, and Public DNS namespaces
- **Service Discovery**: Create and manage CloudMap services with configurable DNS settings
- **Health Checks**: Configurable health checks for services (standard and custom)
- **Lambda Function URL Support**: Register Lambda Function URLs in CloudMap for service discovery
- **ECS Integration**: IAM roles for ECS service discovery
- **Flexible Configuration**: Support for existing namespaces and custom attributes

## Lambda Function URL Registration

This module supports registering Lambda Function URLs in CloudMap for service discovery within VPCs. This allows services to resolve Lambda functions by DNS without hardcoding URLs.

### Example Usage

```hcl
module "cloudmap" {
source = "path/to/module"

# Create private DNS namespace
create_private_dns_namespace = true
namespace_name = "api.internal"
vpc_id = data.aws_vpc.default.id

# Define service with CNAME record type
services = {
"api-service" = {
name = "api-service"
dns_record_type = "CNAME" # Required for Lambda Function URL
routing_policy = "WEIGHTED"
health_check_custom_config = true
}
}

# Enable Lambda registration
enable_lambda_registration = true
lambda_instance_id = "api-lambda-01"
lambda_url = aws_lambda_function_url.api.function_url
lambda_service_name = "api-service"
lambda_attributes = {
"environment" = "production"
"version" = "v1.0.0"
"function_name" = aws_lambda_function.api.function_name
}
}
```

### Benefits

- **Consistent DNS Resolution**: Services can resolve Lambda functions using standard DNS
- **VPC Integration**: Lambda functions appear as local services within VPC
- **Health Monitoring**: CloudMap can monitor Lambda function health
- **Automatic Failover**: Support for multiple Lambda instances with load balancing

## Examples

- [Basic HTTP Namespace](examples/basic-http-namespace/): Simple HTTP namespace with EC2 instance
- [Custom Registry](examples/custom-registry/): Mixed service types with Lambda integration
- [Lambda Function URL](examples/lambda/): Complete Lambda Function URL registration example
Loading