Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/Websites/Websites.Test/ScenarioTests/CertificatesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,11 @@ public void TestRemoveAzWebAppCertificate()
{
WebsitesController.NewInstance.RunPsTest(_logger, "Test-RemoveAzWebAppCertificate");
}
[Fact]
[Trait(Category.AcceptanceType, Category.CheckIn)]
public void TestImportAzWebAppKeyVaultCertificate()
{
WebsitesController.NewInstance.RunPsTest(_logger, "Test-ImportAzWebAppKeyVaultCertificate");
}
}
}
21 changes: 21 additions & 0 deletions src/Websites/Websites.Test/ScenarioTests/CertificatesTests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -138,5 +138,26 @@ function Test-RemoveAzWebAppCertificate
}
finally{

}
}

<#
.SYNOPSIS
Tests creating a new Web Hosting Plan.
#>
function Test-ImportAzWebAppKeyVaultCertificate
{
$rgname = "testkv1611"
$wname = "testasewebapp"
$keyvaultname = "testkv1611"
$keyvaultcertname = "testcertname1611"
try
{
#Setup
$kvcert = Import-AzWebAppKeyVaultCertificate -ResourceGroupName $rgname -WebAppName $wname -KeyVaultName $keyvaultname -CertName $keyvaultcertname

}
finally{

}
}
13 changes: 12 additions & 1 deletion src/Websites/Websites.Test/ScenarioTests/WebsitesController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
using System.IO;
using System.Linq;
using Microsoft.Azure.Management.Internal.Resources;
using Microsoft.Azure.Commands.Common.KeyVault.Version2016_10_1;

namespace Microsoft.Azure.Commands.Websites.Test.ScenarioTests
{
Expand All @@ -40,6 +41,8 @@ public class WebsitesController

public AuthorizationManagementClient AuthorizationManagementClient { get; private set; }

public KeyVaultManagementClient KeyVaultManagementClient { get; private set; }

public string UserDomain { get; private set; }

public static WebsitesController NewInstance => new WebsitesController();
Expand All @@ -57,12 +60,14 @@ public void RunPsTest(XunitTracingInterceptor logger, params string[] scripts)
var mockName = sf.GetMethod().Name;
_helper.TracingInterceptor = logger;

logger.Information(string.Format("Test method entered: {0}.{1}", callingClassType, mockName));
RunPsTestWorkflow(
() => scripts,
// no custom cleanup
null,
callingClassType,
mockName);
logger.Information(string.Format("Test method finished: {0}.{1}", callingClassType, mockName));
}

public void RunPsTestWorkflow(
Expand Down Expand Up @@ -120,12 +125,13 @@ private void SetupManagementClients(MockContext context)
NewResourceManagementClient = GetResourceManagementClient(context);
WebsitesManagementClient = GetWebsitesManagementClient(context);
AuthorizationManagementClient = GetAuthorizationManagementClient(context);

KeyVaultManagementClient = GetKeyVaultManagementClient(context);
var armStorageManagementClient = GetArmStorageManagementClient(context);
_helper.SetupManagementClients(
NewResourceManagementClient,
WebsitesManagementClient,
AuthorizationManagementClient,
KeyVaultManagementClient,
armStorageManagementClient
);
}
Expand All @@ -149,5 +155,10 @@ private static WebSiteManagementClient GetWebsitesManagementClient(MockContext c
{
return context.GetServiceClient<WebSiteManagementClient>(TestEnvironmentFactory.GetTestEnvironment());
}

private static KeyVaultManagementClient GetKeyVaultManagementClient(MockContext context)
{
return context.GetServiceClient<KeyVaultManagementClient>(TestEnvironmentFactory.GetTestEnvironment());
}
}
}

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/Websites/Websites/Az.Websites.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ CmdletsToExport = 'Get-AzAppServicePlan', 'Set-AzAppServicePlan',
'Update-AzWebAppAccessRestrictionConfig',
'Add-AzWebAppTrafficRouting', 'Remove-AzWebAppTrafficRouting',
'Get-AzWebAppTrafficRouting', 'Update-AzWebAppTrafficRouting',
'New-AzWebAppCertificate', 'Remove-AzWebAppCertificate'
'New-AzWebAppCertificate', 'Remove-AzWebAppCertificate',
'Import-AzWebAppKeyVaultCertificate'

