簡體   English   中英

從守護程序創建新的Azure SQL Server

[英]Creating New Azure SQL Server From Daemon

如何使用Azure SDK從守護程序(技術上是隊列處理器)在資源組內創建新的Azure SQL Server? 我遇到的問題是嘗試執行創建時的授權錯誤。 這是例外:

Hyak.Common.CloudException AuthorizationFailed:對象ID為“ XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX”的客戶端“ XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXX”沒有執行操作“ Microsoft.Sql /服務器/寫入”的權限范圍'/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/{myResourceGroupName}/providers/Microsoft.Sql/servers/{newServerName}”。

(實際的異常在每個占位符中都有實際值。)

我正在使用Microsoft.Azure.Management.Sql NuGet程序包,版本0.38.0-prerelease(當前最新可用)。

我以前曾嘗試使用CertificateCloudCredentials進行更改-但是它產生了以下異常:

Hyak.Common.CloudException AuthenticationFailed:身份驗證失敗。 “授權”標頭不存在或格式無效。

現在,我使用TokenCloudCredentials ,它是通過以下方式獲得的:

AuthenticationContext aContext = new AuthenticationContext(string.Format(
            anApiConfiguration.LoginUriFormat,
            anApiConfiguration.TenantId));
ClientCredential aClientCredential = new ClientCredential(
            anApiConfiguration.ClientId, 
            anApiConfiguration.ClientSecretKey);
AuthenticationResult aTokenResponse = await aContext.AcquireTokenAsync(
            anApiConfiguration.BaseResourceUrl, 
            aClientCredential);

由此,我成功獲得了令牌。 然后,我按如下方式使用該令牌:

SqlManagementClient sql = new SqlManagementClient(anAuthToken);
ServerCreateOrUpdateProperties someProperties = 
    new ServerCreateOrUpdateProperties {
        AdministratorLogin = someSettings.AdminAccountName,
        AdministratorLoginPassword = someSettings.AdminPassword,
        Version = "12.0"
};
ServerGetResponse aCreateResponse = 
    await sql.Servers.CreateOrUpdateAsync(
        someSettings.GetResourceGroup(aRegionType),
        aServerName, 
        new ServerCreateOrUpdateParameters(someProperties, aRegion));

最后一行,即CreateOrUpdateAsync調用,是在本文頂部產生異常的原因。

在Azure Active Directory中,客戶端應用程序被授予Windows Azure Service Management API應用程序中的Access Azure服務管理(預覽)委托權限(該應用程序存在的唯一一種權限)。 (如果有關系,我還向客戶端應用程序授予了Windows Azure Active Directory應用程序的所有可用權限。)

我想我已經弄清楚了問題所在以及如何解決(我也能夠在工作計算機上重現此問題)。

原因

看起來在示例應用程序中,獲取身份驗證令牌的默認方法是使用錯誤的帳戶。 例如,我的訂閱和應用程序在我的example@outlook.com電子郵件帳戶下,但是當我從工作計算機運行控制台應用程序時,該應用程序獲得了username@company.com的令牌,並嘗試在該帳戶下執行操作。 似乎獲取身份驗證令牌的代碼正在使用某些來自計算機(IE?)的緩存帳戶信息。

