Skip to content
Open
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
64 changes: 63 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ The following inputs can be used as `step.with` keys
| `tf_state_file_name_append` | String | Appends a string to the tf-state-file. Setting this to `unique` will generate `tf-state-aws-unique`. (Can co-exist with `tf_state_file_name`) |
| `tf_state_bucket` | String | AWS S3 bucket name to use for Terraform state. See [note](#s3-buckets-naming) |
| `tf_state_bucket_destroy` | Boolean | Force purge and deletion of S3 bucket defined. Only evaluated when `tf_stack_destroy` is also `true`, so it is safe to leave this enabled when standing up your stack. Defaults to `false`. |
| `tf_state_bucket_prevent_destroy` | Boolean | Prevent Terraform from destroying the S3 state bucket. Set to `true` to enable lifecycle prevent_destroy. Defaults to `true`. |
| `tf_targets` | List | A list of targets to create before the full stack creation. |
| `ansible_skip` | Boolean | Skip Ansible execution after Terraform excecution. Default is `false`.|
| `ansible_ssh_to_private_ip` | Boolean | Make Ansible connect to the private IP of the instance. Only usefull if using a hosted runner in the same network. Default is `false`. |
Expand Down Expand Up @@ -243,6 +244,7 @@ The following inputs can be used as `step.with` keys
| `aws_ec2_user_data_file` | String | Relative path in the repo for a user provided script to be executed with Terraform EC2 Instance creation. See [this note](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html#user-data-shell-scripts). Make sure the add the executable flag to the file. |
| `aws_ec2_user_data_replace_on_change`| Boolean | If `aws_ec2_user_data_file` file changes, instance will stop and start. Hence public IP will change. This will destroy and recreate the instance. Defaults to `true`. |
| `aws_ec2_additional_tags` | JSON | Add additional tags to the terraform [default tags](https://www.hashicorp.com/blog/default-tags-in-the-terraform-aws-provider), any tags put here will be added to ec2 provisioned resources.|
| `aws_ec2_prevent_destroy` | Boolean | Prevent Terraform from destroying the EC2 instance. Set to `true` to enable lifecycle prevent_destroy. Defaults to `true`. |
<hr/>
<br/>

Expand All @@ -261,6 +263,7 @@ The following inputs can be used as `step.with` keys
| `aws_vpc_single_nat_gateway` | Boolean | Toggles only one NAT gateway for all of the public subnets. Defaults to `false`. |
| `aws_vpc_external_nat_ip_ids` | String | **Existing** comma separated list of IP IDs if reusing. (ElasticIPs). |
| `aws_vpc_additional_tags` | JSON | Add additional tags to the terraform [default tags](https://www.hashicorp.com/blog/default-tags-in-the-terraform-aws-provider), any tags put here will be added to vpc provisioned resources.|
| `aws_vpc_prevent_destroy` | Boolean | Prevent Terraform from destroying the VPC. Set to `true` to enable lifecycle prevent_destroy. Defaults to `true`. |
<hr/>
<br/>

Expand All @@ -276,6 +279,7 @@ The following inputs can be used as `step.with` keys
| `aws_r53_create_root_cert` | Boolean | Generates and manage the root cert for the application. **See note**. Default is `false`. |
| `aws_r53_create_sub_cert` | Boolean | Generates and manage the sub-domain certificate for the application. **See note**. Default is `false`. |
| `aws_r53_additional_tags` | JSON | Add additional tags to the terraform [default tags](https://www.hashicorp.com/blog/default-tags-in-the-terraform-aws-provider), any tags put here will be added to R53 provisioned resources.|
| `aws_r53_cert_prevent_destroy` | Boolean | Prevent Terraform from destroying Route53 certificates. Set to `true` to enable lifecycle prevent_destroy. Defaults to `true`. |
<hr/>
<br/>

Expand All @@ -292,6 +296,7 @@ The following inputs can be used as `step.with` keys
| `aws_elb_access_log_bucket_name` | String | S3 bucket name to store the ELB access logs. Defaults to `${aws_resource_identifier}-logs` (or `-lg `depending of length). **Bucket will be deleted if stack is destroyed.** |
| `aws_elb_access_log_expire` | String | Delete the access logs after this amount of days. Defaults to `90`. Set to `0` in order to disable this policy. |
| `aws_elb_additional_tags` | JSON | Add additional tags to the terraform [default tags](https://www.hashicorp.com/blog/default-tags-in-the-terraform-aws-provider), any tags put here will be added to elb provisioned resources.|
| `aws_elb_prevent_destroy` | Boolean | Prevent Terraform from destroying the load balancer. Set to `true` to enable lifecycle prevent_destroy. Defaults to `true`. |
<hr/>
<br/>

Expand Down Expand Up @@ -334,6 +339,7 @@ The following inputs can be used as `step.with` keys
| `aws_efs_mount_target` | String | Directory path in efs to mount directory to. Default is `/`. |
| `aws_efs_ec2_mount_point` | String | The `aws_efs_ec2_mount_point` input represents the folder path within the EC2 instance to the data directory. Default is `/user/ubuntu/<application_repo>/data`. Additionally, this value is loaded into the docker-compose `.env` file as `HOST_DIR`. |
| `aws_efs_additional_tags` | JSON | Add additional tags to the terraform [default tags](https://www.hashicorp.com/blog/default-tags-in-the-terraform-aws-provider), any tags put here will be added to efs provisioned resources.|
| `aws_efs_prevent_destroy` | Boolean | Prevent Terraform from destroying the EFS file system. Set to `true` to enable lifecycle prevent_destroy. Defaults to `true`. |
<hr/>
<br/>

Expand Down Expand Up @@ -365,8 +371,9 @@ The following inputs can be used as `step.with` keys
| `aws_rds_db_cloudwatch_logs_exports`| String | Set of log types to enable for exporting to CloudWatch logs. Defaults to `postgresql`. Options are MySQL and MariaDB: `audit,error,general,slowquery`. PostgreSQL: `postgresql,upgrade`. MSSQL: `agent,error`. Oracle: `alert,audit,listener,trace`. |
| `aws_rds_db_multi_az` | Boolean| Specifies if the RDS instance is multi-AZ. Defaults to `false`. |
| `aws_rds_db_maintenance_window` | String | The window to perform maintenance in. Eg: `Mon:00:00-Mon:03:00` |
| `aws_rds_db_apply_immediately` | Boolean | Specifies whether any database modifications are applied immediately, or during the next maintenance window. Defaults to `false`.|
| `aws_rds_db_apply_immediately` | Boolean | Specifies whether any database modifications are applied immediately, or during the next maintenance window. Defaults to `false`.|
| `aws_rds_db_additional_tags` | JSON | Add additional tags to the terraform [default tags](https://www.hashicorp.com/blog/default-tags-in-the-terraform-aws-provider), any tags put here will be added to RDS provisioned resources.|
| `aws_rds_db_prevent_destroy` | Boolean | Prevent Terraform from destroying the RDS database. Set to `true` to enable lifecycle prevent_destroy. Defaults to `true`. **Important: This protects your database from accidental deletion.** |
<hr/>
<br/>

Expand Down Expand Up @@ -463,6 +470,61 @@ Option 2, you have access to the `aws_efs_fs_id` attributes, which will mount an

If you set `aws_efs_create_mount_target` and `aws_efs_create_ha`, mount targets will be created for all of the availability zones of the region.

## Protecting Resources with Prevent Destroy

To protect critical infrastructure from accidental deletion, the `prevent_destroy` lifecycle flag is **enabled by default** on various AWS resources. When enabled, Terraform will refuse to destroy the resource, providing an extra layer of safety for your production infrastructure.

### Available Prevent Destroy Flags

The following resources have `prevent_destroy` enabled by default (all default to `true`):

- **`tf_state_bucket_prevent_destroy`** - Protects the S3 bucket containing Terraform state
- **`aws_ec2_prevent_destroy`** - Protects the EC2 instance
- **`aws_vpc_prevent_destroy`** - Protects the VPC infrastructure
- **`aws_r53_cert_prevent_destroy`** - Protects Route53 certificates
- **`aws_elb_prevent_destroy`** - Protects the Elastic Load Balancer
- **`aws_efs_prevent_destroy`** - Protects the EFS file system
- **`aws_rds_db_prevent_destroy`** - Protects the RDS database

### Example Usage - Disabling Protection

Since protection is enabled by default, you typically only need to explicitly set these flags if you want to **disable** protection:

```yaml
name: Deploy without resource protection
on:
push:
branches: [ develop ]

jobs:
EC2-Deploy:
runs-on: ubuntu-latest
steps:
- id: deploy
uses: bitovi/[email protected]
with:
aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws_default_region: us-east-1

# Disable protection for development environment
aws_ec2_prevent_destroy: false
aws_vpc_prevent_destroy: false

# Keep database protected even in dev
aws_rds_db_enable: true
aws_rds_db_prevent_destroy: true # Explicitly keep enabled
```

### Important Notes

- **All resources are protected by default** with `prevent_destroy` set to `true`
- This provides a safety net against accidental infrastructure deletion
- When `prevent_destroy` is enabled, you must manually disable it before destroying the stack
- To destroy a protected resource: set the flag to `false`, apply the changes, then run the destroy operation
- For production environments, it's recommended to keep these protections enabled
- The Terraform state bucket protection is independent of `tf_state_bucket_destroy`

## Adding external RDS Database

If `aws_rds_db_enable` is set to `true`, this action will deploy a Postgres RDS database.
Expand Down
35 changes: 35 additions & 0 deletions action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ inputs:
tf_state_bucket_destroy:
description: 'Force purge and deletion of S3 bucket defined. Only evaluated when `tf_stack_destroy` is also true, so it is safe to leave this enabled when standing up your stack.'
required: false
tf_state_bucket_prevent_destroy:
description: 'Prevent Terraform from destroying the S3 state bucket. Set to true to enable lifecycle prevent_destroy.'
required: false
default: true
tf_targets: # targets
description: 'A list of targets to create before the full stack creation.'
required: false
Expand Down Expand Up @@ -129,6 +133,10 @@ inputs:
aws_ec2_additional_tags:
description: 'A JSON object of additional tags that will be included on created resources. Example: `{"key1": "value1", "key2": "value2"}`'
required: false
aws_ec2_prevent_destroy:
description: 'Prevent Terraform from destroying the EC2 instance. Set to true to enable lifecycle prevent_destroy.'
required: false
default: true

# AWS VPC Inputs
aws_vpc_create:
Expand Down Expand Up @@ -167,6 +175,10 @@ inputs:
aws_vpc_additional_tags:
description: 'A JSON object of additional tags that will be included on created resources. Example: `{"key1": "value1", "key2": "value2"}`'
required: false
aws_vpc_prevent_destroy:
description: 'Prevent Terraform from destroying the VPC. Set to true to enable lifecycle prevent_destroy.'
required: false
default: true

# AWS Route53 Domains abd Certificates
aws_r53_enable:
Expand Down Expand Up @@ -196,6 +208,10 @@ inputs:
aws_r53_additional_tags:
description: 'A JSON object of additional tags that will be included on created resources. Example: `{"key1": "value1", "key2": "value2"}`'
required: false
aws_r53_cert_prevent_destroy:
description: 'Prevent Terraform from destroying Route53 certificates. Set to true to enable lifecycle prevent_destroy.'
required: false
default: true

# AWS ELB
aws_elb_create:
Expand Down Expand Up @@ -230,6 +246,10 @@ inputs:
aws_elb_additional_tags:
description: 'A JSON object of additional tags that will be included on created resources. Example: `{"key1": "value1", "key2": "value2"}`'
required: false
aws_elb_prevent_destroy:
description: 'Prevent Terraform from destroying the load balancer. Set to true to enable lifecycle prevent_destroy.'
required: false
default: true

# Docker
docker_install:
Expand Down Expand Up @@ -322,6 +342,10 @@ inputs:
aws_efs_additional_tags:
description: 'A list of strings that will be added to created resources'
required: false
aws_efs_prevent_destroy:
description: 'Prevent Terraform from destroying the EFS file system. Set to true to enable lifecycle prevent_destroy.'
required: false
default: true

# AWS RDS
aws_rds_db_enable: # aws_enable_postgres
Expand Down Expand Up @@ -405,6 +429,10 @@ inputs:
aws_rds_db_additional_tags:
description: 'A JSON object of additional tags that will be included on created resources. Example: `{"key1": "value1", "key2": "value2"}`'
required: false
aws_rds_db_prevent_destroy:
description: 'Prevent Terraform from destroying the RDS database. Set to true to enable lifecycle prevent_destroy.'
required: false
default: true

# RDS Proxy
aws_db_proxy_name:
Expand Down Expand Up @@ -629,6 +657,7 @@ runs:
tf_state_file_name_append: ${{ inputs.tf_state_file_name_append }}
tf_state_bucket: ${{ inputs.tf_state_bucket }}
tf_state_bucket_destroy: ${{ inputs.tf_state_bucket_destroy }}
tf_state_bucket_prevent_destroy: ${{ inputs.tf_state_bucket_prevent_destroy }}
tf_targets: ${{ inputs.tf_targets || inputs.targets }}
ansible_skip: ${{ inputs.ansible_skip }}
ansible_ssh_to_private_ip: ${{ inputs.ansible_ssh_to_private_ip }}
Expand Down Expand Up @@ -657,6 +686,7 @@ runs:
aws_ec2_user_data_file: ${{ inputs.aws_ec2_user_data_file }}
aws_ec2_user_data_replace_on_change: ${{ inputs.aws_ec2_user_data_replace_on_change }}
aws_ec2_additional_tags: ${{ inputs.aws_ec2_additional_tags }}
aws_ec2_prevent_destroy: ${{ inputs.aws_ec2_prevent_destroy }}

## AWS VPC
aws_vpc_create: ${{ inputs.aws_vpc_create }}
Expand All @@ -671,6 +701,7 @@ runs:
aws_vpc_single_nat_gateway: ${{ inputs.aws_vpc_single_nat_gateway }}
aws_vpc_external_nat_ip_ids: ${{ inputs.aws_vpc_external_nat_ip_ids }}
aws_vpc_additional_tags: ${{ inputs.aws_vpc_additional_tags }}
aws_vpc_prevent_destroy: ${{ inputs.aws_vpc_prevent_destroy }}

# AWS Route53 Domains abd Certificates
aws_r53_enable: ${{ inputs.aws_r53_enable }}
Expand All @@ -682,6 +713,7 @@ runs:
aws_r53_create_root_cert: ${{ inputs.aws_r53_create_root_cert || inputs.create_root_cert }}
aws_r53_create_sub_cert: ${{ inputs.aws_r53_create_sub_cert || inputs.create_sub_cert }}
aws_r53_additional_tags: ${{ inputs.aws_r53_additional_tags }}
aws_r53_cert_prevent_destroy: ${{ inputs.aws_r53_cert_prevent_destroy }}

# AWS ELB
aws_elb_create: ${{ inputs.aws_elb_create }}
Expand All @@ -694,6 +726,7 @@ runs:
aws_elb_access_log_bucket_name: ${{ inputs.aws_elb_access_log_bucket_name }}
aws_elb_access_log_expire: ${{ inputs.aws_elb_access_log_expire }}
aws_elb_additional_tags: ${{ inputs.aws_elb_additional_tags }}
aws_elb_prevent_destroy: ${{ inputs.aws_elb_prevent_destroy }}

# Docker
docker_install: ${{ inputs.docker_install }}
Expand Down Expand Up @@ -725,6 +758,7 @@ runs:
aws_efs_enable_backup_policy: ${{ inputs.aws_efs_enable_backup_policy || inputs.aws_enable_efs_backup_policy }}
aws_efs_transition_to_inactive: ${{ inputs.aws_efs_transition_to_inactive }}
aws_efs_additional_tags: ${{ inputs.aws_efs_additional_tags }}
aws_efs_prevent_destroy: ${{ inputs.aws_efs_prevent_destroy }}

# AWS RDS
aws_rds_db_enable: ${{ inputs.aws_rds_db_enable || inputs.aws_enable_postgres }}
Expand Down Expand Up @@ -754,6 +788,7 @@ runs:
aws_rds_db_maintenance_window: ${{ inputs.aws_rds_db_maintenance_window }}
aws_rds_db_apply_immediately: ${{ inputs.aws_rds_db_apply_immediately }}
aws_rds_db_additional_tags: ${{ inputs.aws_rds_db_additional_tags }}
aws_rds_db_prevent_destroy: ${{ inputs.aws_rds_db_prevent_destroy }}

# DB Proxy
aws_db_proxy_name : ${{ inputs.aws_db_proxy_name }}
Expand Down