Skip to content

Commit

Permalink
Add home directory inputs (#27)
Browse files Browse the repository at this point in the history
* Add home directory inputs

* Override default sftp user resource inputs

* Revert the id change

* Multi bucket, rm index, tag it all
  • Loading branch information
nitrocode authored Aug 4, 2022
1 parent 770061d commit 15dcc90
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 37 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ Available targets:
| [aws_iam_policy_document.assume_role_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.s3_access_for_sftp_users](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_partition.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
| [aws_s3_bucket.landing](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_bucket) | data source |

## Inputs
Expand Down Expand Up @@ -195,7 +196,7 @@ Available targets:
| <a name="input_restricted_home"></a> [restricted\_home](#input\_restricted\_home) | Restricts SFTP users so they only have access to their home directories. | `bool` | `true` | no |
| <a name="input_s3_bucket_name"></a> [s3\_bucket\_name](#input\_s3\_bucket\_name) | This is the bucket that the SFTP users will use when managing files | `string` | n/a | yes |
| <a name="input_security_policy_name"></a> [security\_policy\_name](#input\_security\_policy\_name) | Specifies the name of the security policy that is attached to the server. Possible values are TransferSecurityPolicy-2018-11, TransferSecurityPolicy-2020-06, and TransferSecurityPolicy-FIPS-2020-06. Default value is: TransferSecurityPolicy-2018-11. | `string` | `"TransferSecurityPolicy-2018-11"` | no |
| <a name="input_sftp_users"></a> [sftp\_users](#input\_sftp\_users) | List of SFTP usernames and public keys | <pre>map(object({<br> user_name = string,<br> public_key = string<br> }))</pre> | `{}` | no |
| <a name="input_sftp_users"></a> [sftp\_users](#input\_sftp\_users) | List of SFTP usernames and public keys. The keys `user_name`, `public_key` are required. The keys `s3_bucket_name` are optional. | `any` | `{}` | no |
| <a name="input_stage"></a> [stage](#input\_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no |
| <a name="input_subnet_ids"></a> [subnet\_ids](#input\_subnet\_ids) | A list of subnet IDs that are required to host your SFTP server endpoint in your VPC. This property can only be used when endpoint\_type is set to VPC. | `list(string)` | `[]` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).<br>Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no |
Expand Down
3 changes: 2 additions & 1 deletion docs/terraform.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
| [aws_iam_policy_document.assume_role_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.s3_access_for_sftp_users](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_partition.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
| [aws_s3_bucket.landing](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_bucket) | data source |

## Inputs
Expand Down Expand Up @@ -65,7 +66,7 @@
| <a name="input_restricted_home"></a> [restricted\_home](#input\_restricted\_home) | Restricts SFTP users so they only have access to their home directories. | `bool` | `true` | no |
| <a name="input_s3_bucket_name"></a> [s3\_bucket\_name](#input\_s3\_bucket\_name) | This is the bucket that the SFTP users will use when managing files | `string` | n/a | yes |
| <a name="input_security_policy_name"></a> [security\_policy\_name](#input\_security\_policy\_name) | Specifies the name of the security policy that is attached to the server. Possible values are TransferSecurityPolicy-2018-11, TransferSecurityPolicy-2020-06, and TransferSecurityPolicy-FIPS-2020-06. Default value is: TransferSecurityPolicy-2018-11. | `string` | `"TransferSecurityPolicy-2018-11"` | no |
| <a name="input_sftp_users"></a> [sftp\_users](#input\_sftp\_users) | List of SFTP usernames and public keys | <pre>map(object({<br> user_name = string,<br> public_key = string<br> }))</pre> | `{}` | no |
| <a name="input_sftp_users"></a> [sftp\_users](#input\_sftp\_users) | List of SFTP usernames and public keys. The keys `user_name`, `public_key` are required. The keys `s3_bucket_name` are optional. | `any` | `{}` | no |
| <a name="input_stage"></a> [stage](#input\_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no |
| <a name="input_subnet_ids"></a> [subnet\_ids](#input\_subnet\_ids) | A list of subnet IDs that are required to host your SFTP server endpoint in your VPC. This property can only be used when endpoint\_type is set to VPC. | `list(string)` | `[]` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).<br>Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no |
Expand Down
19 changes: 14 additions & 5 deletions examples/complete/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,32 @@ provider "awsutils" {
}

module "s3_bucket" {
source = "cloudposse/s3-bucket/aws"
version = "2.0.3"
source = "cloudposse/s3-bucket/aws"
version = "2.0.3"

for_each = toset(["home", "extra"])

acl = "private"
enabled = true
user_enabled = false
versioning_enabled = false
force_destroy = true

attributes = [each.value]

context = module.this.context
}

module "example" {
module "sftp" {
source = "../.."

sftp_users = var.sftp_users
sftp_users = merge(var.sftp_users, {
kenny = merge({
s3_bucket_name = module.s3_bucket["extra"].bucket_id
}, var.sftp_users["kenny"])
})

s3_bucket_name = module.s3_bucket.bucket_id
s3_bucket_name = module.s3_bucket["home"].bucket_id

context = module.this.context
}
6 changes: 3 additions & 3 deletions examples/complete/outputs.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
output "id" {
description = "ID of the created example"
value = module.example.id
value = module.sftp.id
}

output "transfer_endpoint" {
description = "Endpoint for your SFTP connection"
value = module.example.transfer_endpoint
}
value = module.sftp.transfer_endpoint
}
2 changes: 1 addition & 1 deletion examples/vpc/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ module "s3_bucket" {
}


module "example" {
module "sftp" {
source = "../.."

eip_enabled = true
Expand Down
6 changes: 3 additions & 3 deletions examples/vpc/outputs.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
output "id" {
description = "ID of the created example"
value = module.example.id
value = module.sftp.id
}

output "transfer_endpoint" {
description = "Endpoint for your SFTP connection"
value = module.example.transfer_endpoint
}
value = module.sftp.transfer_endpoint
}
64 changes: 48 additions & 16 deletions main.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
locals {
enabled = module.this.enabled

is_vpc = var.vpc_id != null
user_names = keys(var.sftp_users)
user_names_map = { for idx, user in local.user_names : idx => user }
s3_arn_prefix = "arn:${one(data.aws_partition.default[*].partition)}:s3:::"

is_vpc = var.vpc_id != null

user_names = keys(var.sftp_users)

user_names_map = {
for user, val in var.sftp_users :
user => merge(val, {
s3_bucket_arn = lookup(val, "s3_bucket_name", null) != null ? "${local.s3_arn_prefix}${lookup(val, "s3_bucket_name")}" : one(data.aws_s3_bucket.landing[*].arn)
})
}
}

data "aws_partition" "default" {
count = local.enabled ? 1 : 0
}

data "aws_s3_bucket" "landing" {
Expand Down Expand Up @@ -41,19 +54,28 @@ resource "aws_transfer_user" "default" {
for_each = local.enabled ? var.sftp_users : {}

server_id = join("", aws_transfer_server.default[*].id)
role = aws_iam_role.s3_access_for_sftp_users[index(local.user_names, each.value.user_name)].arn
role = aws_iam_role.s3_access_for_sftp_users[each.value.user_name].arn

user_name = each.value.user_name

home_directory_type = var.restricted_home ? "LOGICAL" : "PATH"
home_directory = !var.restricted_home ? "/${var.s3_bucket_name}" : null
home_directory_type = lookup(each.value, "home_directory_type", null) != null ? lookup(each.value, "home_directory_type") : (var.restricted_home ? "LOGICAL" : "PATH")
home_directory = lookup(each.value, "home_directory", null) != null ? lookup(each.value, "home_directory") : (!var.restricted_home ? "/${lookup(each.value, "s3_bucket_name", var.s3_bucket_name)}" : null)

dynamic "home_directory_mappings" {
for_each = var.restricted_home ? [1] : []
for_each = var.restricted_home ? (
lookup(each.value, "home_directory_mappings", null) != null ? lookup(each.value, "home_directory_mappings") : [
{
entry = "/"
# Specifically do not use $${Transfer:UserName} since subsequent terraform plan/applies will try to revert
# the value back to $${Tranfer:*} value
target = format("/%s/%s", lookup(each.value, "s3_bucket_name", var.s3_bucket_name), each.value.user_name)
}
]
) : toset([])

content {
entry = "/"
target = "/${var.s3_bucket_name}/$${Transfer:UserName}"
entry = lookup(home_directory_mappings.value, "entry")
target = lookup(home_directory_mappings.value, "target")
}
}

Expand All @@ -77,6 +99,8 @@ resource "aws_eip" "sftp" {
count = local.enabled && var.eip_enabled ? length(var.subnet_ids) : 0

vpc = local.is_vpc

tags = module.this.tags
}

# Custom Domain
Expand Down Expand Up @@ -127,7 +151,7 @@ data "aws_iam_policy_document" "s3_access_for_sftp_users" {
]

resources = [
join("", data.aws_s3_bucket.landing[*].arn)
each.value.s3_bucket_arn,
]
}

Expand All @@ -146,7 +170,7 @@ data "aws_iam_policy_document" "s3_access_for_sftp_users" {
]

resources = [
var.restricted_home ? "${join("", data.aws_s3_bucket.landing[*].arn)}/${each.value}/*" : "${join("", data.aws_s3_bucket.landing[*].arn)}/*"
var.restricted_home ? "${each.value.s3_bucket_arn}/${each.value.user_name}/*" : "${each.value.s3_bucket_arn}/*"
]
}
}
Expand Down Expand Up @@ -175,32 +199,38 @@ module "iam_label" {
source = "cloudposse/label/null"
version = "0.25.0"

attributes = ["transfer", "s3", each.value]
attributes = ["transfer", "s3", each.value.user_name]

context = module.this.context
}

resource "aws_iam_policy" "s3_access_for_sftp_users" {
for_each = local.enabled ? local.user_names_map : {}

name = module.iam_label[index(local.user_names, each.value)].id
policy = data.aws_iam_policy_document.s3_access_for_sftp_users[index(local.user_names, each.value)].json
name = module.iam_label[each.value.user_name].id
policy = data.aws_iam_policy_document.s3_access_for_sftp_users[each.value.user_name].json

tags = module.this.tags
}

resource "aws_iam_role" "s3_access_for_sftp_users" {
for_each = local.enabled ? local.user_names_map : {}

name = module.iam_label[index(local.user_names, each.value)].id
name = module.iam_label[each.value.user_name].id

assume_role_policy = join("", data.aws_iam_policy_document.assume_role_policy[*].json)
managed_policy_arns = [aws_iam_policy.s3_access_for_sftp_users[index(local.user_names, each.value)].arn]
managed_policy_arns = [aws_iam_policy.s3_access_for_sftp_users[each.value.user_name].arn]

tags = module.this.tags
}

resource "aws_iam_policy" "logging" {
count = local.enabled ? 1 : 0

name = module.logging_label.id
policy = join("", data.aws_iam_policy_document.logging[*].json)

tags = module.this.tags
}

resource "aws_iam_role" "logging" {
Expand All @@ -209,4 +239,6 @@ resource "aws_iam_role" "logging" {
name = module.logging_label.id
assume_role_policy = join("", data.aws_iam_policy_document.assume_role_policy[*].json)
managed_policy_arns = [join("", aws_iam_policy.logging[*].arn)]

tags = module.this.tags
}
2 changes: 1 addition & 1 deletion outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ output "elastic_ips" {

output "s3_access_role_arns" {
description = "Role ARNs for the S3 access"
value = { for idx, user in local.user_names_map : user => aws_iam_role.s3_access_for_sftp_users[idx].arn }
value = { for user, val in aws_iam_role.s3_access_for_sftp_users : user => val.arn }
}
8 changes: 2 additions & 6 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@ variable "domain" {
}

variable "sftp_users" {
type = map(object({
user_name = string,
public_key = string
}))

type = any
default = {}
description = "List of SFTP usernames and public keys"
description = "List of SFTP usernames and public keys. The keys `user_name`, `public_key` are required. The keys `s3_bucket_name` are optional."
}

variable "restricted_home" {
Expand Down

0 comments on commit 15dcc90

Please sign in to comment.