您看到的錯誤消息與RBAC(基於角色的訪問控制)有關,該RBAC限制了經過身份驗證但未經授權的帳戶對您的資源執行操作( https://azure.microsoft.com/en-us/documentation/articles/role-based-訪問控制配置/ )。

您可以稍微更改一下代碼,以告知執行操作時使用哪個帳戶。 在示例應用程序中,將“ GetAccessTokenUsingUserCredentials”方法更改為如下所示:

    private static AuthenticationResult GetAccessTokenUsingUserCredentials(UserCredential userCredential)
    {
        AuthenticationContext authContext = new AuthenticationContext
            ("https://login.windows.net/" /* AAD URI */
            + "YOU.onmicrosoft.com" /* Tenant ID or AAD domain */);

        AuthenticationResult token = authContext.AcquireToken(
            "https://management.azure.com/"/* the Azure Resource Management endpoint */,
            "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" /* application client ID from AAD*/,
            new Uri("XXXX" /* redirect URI */,
            PromptBehavior.Auto,
            new UserIdentifier(userCredential.UserName, UserIdentifierType.RequiredDisplayableId));

        return token;
    }

在主函數中,將獲得令牌的行更改為:

        var token = GetAccessTokenUsingUserCredentials(new UserCredential("<desired_account_email>"));

您應該可以對其進行一些修改,以便也輸入密碼,這樣就不會彈出AAD登錄框。

希望對您有用!

編輯:這是如何使它適用於Web應用程序:

  1. 從Web應用程序的“配置”頁面獲取客戶端ID和密鑰(您需要選擇密鑰的持續時間,然后單擊“保存”以生成密鑰)
  2. 在應用程序中更改身份驗證代碼,如下所示:

     private static AuthenticationResult GetAccessTokenForWebApp() { AuthenticationContext authContext = new AuthenticationContext ("https://login.windows.net/" /* AAD URI */ + "YOU.onmicrosoft.com" /* Tenant ID or AAD domain */); ClientCredential cc = new ClientCredential("<client_id>", "<key>"); AuthenticationResult token = authContext.AcquireToken( "https://management.azure.com/"/* the Azure Resource Management endpoint */, cc); return token; } 
  3. 在這一點上,如果您嘗試運行該應用程序,將收到一個類似於以下內容的身份驗證錯誤:

Hyak.Common.CloudException AuthorizationFailed:對象ID為“ XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX”的客戶端“ XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXXXX”沒有執行操作“ Microsoft.Sql /服務器/寫入”的權限范圍'/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/{myResourceGroupName}/providers/Microsoft.Sql/servers/{newServerName}”。

這是因為您需要為應用程序/服務主體添加RBAC角色。 從錯誤消息中,您需要復制“對象ID”,這是將用於角色分配的AD對象ID。

  1. 獲取適用於Windows Azure的最新Powershell cmdlet: http : //azure.microsoft.com/zh-cn/downloads/
  2. 一旦安裝了powershell,請運行以下命令:

     Switch-AzureMode AzureResourceManager #_this will be deprecated soon_ Add-AzureAccount # you will be prompted for your credentials New-AzureRoleAssignment -ObjectId <your_object_id> -RoleDefinitionName <role_name> # You can use "Contributor" to give the web app access to basically everything. # You can look in portal.azure.com for the roles that are available 
    1. 當上述運行時,您應該看到輸出,該對象ID已添加到角色中。

您的Web應用程序現在應該可以運行了!

一些獎勵閱讀:

對於服務主體/應用程序登錄: http : //azure.microsoft.com/zh-cn/documentation/articles/resource-group-authenticate-service-principal/

對於代表登錄: https : //msdn.microsoft.com/zh-cn/library/azure/dn790557.aspx

我編寫了一個控制台應用程序來測試各種情況。 盡管我需要嘗試更多的情況,但在這一點上,只有兩個我成功了:

  • 具有ClientId_RedirectUri_PromptBehavior的NativeClientApp
  • 帶有ClientId_RedirectUri_PromptBehavior_UserIdentifier的NativeClientApp

如果您有興趣,請參見下面的源代碼。 另外,我現在僅測試資源組的創建,因為這比創建Sql Server實例要少得多。 兩者似乎都產生相同的錯誤。

初步結果

結果輸出顯示案例,結果和繼續的提示。

WebApp with ClientCertificate
The method or operation is not implemented.
Press any key to continue.

WebApp with ClientAssertion
The method or operation is not implemented.
Press any key to continue.

WebApp with ClientCredential
AuthorizationFailed: The client '7a31a564-20ba-4ac1-a2ee-4f5e35a70dcc' with object id '7a31a564-20ba-4ac1-a2ee-4f5e35a70dcc' does not have authorization to perform action 'Microsoft.Resources/subscriptions/resourcegroups/write' ov
er scope '/subscriptions/14929cfc-3501-48cf-a5c9-b24a7daaf694/resourcegroups/MY_RESOURCE_GROUP_NAME635776010237527878'.
Press any key to continue.

WebApp with ClientId_UserAssertion
The method or operation is not implemented.
Press any key to continue.

WebApp with ClientCredential_UserAssertion
AADSTS50027: Invalid JWT token. AADSTS50027: Invalid JWT token. Token format not valid.
Trace ID: a64f0683-23ae-4461-8546-55293f7ff1d3
Correlation ID: 62cc80e9-f013-4a74-8031-3294e69d4478
Timestamp: 2015-09-12 03:43:57Z
Press any key to continue.

WebApp with ClientAssertion_UserAssertion
The method or operation is not implemented.
Press any key to continue.

WebApp with ClientCertificate_UserAssertion
The method or operation is not implemented.
Press any key to continue.

WebApp with ClientId_RedirectUri
The method or operation is not implemented.
Press any key to continue.

WebApp with ClientId_UserCredential
missing_federation_metadata_url: Federation Metadata Url is missing for federated user. This user type is unsupported.
Press any key to continue.

WebApp with ClientId_RedirectUri_PromptBehavior
AADSTS90014: The request body must contain the following parameter: 'client_secret or client_assertion'.
Trace ID: 06fde160-bd2b-4f16-b49e-0f0ff8e17f48
Correlation ID: baabb83f-cebb-48ba-b2be-1efb53ec3121
Timestamp: 2015-09-12 03:44:21Z
Press any key to continue.

WebApp with ClientId_RedirectUri_PromptBehavior_UserIdentifier
AADSTS90014: The request body must contain the following parameter: 'client_secret or client_assertion'.
Trace ID: 6110ef02-a6b0-4e41-b0e5-db97b13c66ce
Correlation ID: e6f6526a-8395-480a-8ac7-b75903b324d9
Timestamp: 2015-09-12 03:44:30Z
Press any key to continue.

WebApp with ClientId_RedirectUri_PromptBehavior_UserIdentifier_ExtraQueryParams
The method or operation is not implemented.
Press any key to continue.

NativeClientApp with ClientCertificate
The method or operation is not implemented.
Press any key to continue.

NativeClientApp with ClientAssertion
The method or operation is not implemented.
Press any key to continue.

NativeClientApp with ClientCredential
Value cannot be null.
Parameter name: clientSecret
Press any key to continue.

NativeClientApp with ClientId_UserAssertion
The method or operation is not implemented.
Press any key to continue.

NativeClientApp with ClientCredential_UserAssertion
Value cannot be null.
Parameter name: clientSecret
Press any key to continue.

NativeClientApp with ClientAssertion_UserAssertion
The method or operation is not implemented.
Press any key to continue.

NativeClientApp with ClientCertificate_UserAssertion
The method or operation is not implemented.
Press any key to continue.

NativeClientApp with ClientId_RedirectUri
The method or operation is not implemented.
Press any key to continue.

NativeClientApp with ClientId_UserCredential
missing_federation_metadata_url: Federation Metadata Url is missing for federated user. This user type is unsupported.
Press any key to continue.

NativeClientApp with ClientId_RedirectUri_PromptBehavior
Success! Created MY_RESOURCE_GROUP_NAME635776011040240760
Press any key to continue.

NativeClientApp with ClientId_RedirectUri_PromptBehavior_UserIdentifier
Success! Created MY_RESOURCE_GROUP_NAME635776011079693849
Press any key to continue.

NativeClientApp with ClientId_RedirectUri_PromptBehavior_UserIdentifier_ExtraQueryParams
The method or operation is not implemented.
Press any key to continue.

Testing complete.:)

Program.cs中

using System;
using Microsoft.Azure;
using Microsoft.Azure.Management.Resources;
using Microsoft.Azure.Management.Resources.Models;
using Microsoft.Azure.Management.Sql;
using Microsoft.Azure.Management.Sql.Models;
using Microsoft.IdentityModel.Clients.ActiveDirectory;

namespace CreateNewAzureSQLServer
{
    class Program
    {
        private static string

            domain = "MY_DOMAIN.onmicrosoft.com",
            resource = "https://management.azure.com/",
            subscriptionId = "xxxxx-xxxxx-xxxxx-xxxxx",

            // web
            clientId_web = "xxxxx-xxxxx-xxxxx-xxxxx",
            clientSecret_web = "xxxxx=",
            redirectUri_web = "http://myWebApp",

            // native
            clientId_native = "xxxxx-xxxxx-xxxxx-xxxxx",
            clientSecret_native = string.Empty,
            redirectUri_native = "http://myNativeClientApp",

            // adminstrator
            userName = "MY_USERNAME",
            userPassword = "MY_PASSWORD",

            // create
            adminAccountName = "MY_ADMIN_ACCOUNT_NAME",
            adminAccountPwd = "MY_ACCOUNT_ADMIN_PWD",
            resourceGroupName = "MY_RESOURCE_GROUP_NAME",
            serverName = "MY_SERVER_NAME",
            location = "West US";

        private static AuthenticationResult GetAccessToken(
            string clientId, string redirectUri, string clientSecret, AuthType type)
        {
            var authority = "https://login.windows.net/" + domain;
            var authContext = new AuthenticationContext(authority);
            authContext.TokenCache.Clear();
            AuthenticationResult token = null;

            switch (type)
            {
                case AuthType.ClientCertificate:
                    throw new NotImplementedException();
                    break;

                case AuthType.ClientAssertion:
                    throw new NotImplementedException();
                    break;

                case AuthType.ClientCredential:                       
                    token = authContext.AcquireToken(resource,
                        new ClientCredential(clientId, clientSecret));
                    break;

                case AuthType.ClientId_UserAssertion:
                    throw new NotImplementedException();
                    break;

                case AuthType.ClientCredential_UserAssertion:
                    token = authContext.AcquireToken(resource,
                        new ClientCredential(clientId, clientSecret),
                        new UserAssertion(userPassword, "username", userName));
                    break;

                case AuthType.ClientAssertion_UserAssertion:
                    throw new NotImplementedException();
                    break;

                case AuthType.ClientCertificate_UserAssertion:
                    throw new NotImplementedException();
                    break;

                case AuthType.ClientId_RedirectUri:
                    throw new NotImplementedException();
                    break;

                case AuthType.ClientId_UserCredential:
                    token = authContext.AcquireToken(resource,
                        clientId,
                        new UserCredential(userName, userPassword));
                    break;

                case AuthType.ClientId_RedirectUri_PromptBehavior:
                    token = authContext.AcquireToken(resource,
                        clientId,
                        new Uri(redirectUri),
                        PromptBehavior.Auto);
                    break;

                case AuthType.ClientId_RedirectUri_PromptBehavior_UserIdentifier:                        
                    var cred = new UserCredential(userName);
                    token = authContext.AcquireToken(resource,
                        clientId,
                        new Uri(redirectUri),
                        PromptBehavior.Auto,
                        new UserIdentifier(cred.UserName, UserIdentifierType.RequiredDisplayableId));
                    break;

                case AuthType.ClientId_RedirectUri_PromptBehavior_UserIdentifier_ExtraQueryParams:
                    throw new NotImplementedException();
                    break;

                default:
                    break;
            };

            return token;
        }

        static void CreateSqlServer(TokenCloudCredentials creds)
        {
            var client = new SqlManagementClient(creds);
            var someProperties = new ServerCreateOrUpdateProperties
            {
                AdministratorLogin = adminAccountName,
                AdministratorLoginPassword = adminAccountPwd,
                Version = "12"
            };

            var parameters = new ServerCreateOrUpdateParameters(someProperties, location);
            ServerGetResponse aCreateResponse
                = client.Servers.CreateOrUpdate(resourceGroupName, serverName, parameters);
        }

        static string CreateResourceGroup(TokenCloudCredentials creds)
        {
            var uniqueResourceGroupName = resourceGroupName + DateTime.Now.Ticks.ToString();
            var resourceClient = new ResourceManagementClient(creds);
            var resourceGroupParameters = new ResourceGroup()
            {
                Location = location
            };
            var resourceGroupResult = resourceClient
                .ResourceGroups
                .CreateOrUpdate(uniqueResourceGroupName, resourceGroupParameters);

            return uniqueResourceGroupName;
        }

        static void Main(string[] args)
        {
            foreach (AppType appType in Enum.GetValues(typeof(AppType)))
            {
                var clientId = appType == AppType.WebApp ? clientId_web : clientId_native;
                var clientSecret = appType == AppType.WebApp ? clientSecret_web : clientSecret_native;
                var redirectUri = appType == AppType.WebApp ? redirectUri_web : redirectUri_native;

                foreach (AuthType authType in Enum.GetValues(typeof(AuthType)))
                {
                    try
                    {
                        Console.WriteLine(appType.ToString() + " with " + authType.ToString());
                        var token = GetAccessToken(clientId, redirectUri, clientSecret, authType);
                        var creds = new TokenCloudCredentials(subscriptionId, token.AccessToken);
                        var resourceGroupName = CreateResourceGroup(creds);
                        Console.WriteLine("Success! Created " + resourceGroupName);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }

                    Console.WriteLine("Press any key to continue.");
                    Console.ReadLine();
                }
            }

            Console.WriteLine("Testing complete.:)");
            Console.ReadLine();

            //CreateSqlServer(creds);
        }

        enum AppType
        {
            WebApp,
            NativeClientApp
        }

        enum AuthType
        {
            ClientCertificate,
            ClientAssertion,
            ClientCredential,
            ClientId_UserAssertion,
            ClientCredential_UserAssertion,
            ClientAssertion_UserAssertion,
            ClientCertificate_UserAssertion,
            ClientId_RedirectUri,
            ClientId_UserCredential,
            ClientId_RedirectUri_PromptBehavior,
            ClientId_RedirectUri_PromptBehavior_UserIdentifier,
            ClientId_RedirectUri_PromptBehavior_UserIdentifier_ExtraQueryParams
        }
    }
}

packages.config

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Hyak.Common" version="1.0.2" targetFramework="net452" />
  <package id="Microsoft.Azure.Common" version="2.1.0" targetFramework="net452" />
  <package id="Microsoft.Azure.Common.Authentication" version="1.1.5-preview" targetFramework="net452" />
  <package id="Microsoft.Azure.Common.Dependencies" version="1.0.0" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.Resources" version="2.18.7-preview" targetFramework="net452" />
  <package id="Microsoft.Azure.Management.Sql" version="0.38.0-prerelease" targetFramework="net452" />
  <package id="Microsoft.Bcl" version="1.1.9" targetFramework="net452" />
  <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net452" />
  <package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net452" />
  <package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="2.18.206251556" targetFramework="net452" />
  <package id="Microsoft.Net.Http" version="2.2.22" targetFramework="net452" />
  <package id="Microsoft.Rest.ClientRuntime" version="1.2.0" targetFramework="net452" />
  <package id="Microsoft.Rest.ClientRuntime.Azure.Authentication" version="0.9.3" targetFramework="net452" />
  <package id="Newtonsoft.Json" version="6.0.4" targetFramework="net452" />
</packages>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM