Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aws_transfer_server - add protocol_details #28621

Merged
3 changes: 3 additions & 0 deletions .changelog/28621.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_transfer_server: Add `protocol_details` argument
```
102 changes: 102 additions & 0 deletions internal/service/transfer/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,43 @@ func ResourceServer() *schema.Resource {
Sensitive: true,
ValidateFunc: validation.StringLenBetween(0, 512),
},
"protocol_details": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"as2_transports": {
Type: schema.TypeSet,
Optional: true,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice(transfer.As2Transport_Values(), false),
},
},
"passive_ip": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringLenBetween(0, 15),
},
"set_stat_option": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringInSlice(transfer.SetStatOption_Values(), false),
},
"tls_session_resumption_mode": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringInSlice(transfer.TlsSessionResumptionMode_Values(), false),
},
},
},
},
"protocols": {
Type: schema.TypeSet,
MinItems: 1,
Expand Down Expand Up @@ -317,6 +354,10 @@ func resourceServerCreate(ctx context.Context, d *schema.ResourceData, meta inte
input.PreAuthenticationLoginBanner = aws.String(v.(string))
}

if v, ok := d.GetOk("protocol_details"); ok && len(v.([]interface{})) > 0 {
input.ProtocolDetails = expandProtocolDetails(v.([]interface{}))
}

if v, ok := d.GetOk("protocols"); ok && v.(*schema.Set).Len() > 0 {
input.Protocols = flex.ExpandStringSet(v.(*schema.Set))
}
Expand Down Expand Up @@ -444,6 +485,9 @@ func resourceServerRead(ctx context.Context, d *schema.ResourceData, meta interf
d.Set("logging_role", output.LoggingRole)
d.Set("post_authentication_login_banner", output.PostAuthenticationLoginBanner)
d.Set("pre_authentication_login_banner", output.PreAuthenticationLoginBanner)
if err := d.Set("protocol_details", flattenProtocolDetails(output.ProtocolDetails)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting protocol_details: %s", err)
}
d.Set("protocols", aws.StringValueSlice(output.Protocols))
d.Set("security_policy_name", output.SecurityPolicyName)
if output.IdentityProviderDetails != nil {
Expand Down Expand Up @@ -620,6 +664,10 @@ func resourceServerUpdate(ctx context.Context, d *schema.ResourceData, meta inte
input.PreAuthenticationLoginBanner = aws.String(d.Get("pre_authentication_login_banner").(string))
}

if d.HasChange("protocol_details") {
input.ProtocolDetails = expandProtocolDetails(d.Get("protocol_details").([]interface{}))
}

if d.HasChange("protocols") {
input.Protocols = flex.ExpandStringSet(d.Get("protocols").(*schema.Set))
}
Expand Down Expand Up @@ -811,6 +859,60 @@ func flattenEndpointDetails(apiObject *transfer.EndpointDetails, securityGroupID
return tfMap
}

func expandProtocolDetails(m []interface{}) *transfer.ProtocolDetails {
if len(m) < 1 || m[0] == nil {
return nil
}

tfMap := m[0].(map[string]interface{})

apiObject := &transfer.ProtocolDetails{}

if v, ok := tfMap["as2_transports"].(*schema.Set); ok && v.Len() > 0 {
apiObject.As2Transports = flex.ExpandStringSet(v)
}

if v, ok := tfMap["passive_ip"].(string); ok && len(v) > 0 {
apiObject.PassiveIp = aws.String(v)
}

if v, ok := tfMap["set_stat_option"].(string); ok && len(v) > 0 {
apiObject.SetStatOption = aws.String(v)
}

if v, ok := tfMap["tls_session_resumption_mode"].(string); ok && len(v) > 0 {
apiObject.TlsSessionResumptionMode = aws.String(v)
}

return apiObject
}

func flattenProtocolDetails(apiObject *transfer.ProtocolDetails) []interface{} {
if apiObject == nil {
return nil
}

tfMap := map[string]interface{}{}

if v := apiObject.As2Transports; v != nil {
tfMap["as2_transport"] = aws.StringValueSlice(v)
}

if v := apiObject.PassiveIp; v != nil {
tfMap["passive_ip"] = aws.StringValue(v)
}

if v := apiObject.SetStatOption; v != nil {
tfMap["set_stat_option"] = aws.StringValue(v)
}

if v := apiObject.TlsSessionResumptionMode; v != nil {
tfMap["tls_session_resumption_mode"] = aws.StringValue(v)
}

return []interface{}{tfMap}
}

func expandWorkflowDetails(tfMap []interface{}) *transfer.WorkflowDetails {
apiObject := &transfer.WorkflowDetails{
OnPartialUpload: []*transfer.WorkflowDetail{},
Expand Down
60 changes: 60 additions & 0 deletions internal/service/transfer/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ func testAccServer_basic(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "logging_role", ""),
resource.TestCheckResourceAttr(resourceName, "post_authentication_login_banner", ""),
resource.TestCheckResourceAttr(resourceName, "pre_authentication_login_banner", ""),
resource.TestCheckResourceAttr(resourceName, "protocol_details.#", "1"),
resource.TestCheckResourceAttr(resourceName, "protocol_details.0.as2_transports.#", "0"),
resource.TestCheckResourceAttr(resourceName, "protocol_details.0.passive_ip", "AUTO"),
resource.TestCheckResourceAttr(resourceName, "protocol_details.0.set_stat_option", "DEFAULT"),
resource.TestCheckResourceAttr(resourceName, "protocol_details.0.tls_session_resumption_mode", "ENFORCED"),
resource.TestCheckResourceAttr(resourceName, "protocols.#", "1"),
resource.TestCheckTypeSetElemAttr(resourceName, "protocols.*", "SFTP"),
resource.TestCheckResourceAttr(resourceName, "security_policy_name", "TransferSecurityPolicy-2018-11"),
Expand Down Expand Up @@ -791,6 +796,49 @@ func testAccServer_protocols(t *testing.T) {
})
}

func testAccServer_protocolDetails(t *testing.T) {
ctx := acctest.Context(t)
var s transfer.DescribedServer
resourceName := "aws_transfer_server.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t); testAccPreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, transfer.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckServerDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccServerConfig_protocolDetails("AUTO", "DEFAULT", "ENFORCED"),
Check: resource.ComposeTestCheckFunc(
testAccCheckServerExists(ctx, resourceName, &s),
resource.TestCheckResourceAttr(resourceName, "protocol_details.#", "1"),
resource.TestCheckResourceAttr(resourceName, "protocol_details.0.as2_transports.#", "0"),
resource.TestCheckResourceAttr(resourceName, "protocol_details.0.passive_ip", "AUTO"),
resource.TestCheckResourceAttr(resourceName, "protocol_details.0.set_stat_option", "DEFAULT"),
resource.TestCheckResourceAttr(resourceName, "protocol_details.0.tls_session_resumption_mode", "ENFORCED"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"force_destroy"},
},
{
Config: testAccServerConfig_protocolDetails("8.8.8.8", "ENABLE_NO_OP", "DISABLED"),
Check: resource.ComposeTestCheckFunc(
testAccCheckServerExists(ctx, resourceName, &s),
resource.TestCheckResourceAttr(resourceName, "protocol_details.#", "1"),
resource.TestCheckResourceAttr(resourceName, "protocol_details.0.as2_transports.#", "0"),
resource.TestCheckResourceAttr(resourceName, "protocol_details.0.passive_ip", "8.8.8.8"),
resource.TestCheckResourceAttr(resourceName, "protocol_details.0.set_stat_option", "ENABLE_NO_OP"),
resource.TestCheckResourceAttr(resourceName, "protocol_details.0.tls_session_resumption_mode", "DISABLED"),
),
},
},
})
}

func testAccServer_apiGateway(t *testing.T) {
ctx := acctest.Context(t)
var conf transfer.DescribedServer
Expand Down Expand Up @@ -1752,6 +1800,18 @@ resource "aws_transfer_server" "test" {
`, rName))
}

