如何使用 Pulumi 为 Web App 添加身份验证
How to add Authentiction to WebApp with Pulumi
我正在尝试向 Pulumi WebApp 添加身份验证提供程序,但我完全不清楚如何实现。包 @pulumi/azure-native/web
中的 class WebApp
仅提供 属性 identity
但没有 属性 分配,例如微软广告。谁能提供有关如何设置的提示?
有一些 Pulumi Azure pre-requisites 并在您的租户和 Azure 订阅中拥有适当的权限。
按照以下步骤使用 pulumi 将身份验证添加到应用程序服务 webapp 并部署:
正在创建项目:
首先创建应用程序,然后添加我们创建 Azure AD application registration.
所需的 AzureAD 包
pulumi new azure-csharp `
--name easyauth-webapp `
--description "azure ad secured app" `
--stack dev `
--config azure-native:location=eastus
dotnet add package Pulumi.AzureAD
接下来我们需要更新 pulumi.dev.yaml
文件的内容以包含一些额外的配置项。将以下内容粘贴到文件中:
config:
azure-native:location: eastus
azure-native:subscriptionId: UPDATE_ME
azure-native:tenantId: UPDATE_ME
easyauth-webapp:tenantId: UPDATE_ME
easyauth-webapp:ownerId: UPDATE_ME
easyauth-webapp:siteName: UPDATE_ME
easyauth-webapp:appRegistrationName: UPDATE_ME
您可以将 siteName
和 appRegistrationName
设置为您想要的任何值。
subscriptionId
和 tenantId
应分别设置为您的 Azure 应用服务和 Azure AD 应用程序注册的适当目标。
以下命令可能有助于检索这些值:
# Get your user's id
az ad signed-in-user show --query objectId
# List all subscriptions (and their tenant) that you have access to
az account list
部署网站(无安全):
接下来我们将创建我们要部署的网站。我们将使用 run from ZIP package 功能来部署 wwwroot
文件夹的内容。
创建该文件夹并向 index.htm
文件添加一些内容:
例如:
<!-- wwwroot/index.htm -->
<html>
<head>
<title>A very secure app</title>
</head>
<body>
Hello EasyAuth with Pulumi!
</body>
</html>
现在我们可以使用 Pulumi 将此文件部署到 Azure。
修改 MyStack.cs
文件以包含以下代码,该代码改编自 Pulumi Function Stack example:
// MyStack.cs
using System;
using Pulumi;
using Pulumi.AzureAD;
using Pulumi.AzureAD.Inputs;
using Pulumi.AzureNative.Resources;
using Pulumi.AzureNative.Storage;
using Pulumi.AzureNative.Storage.Inputs;
using Pulumi.AzureNative.Web;
using Pulumi.AzureNative.Web.Inputs;
class MyStack : Stack
{
public MyStack()
{
var config = new Pulumi.Config();
var tenantId = config.Require("tenantId");
var ownerId = config.Require("ownerId");
var siteName = config.Require("siteName");
var appRegistrationName = config.Require("appRegistrationName");
var rg = new ResourceGroup($"RG-{siteName}");
var storageAccount = new StorageAccount("storageaccount", new StorageAccountArgs
{
ResourceGroupName = rg.Name,
Kind = "StorageV2",
Sku = new SkuArgs
{
Name = SkuName.Standard_LRS,
},
});
var appServicePlan = new AppServicePlan("appserviceplan", new AppServicePlanArgs
{
ResourceGroupName = rg.Name,
Kind = "App",
Sku = new SkuDescriptionArgs
{
Tier = "Basic",
Name = "B1",
},
});
var container = new BlobContainer("zips", new BlobContainerArgs
{
AccountName = storageAccount.Name,
PublicAccess = PublicAccess.None,
ResourceGroupName = rg.Name,
});
var blob = new Blob("appservice-blob", new BlobArgs
{
ResourceGroupName = rg.Name,
AccountName = storageAccount.Name,
ContainerName = container.Name,
Type = BlobType.Block,
Source = new FileArchive("wwwroot"),
});
var codeBlobUrl = SignedBlobReadUrl(blob, container, storageAccount, rg);
var app = new WebApp("app", new WebAppArgs
{
Name = siteName,
ResourceGroupName = rg.Name,
ServerFarmId = appServicePlan.Id,
SiteConfig = new SiteConfigArgs
{
AppSettings = {
new NameValuePairArgs{
Name = "WEBSITE_RUN_FROM_PACKAGE",
Value = codeBlobUrl,
}
},
}
});
this.Endpoint = app.DefaultHostName;
}
// From https://github.com/pulumi/examples/blob/master/azure-cs-functions/FunctionsStack.cs
private static Output<string> SignedBlobReadUrl(Blob blob, BlobContainer container, StorageAccount account, ResourceGroup resourceGroup)
{
return Output.Tuple<string, string, string, string>(
blob.Name, container.Name, account.Name, resourceGroup.Name).Apply(t =>
{
(string blobName, string containerName, string accountName, string resourceGroupName) = t;
var blobSAS = ListStorageAccountServiceSAS.InvokeAsync(new ListStorageAccountServiceSASArgs
{
AccountName = accountName,
Protocols = HttpProtocol.Https,
SharedAccessStartTime = "2021-01-01",
SharedAccessExpiryTime = "2030-01-01",
Resource = SignedResource.C,
ResourceGroupName = resourceGroupName,
Permissions = Permissions.R,
CanonicalizedResource = "/blob/" + accountName + "/" + containerName,
ContentType = "application/json",
CacheControl = "max-age=5",
ContentDisposition = "inline",
ContentEncoding = "deflate",
});
return Output.Format($"https://{accountName}.blob.core.windows.net/{containerName}/{blobName}?{blobSAS.Result.ServiceSasToken}");
});
}
[Output] public Output<string> Endpoint { get; set; }
}
我们现在可以部署站点并验证它是否按预期工作:
pulumi up --stack dev
curl (pulumi stack --stack dev output Endpoint)
[
保护站点:
要配置 Easy Auth,我们首先创建一个 Azure AD 应用程序注册。
在此示例中,我指定 AzureADMyOrg
来限制对部署应用程序注册的租户的访问。我还添加了一个 RedirectUri
指向已部署站点的 Easy Auth 中间件。需要密码才能用作客户端密码(在这种情况下,Web 应用程序是客户端)。
创建应用程序注册后,我们可以将 WebAppAuthSettings 添加到我们的站点。该示例指定没有匿名访问(使用 RedirectToLoginPage
),并使用 ClientId
和 ClientSecret
(密码)将站点连接到应用程序注册。
将下面的代码粘贴到上面 MyStack.cs
中的 this.Endpoint...
代码之后:
// MyStack.cs
// After this.Endpoint = app.DefaultHostName;
var adApp = new Application("ADAppRegistration", new ApplicationArgs
{
DisplayName = appRegistrationName,
SignInAudience = "AzureADMyOrg",
Owners = new[] { ownerId },
Web = new ApplicationWebArgs
{
ImplicitGrant = new ApplicationWebImplicitGrantArgs
{
IdTokenIssuanceEnabled = true
},
RedirectUris = new System.Collections.Generic.List<string> { $"https://{siteName}.azurewebsites.net/.auth/login/aad/callback" }
}
}
);
var applicationPassword = new ApplicationPassword("appPassword", new ApplicationPasswordArgs
{
ApplicationObjectId = adApp.Id,
DisplayName = "Client secret for web app"
});
var allowedAudience = adApp.ApplicationId.Apply(id => $"api://{id}");
var authSettings = new WebAppAuthSettings("authSettings", new WebAppAuthSettingsArgs
{
ResourceGroupName = rg.Name,
Name = app.Name,
Enabled = true,
UnauthenticatedClientAction = UnauthenticatedClientAction.RedirectToLoginPage,
DefaultProvider = BuiltInAuthenticationProvider.AzureActiveDirectory,
ClientId = adApp.ApplicationId,
ClientSecret = applicationPassword.Value,
Issuer = $"https://sts.windows.net/{tenantId}/v2.0",
AllowedAudiences = new[] { allowedAudience },
});
我们现在可以更新站点,从命令行我们不能比这更进一步。
但在浏览器中,我们将被重定向以完成登录流程并访问该站点。
pulumi up --stack dev
# Redirect to HTTPS
curl (pulumi stack --stack dev output Endpoint)
# Access denied
curl "https://$(pulumi stack --stack dev output Endpoint)"
有关 pulumi 示例,请参考此 Github link。
我正在尝试向 Pulumi WebApp 添加身份验证提供程序,但我完全不清楚如何实现。包 @pulumi/azure-native/web
中的 class WebApp
仅提供 属性 identity
但没有 属性 分配,例如微软广告。谁能提供有关如何设置的提示?
有一些 Pulumi Azure pre-requisites 并在您的租户和 Azure 订阅中拥有适当的权限。
按照以下步骤使用 pulumi 将身份验证添加到应用程序服务 webapp 并部署:
正在创建项目:
首先创建应用程序,然后添加我们创建 Azure AD application registration.
所需的 AzureAD 包pulumi new azure-csharp `
--name easyauth-webapp `
--description "azure ad secured app" `
--stack dev `
--config azure-native:location=eastus
dotnet add package Pulumi.AzureAD
接下来我们需要更新 pulumi.dev.yaml
文件的内容以包含一些额外的配置项。将以下内容粘贴到文件中:
config:
azure-native:location: eastus
azure-native:subscriptionId: UPDATE_ME
azure-native:tenantId: UPDATE_ME
easyauth-webapp:tenantId: UPDATE_ME
easyauth-webapp:ownerId: UPDATE_ME
easyauth-webapp:siteName: UPDATE_ME
easyauth-webapp:appRegistrationName: UPDATE_ME
您可以将 siteName
和 appRegistrationName
设置为您想要的任何值。
subscriptionId
和 tenantId
应分别设置为您的 Azure 应用服务和 Azure AD 应用程序注册的适当目标。
以下命令可能有助于检索这些值:
# Get your user's id
az ad signed-in-user show --query objectId
# List all subscriptions (and their tenant) that you have access to
az account list
部署网站(无安全):
接下来我们将创建我们要部署的网站。我们将使用 run from ZIP package 功能来部署 wwwroot
文件夹的内容。
创建该文件夹并向 index.htm
文件添加一些内容:
例如:
<!-- wwwroot/index.htm -->
<html>
<head>
<title>A very secure app</title>
</head>
<body>
Hello EasyAuth with Pulumi!
</body>
</html>
现在我们可以使用 Pulumi 将此文件部署到 Azure。
修改 MyStack.cs
文件以包含以下代码,该代码改编自 Pulumi Function Stack example:
// MyStack.cs
using System;
using Pulumi;
using Pulumi.AzureAD;
using Pulumi.AzureAD.Inputs;
using Pulumi.AzureNative.Resources;
using Pulumi.AzureNative.Storage;
using Pulumi.AzureNative.Storage.Inputs;
using Pulumi.AzureNative.Web;
using Pulumi.AzureNative.Web.Inputs;
class MyStack : Stack
{
public MyStack()
{
var config = new Pulumi.Config();
var tenantId = config.Require("tenantId");
var ownerId = config.Require("ownerId");
var siteName = config.Require("siteName");
var appRegistrationName = config.Require("appRegistrationName");
var rg = new ResourceGroup($"RG-{siteName}");
var storageAccount = new StorageAccount("storageaccount", new StorageAccountArgs
{
ResourceGroupName = rg.Name,
Kind = "StorageV2",
Sku = new SkuArgs
{
Name = SkuName.Standard_LRS,
},
});
var appServicePlan = new AppServicePlan("appserviceplan", new AppServicePlanArgs
{
ResourceGroupName = rg.Name,
Kind = "App",
Sku = new SkuDescriptionArgs
{
Tier = "Basic",
Name = "B1",
},
});
var container = new BlobContainer("zips", new BlobContainerArgs
{
AccountName = storageAccount.Name,
PublicAccess = PublicAccess.None,
ResourceGroupName = rg.Name,
});
var blob = new Blob("appservice-blob", new BlobArgs
{
ResourceGroupName = rg.Name,
AccountName = storageAccount.Name,
ContainerName = container.Name,
Type = BlobType.Block,
Source = new FileArchive("wwwroot"),
});
var codeBlobUrl = SignedBlobReadUrl(blob, container, storageAccount, rg);
var app = new WebApp("app", new WebAppArgs
{
Name = siteName,
ResourceGroupName = rg.Name,
ServerFarmId = appServicePlan.Id,
SiteConfig = new SiteConfigArgs
{
AppSettings = {
new NameValuePairArgs{
Name = "WEBSITE_RUN_FROM_PACKAGE",
Value = codeBlobUrl,
}
},
}
});
this.Endpoint = app.DefaultHostName;
}
// From https://github.com/pulumi/examples/blob/master/azure-cs-functions/FunctionsStack.cs
private static Output<string> SignedBlobReadUrl(Blob blob, BlobContainer container, StorageAccount account, ResourceGroup resourceGroup)
{
return Output.Tuple<string, string, string, string>(
blob.Name, container.Name, account.Name, resourceGroup.Name).Apply(t =>
{
(string blobName, string containerName, string accountName, string resourceGroupName) = t;
var blobSAS = ListStorageAccountServiceSAS.InvokeAsync(new ListStorageAccountServiceSASArgs
{
AccountName = accountName,
Protocols = HttpProtocol.Https,
SharedAccessStartTime = "2021-01-01",
SharedAccessExpiryTime = "2030-01-01",
Resource = SignedResource.C,
ResourceGroupName = resourceGroupName,
Permissions = Permissions.R,
CanonicalizedResource = "/blob/" + accountName + "/" + containerName,
ContentType = "application/json",
CacheControl = "max-age=5",
ContentDisposition = "inline",
ContentEncoding = "deflate",
});
return Output.Format($"https://{accountName}.blob.core.windows.net/{containerName}/{blobName}?{blobSAS.Result.ServiceSasToken}");
});
}
[Output] public Output<string> Endpoint { get; set; }
}
我们现在可以部署站点并验证它是否按预期工作:
pulumi up --stack dev
curl (pulumi stack --stack dev output Endpoint)
[
保护站点:
要配置 Easy Auth,我们首先创建一个 Azure AD 应用程序注册。
在此示例中,我指定 AzureADMyOrg
来限制对部署应用程序注册的租户的访问。我还添加了一个 RedirectUri
指向已部署站点的 Easy Auth 中间件。需要密码才能用作客户端密码(在这种情况下,Web 应用程序是客户端)。
创建应用程序注册后,我们可以将 WebAppAuthSettings 添加到我们的站点。该示例指定没有匿名访问(使用 RedirectToLoginPage
),并使用 ClientId
和 ClientSecret
(密码)将站点连接到应用程序注册。
将下面的代码粘贴到上面 MyStack.cs
中的 this.Endpoint...
代码之后:
// MyStack.cs
// After this.Endpoint = app.DefaultHostName;
var adApp = new Application("ADAppRegistration", new ApplicationArgs
{
DisplayName = appRegistrationName,
SignInAudience = "AzureADMyOrg",
Owners = new[] { ownerId },
Web = new ApplicationWebArgs
{
ImplicitGrant = new ApplicationWebImplicitGrantArgs
{
IdTokenIssuanceEnabled = true
},
RedirectUris = new System.Collections.Generic.List<string> { $"https://{siteName}.azurewebsites.net/.auth/login/aad/callback" }
}
}
);
var applicationPassword = new ApplicationPassword("appPassword", new ApplicationPasswordArgs
{
ApplicationObjectId = adApp.Id,
DisplayName = "Client secret for web app"
});
var allowedAudience = adApp.ApplicationId.Apply(id => $"api://{id}");
var authSettings = new WebAppAuthSettings("authSettings", new WebAppAuthSettingsArgs
{
ResourceGroupName = rg.Name,
Name = app.Name,
Enabled = true,
UnauthenticatedClientAction = UnauthenticatedClientAction.RedirectToLoginPage,
DefaultProvider = BuiltInAuthenticationProvider.AzureActiveDirectory,
ClientId = adApp.ApplicationId,
ClientSecret = applicationPassword.Value,
Issuer = $"https://sts.windows.net/{tenantId}/v2.0",
AllowedAudiences = new[] { allowedAudience },
});
我们现在可以更新站点,从命令行我们不能比这更进一步。 但在浏览器中,我们将被重定向以完成登录流程并访问该站点。
pulumi up --stack dev
# Redirect to HTTPS
curl (pulumi stack --stack dev output Endpoint)
# Access denied
curl "https://$(pulumi stack --stack dev output Endpoint)"
有关 pulumi 示例,请参考此 Github link。