diff --git a/azurerm/data_source_sql_server.go b/azurerm/data_source_sql_server.go index f90fabcfac02..c5e28b9ecd49 100644 --- a/azurerm/data_source_sql_server.go +++ b/azurerm/data_source_sql_server.go @@ -47,6 +47,27 @@ func dataSourceSqlServer() *schema.Resource { Computed: true, }, + "identity": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Computed: true, + }, + "principal_id": { + Type: schema.TypeString, + Computed: true, + }, + "tenant_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "tags": tags.SchemaDataSource(), }, } @@ -83,5 +104,9 @@ func dataSourceArmSqlServerRead(d *schema.ResourceData, meta interface{}) error d.Set("administrator_login", props.AdministratorLogin) } + if err := d.Set("identity", flattenAzureRmSqlServerIdentity(resp.Identity)); err != nil { + return fmt.Errorf("Error setting `identity`: %+v", err) + } + return tags.FlattenAndSet(d, resp.Tags) } diff --git a/azurerm/resource_arm_sql_server.go b/azurerm/resource_arm_sql_server.go index 4a0ad1dec02a..97e87ead26e8 100644 --- a/azurerm/resource_arm_sql_server.go +++ b/azurerm/resource_arm_sql_server.go @@ -74,6 +74,31 @@ func resourceArmSqlServer() *schema.Resource { Computed: true, }, + "identity": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "SystemAssigned", + }, false), + }, + "principal_id": { + Type: schema.TypeString, + Computed: true, + }, + "tenant_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "tags": tags.Schema(), }, } @@ -115,6 +140,11 @@ func resourceArmSqlServerCreateUpdate(d *schema.ResourceData, meta interface{}) }, } + if _, ok := d.GetOk("identity"); ok { + sqlServerIdentity := expandAzureRmSqlServerIdentity(d) + parameters.Identity = sqlServerIdentity + } + if d.HasChange("administrator_login_password") { adminPassword := d.Get("administrator_login_password").(string) parameters.ServerProperties.AdministratorLoginPassword = utils.String(adminPassword) @@ -173,6 +203,10 @@ func resourceArmSqlServerRead(d *schema.ResourceData, meta interface{}) error { d.Set("location", azure.NormalizeLocation(*location)) } + if err := d.Set("identity", flattenAzureRmSqlServerIdentity(resp.Identity)); err != nil { + return fmt.Errorf("Error setting `identity`: %+v", err) + } + if serverProperties := resp.ServerProperties; serverProperties != nil { d.Set("version", serverProperties.Version) d.Set("administrator_login", serverProperties.AdministratorLogin) @@ -202,3 +236,30 @@ func resourceArmSqlServerDelete(d *schema.ResourceData, meta interface{}) error return future.WaitForCompletionRef(ctx, client.Client) } + +func expandAzureRmSqlServerIdentity(d *schema.ResourceData) *sql.ResourceIdentity { + identities := d.Get("identity").([]interface{}) + if len(identities) == 0 { + return &sql.ResourceIdentity{} + } + identity := identities[0].(map[string]interface{}) + identityType := sql.IdentityType(identity["type"].(string)) + return &sql.ResourceIdentity{ + Type: identityType, + } +} +func flattenAzureRmSqlServerIdentity(identity *sql.ResourceIdentity) []interface{} { + if identity == nil { + return []interface{}{} + } + result := make(map[string]interface{}) + result["type"] = identity.Type + if identity.PrincipalID != nil { + result["principal_id"] = identity.PrincipalID.String() + } + if identity.TenantID != nil { + result["tenant_id"] = identity.TenantID.String() + } + + return []interface{}{result} +} diff --git a/azurerm/resource_arm_sql_server_test.go b/azurerm/resource_arm_sql_server_test.go index eb35989e918a..a6a6f5308c2d 100644 --- a/azurerm/resource_arm_sql_server_test.go +++ b/azurerm/resource_arm_sql_server_test.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/terraform" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -120,6 +121,68 @@ func TestAccAzureRMSqlServer_withTags(t *testing.T) { }) } +func TestAccAzureRMSqlServer_withIdentity(t *testing.T) { + resourceName := "azurerm_sql_server.test" + ri := tf.AccRandTimeInt() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMSqlServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMSqlServer_withIdentity(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMSqlServerExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "identity.0.type", "SystemAssigned"), + resource.TestMatchResourceAttr(resourceName, "identity.0.principal_id", validate.UUIDRegExp), + resource.TestMatchResourceAttr(resourceName, "identity.0.tenant_id", validate.UUIDRegExp), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"administrator_login_password"}, + }, + }, + }) +} + +func TestAccAzureRMSqlServer_updateWithIdentityAdded(t *testing.T) { + resourceName := "azurerm_sql_server.test" + ri := tf.AccRandTimeInt() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMSqlServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMSqlServer_basic(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMSqlServerExists(resourceName), + ), + }, + { + Config: testAccAzureRMSqlServer_withIdentity(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMSqlServerExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "identity.0.type", "SystemAssigned"), + resource.TestMatchResourceAttr(resourceName, "identity.0.principal_id", validate.UUIDRegExp), + resource.TestMatchResourceAttr(resourceName, "identity.0.tenant_id", validate.UUIDRegExp), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"administrator_login_password"}, + }, + }, + }) +} + func testCheckAzureRMSqlServerExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { // Ensure we have enough information in state to look up in API @@ -276,3 +339,25 @@ resource "azurerm_sql_server" "test" { } `, rInt, location, rInt) } + +func testAccAzureRMSqlServer_withIdentity(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_sql_server" "test" { + name = "acctestsqlserver%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + version = "12.0" + administrator_login = "mradministrator" + administrator_login_password = "thisIsDog11" + + identity { + type = "SystemAssigned" + } +} +`, rInt, location, rInt) +} diff --git a/website/docs/d/sql_server.html.markdown b/website/docs/d/sql_server.html.markdown index a3bfffc0f469..3152d3493b7e 100644 --- a/website/docs/d/sql_server.html.markdown +++ b/website/docs/d/sql_server.html.markdown @@ -39,4 +39,16 @@ output "sql_server_id" { * `administrator_login` - The administrator username of the SQL Server. +* `identity` - An `identity` block as defined below. + * `tags` - A mapping of tags assigned to the resource. + +--- + +An `identity` block exports the following: + +* `principal_id` - The ID of the Principal (Client) in Azure Active Directory. + +* `tenant_id` - The ID of the Azure Active Directory Tenant. + +* `type` - The identity type of the SQL Server. diff --git a/website/docs/r/sql_server.html.markdown b/website/docs/r/sql_server.html.markdown index 667ab98af211..238d2b3b8bfa 100644 --- a/website/docs/r/sql_server.html.markdown +++ b/website/docs/r/sql_server.html.markdown @@ -51,8 +51,18 @@ The following arguments are supported: * `administrator_login_password` - (Required) The password associated with the `administrator_login` user. Needs to comply with Azure's [Password Policy](https://msdn.microsoft.com/library/ms161959.aspx) +* `identity` - (Optional) An `identity` block as defined below. + * `tags` - (Optional) A mapping of tags to assign to the resource. +--- + +An `identity` block supports the following: + +* `type` - (Required) Specifies the identity type of the SQL Server. At this time the only allowed value is `SystemAssigned`. + +~> **NOTE:** The assigned `principal_id` and `tenant_id` can be retrieved after the identity `type` has been set to `SystemAssigned` and the SQL Server has been created. More details are available below. + ## Attributes Reference The following attributes are exported: @@ -60,6 +70,16 @@ The following attributes are exported: * `id` - The SQL Server ID. * `fully_qualified_domain_name` - The fully qualified domain name of the Azure SQL Server (e.g. myServerName.database.windows.net) +--- + +`identity` exports the following: + +* `principal_id` - The Principal ID for the Service Principal associated with the Identity of this SQL Server. + +* `tenant_id` - The Tenant ID for the Service Principal associated with the Identity of this SQL Server. + +-> You can access the Principal ID via `${azurerm_sql_server.test.identity.0.principal_id}` and the Tenant ID via `${azurerm_sql_server.test.identity.0.tenant_id}` + ## Import SQL Servers can be imported using the `resource id`, e.g.