diff --git a/aws/provider.go b/aws/provider.go index 2bb6b8050ac..531bdf313b8 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -669,6 +669,7 @@ func Provider() terraform.ResourceProvider { "aws_subnet": resourceAwsSubnet(), "aws_swf_domain": resourceAwsSwfDomain(), "aws_transfer_server": resourceAwsTransferServer(), + "aws_transfer_ssh_key": resourceAwsTransferSshKey(), "aws_transfer_user": resourceAwsTransferUser(), "aws_volume_attachment": resourceAwsVolumeAttachment(), "aws_vpc_dhcp_options_association": resourceAwsVpcDhcpOptionsAssociation(), diff --git a/aws/resource_aws_transfer_ssh_key.go b/aws/resource_aws_transfer_ssh_key.go new file mode 100644 index 00000000000..332916c89c7 --- /dev/null +++ b/aws/resource_aws_transfer_ssh_key.go @@ -0,0 +1,150 @@ +package aws + +import ( + "fmt" + "log" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/transfer" + + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsTransferSshKey() *schema.Resource { + + return &schema.Resource{ + Create: resourceAwsTransferSshKeyCreate, + Read: resourceAwsTransferSshKeyRead, + Delete: resourceAwsTransferSshKeyDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "body": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + old = cleanSshKey(old) + new = cleanSshKey(new) + return strings.Trim(old, "\n") == strings.Trim(new, "\n") + }, + }, + + "server_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateTransferServerID, + }, + + "user_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateTransferUserName, + }, + }, + } +} + +func resourceAwsTransferSshKeyCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).transferconn + userName := d.Get("user_name").(string) + serverID := d.Get("server_id").(string) + + createOpts := &transfer.ImportSshPublicKeyInput{ + ServerId: aws.String(serverID), + UserName: aws.String(userName), + SshPublicKeyBody: aws.String(d.Get("body").(string)), + } + + log.Printf("[DEBUG] Create Transfer SSH Public Key Option: %#v", createOpts) + + resp, err := conn.ImportSshPublicKey(createOpts) + if err != nil { + return fmt.Errorf("Error importing ssh public key: %s", err) + } + + d.SetId(fmt.Sprintf("%s/%s/%s", serverID, userName, *resp.SshPublicKeyId)) + + return nil +} + +func resourceAwsTransferSshKeyRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).transferconn + serverID, userName, sshKeyID, err := decodeTransferSshKeyId(d.Id()) + if err != nil { + return fmt.Errorf("error parsing Transfer SSH Public Key ID: %s", err) + } + + descOpts := &transfer.DescribeUserInput{ + UserName: aws.String(userName), + ServerId: aws.String(serverID), + } + + log.Printf("[DEBUG] Describe Transfer User Option: %#v", descOpts) + + resp, err := conn.DescribeUser(descOpts) + if err != nil { + if isAWSErr(err, transfer.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] Transfer User (%s) for Server (%s) not found, removing ssh public key (%s) from state", userName, serverID, sshKeyID) + d.SetId("") + return nil + } + return err + } + + var body string + for _, s := range resp.User.SshPublicKeys { + if sshKeyID == *s.SshPublicKeyId { + body = *s.SshPublicKeyBody + } + } + + if body == "" { + log.Printf("[WARN] No such ssh public key found for User (%s) in Server (%s)", userName, serverID) + d.SetId("") + } + + d.Set("server_id", resp.ServerId) + d.Set("user_name", resp.User.UserName) + d.Set("body", body) + + return nil +} + +func resourceAwsTransferSshKeyDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).transferconn + serverID, userName, sshKeyID, err := decodeTransferSshKeyId(d.Id()) + if err != nil { + return fmt.Errorf("error parsing Transfer SSH Public Key ID: %s", err) + } + + delOpts := &transfer.DeleteSshPublicKeyInput{ + UserName: aws.String(userName), + ServerId: aws.String(serverID), + SshPublicKeyId: aws.String(sshKeyID), + } + + log.Printf("[DEBUG] Delete Transfer SSH Public Key Option: %#v", delOpts) + + _, err = conn.DeleteSshPublicKey(delOpts) + if err != nil { + if isAWSErr(err, transfer.ErrCodeResourceNotFoundException, "") { + return nil + } + return fmt.Errorf("error deleting Transfer User Ssh Key (%s): %s", d.Id(), err) + } + + return nil +} + +func decodeTransferSshKeyId(id string) (string, string, string, error) { + idParts := strings.SplitN(id, "/", 3) + if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { + return "", "", "", fmt.Errorf("unexpected format of ID (%s), expected SERVERID/USERNAME/SSHKEYID", id) + } + return idParts[0], idParts[1], idParts[2], nil +} diff --git a/aws/resource_aws_transfer_ssh_key_test.go b/aws/resource_aws_transfer_ssh_key_test.go new file mode 100644 index 00000000000..819c2a1e10c --- /dev/null +++ b/aws/resource_aws_transfer_ssh_key_test.go @@ -0,0 +1,175 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/transfer" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAWSTransferSshKey_basic(t *testing.T) { + var conf transfer.SshPublicKey + rName := acctest.RandString(5) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSTransferSshKeyDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSTransferSshKeyConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferSshKeyExists("aws_transfer_ssh_key.foo", &conf), + resource.TestCheckResourceAttrPair( + "aws_transfer_ssh_key.foo", "server_id", "aws_transfer_server.foo", "id"), + resource.TestCheckResourceAttrPair( + "aws_transfer_ssh_key.foo", "user_name", "aws_transfer_user.foo", "user_name"), + ), + }, + { + ResourceName: "aws_transfer_user.foo", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckAWSTransferSshKeyExists(n string, res *transfer.SshPublicKey) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No Transfer Ssh Public Key ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).transferconn + serverID, userName, sshKeyID, err := decodeTransferSshKeyId(rs.Primary.ID) + if err != nil { + return fmt.Errorf("error parsing Transfer SSH Public Key ID: %s", err) + } + + describe, err := conn.DescribeUser(&transfer.DescribeUserInput{ + ServerId: aws.String(serverID), + UserName: aws.String(userName), + }) + + if err != nil { + return err + } + + for _, sshPublicKey := range describe.User.SshPublicKeys { + if sshKeyID == *sshPublicKey.SshPublicKeyId { + *res = *sshPublicKey + return nil + } + } + + return fmt.Errorf("Transfer Ssh Public Key doesn't exists.") + } +} + +func testAccCheckAWSTransferSshKeyDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).transferconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_transfer_ssh_key" { + continue + } + serverID, userName, sshKeyID, err := decodeTransferSshKeyId(rs.Primary.ID) + if err != nil { + return fmt.Errorf("error parsing Transfer SSH Public Key ID: %s", err) + } + + describe, err := conn.DescribeUser(&transfer.DescribeUserInput{ + UserName: aws.String(userName), + ServerId: aws.String(serverID), + }) + + if isAWSErr(err, transfer.ErrCodeResourceNotFoundException, "") { + continue + } + + if err != nil { + return err + } + + for _, sshPublicKey := range describe.User.SshPublicKeys { + if sshKeyID == *sshPublicKey.SshPublicKeyId { + return fmt.Errorf("Transfer SSH Public Key still exists") + } + } + } + + return nil +} + +func testAccAWSTransferSshKeyConfig_basic(rName string) string { + return fmt.Sprintf(` +resource "aws_transfer_server" "foo" { + identity_provider_type = "SERVICE_MANAGED" +} + + +resource "aws_iam_role" "foo" { + name = "tf-test-transfer-user-iam-role-%s" + + assume_role_policy = <aws_transfer_server + > + aws_transfer_ssh_key + + > aws_transfer_user diff --git a/website/docs/r/transfer_ssh_key.html.markdown b/website/docs/r/transfer_ssh_key.html.markdown new file mode 100644 index 00000000000..d51c10a8fb3 --- /dev/null +++ b/website/docs/r/transfer_ssh_key.html.markdown @@ -0,0 +1,96 @@ +--- +layout: "aws" +page_title: "AWS: aws_transfer_ssh_key" +sidebar_current: "docs-aws-resource-transfer-ssh-key" +description: |- + Provides a AWS Transfer SSH Public Key resource. +--- + +# aws_transfer_ssh_key + +Provides a AWS Transfer User resource. + + +```hcl +resource "aws_transfer_server" "foo" { + identity_provider_type = "SERVICE_MANAGED" + + tags { + NAME = "tf-acc-test-transfer-server" + } +} + + +resource "aws_iam_role" "foo" { + name = "tf-test-transfer-user-iam-role-%s" + + assume_role_policy = <