diff --git a/.changelog/37015.txt b/.changelog/37015.txt new file mode 100644 index 00000000000..9e55f84bb0c --- /dev/null +++ b/.changelog/37015.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_transfer_server: Add `sftp_authentication_methods` argument +``` \ No newline at end of file diff --git a/internal/service/transfer/server.go b/internal/service/transfer/server.go index 010c0b72b2a..ba2c8c20de7 100644 --- a/internal/service/transfer/server.go +++ b/internal/service/transfer/server.go @@ -243,6 +243,12 @@ func resourceServer() *schema.Resource { Default: SecurityPolicyName2018_11, ValidateFunc: validation.StringInSlice(SecurityPolicyName_Values(), false), }, + "sftp_authentication_methods": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(transfer.SftpAuthenticationMethods_Values(), false), + }, "structured_log_destinations": { Type: schema.TypeSet, Elem: &schema.Schema{ @@ -372,6 +378,14 @@ func resourceServerCreate(ctx context.Context, d *schema.ResourceData, meta inte input.IdentityProviderDetails.InvocationRole = aws.String(v.(string)) } + if v, ok := d.GetOk("sftp_authentication_methods"); ok { + if input.IdentityProviderDetails == nil { + input.IdentityProviderDetails = &transfer.IdentityProviderDetails{} + } + + input.IdentityProviderDetails.SftpAuthenticationMethods = aws.String(v.(string)) + } + if v, ok := d.GetOk("logging_role"); ok { input.LoggingRole = aws.String(v.(string)) } @@ -514,6 +528,11 @@ func resourceServerRead(ctx context.Context, d *schema.ResourceData, meta interf } else { d.Set("invocation_role", "") } + if output.IdentityProviderDetails != nil { + d.Set("sftp_authentication_methods", output.IdentityProviderDetails.SftpAuthenticationMethods) + } else { + d.Set("sftp_authentication_methods", "") + } d.Set("logging_role", output.LoggingRole) d.Set("post_authentication_login_banner", output.PostAuthenticationLoginBanner) d.Set("pre_authentication_login_banner", output.PreAuthenticationLoginBanner) @@ -657,7 +676,7 @@ func resourceServerUpdate(ctx context.Context, d *schema.ResourceData, meta inte } } - if d.HasChanges("directory_id", "function", "invocation_role", "url") { + if d.HasChanges("directory_id", "function", "invocation_role", "sftp_authentication_methods", "url") { identityProviderDetails := &transfer.IdentityProviderDetails{} if attr, ok := d.GetOk("directory_id"); ok { @@ -672,6 +691,10 @@ func resourceServerUpdate(ctx context.Context, d *schema.ResourceData, meta inte identityProviderDetails.InvocationRole = aws.String(attr.(string)) } + if attr, ok := d.GetOk("sftp_authentication_methods"); ok { + identityProviderDetails.SftpAuthenticationMethods = aws.String(attr.(string)) + } + if attr, ok := d.GetOk("url"); ok { identityProviderDetails.Url = aws.String(attr.(string)) } diff --git a/internal/service/transfer/server_test.go b/internal/service/transfer/server_test.go index e43255f821a..66d1b6667e6 100644 --- a/internal/service/transfer/server_test.go +++ b/internal/service/transfer/server_test.go @@ -1005,6 +1005,7 @@ func testAccServer_apiGateway(t *testing.T) { testAccCheckServerExists(ctx, resourceName, &conf), resource.TestCheckResourceAttr(resourceName, "identity_provider_type", "API_GATEWAY"), resource.TestCheckResourceAttrPair(resourceName, "invocation_role", "aws_iam_role.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "sftp_authentication_methods", "PUBLIC_KEY_OR_PASSWORD"), ), }, { @@ -1210,6 +1211,78 @@ func testAccServer_lambdaFunction(t *testing.T) { testAccCheckServerExists(ctx, resourceName, &conf), resource.TestCheckResourceAttrPair(resourceName, "function", "aws_lambda_function.test", "arn"), resource.TestCheckResourceAttr(resourceName, "identity_provider_type", "AWS_LAMBDA"), + resource.TestCheckResourceAttr(resourceName, "sftp_authentication_methods", "PUBLIC_KEY_OR_PASSWORD"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, + }, + }) +} + +func testAccServer_identityProviderType_sftpAuthenticationMethods(t *testing.T) { + ctx := acctest.Context(t) + var conf transfer.DescribedServer + resourceName := "aws_transfer_server.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckAPIGatewayTypeEDGE(t); testAccPreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.TransferServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccServerConfig_identityProviderType_sftpAuthenticationMethods(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckServerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "identity_provider_type", "API_GATEWAY"), + resource.TestCheckResourceAttrPair(resourceName, "invocation_role", "aws_iam_role.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "sftp_authentication_methods", "PASSWORD"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, + }, + }) +} + +func testAccServer_updateIdentityProviderType_sftpAuthenticationMethods(t *testing.T) { + ctx := acctest.Context(t) + var conf transfer.DescribedServer + resourceName := "aws_transfer_server.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckAPIGatewayTypeEDGE(t); testAccPreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.TransferServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccServerConfig_identityProviderType_sftpAuthenticationMethods(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckServerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "identity_provider_type", "API_GATEWAY"), + resource.TestCheckResourceAttrPair(resourceName, "invocation_role", "aws_iam_role.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "sftp_authentication_methods", "PASSWORD"), + ), + }, + { + Config: testAccServerConfig_identityProviderType_sftpAuthenticationMethods_updated(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckServerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "identity_provider_type", "API_GATEWAY"), + resource.TestCheckResourceAttrPair(resourceName, "invocation_role", "aws_iam_role.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "sftp_authentication_methods", "PUBLIC_KEY_AND_PASSWORD"), ), }, { @@ -1228,7 +1301,7 @@ func testAccServer_authenticationLoginBanners(t *testing.T) { resourceName := "aws_transfer_server.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(ctx, t) }, + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckAPIGatewayTypeEDGE(t); testAccPreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.TransferServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckServerDestroy(ctx), @@ -2160,6 +2233,38 @@ resource "aws_transfer_server" "test" { `, rName, forceDestroy)) } +func testAccServerConfig_identityProviderType_sftpAuthenticationMethods(rName string) string { + return acctest.ConfigCompose(testAccServerConfig_apiGatewayBase(rName), testAccServerConfig_loggingRoleBase(rName), fmt.Sprintf(` +resource "aws_transfer_server" "test" { + identity_provider_type = "API_GATEWAY" + url = "${aws_api_gateway_deployment.test.invoke_url}${aws_api_gateway_resource.test.path}" + invocation_role = aws_iam_role.test.arn + logging_role = aws_iam_role.test.arn + sftp_authentication_methods = "PASSWORD" + + tags = { + Name = %[1]q + } +} +`, rName)) +} + +func testAccServerConfig_identityProviderType_sftpAuthenticationMethods_updated(rName string) string { + return acctest.ConfigCompose(testAccServerConfig_apiGatewayBase(rName), testAccServerConfig_loggingRoleBase(rName), fmt.Sprintf(` +resource "aws_transfer_server" "test" { + identity_provider_type = "API_GATEWAY" + url = "${aws_api_gateway_deployment.test.invoke_url}${aws_api_gateway_resource.test.path}" + invocation_role = aws_iam_role.test.arn + logging_role = aws_iam_role.test.arn + sftp_authentication_methods = "PUBLIC_KEY_AND_PASSWORD" + + tags = { + Name = %[1]q + } +} +`, rName)) +} + func testAccServerConfig_workflow(rName string) string { return fmt.Sprintf(` resource "aws_iam_role" "test" { diff --git a/internal/service/transfer/transfer_test.go b/internal/service/transfer/transfer_test.go index 06ab4673cbf..a67bd0d049d 100644 --- a/internal/service/transfer/transfer_test.go +++ b/internal/service/transfer/transfer_test.go @@ -25,27 +25,29 @@ func TestAccTransfer_serial(t *testing.T) { "tags": testAccAgreement_tags, }, "Server": { - "basic": testAccServer_basic, - "disappears": testAccServer_disappears, - "tags": testAccServer_tags, - "APIGateway": testAccServer_apiGateway, - "APIGatewayForceDestroy": testAccServer_apiGateway_forceDestroy, - "AuthenticationLoginBanners": testAccServer_authenticationLoginBanners, - "DataSourceBasic": testAccServerDataSource_basic, - "DataSourceServiceManaged": testAccServerDataSource_Service_managed, - "DataSourceAPIGateway": testAccServerDataSource_apigateway, - "DirectoryService": testAccServer_directoryService, - "Domain": testAccServer_domain, - "ForceDestroy": testAccServer_forceDestroy, - "HostKey": testAccServer_hostKey, - "LambdaFunction": testAccServer_lambdaFunction, - "Protocols": testAccServer_protocols, - "ProtocolDetails": testAccServer_protocolDetails, - "S3StorageOptions": testAccServer_s3StorageOptions, - "SecurityPolicy": testAccServer_securityPolicy, - "SecurityPolicyFIPS": testAccServer_securityPolicyFIPS, - "StructuredLogDestinations": testAccServer_structuredLogDestinations, - "UpdateEndpointTypePublicToVPC": testAccServer_updateEndpointType_publicToVPC, + "basic": testAccServer_basic, + "disappears": testAccServer_disappears, + "tags": testAccServer_tags, + "APIGateway": testAccServer_apiGateway, + "APIGatewayForceDestroy": testAccServer_apiGateway_forceDestroy, + "AuthenticationLoginBanners": testAccServer_authenticationLoginBanners, + "DataSourceBasic": testAccServerDataSource_basic, + "DataSourceServiceManaged": testAccServerDataSource_Service_managed, + "DataSourceAPIGateway": testAccServerDataSource_apigateway, + "DirectoryService": testAccServer_directoryService, + "Domain": testAccServer_domain, + "ForceDestroy": testAccServer_forceDestroy, + "HostKey": testAccServer_hostKey, + "LambdaFunction": testAccServer_lambdaFunction, + "Protocols": testAccServer_protocols, + "ProtocolDetails": testAccServer_protocolDetails, + "S3StorageOptions": testAccServer_s3StorageOptions, + "SecurityPolicy": testAccServer_securityPolicy, + "SecurityPolicyFIPS": testAccServer_securityPolicyFIPS, + "SftpAuthenticationMethods": testAccServer_identityProviderType_sftpAuthenticationMethods, + "UpdateSftpAuthenticationMethods": testAccServer_updateIdentityProviderType_sftpAuthenticationMethods, + "StructuredLogDestinations": testAccServer_structuredLogDestinations, + "UpdateEndpointTypePublicToVPC": testAccServer_updateEndpointType_publicToVPC, "UpdateEndpointTypePublicToVPCAddressAllocationIDs": testAccServer_updateEndpointType_publicToVPC_addressAllocationIDs, "UpdateEndpointTypeVPCEndpointToVPC": testAccServer_updateEndpointType_vpcEndpointToVPC, "UpdateEndpointTypeVPCEndpointToVPCAddressAllocationIDs": testAccServer_updateEndpointType_vpcEndpointToVPC_addressAllocationIDs, diff --git a/website/docs/r/transfer_server.html.markdown b/website/docs/r/transfer_server.html.markdown index bf114fe8316..1b7631f363b 100644 --- a/website/docs/r/transfer_server.html.markdown +++ b/website/docs/r/transfer_server.html.markdown @@ -140,6 +140,7 @@ This resource supports the following arguments: * `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`. * `function` - (Optional) The ARN for a lambda function to use for the Identity provider. +* `sftp_authentication_methods` - (Optional) For SFTP-enabled servers, and for custom identity providers only. Valid values are `PASSWORD`, `PUBLIC_KEY`, `PUBLIC_KEY_OR_PASSWORD` and `PUBLIC_KEY_AND_PASSWORD`. Default value is: `PUBLIC_KEY_OR_PASSWORD`. * `logging_role` - (Optional) Amazon Resource Name (ARN) of an IAM role that allows the service to write your SFTP users’ activity to your Amazon CloudWatch logs for monitoring and auditing purposes. * `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.