func testAccServerConfig_protocolDetails(passive_ip, set_stat_option, tls_session_resumption_mode string) string {
return fmt.Sprintf(`
resource "aws_transfer_server" "test" {
protocol_details {
passive_ip = %[1]q
set_stat_option = %[2]q
tls_session_resumption_mode = %[3]q
}
}
`, passive_ip, set_stat_option, tls_session_resumption_mode)
}

func testAccServerConfig_rootCA(domain string) string {
return fmt.Sprintf(`
resource "aws_acmpca_certificate_authority" "test" {
Expand Down
1 change: 1 addition & 0 deletions internal/service/transfer/transfer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func TestAccTransfer_serial(t *testing.T) {
"HostKey": testAccServer_hostKey,
"LambdaFunction": testAccServer_lambdaFunction,
"Protocols": testAccServer_protocols,
"ProtocolDetails": testAccServer_protocolDetails,
"SecurityPolicy": testAccServer_securityPolicy,
"UpdateEndpointTypePublicToVPC": testAccServer_updateEndpointType_publicToVPC,
"UpdateEndpointTypePublicToVPCAddressAllocationIDs": testAccServer_updateEndpointType_publicToVPC_addressAllocationIDs,
Expand Down
10 changes: 9 additions & 1 deletion website/docs/r/transfer_server.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ The following arguments are supported:
* `endpoint_details` - (Optional) The virtual private cloud (VPC) endpoint settings that you want to configure for your SFTP server. Fields documented below.
* `endpoint_type` - (Optional) The type of endpoint that you want your SFTP server connect to. If you connect to a `VPC` (or `VPC_ENDPOINT`), your SFTP server isn't accessible over the public internet. If you want to connect your SFTP server via public internet, set `PUBLIC`. Defaults to `PUBLIC`.
* `invocation_role` - (Optional) Amazon Resource Name (ARN) of the IAM role used to authenticate the user account with an `identity_provider_type` of `API_GATEWAY`.
* `host_key` - (Optional) RSA private key (e.g., as generated by the `ssh-keygen -N "" -m PEM -f my-new-server-key` command).
* `host_key` - (Optional) RSA, ECDSA, or ED25519 private key (e.g., as generated by the `ssh-keygen -t rsa -b 2048 -N "" -m PEM -f my-new-server-key`, `ssh-keygen -t ecdsa -b 256 -N "" -m PEM -f my-new-server-key` or `ssh-keygen -t ed25519 -N "" -f my-new-server-key` commands).
* `url` - (Optional) - URL of the service endpoint used to authenticate users with an `identity_provider_type` of `API_GATEWAY`.
* `identity_provider_type` - (Optional) The mode of authentication enabled for this service. The default value is `SERVICE_MANAGED`, which allows you to store and access SFTP user credentials within the service. `API_GATEWAY` indicates that user authentication requires a call to an API Gateway endpoint URL provided by you to integrate an identity provider of your choice. Using `AWS_DIRECTORY_SERVICE` will allow for authentication against AWS Managed Active Directory or Microsoft Active Directory in your on-premises environment, or in AWS using AD Connectors. Use the `AWS_LAMBDA` value to directly use a Lambda function as your identity provider. If you choose this value, you must specify the ARN for the lambda function in the `function` argument.
* `directory_id` - (Optional) The directory service ID of the directory service you want to connect to with an `identity_provider_type` of `AWS_DIRECTORY_SERVICE`.
Expand All @@ -108,6 +108,7 @@ The following arguments are supported:
* `force_destroy` - (Optional) A boolean that indicates all users associated with the server should be deleted so that the Server can be destroyed without error. The default value is `false`. This option only applies to servers configured with a `SERVICE_MANAGED` `identity_provider_type`.
* `post_authentication_login_banner`- (Optional) Specify a string to display when users connect to a server. This string is displayed after the user authenticates. The SFTP protocol does not support post-authentication display banners.
* `pre_authentication_login_banner`- (Optional) Specify a string to display when users connect to a server. This string is displayed before the user authenticates.
* `protocol_details`- (Optional) The protocol settings that are configured for your server.
* `security_policy_name` - (Optional) Specifies the name of the security policy that is attached to the server. Possible values are `TransferSecurityPolicy-2018-11`, `TransferSecurityPolicy-2020-06`, `TransferSecurityPolicy-FIPS-2020-06` and `TransferSecurityPolicy-2022-03`. Default value is: `TransferSecurityPolicy-2018-11`.
* `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level.
* `workflow_details` - (Optional) Specifies the workflow details. See Workflow Details below.
Expand All @@ -120,6 +121,13 @@ The following arguments are supported:
* `vpc_endpoint_id` - (Optional) The ID of the VPC endpoint. This property can only be used when `endpoint_type` is set to `VPC_ENDPOINT`
* `vpc_id` - (Optional) The VPC ID of the virtual private cloud in which the SFTP server's endpoint will be hosted. This property can only be used when `endpoint_type` is set to `VPC`.

### Protocol Details

* `as2_transports` - (Optional) Indicates the transport method for the AS2 messages. Currently, only `HTTP` is supported.
* `passive_ip` - (Optional) Indicates passive mode, for FTP and FTPS protocols. Enter a single IPv4 address, such as the public IP address of a firewall, router, or load balancer.
* `set_stat_option` - (Optional) Use to ignore the error that is generated when the client attempts to use `SETSTAT` on a file you are uploading to an S3 bucket. Valid values: `DEFAULT`, `ENABLE_NO_OP`.
* `tls_session_resumption_mode` - (Optional) A property used with Transfer Family servers that use the FTPS protocol. Provides a mechanism to resume or share a negotiated secret key between the control and data connection for an FTPS session. Valid values: `DISABLED`, `ENABLED`, `ENFORCED`.

### Workflow Details

* `on_upload` - (Optional) A trigger that starts a workflow: the workflow begins to execute after a file is uploaded. See Workflow Detail below.
Expand Down