Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a9b8c67
Build alarm to slack function from source code. Manage logs. Update t…
mianava Apr 25, 2026
9e2d3da
Enable source code updates via Tofu. Manage cloudwatch logs. Refine IAM.
mianava Apr 25, 2026
ca1aed8
Manage sqs iam access
mianava Apr 25, 2026
d24e52d
Allow CICD only when source is not provided.
mianava Apr 25, 2026
1711714
Remove unusable permission for an assumed role
mianava Apr 25, 2026
0cdc775
Enable log tag management from github
mianava Apr 25, 2026
3bc9837
Create dummy function if no other configuration is available.
mianava Apr 25, 2026
b85fc09
Use security group rule instead of inline so security gorup rules can…
mianava Apr 27, 2026
9dbe1b6
Ensure security groups can be refined
mianava Apr 27, 2026
b25b0c7
Only force log retention in prod
mianava Apr 27, 2026
72fd839
Add a liveness check
mianava May 5, 2026
ab0a1e4
Set up place for test function
mianava May 5, 2026
6df91f7
AB2D-7227 update to java25 (#460)
keeyanghoreshi-rgb May 4, 2026
cf406cc
Ls/dpc 5387 quicksight lambda updates (#459)
lukey-luke May 4, 2026
1961e95
BCDA-9967: add model short name (#461)
bhagatparwinder May 5, 2026
a7596e8
BCDA-9967: update column order to match existing view (#462)
bhagatparwinder May 5, 2026
89fda66
PLT-1661 Snyk and sonarqube checks on python logic (#453)
mianava May 5, 2026
7ef9737
Remove outdated documentation
mianava May 5, 2026
4d6a342
Add rollback support
mianava May 6, 2026
8badb99
Add lambda function for testing
mianava May 6, 2026
42e7ed7
Add workflow to test lambda function and tear down upon success.
mianava May 6, 2026
e42c677
Merge branch 'main' into PLT-1666/alarmtoslack
mianava May 6, 2026
0bf3a7a
Updating testing for alarm to slack lambda
mianava May 6, 2026
8743178
Configure testable lambda function that's ephemeral.
mianava May 6, 2026
db1bee0
Lookup by id
mianava May 6, 2026
e2beccb
Remove permissions boundary as no longer required
mianava May 6, 2026
ef94db1
Set backend properly for destroy
mianava May 6, 2026
01cc647
Run tests only and wait for other PR for code scannign
mianava May 6, 2026
829c64e
Ensure naming uniqueness
mianava May 6, 2026
a013663
Prevent redundant labeling
mianava May 6, 2026
94ecab2
Remove unused actions
mianava May 6, 2026
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
20 changes: 13 additions & 7 deletions .github/workflows/alarm-to-slack-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@ on:
paths:
- 'terraform/services/alarm-to-slack/lambda_src/**/*.py'
- 'terraform/services/alarm-to-slack/lambda_src/**/requirements.txt'
- 'terraform/modules/function/**'

jobs:
python-checks:
uses: ./.github/workflows/python-checks-reusable.yml
with:
source_path: terraform/services/alarm-to-slack/lambda_src
sonar_project_key: cdap-alarm-to-slack
sonar_project_name: "CDAP Alarm to Slack"
python-tests:
runs-on: codebuild-cdap-${{ github.ref_name == 'main' && 'prod' || 'non-prod' }}-${{ github.run_id }}-${{ github.run_attempt }}
defaults:
run:
working-directory: terraform/services/alarm-to-slack/lambda_src
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.3.0
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install pytest pytest-cov
- name: Run tests
run: pytest test_lambda_function.py -v --cov=lambda_function --cov-report=term-missing
1 change: 0 additions & 1 deletion .github/workflows/set_log_retention_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ on:
paths:
- 'scripts/set_log_retention/*.py'
- 'scripts/set_log_retention/requirements.txt'
- 'terraform/modules/function/**'

jobs:
python-checks:
Expand Down
67 changes: 67 additions & 0 deletions .github/workflows/tftesting-function.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: tftesting-lambda

on:
workflow_dispatch:
pull_request:
paths:
- 'terraform/services/tftesting/function/**'
- 'terraform/modules/function/**'
- '.github/workflows/tftesting-function.yml'
push:
branches:
- main
paths:
- 'terraform/services/tftesting/function/**'
- 'terraform/modules/function/**'
- '.github/workflows/tftesting-function.yml'

concurrency:
group: tftesting-function
cancel-in-progress: true

env:
TENV_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
APP: cdap
ENV: test
TF_DIR: terraform/services/tftesting/function

permissions:
contents: read
id-token: write

jobs:
apply:
name: Tofu Apply
runs-on: codebuild-cdap-non-prod-${{ github.run_id }}-${{ github.run_attempt }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.3.0
- uses: cmsgov/cdap/actions/setup-tenv@f4c14d47cc20e7f6de9112d7155af1213c9bca5a
- uses: aws-actions/configure-aws-credentials@ec61189d14ec14c8efccab744f656cffd0e33f37 # v6.1.0
with:
role-to-assume: arn:aws:iam::${{ secrets.NON_PROD_ACCOUNT }}:role/delegatedadmin/developer/${{ env.APP }}-${{ env.ENV }}-github-actions
aws-region: ${{ vars.AWS_REGION }}
- name: Tofu Init
working-directory: ${{ env.TF_DIR }}
run: tofu init -reconfigure -backend-config="../../../backends/${{ env.APP }}-${{ env.ENV }}.s3.tfbackend"
- name: Tofu Apply
working-directory: ${{ env.TF_DIR }}
run: tofu apply

destroy:
name: Tofu Destroy
if: success()
needs: apply
runs-on: codebuild-cdap-non-prod-${{ github.run_id }}-${{ github.run_attempt }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.3.0
- uses: cmsgov/cdap/actions/setup-tenv@f4c14d47cc20e7f6de9112d7155af1213c9bca5a
- uses: aws-actions/configure-aws-credentials@ec61189d14ec14c8efccab744f656cffd0e33f37 # v6.1.0
with:
role-to-assume: arn:aws:iam::${{ secrets.NON_PROD_ACCOUNT }}:role/delegatedadmin/developer/${{ env.APP }}-${{ env.ENV }}-github-actions
aws-region: ${{ vars.AWS_REGION }}
- name: Tofu Init
working-directory: ${{ env.TF_DIR }}
run: tofu init -reconfigure -backend-config="../../../backends/${{ env.APP }}-${{ env.ENV }}.s3.tfbackend"
- name: Tofu Destroy
working-directory: ${{ env.TF_DIR }}
run: tofu destroy -auto-approve
124 changes: 123 additions & 1 deletion terraform/modules/function/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,126 @@

This is a generic module for creating lambda function resources in CMS Cloud. Use it in terraform services where a lambda function is needed.

Note that a dummy function is included to allow for initialization. It is meant to be replaced once the function has been created.
Note that a dummy function will be made if source_dir with function logic is not yet provided or github_actions_repo is not defined.
The dummy function allows for infrastructure scaffolding before source code is written.
If source code is written and the lifecycle is managed outside of terraform, set github_actions_repo.

<!-- BEGIN_TF_DOCS -->
<!--WARNING: GENERATED CONTENT with terraform-docs, e.g.
'terraform-docs --config "$(git rev-parse --show-toplevel)/.terraform-docs.yml" .'
Manually updating sections between TF_DOCS tags may be overwritten.
See https://terraform-docs.io/user-guide/configuration/ for more information.
-->
## Providers

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

<!--WARNING: GENERATED CONTENT with terraform-docs, e.g.
'terraform-docs --config "$(git rev-parse --show-toplevel)/.terraform-docs.yml" .'
Manually updating sections between TF_DOCS tags may be overwritten.
See https://terraform-docs.io/user-guide/configuration/ for more information.
-->
## Requirements

No requirements.

<!--WARNING: GENERATED CONTENT with terraform-docs, e.g.
'terraform-docs --config "$(git rev-parse --show-toplevel)/.terraform-docs.yml" .'
Manually updating sections between TF_DOCS tags may be overwritten.
See https://terraform-docs.io/user-guide/configuration/ for more information.
-->
## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_app"></a> [app](#input\_app) | The application name (ab2d, bcda, cdap dpc) | `string` | n/a | yes |
| <a name="input_description"></a> [description](#input\_description) | Description of the lambda function | `string` | n/a | yes |
| <a name="input_env"></a> [env](#input\_env) | The application environment (dev, test, sandbox, prod) | `string` | n/a | yes |
| <a name="input_name"></a> [name](#input\_name) | Name of the lambda function | `string` | n/a | yes |
| <a name="input_architecture"></a> [architecture](#input\_architecture) | Lambda function CPU architecture. Use arm64 for Graviton (better price/performance for most workloads). | `string` | `"x86_64"` | no |
| <a name="input_egress_rules"></a> [egress\_rules](#input\_egress\_rules) | List of egress rules to apply to the security group | <pre>list(object({<br/> name = string<br/> from_port = number<br/> to_port = number<br/> protocol = string<br/> cidr_ipv4 = optional(string)<br/> cidr_ipv6 = optional(string)<br/> referenced_sg_id = optional(string)<br/> description = optional(string)<br/> }))</pre> | <pre>[<br/> {<br/> "cidr_ipv4": "0.0.0.0/0",<br/> "description": "Allow all egress traffic (IPv4) - migration default",<br/> "from_port": 0,<br/> "name": "allow-all-ipv4",<br/> "protocol": "-1",<br/> "to_port": 0<br/> },<br/> {<br/> "cidr_ipv6": "::/0",<br/> "description": "Allow all egress traffic (IPv6) - migration default",<br/> "from_port": 0,<br/> "name": "allow-all-ipv6",<br/> "protocol": "-1",<br/> "to_port": 0<br/> }<br/>]</pre> | no |
| <a name="input_environment_variables"></a> [environment\_variables](#input\_environment\_variables) | Map of environment variables for the function | `map(string)` | `{}` | no |
| <a name="input_extra_kms_key_arns"></a> [extra\_kms\_key\_arns](#input\_extra\_kms\_key\_arns) | Optional list of additional KMS key ARNs the Lambda can use | `list(string)` | `[]` | no |
| <a name="input_function_role_inline_policies"></a> [function\_role\_inline\_policies](#input\_function\_role\_inline\_policies) | Inline policies (in JSON) for the function IAM role | `map(string)` | `{}` | no |
| <a name="input_github_actions_repos"></a> [github\_actions\_repos](#input\_github\_actions\_repos) | Used for integration tests and, when source\_dir is null,<br/>for CI/CD workflows that upload the function zip.<br/>Format: "repo:CMSgov/<repo-name>:*" or a more specific ref pattern.<br/>Defaults to empty — no GitHub Actions access unless explicitly granted. | `list(string)` | `[]` | no |
| <a name="input_handler"></a> [handler](#input\_handler) | Lambda function handler | `string` | `"function_handler"` | no |
| <a name="input_layer_arns"></a> [layer\_arns](#input\_layer\_arns) | Optional list of layer arns | `list(string)` | `[]` | no |
| <a name="input_liveness_check_enabled"></a> [liveness\_check\_enabled](#input\_liveness\_check\_enabled) | Enables a deploy-time liveness check that invokes the Lambda function<br/>immediately after deployment to verify it is healthy and correctly configured.<br/><br/>When enabled, an aws\_lambda\_invocation resource is created that sends a<br/>{ "RequestType": "LivenessCheck" } payload to the Lambda function after<br/>each deployment. The invocation is re-triggered whenever the Lambda source<br/>code changes (tracked via source\_code\_hash).<br/><br/>The Lambda function is responsible for implementing the liveness check logic<br/>in its handler. This may include verifying external dependencies, validating<br/>configuration, checking connectivity to downstream services, or any other<br/>health validation relevant to the function's purpose.<br/><br/>If the liveness check fails, the Lambda should raise an exception. This<br/>surfaces as a function error and causes the Tofu apply to fail, alerting<br/>the deploying team immediately.<br/><br/>Recommended: true in all environments to catch misconfiguration at deploy time. | `bool` | `true` | no |
| <a name="input_log_retention_days"></a> [log\_retention\_days](#input\_log\_retention\_days) | Number of days to retain Lambda function logs in CloudWatch. If null, no retention policy is set and retention is managed externally (e.g., via cdap/scripts/set\_log\_retention/). | `number` | `180` | no |
| <a name="input_memory_size"></a> [memory\_size](#input\_memory\_size) | Lambda function memory size | `number` | `null` | no |
| <a name="input_rollback_version"></a> [rollback\_version](#input\_rollback\_version) | Pin the live alias to a specific version for rollback. Set to null for normal deploys (alias tracks latest published version). | `string` | `null` | no |
| <a name="input_runtime"></a> [runtime](#input\_runtime) | Lambda function runtime | `string` | `"python3.11"` | no |
| <a name="input_schedule_expression"></a> [schedule\_expression](#input\_schedule\_expression) | Cron or rate expression for a scheduled function | `string` | `""` | no |
| <a name="input_source_code_version"></a> [source\_code\_version](#input\_source\_code\_version) | Optional S3 object version of function.zip uploaded to module's zip\_bucket by external sources. | `string` | `null` | no |
| <a name="input_source_dir"></a> [source\_dir](#input\_source\_dir) | Path to the Lambda source directory to zip and upload. If set, the module manages zipping and deployment. If null, an external process (or dummy zip) is used. | `string` | `null` | no |
| <a name="input_source_dir_excludes"></a> [source\_dir\_excludes](#input\_source\_dir\_excludes) | List of glob (**/*) patterns to exclude when zipping the source directory. | `list(string)` | `[]` | no |
| <a name="input_ssm_parameter_paths"></a> [ssm\_parameter\_paths](#input\_ssm\_parameter\_paths) | List of SSM parameter ARNs or path patterns this function is permitted to read.<br/>Each entry should be a full ARN or ARN pattern. This can be retrieved from platform.module.ssm.ssm\_root\_name.parameter\_name.arn.<br/>If empty (default), the function receives no SSM access.<br/>Do not use broad wildcards — scope each entry to the specific parameters this function requires. | `list(string)` | `[]` | no |
| <a name="input_timeout"></a> [timeout](#input\_timeout) | Lambda function timeout | `number` | `900` | no |

<!--WARNING: GENERATED CONTENT with terraform-docs, e.g.
'terraform-docs --config "$(git rev-parse --show-toplevel)/.terraform-docs.yml" .'
Manually updating sections between TF_DOCS tags may be overwritten.
See https://terraform-docs.io/user-guide/configuration/ for more information.
-->
## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_subnets"></a> [subnets](#module\_subnets) | ../subnets | n/a |
| <a name="module_vpc"></a> [vpc](#module\_vpc) | ../vpc | n/a |
| <a name="module_zip_bucket"></a> [zip\_bucket](#module\_zip\_bucket) | ../bucket | n/a |

<!--WARNING: GENERATED CONTENT with terraform-docs, e.g.
'terraform-docs --config "$(git rev-parse --show-toplevel)/.terraform-docs.yml" .'
Manually updating sections between TF_DOCS tags may be overwritten.
See https://terraform-docs.io/user-guide/configuration/ for more information.
-->
## Resources

| Name | Type |
|------|------|
| [aws_cloudwatch_event_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_rule) | resource |
| [aws_cloudwatch_event_target.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_event_target) | resource |
| [aws_cloudwatch_log_group.function](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
| [aws_iam_role.function](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy.default_function](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
| [aws_iam_role_policy.extra_policies](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
| [aws_lambda_alias.live](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_alias) | resource |
| [aws_lambda_function.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource |
| [aws_lambda_invocation.liveness_check](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_invocation) | resource |
| [aws_lambda_permission.cloudwatch_events](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |
| [aws_s3_object.empty_function_zip](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_object) | resource |
| [aws_s3_object.function_zip](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_object) | resource |
| [aws_security_group.function](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
| [aws_vpc_security_group_egress_rule.ipv4](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_egress_rule) | resource |
| [aws_vpc_security_group_egress_rule.ipv6](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_egress_rule) | resource |
| [aws_vpc_security_group_egress_rule.sg_source](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_egress_rule) | resource |
| [archive_file.function](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_iam_openid_connect_provider.github](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_openid_connect_provider) | data source |
| [aws_iam_policy_document.cicd_manage_lambda_objects](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.default_function](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.function_assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_role.admin](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_role) | data source |
| [aws_iam_role.dasg_admin](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_role) | data source |
| [aws_kms_alias.kms_key](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/kms_alias) | data source |

<!--WARNING: GENERATED CONTENT with terraform-docs, e.g.
'terraform-docs --config "$(git rev-parse --show-toplevel)/.terraform-docs.yml" .'
Manually updating sections between TF_DOCS tags may be overwritten.
See https://terraform-docs.io/user-guide/configuration/ for more information.
-->
## Outputs

| Name | Description |
|------|-------------|
| <a name="output_alias_arn"></a> [alias\_arn](#output\_alias\_arn) | ARN of the live alias |
| <a name="output_function_version"></a> [function\_version](#output\_function\_version) | Published version number of the Lambda function |
| <a name="output_name"></a> [name](#output\_name) | Name for the lambda function |
| <a name="output_role_arn"></a> [role\_arn](#output\_role\_arn) | ARN of the IAM role for the function |
| <a name="output_security_group_id"></a> [security\_group\_id](#output\_security\_group\_id) | ID for the security group for the function |
| <a name="output_zip_bucket"></a> [zip\_bucket](#output\_zip\_bucket) | Bucket name for the function.zip file |
<!-- END_TF_DOCS -->
Loading
Loading