# Variables to export from this module
# VariablesToExport = @()
Expand Down
1 change: 1 addition & 0 deletions src/Websites/Websites/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- Additional information about change #1
-->
## Upcoming Release
* Added support for Importing a keyvault certificate to WebApp.

## Version 2.2.0
* Added support for App Service Managed certificates
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters;
using Microsoft.Azure.Commands.WebApps.Models;
using Microsoft.Azure.Commands.WebApps.Models.WebApp;
using Microsoft.Azure.Commands.WebApps.Utilities;
using Microsoft.Azure.Management.Internal.Resources.Utilities;
using Microsoft.Azure.Management.Internal.Resources.Utilities.Models;
using Microsoft.Azure.Management.WebSites.Models;
using System.Management.Automation;
using System.Net;

namespace Microsoft.Azure.Commands.WebApps.Cmdlets.WebApps
{
/// <summary>
/// this commandlet will let you import a keyvault to Webapp
/// </summary>
[Cmdlet("Import", ResourceManager.Common.AzureRMConstants.AzureRMPrefix + "WebAppKeyVaultCertificate", SupportsShouldProcess = true)]
[OutputType(typeof(PSCertificate))]
public class ImportAzWebAppKeyVaultCertificate : WebAppBaseClientCmdLet
{
const string ParameterSet1Name = "S1";

[Parameter(ParameterSetName = ParameterSet1Name, Position = 0, Mandatory = true, HelpMessage = "The name of the keyvault.")]
[ValidateNotNullOrEmpty]
public string KeyVaultName { get; set; }

[Parameter(ParameterSetName = ParameterSet1Name, Position = 1, Mandatory = true, HelpMessage = "KeyVaultCertName of the certificate created in keyvault")]
[ValidateNotNullOrEmpty]
public string CertName { get; set; }

[Parameter(ParameterSetName = ParameterSet1Name, Position = 2, Mandatory = true, HelpMessage = "The name of the webapp resource group.")]
[ResourceGroupCompleter]
[ValidateNotNullOrEmpty]
public string ResourceGroupName { get; set; }

[Parameter(ParameterSetName = ParameterSet1Name, Position = 3, Mandatory = true, HelpMessage = "The name of the webapp.")]
[ValidateNotNullOrEmpty]
public string WebAppName { get; set; }

[Parameter(ParameterSetName = ParameterSet1Name, Mandatory = false, HelpMessage = "The name of the webapp slot.")]
[ValidateNotNullOrEmpty]
public string Slot { get; set; }

public override void ExecuteCmdlet()
{
if (!string.IsNullOrWhiteSpace(ResourceGroupName) && !string.IsNullOrWhiteSpace(WebAppName))
{
var webApp = new PSSite(WebsitesClient.GetWebApp(ResourceGroupName, WebAppName, Slot));
var location = webApp.Location;
var serverFarmId = webApp.ServerFarmId;
string kvid = string.Empty;
string kvresourcegrpname = string.Empty;
var keyvaultResources = this.ResourcesClient.ResourceManagementClient.FilterResources(new FilterResourcesOptions
{
ResourceType = "Microsoft.KeyVault/Vaults"
}).ToArray();

foreach (var kv in keyvaultResources)
{
if (kv.Name == KeyVaultName)
{
kvid = kv.Id;
kvresourcegrpname = kv.ResourceGroupName;
break;
}
}
if (string.IsNullOrEmpty(kvid))
{
kvid = KeyVaultName;
}
string keyvaultperm;
keyvaultperm = CmdletHelpers.CheckServicePrincipalPermissions(this.ResourcesClient, this.KeyvaultClient,kvresourcegrpname, KeyVaultName);
var lnk = "https://azure.github.io/AppService/2016/05/24/Deploying-Azure-Web-App-Certificate-through-Key-Vault.html";
if ((keyvaultperm != "Get") & (keyvaultperm != "get"))
{
WriteWarning("Unable to verify Key Vault permissions.");
WriteWarning("You may need to grant Microsoft.Azure.WebSites service principal the Secret:Get permission");
WriteWarning(string.Format("Find more details here: '{0}'", lnk));
}

Certificate kvc = null;
var certificate = new Certificate(
location: location,
keyVaultId: kvid,
password: "",
keyVaultSecretName: CertName,
serverFarmId: serverFarmId
);

if (this.ShouldProcess(this.WebAppName, string.Format($"Importing keyvault certificate for Web App '{WebAppName}'")))
{
try
{
kvc = WebsitesClient.CreateCertificate(ResourceGroupName, CertName, certificate);
}
catch (DefaultErrorResponseException e)
{
if (e.Response.StatusCode != HttpStatusCode.Conflict)
{
throw e;
}
}
}
WriteObject(kvc);
}

}
}
}
20 changes: 19 additions & 1 deletion src/Websites/Websites/Models.WebApp/WebAppBaseClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

