From 349e2bff11ead4d6dd33ba82b0a259291823ca61 Mon Sep 17 00:00:00 2001 From: Aris van Ommeren Date: Fri, 12 Nov 2021 17:10:45 +0100 Subject: [PATCH 1/2] `azurerm_sql_active_directory_administrator` - Support for `azuread_authentication_only` --- internal/services/sql/client/client.go | 10 ++- .../sql/sql_administrator_resource.go | 58 ++++++++++++++-- .../sql/sql_administrator_resource_test.go | 66 +++++++++++++++++++ 3 files changed, 126 insertions(+), 8 deletions(-) diff --git a/internal/services/sql/client/client.go b/internal/services/sql/client/client.go index d74aaa3c58cb..9c8d0617b1c2 100644 --- a/internal/services/sql/client/client.go +++ b/internal/services/sql/client/client.go @@ -3,6 +3,7 @@ package client import ( "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/2017-03-01-preview/sql" msi "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/2018-06-01-preview/sql" + aadAdmin "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v5.0/sql" "github.com/hashicorp/terraform-provider-azurerm/internal/common" ) @@ -18,7 +19,8 @@ type Client struct { ServersClient *sql.ServersClient ServerExtendedBlobAuditingPoliciesClient *sql.ExtendedServerBlobAuditingPoliciesClient ServerConnectionPoliciesClient *sql.ServerConnectionPoliciesClient - ServerAzureADAdministratorsClient *sql.ServerAzureADAdministratorsClient + ServerAzureADAdministratorsClient *aadAdmin.ServerAzureADAdministratorsClient + ServerAzureADOnlyAuthenticationsClient *aadAdmin.ServerAzureADOnlyAuthenticationsClient ServerSecurityAlertPoliciesClient *sql.ServerSecurityAlertPoliciesClient VirtualNetworkRulesClient *sql.VirtualNetworkRulesClient } @@ -55,9 +57,12 @@ func NewClient(o *common.ClientOptions) *Client { serverConnectionPoliciesClient := sql.NewServerConnectionPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&serverConnectionPoliciesClient.Client, o.ResourceManagerAuthorizer) - serverAzureADAdministratorsClient := sql.NewServerAzureADAdministratorsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + serverAzureADAdministratorsClient := aadAdmin.NewServerAzureADAdministratorsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&serverAzureADAdministratorsClient.Client, o.ResourceManagerAuthorizer) + serverAzureADOnlyAuthenticationsClient := aadAdmin.NewServerAzureADOnlyAuthenticationsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&serverAzureADOnlyAuthenticationsClient.Client, o.ResourceManagerAuthorizer) + virtualNetworkRulesClient := sql.NewVirtualNetworkRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&virtualNetworkRulesClient.Client, o.ResourceManagerAuthorizer) @@ -78,6 +83,7 @@ func NewClient(o *common.ClientOptions) *Client { ManagedDatabasesClient: &managedDatabasesClient, ServersClient: &serversClient, ServerAzureADAdministratorsClient: &serverAzureADAdministratorsClient, + ServerAzureADOnlyAuthenticationsClient: &serverAzureADOnlyAuthenticationsClient, ServerConnectionPoliciesClient: &serverConnectionPoliciesClient, ServerExtendedBlobAuditingPoliciesClient: &serverExtendedBlobAuditingPoliciesClient, ServerSecurityAlertPoliciesClient: &serverSecurityAlertPoliciesClient, diff --git a/internal/services/sql/sql_administrator_resource.go b/internal/services/sql/sql_administrator_resource.go index b6a005c0ae9e..0a8af6edfbe5 100644 --- a/internal/services/sql/sql_administrator_resource.go +++ b/internal/services/sql/sql_administrator_resource.go @@ -3,9 +3,10 @@ package sql import ( "fmt" "log" + "net/http" "time" - "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/2017-03-01-preview/sql" + "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v5.0/sql" "github.com/gofrs/uuid" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" @@ -58,12 +59,19 @@ func resourceSqlAdministrator() *pluginsdk.Resource { Required: true, ValidateFunc: validation.IsUUID, }, + + "azuread_authentication_only": { + Type: pluginsdk.TypeBool, + Optional: true, + Computed: true, + }, }, } } func resourceSqlActiveDirectoryAdministratorCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Sql.ServerAzureADAdministratorsClient + aadOnlyAuthentictionsClient := meta.(*clients.Client).Sql.ServerAzureADOnlyAuthenticationsClient ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -86,8 +94,18 @@ func resourceSqlActiveDirectoryAdministratorCreateUpdate(d *pluginsdk.ResourceDa } } + aadOnlyDeleteFuture, err := aadOnlyAuthentictionsClient.Delete(ctx, resGroup, serverName) + if err != nil { + if aadOnlyDeleteFuture.Response() == nil || aadOnlyDeleteFuture.Response().StatusCode != http.StatusBadRequest { + return fmt.Errorf("deleting AD Only Authentications AAD Administrator (Server %q / Resource Group %q): %+v", serverName, resGroup, err) + } + log.Printf("[INFO] AD Only Authentication is not removed as AD Admin is not set for AAD Administrator (Server %q / Resource Group %q): %+v", serverName, resGroup, err) + } else if err = aadOnlyDeleteFuture.WaitForCompletionRef(ctx, aadOnlyAuthentictionsClient.Client); err != nil { + return fmt.Errorf("waiting for deletion of AD Only Authentications for AAD Administrator (Server %q / Resource Group %q): %+v", serverName, resGroup, err) + } + parameters := sql.ServerAzureADAdministrator{ - ServerAdministratorProperties: &sql.ServerAdministratorProperties{ + AdministratorProperties: &sql.AdministratorProperties{ AdministratorType: utils.String("ActiveDirectory"), Login: utils.String(login), Sid: &objectId, @@ -104,6 +122,22 @@ func resourceSqlActiveDirectoryAdministratorCreateUpdate(d *pluginsdk.ResourceDa return fmt.Errorf("waiting for creation/update of AAD Administrator (Server %q / Resource Group %q): %+v", serverName, resGroup, err) } + if aadOnlyAuthentictionsEnabled, ok := d.GetOk("azuread_authentication_only"); ok && aadOnlyAuthentictionsEnabled != nil && aadOnlyAuthentictionsEnabled.(bool) { + aadOnlyAuthentictionsParams := sql.ServerAzureADOnlyAuthentication{ + AzureADOnlyAuthProperties: &sql.AzureADOnlyAuthProperties{ + AzureADOnlyAuthentication: utils.Bool(aadOnlyAuthentictionsEnabled.(bool)), + }, + } + aadOnlyEnabledFuture, err := aadOnlyAuthentictionsClient.CreateOrUpdate(ctx, resGroup, serverName, aadOnlyAuthentictionsParams) + if err != nil { + return fmt.Errorf("setting AAD only authentication for SQL Administrator (Server %q / Resource Group %q): %+v", serverName, resGroup, err) + } + + if err = aadOnlyEnabledFuture.WaitForCompletionRef(ctx, aadOnlyAuthentictionsClient.Client); err != nil { + return fmt.Errorf("waiting for setting of AAD only authentication for SQL Administrator (Server %q / Resource Group %q): %+v", serverName, resGroup, err) + } + } + resp, err := client.Get(ctx, resGroup, serverName) if err != nil { return fmt.Errorf("retrieving SQL Administrator (Resource Group %q, Server %q): %+v", resGroup, serverName, err) @@ -126,12 +160,12 @@ func resourceSqlActiveDirectoryAdministratorRead(d *pluginsdk.ResourceData, meta resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName) if err != nil { if utils.ResponseWasNotFound(resp.Response) { - log.Printf("[INFO] AAD Administrator %q (Server %q / Resource Group %q) was not found - removing from state", id.AdministratorName, id.ServerName, id.ResourceGroup) + log.Printf("[INFO] %q not found - removing from state", id) d.SetId("") return nil } - return fmt.Errorf("retrieving AAD Administrator %q (Server %q / Resource Group %q): %+v", id.AdministratorName, id.ServerName, id.ResourceGroup, err) + return fmt.Errorf("retrieving %q: %+v", id, err) } d.Set("server_name", id.ServerName) @@ -140,12 +174,14 @@ func resourceSqlActiveDirectoryAdministratorRead(d *pluginsdk.ResourceData, meta d.Set("login", resp.Login) d.Set("object_id", resp.Sid.String()) d.Set("tenant_id", resp.TenantID.String()) + d.Set("azuread_authentication_only", resp.AzureADOnlyAuthentication) return nil } func resourceSqlActiveDirectoryAdministratorDelete(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Sql.ServerAzureADAdministratorsClient + aadOnlyAuthentictionsClient := meta.(*clients.Client).Sql.ServerAzureADOnlyAuthenticationsClient ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() @@ -154,12 +190,22 @@ func resourceSqlActiveDirectoryAdministratorDelete(d *pluginsdk.ResourceData, me return err } + aadOnlyDeleteFuture, err := aadOnlyAuthentictionsClient.Delete(ctx, id.ResourceGroup, id.ServerName) + if err != nil { + if aadOnlyDeleteFuture.Response() == nil || aadOnlyDeleteFuture.Response().StatusCode != http.StatusBadRequest { + return fmt.Errorf("deleting AD Only Authentications for %q: %+v", id, err) + } + log.Printf("[INFO] AD Only Authentication is not removed as AD Admin is not set for %q: %+v", id, err) + } else if err = aadOnlyDeleteFuture.WaitForCompletionRef(ctx, aadOnlyAuthentictionsClient.Client); err != nil { + return fmt.Errorf("waiting for deletion of AD Only Authentications for %q: %+v", id, err) + } + future, err := client.Delete(ctx, id.ResourceGroup, id.ServerName) if err != nil { - return fmt.Errorf("deleting AAD Administrator %q (Server %q / Resource Group %q): %+v", id.AdministratorName, id.ServerName, id.ResourceGroup, err) + return fmt.Errorf("deleting %q: %+v", id, err) } if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for deletion of AAD Administrator %q (Server %q / Resource Group %q): %+v", id.AdministratorName, id.ServerName, id.ResourceGroup, err) + return fmt.Errorf("waiting for deletion of %q: %+v", id, err) } return nil diff --git a/internal/services/sql/sql_administrator_resource_test.go b/internal/services/sql/sql_administrator_resource_test.go index 5aa105a53b8a..b66d3d7bd620 100644 --- a/internal/services/sql/sql_administrator_resource_test.go +++ b/internal/services/sql/sql_administrator_resource_test.go @@ -36,6 +36,38 @@ func TestAccSqlAdministrator_basic(t *testing.T) { ), }, data.ImportStep(), + { + Config: r.aadOnlyAuthEnabled(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("azuread_authentication_only").HasValue("true"), + ), + }, + data.ImportStep(), + }) +} + +func TestAccSqlAdministrator_aadOnlyAuth(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_sql_active_directory_administrator", "test") + r := SqlAdministratorResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.aadOnlyAuthEnabled(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("azuread_authentication_only").HasValue("true"), + ), + }, + data.ImportStep(), + { + Config: r.aadOnlyAuthEnabled(data, false), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("azuread_authentication_only").HasValue("false"), + ), + }, + data.ImportStep(), }) } @@ -173,3 +205,37 @@ resource "azurerm_sql_active_directory_administrator" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } + +func (r SqlAdministratorResource) aadOnlyAuthEnabled(data acceptance.TestData, enabled bool) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_client_config" "current" { +} + +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" +} + +resource "azurerm_sql_active_directory_administrator" "test" { + server_name = azurerm_sql_server.test.name + resource_group_name = azurerm_resource_group.test.name + login = "sqladmin" + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = data.azurerm_client_config.current.client_id + azuread_authentication_only = %t +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, enabled) +} From fc9ec53ee9dbc8eadeed252424d3d58c45561971 Mon Sep 17 00:00:00 2001 From: Aris van Ommeren Date: Mon, 15 Nov 2021 10:58:48 +0100 Subject: [PATCH 2/2] Docs --- website/docs/r/sql_active_directory_administrator.html.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/r/sql_active_directory_administrator.html.markdown b/website/docs/r/sql_active_directory_administrator.html.markdown index a06a3b7ae80b..a183d55f5ea2 100644 --- a/website/docs/r/sql_active_directory_administrator.html.markdown +++ b/website/docs/r/sql_active_directory_administrator.html.markdown @@ -52,6 +52,8 @@ The following arguments are supported: * `tenant_id` - (Required) The Azure Tenant ID +* `azuread_authentication_only` - (Optional) Specifies whether only AD Users and administrators can be used to login (`true`) or also local database users (`false`). + ## Attributes Reference The following attributes are exported: