diff --git a/.github/workflows/checkov.yml b/.github/workflows/checkov.yml index e80cc14..33fc0b5 100644 --- a/.github/workflows/checkov.yml +++ b/.github/workflows/checkov.yml @@ -15,7 +15,12 @@ jobs: python-version: 3.9 - name: Scan with Checkov id: checkov - uses: bridgecrewio/checkov-action@master + uses: bridgecrewio/checkov-action@v12 with: directory: . framework: terraform + quiet: true + download_external_modules: false + output_format: cli,sarif + output_file_path: console,results.sarif + skip_path: examples diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7bdf7f8..7e7348e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,16 +26,21 @@ jobs: python-version: 3.9 - name: Scan with Checkov id: checkov - uses: bridgecrewio/checkov-action@master + uses: bridgecrewio/checkov-action@v12 with: directory: . framework: terraform + quiet: true + download_external_modules: false + output_format: cli,sarif + output_file_path: console,results.sarif + skip_path: examples release: runs-on: ubuntu-latest needs: [test, checkov] steps: - uses: actions/checkout@v3 - - uses: "marvinpinto/action-automatic-releases@v1.1.2" + - uses: "marvinpinto/action-automatic-releases@919008cf3f741b179569b7a6fb4d8860689ab7f0" # v1.2.1 with: repo_token: "${{ secrets.GITHUB_TOKEN }}" prerelease: false diff --git a/.gitignore b/.gitignore index 724db31..3c40055 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # Local .terraform directories -.terraform* +**/.terraform/* # .tfstate files *.tfstate @@ -7,12 +7,14 @@ # Crash log files crash.log +crash.*.log -# Ignore any .tfvars files that are generated automatically for each Terraform run. Most -# .tfvars files are managed as part of configuration and so should be included in -# version control. -# +# Exclude all .tfvars files, which are likely to contain sensitive data, such as +# password, private keys, and other secrets. These should not be part of version +# control as they are data points which are potentially sensitive and subject +# to change depending on the environment. *.tfvars +*.tfvars.json # Ignore override files as they are usually used to override resources locally and so # are not checked in @@ -22,12 +24,14 @@ override.tf.json *_override.tf.json # Include override files you do wish to add to version control using negated pattern -# # !example_override.tf # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan # example: *tfplan* -provider.tf -header.tf -*.sh +# Ignore CLI configuration files +.terraformrc +terraform.rc + +# Lock file +*.lock.hcl diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..41361c5 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,35 @@ +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-json + - id: check-symlinks + - id: detect-private-key + - id: no-commit-to-branch +- repo: https://github.com/gitleaks/gitleaks + rev: v8.16.1 + hooks: + - id: gitleaks +- repo: https://github.com/antonbabenko/pre-commit-terraform + rev: v1.81.0 + hooks: + - id: terraform_fmt + - id: terraform_validate + exclude: examples/ + - id: terraform_tflint + exclude: examples/ + args: + - --args=--config=__GIT_WORKING_DIR__/.tflint.hcl --fix +- repo: https://github.com/bridgecrewio/checkov.git + rev: "2.3.314" + hooks: + - id: checkov + args: ["--quiet", "--compact", "--framework", "terraform", "--download-external-modules", "false", "--skip-path", "examples"] +- repo: https://github.com/terraform-docs/terraform-docs + rev: v0.16.0 + hooks: + - id: terraform-docs-go + args: ["."] diff --git a/.terraform-docs.yml b/.terraform-docs.yml new file mode 100644 index 0000000..66b41fb --- /dev/null +++ b/.terraform-docs.yml @@ -0,0 +1,63 @@ +formatter: "markdown table" # this is required + +header-from: .tf-header.md +footer-from: .tf-footer.md + +recursive: + enabled: false + path: modules + +sections: + hide: + - resources + - data-sources + - modules + - providers + +content: |- + {{ .Header }} + + # Usage Instructions + ## Example + ```hcl + {{ include "examples/default.tf" }} + ``` + + {{ .Requirements }} + + {{ .Inputs }} + + {{ .Outputs }} + + {{ .Footer }} + +output: + file: README.md + mode: inject + template: |- + + {{ .Content }} + + +output-values: + enabled: false + from: "" + +sort: + enabled: true + by: name + +settings: + anchor: false + color: true + default: true + description: false + escape: false + hide-empty: false + html: false + indent: 2 + lockfile: false # because .terraform.lock.hcl is not checked in the repository + read-comments: true + required: true + sensitive: false + type: true diff --git a/.tf-footer.md b/.tf-footer.md new file mode 100644 index 0000000..e69de29 diff --git a/.tf-header.md b/.tf-header.md new file mode 100644 index 0000000..a9cf48e --- /dev/null +++ b/.tf-header.md @@ -0,0 +1,14 @@ +# Create a managed public or internal facing SFTP server using AWS Transfer service + +![License](https://img.shields.io/github/license/terrablocks/aws-sftp-server?style=for-the-badge) ![Tests](https://img.shields.io/github/actions/workflow/status/terrablocks/aws-sftp-server/tests.yml?branch=main&label=Test&style=for-the-badge) ![Checkov](https://img.shields.io/github/actions/workflow/status/terrablocks/aws-sftp-server/checkov.yml?branch=main&label=Checkov&style=for-the-badge) ![Commit](https://img.shields.io/github/last-commit/terrablocks/aws-sftp-server?style=for-the-badge) ![Release](https://img.shields.io/github/v/release/terrablocks/aws-sftp-server?style=for-the-badge) + +This terraform module will deploy the following services: +- IAM + - Role + - Role Policy +- Route53 + - DNS Record +- Transfer + - Server + - User + - SSH Key diff --git a/.tflint.hcl b/.tflint.hcl new file mode 100644 index 0000000..a2066b4 --- /dev/null +++ b/.tflint.hcl @@ -0,0 +1,10 @@ +plugin "aws" { + enabled = true + version = "0.24.3" + source = "github.com/terraform-linters/tflint-ruleset-aws" +} + +plugin "terraform" { + enabled = true + preset = "all" +} diff --git a/README.md b/README.md index 2a772fb..dedf0b5 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ module "sftp" { | Name | Version | |------|---------| | terraform | >= 1.3.0 | -| aws | >= 4.0.0 | +| aws | >= 5.0.0 | | random | >= 3.1.0 | ## Inputs @@ -35,6 +35,7 @@ module "sftp" { |------|-------------|------|---------|:--------:| | name | Name of SFTP server. Ignore it to generate a random name for server | `string` | `null` | no | | sftp_type | Type of SFTP server. **Valid values:** `PUBLIC`, `VPC` or `VPC_ENDPOINT` | `string` | `"PUBLIC"` | no | +| storage_type | Where to store the files. **Valid values:** `S3` or `EFS` | `string` | `"S3"` | no | | protocols | List of file transfer protocol(s) over which your FTP client can connect to your server endpoint. **Possible Values:** FTP, FTPS and SFTP | `list(string)` |
[
"SFTP"
]
| no | | certificate_arn | ARN of ACM certificate. Required only in case of FTPS protocol | `string` | `null` | no | | endpoint_details | A block required to setup SFTP server if type is set to `VPC` or `VPC_ENDPOINT`
{
vpc_id = (Optional) ID of VPC in which SFTP server endpoint will be hosted. Required if endpoint type is set to VPC
vpc_endpoint_id = (Optional) The ID of VPC endpoint to use for hosting internal SFTP server. Required if endpoint type is set to VPC_ENDPOINT
subnet_ids = (Optional) List of subnets ids within the VPC for hosting SFTP server endpoint. Required if endpoint type is set to VPC
security_group_ids = (Optional) List of security groups to attach to the SFTP endpoint. Supported only if endpoint is to type VPC. If left blank for VPC, a security group with port 22 open to the world will be created and attached
address_allocation_ids = (Optional) List of address allocation IDs to attach an Elastic IP address to your SFTP server endpoint. Supported only if endpoint type is set to VPC. If left blank for VPC, an EIP will be automatically created per subnet and attached
}
|
object({
vpc_id = optional(string)
vpc_endpoint_id = optional(string)
subnet_ids = optional(list(string))
security_group_ids = optional(list(string))
address_allocation_ids = optional(list(string))
})
| `{}` | no | @@ -45,8 +46,14 @@ module "sftp" { | function_arn | ARN of the lambda function to authenticate users when `identity_provider_type` is of type `AWS_LAMBDA` | `string` | `null` | no | | logging_role | ARN of an IAM role to allow to write SFTP users activity to Amazon CloudWatch logs | `string` | `null` | no | | force_destroy | Whether to delete all the users associated with server so that server can be deleted successfully. **Note:** Supported only if `identity_provider_type` is set to `SERVICE_MANAGED` | `bool` | `true` | no | -| security_policy_name | Specifies the name of the [security policy](https://docs.aws.amazon.com/transfer/latest/userguide/security-policies.html) to associate with the server | `string` | `"TransferSecurityPolicy-2020-06"` | no | +| security_policy_name | Specifies the name of the [security policy](https://docs.aws.amazon.com/transfer/latest/userguide/security-policies.html) to associate with the server | `string` | `"TransferSecurityPolicy-2023-05"` | no | | host_key | RSA private key that will be used to identify your server when clients connect to it over SFTP | `string` | `null` | no | +| pre_authentication_login_banner | Message to display to user when trying to connect to the server **before** authentication | `string` | `null` | no | +| post_authentication_login_banner | Message to display to user when trying to connect to the server **after** authentication | `string` | `null` | no | +| as2_transports | Transport method to use for AS2 messages. **Valid values:** `HTTP` | `set(string)` | `null` | no | +| passive_ip | Use passive IP (PASV) capability to attach the IP address of the firewall or the load balancer to your FTPS/FTP server | `string` | `null` | no | +| set_stat_option | Whether the server should ignore SETSTAT command. **Valid values:** `DEFAULT`, `ENABLE_NO_OP` | `string` | `null` | no | +| tls_session_resumption_mode | TLS session resumption mode provides a mechanism to resume recently negotiated encrypted TLS sessions between the client and the FTPS server. Using one of the TLS session resumption modes, you can customize how you want to your FTPS server to process TLS session resumption requests | `string` | `null` | no | | hosted_zone | Hosted zone name to create DNS entry for SFTP server | `string` | `null` | no | | sftp_sub_domain | DNS name for SFTP server. **NOTE: Only sub-domain name required. DO NOT provide entire URL** | `string` | `"sftp"` | no | | sftp_users | Map of users with key as username and value as their home directory. Home directory is the S3 bucket path which user should have access to
{
user = home_dir_path
}
| `map(string)` | `{}` | no | @@ -63,3 +70,80 @@ module "sftp" { | domain_name | Custom DNS name mapped in Route53 for transfer server | | sftp_sg_id | ID of security group created for SFTP server. Available only if SFTP type is VPC and security group is not provided by you | | sftp_eip | Elastic IP attached to the SFTP server. Available only if SFTP type is VPC and allocation id is not provided by you | + + +# Create a managed public or internal facing SFTP server using AWS Transfer service + +![License](https://img.shields.io/github/license/terrablocks/aws-sftp-server?style=for-the-badge) ![Tests](https://img.shields.io/github/actions/workflow/status/terrablocks/aws-sftp-server/tests.yml?branch=main&label=Test&style=for-the-badge) ![Checkov](https://img.shields.io/github/actions/workflow/status/terrablocks/aws-sftp-server/checkov.yml?branch=main&label=Checkov&style=for-the-badge) ![Commit](https://img.shields.io/github/last-commit/terrablocks/aws-sftp-server?style=for-the-badge) ![Release](https://img.shields.io/github/v/release/terrablocks/aws-sftp-server?style=for-the-badge) + +This terraform module will deploy the following services: +- IAM + - Role + - Role Policy +- Route53 + - DNS Record +- Transfer + - Server + - User + - SSH Key + +# Usage Instructions +## Example +```hcl +module "sftp" { + source = "github.com/terrablocks/aws-sftp-server.git" # Always use `ref` to point module to a specific version or hash +} +``` + +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 1.3.0 | +| aws | >= 5.0.0 | +| random | >= 3.1.0 | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| api_gw_url | URL of the service endpoint to authenticate users when `identity_provider_type` is of type `API_GATEWAY` | `string` | `null` | no | +| as2_transports | Transport method to use for AS2 messages. **Valid values:** `HTTP` | `set(string)` | `null` | no | +| certificate_arn | ARN of ACM certificate. Required only in case of FTPS protocol | `string` | `null` | no | +| directory_id | ID of the directory service to authenticate users when `identity_provider_type` is of type `AWS_DIRECTORY_SERVICE` | `string` | `null` | no | +| endpoint_details | A block required to setup SFTP server if type is set to `VPC` or `VPC_ENDPOINT` ```{ vpc_id = (Optional) ID of VPC in which SFTP server endpoint will be hosted. Required if endpoint type is set to VPC vpc_endpoint_id = (Optional) The ID of VPC endpoint to use for hosting internal SFTP server. Required if endpoint type is set to VPC_ENDPOINT subnet_ids = (Optional) List of subnets ids within the VPC for hosting SFTP server endpoint. Required if endpoint type is set to VPC security_group_ids = (Optional) List of security groups to attach to the SFTP endpoint. Supported only if endpoint is to type VPC. If left blank for VPC, a security group with port 22 open to the world will be created and attached address_allocation_ids = (Optional) List of address allocation IDs to attach an Elastic IP address to your SFTP server endpoint. Supported only if endpoint type is set to VPC. If left blank for VPC, an EIP will be automatically created per subnet and attached }``` | ```object({ vpc_id = optional(string) vpc_endpoint_id = optional(string) subnet_ids = optional(list(string)) security_group_ids = optional(list(string)) address_allocation_ids = optional(list(string)) })``` | `{}` | no | +| force_destroy | Whether to delete all the users associated with server so that server can be deleted successfully. **Note:** Supported only if `identity_provider_type` is set to `SERVICE_MANAGED` | `bool` | `true` | no | +| function_arn | ARN of the lambda function to authenticate users when `identity_provider_type` is of type `AWS_LAMBDA` | `string` | `null` | no | +| host_key | RSA private key that will be used to identify your server when clients connect to it over SFTP | `string` | `null` | no | +| hosted_zone | Hosted zone name to create DNS entry for SFTP server | `string` | `null` | no | +| identity_provider_type | Mode of authentication to use for accessing the service. **Valid Values:** `SERVICE_MANAGED`, `API_GATEWAY`, `AWS_DIRECTORY_SERVICE` or `AWS_LAMBDA` | `string` | `"SERVICE_MANAGED"` | no | +| invocation_role | ARN of the IAM role to authenticate the user when `identity_provider_type` is set to `API_GATEWAY` | `string` | `null` | no | +| logging_role | ARN of an IAM role to allow to write SFTP users activity to Amazon CloudWatch logs | `string` | `null` | no | +| name | Name of SFTP server. Ignore it to generate a random name for server | `string` | `null` | no | +| passive_ip | Use passive IP (PASV) capability to attach the IP address of the firewall or the load balancer to your FTPS/FTP server | `string` | `null` | no | +| post_authentication_login_banner | Message to display to user when trying to connect to the server **after** authentication | `string` | `null` | no | +| pre_authentication_login_banner | Message to display to user when trying to connect to the server **before** authentication | `string` | `null` | no | +| protocols | List of file transfer protocol(s) over which your FTP client can connect to your server endpoint. **Possible Values:** FTP, FTPS and SFTP | `list(string)` | ```[ "SFTP" ]``` | no | +| security_policy_name | Specifies the name of the [security policy](https://docs.aws.amazon.com/transfer/latest/userguide/security-policies.html) to associate with the server | `string` | `"TransferSecurityPolicy-2023-05"` | no | +| set_stat_option | Whether the server should ignore SETSTAT command. **Valid values:** `DEFAULT`, `ENABLE_NO_OP` | `string` | `null` | no | +| sftp_sub_domain | DNS name for SFTP server. **NOTE: Only sub-domain name required. DO NOT provide entire URL** | `string` | `"sftp"` | no | +| sftp_type | Type of SFTP server. **Valid values:** `PUBLIC`, `VPC` or `VPC_ENDPOINT` | `string` | `"PUBLIC"` | no | +| sftp_users | Map of users with key as username and value as their home directory. Home directory is the S3 bucket path which user should have access to ```{ user = home_dir_path }``` | `map(string)` | `{}` | no | +| sftp_users_ssh_key | Map of users with key as username and value as their public SSH key ```{ user = ssh_public_key_content }``` | `map(string)` | `{}` | no | +| storage_type | Where to store the files. **Valid values:** `S3` or `EFS` | `string` | `"S3"` | no | +| tags | A map of key value pair to assign to resources | `map(string)` | `{}` | no | +| tls_session_resumption_mode | TLS session resumption mode provides a mechanism to resume recently negotiated encrypted TLS sessions between the client and the FTPS server. Using one of the TLS session resumption modes, you can customize how you want to your FTPS server to process TLS session resumption requests | `string` | `null` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| arn | ARN of transfer server | +| domain_name | Custom DNS name mapped in Route53 for transfer server | +| endpoint | Endpoint of transfer server | +| id | ID of transfer server | +| sftp_eip | Elastic IP attached to the SFTP server. Available only if SFTP type is VPC and allocation id is not provided by you | +| sftp_sg_id | ID of security group created for SFTP server. Available only if SFTP type is VPC and security group is not provided by you | + + + diff --git a/examples/default.tf b/examples/default.tf new file mode 100644 index 0000000..ece13c0 --- /dev/null +++ b/examples/default.tf @@ -0,0 +1,3 @@ +module "sftp" { + source = "github.com/terrablocks/aws-sftp-server.git" # Always use `ref` to point module to a specific version or hash +} diff --git a/main.tf b/main.tf index 124872e..5405081 100644 --- a/main.tf +++ b/main.tf @@ -30,7 +30,7 @@ EOF resource "aws_iam_role_policy" "logging" { count = var.logging_role == null ? 1 : 0 name = "${local.name}-transfer-logging" - role = join(",", aws_iam_role.logging.*.id) + role = join(",", aws_iam_role.logging[*].id) policy = <