diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go
index 16e4f3789..8596b844e 100644
--- a/builtin/providers/aws/provider.go
+++ b/builtin/providers/aws/provider.go
@@ -191,6 +191,7 @@ func Provider() terraform.ResourceProvider {
"aws_iam_policy_attachment": resourceAwsIamPolicyAttachment(),
"aws_iam_role_policy": resourceAwsIamRolePolicy(),
"aws_iam_role": resourceAwsIamRole(),
+ "aws_iam_saml_provider": resourceAwsIamSamlProvider(),
"aws_iam_server_certificate": resourceAwsIAMServerCertificate(),
"aws_iam_user_policy": resourceAwsIamUserPolicy(),
"aws_iam_user": resourceAwsIamUser(),
diff --git a/builtin/providers/aws/resource_aws_iam_saml_provider.go b/builtin/providers/aws/resource_aws_iam_saml_provider.go
new file mode 100644
index 000000000..6a166d711
--- /dev/null
+++ b/builtin/providers/aws/resource_aws_iam_saml_provider.go
@@ -0,0 +1,101 @@
+package aws
+
+import (
+ "time"
+
+ "github.com/aws/aws-sdk-go/aws"
+ "github.com/aws/aws-sdk-go/service/iam"
+
+ "github.com/hashicorp/terraform/helper/schema"
+)
+
+func resourceAwsIamSamlProvider() *schema.Resource {
+ return &schema.Resource{
+ Create: resourceAwsIamSamlProviderCreate,
+ Read: resourceAwsIamSamlProviderRead,
+ Update: resourceAwsIamSamlProviderUpdate,
+ Delete: resourceAwsIamSamlProviderDelete,
+
+ Schema: map[string]*schema.Schema{
+ "arn": &schema.Schema{
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "valid_until": &schema.Schema{
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "name": &schema.Schema{
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ },
+ "saml_metadata_document": &schema.Schema{
+ Type: schema.TypeString,
+ Required: true,
+ },
+ },
+ }
+}
+
+func resourceAwsIamSamlProviderCreate(d *schema.ResourceData, meta interface{}) error {
+ iamconn := meta.(*AWSClient).iamconn
+
+ input := &iam.CreateSAMLProviderInput{
+ Name: aws.String(d.Get("name").(string)),
+ SAMLMetadataDocument: aws.String(d.Get("saml_metadata_document").(string)),
+ }
+
+ out, err := iamconn.CreateSAMLProvider(input)
+ if err != nil {
+ return err
+ }
+
+ d.SetId(*out.SAMLProviderArn)
+
+ return resourceAwsIamSamlProviderRead(d, meta)
+}
+
+func resourceAwsIamSamlProviderRead(d *schema.ResourceData, meta interface{}) error {
+ iamconn := meta.(*AWSClient).iamconn
+
+ input := &iam.GetSAMLProviderInput{
+ SAMLProviderArn: aws.String(d.Id()),
+ }
+ out, err := iamconn.GetSAMLProvider(input)
+ if err != nil {
+ return err
+ }
+
+ validUntil := out.ValidUntil.Format(time.RFC1123)
+ d.Set("valid_until", validUntil)
+ d.Set("saml_metadata_document", *out.SAMLMetadataDocument)
+
+ return nil
+}
+
+func resourceAwsIamSamlProviderUpdate(d *schema.ResourceData, meta interface{}) error {
+ iamconn := meta.(*AWSClient).iamconn
+
+ input := &iam.UpdateSAMLProviderInput{
+ SAMLProviderArn: aws.String(d.Id()),
+ SAMLMetadataDocument: aws.String(d.Get("saml_metadata_document").(string)),
+ }
+ _, err := iamconn.UpdateSAMLProvider(input)
+ if err != nil {
+ return err
+ }
+
+ return resourceAwsIamSamlProviderRead(d, meta)
+}
+
+func resourceAwsIamSamlProviderDelete(d *schema.ResourceData, meta interface{}) error {
+ iamconn := meta.(*AWSClient).iamconn
+
+ input := &iam.DeleteSAMLProviderInput{
+ SAMLProviderArn: aws.String(d.Id()),
+ }
+ _, err := iamconn.DeleteSAMLProvider(input)
+
+ return err
+}
diff --git a/builtin/providers/aws/resource_aws_iam_saml_provider_test.go b/builtin/providers/aws/resource_aws_iam_saml_provider_test.go
new file mode 100644
index 000000000..63ed39588
--- /dev/null
+++ b/builtin/providers/aws/resource_aws_iam_saml_provider_test.go
@@ -0,0 +1,79 @@
+package aws
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/aws/aws-sdk-go/aws"
+ "github.com/aws/aws-sdk-go/service/iam"
+ "github.com/hashicorp/terraform/helper/resource"
+ "github.com/hashicorp/terraform/terraform"
+)
+
+func TestAccAWSIAMSamlProvider_basic(t *testing.T) {
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ CheckDestroy: testAccCheckIAMSamlProviderDestroy,
+ Steps: []resource.TestStep{
+ resource.TestStep{
+ Config: testAccIAMSamlProviderConfig,
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckIAMSamlProvider("aws_iam_saml_provider.salesforce"),
+ ),
+ },
+ resource.TestStep{
+ Config: testAccIAMSamlProviderConfigUpdate,
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckIAMSamlProvider("aws_iam_saml_provider.salesforce"),
+ ),
+ },
+ },
+ })
+}
+
+func testAccCheckIAMSamlProviderDestroy(s *terraform.State) error {
+ if len(s.RootModule().Resources) > 0 {
+ return fmt.Errorf("Expected all resources to be gone, but found: %#v", s.RootModule().Resources)
+ }
+
+ return nil
+}
+
+func testAccCheckIAMSamlProvider(id string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ rs, ok := s.RootModule().Resources[id]
+ if !ok {
+ return fmt.Errorf("Not Found: %s", id)
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("No ID is set")
+ }
+
+ iamconn := testAccProvider.Meta().(*AWSClient).iamconn
+ _, err := iamconn.GetSAMLProvider(&iam.GetSAMLProviderInput{
+ SAMLProviderArn: aws.String(rs.Primary.ID),
+ })
+
+ if err != nil {
+ return err
+ }
+
+ return nil
+ }
+}
+
+const testAccIAMSamlProviderConfig = `
+resource "aws_iam_saml_provider" "salesforce" {
+ name = "tf-salesforce-test"
+ saml_metadata_document = "${file("./test-fixtures/saml-metadata.xml")}"
+}
+`
+
+const testAccIAMSamlProviderConfigUpdate = `
+resource "aws_iam_saml_provider" "salesforce" {
+ name = "tf-salesforce-test"
+ saml_metadata_document = "${file("./test-fixtures/saml-metadata-modified.xml")}"
+}
+`
diff --git a/builtin/providers/aws/test-fixtures/saml-metadata-modified.xml b/builtin/providers/aws/test-fixtures/saml-metadata-modified.xml
new file mode 100644
index 000000000..aaca7afc0
--- /dev/null
+++ b/builtin/providers/aws/test-fixtures/saml-metadata-modified.xml
@@ -0,0 +1,14 @@
+