using Microsoft.Azure.Commands.ResourceManager.Common;
using Microsoft.Azure.Commands.WebApps.Utilities;
using Microsoft.Azure.Commands.WebApps.Models;

namespace Microsoft.Azure.Commands.WebApps.Models
{
Expand Down Expand Up @@ -57,5 +56,24 @@ public WebsitesClient WebsitesClient
}
set { _websitesClient = value; }
}

private KeyVaultClient _keyVaultClient { get; set; }
public KeyVaultClient KeyvaultClient
{
get
{
if (_keyVaultClient == null)
{
_keyVaultClient = new KeyVaultClient(DefaultProfile.DefaultContext)
{
VerboseLogger = WriteVerboseWithTimestamp,
ErrorLogger = WriteErrorWithTimestamp,
WarningLogger = WriteWarningWithTimestamp
};
}
return _keyVaultClient;
}
set { _keyVaultClient = value; }
}
}
}
23 changes: 23 additions & 0 deletions src/Websites/Websites/Utilities/CmdletHelpers.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.Azure.Commands.Common.Authentication;
using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
using Microsoft.Azure.Commands.WebApps.Models;
using Microsoft.Azure.Graph.RBAC.Version1_6.ActiveDirectory;
using Microsoft.Azure.Management.Internal.Network.Version2017_10_01;
using Microsoft.Azure.Management.Internal.Network.Version2017_10_01.Models;
using Microsoft.Azure.Management.Internal.Resources.Utilities;
Expand Down Expand Up @@ -434,6 +435,28 @@ internal static Certificate[] GetCertificates(ResourceClient resourceClient, Web
return certificates.ToArray();
}

internal static string CheckServicePrincipalPermissions(ResourceClient resourceClient, KeyVaultClient keyVaultClient, string resourceGroupName, string keyVault)
{
var perm1 = " ";
var kv2 = keyVaultClient.GetKeyVault(resourceGroupName, keyVault);
foreach (var policy in kv2.Properties.AccessPolicies)
{
if (policy.ObjectId == ("f8daea97-62e7-4026-becf-13c2ea98e8b4"))
{
foreach (var perm in policy.Permissions.Secrets)
{
if ((perm == "Get") || (perm == "get"))
{
perm1 = perm;
Console.WriteLine("Success");
break;
}
}
}
}
return perm1.ToString();
}

internal static SiteConfigResource ConvertToSiteConfigResource(this SiteConfig config)
{
return new SiteConfigResource
Expand Down
40 changes: 40 additions & 0 deletions src/Websites/Websites/Utilities/KeyVaultClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Microsoft.Azure.Commands.Common.Authentication;
using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
using Microsoft.Azure.Commands.Common.KeyVault.Version2016_10_1;
using Microsoft.Azure.Commands.Common.KeyVault.Version2016_10_1.Models;
using System;


namespace Microsoft.Azure.Commands.WebApps.Utilities
{
public class KeyVaultClient
{
public Action<string> VerboseLogger { get; set; }

public Action<string> ErrorLogger { get; set; }

public Action<string> WarningLogger { get; set; }
public KeyVaultClient(IAzureContext context)
{
this.WrappedKeyVaultClient = AzureSession.Instance.ClientFactory.CreateArmClient<KeyVaultManagementClient>(context, AzureEnvironment.Endpoint.ResourceManager);
}

public KeyVaultManagementClient WrappedKeyVaultClient
{
get;
private set;
}

public Vault GetKeyVault(string resourceGroupName, string vaultName)
{
try
{
return this.WrappedKeyVaultClient.Vaults.Get(resourceGroupName, vaultName);
}
catch (Exception ex)
{
throw ex;
}
}
}
}
Loading