http://blog.tylerdoerksen.ca/ Tyler's Azure Blog 2020 2020-01-07T18:33:32Z http://blog.tylerdoerksen.ca/assets/images/bg.png Tyler's Azure Blog http://blog.tylerdoerksen.ca/posts/2019/12/Azure-DevOps-Auth-Failures.html Azure DevOps Git Credential Issues 2019-12-13T00:00:00Z <h2 id="accessing-multiple-azure-devops-organizations-from-the-same-pc">Accessing multiple Azure DevOps Organizations from the same PC</h2> <p>I am not sure if this is a common problem. It was difficult to find forum posts or articles on the exact issue.</p> <p>I use many Azure DevOps organizations on a daily basis, some are attached to the Microsoft corp. Azure AD tenant, a customer's tenant, or using my personal Microsoft Account (aka Live ID)</p> <p>Even though I use the <a href="https://github.com/microsoft/Git-Credential-Manager-for-Windows/blob/master/Docs/CredentialManager.md">Git Credential Manager for Windows</a>, it is common to get the following error when using a personal repo.</p> <pre><code>git pull remote: TF401019: The Git repository with name or identifier Wyam-Blog does not exist or you do not have permissions for the operation you are attempting. fatal: repository 'https://dev.azure.com/tylerd/Blog/_git/Wyam-Blog/' not found </code></pre> <p>Near as I can tell, a silent process in the background is authenticating to Azure DevOps using my corporate account (logged into my PC), acquiring a PAC (Personal Access Token), and storing the token in the Windows Credential vault. However, the problem is I don't want to use my corp credentials when accessing my personal projects.</p> <p>If there is a better way to configure this, or git command to run, please leave a comment below, but for now I will fast-forward to a workaround.</p> <h2 id="workaround">Workaround</h2> <p>If you open the Windows Credential Manager after attempting to access the repo, you will notice that the Git Credential Manager has added a &quot;Generic Credential&quot; to access Azure DevOps</p> <p><img src="/content/images/2019/12/credential-manager.png" class="img-fluid" alt="Windows Credential Manager" /></p> <h3 id="get-new-pac">Get new PAC</h3> <ul> <li>Login to the Azure DevOps project you are trying to access.</li> <li>Under your user settings, open the <strong>Personal access tokens</strong> screen</li> </ul> <p><img src="/content/images/2019/12/get-pac.png" class="img-fluid" alt="Open Personal Access Token Screen" /></p> <ul> <li>Create a new token</li> <li>Set the permissions, for the Git CLI you mainly need <strong>Code: Read &amp; write</strong></li> <li>Copy the new token value</li> <li>On you PC, open Control Panel &gt; Credential Manager</li> <li>Switch to Windows Credentials</li> <li>Under Generic Credentials, find the Azure DevOps organization credential that was created. In my case that was &quot;git:https://tylerd&#64;dev.azure.com/tylerd&quot;</li> <li>Click Edit</li> </ul> <p><img src="/content/images/2019/12/edit-credential.png" class="img-fluid" alt="Edit Credential" /></p> <ul> <li>Replace the Password with your new Personal Access Token</li> <li>Click Save</li> <li>All done!</li> </ul> <p>Try running the Git command again and you should have access to your repo.</p> <p>I am not sure if this is a common problem. It was difficult to find forum posts or articles on the exact issue.</p> http://blog.tylerdoerksen.ca/posts/2019/08/Deploy-Azure-Multi-RG.html Deploying Azure resources to multiple resource groups 2019-08-07T00:00:00Z <p>Azure Resource Manager (ARM) templates provide an excellent, built-in resource configuration and deployment solution. You can find a wealth of templates for deploying anything from a <a href="https://github.com/Azure/azure-quickstart-templates/tree/master/wordpress-app-service-mysql-inapp">Wordpress site on Azure App Service</a>, to a full <a href="https://github.com/Azure/azure-quickstart-templates/tree/master/101-hdinsight-secure-vnet">HDInsight cluster on a private VNET</a>.</p> <!-- more --> <p>Often I work with customers that need to go beyond the basics of ARM Templates, deploying complex solutions across multiple Resource Groups, with different RBAC permissions.</p> <p>So here I will share some tips-and-tricks you may find helpful when authoring complex templates.</p> <h2 id="deploying-to-multiple-azure-resource-groups">Deploying to multiple Azure Resource Groups</h2> <p>First, a very common question, and the title of this post, deploying Azure resources across multiple Resource Groups. You can accomplish this in 3 ways:</p> <ol> <li>Deploy multiple times using a script or deployment engine (Azure DevOps Pipeline)</li> <li>Deploy to a &quot;primary&quot; Resource Group <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-manager-cross-resource-group-deployment" title="Deploy Azure resources to more than one subscription or resource group">with nested templates deploying to other Resource Groups</a></li> <li>Use a <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/deploy-to-subscription" title="Create resource groups and resources at the subscription level">Subscription-level resource template</a> to define all Resource Groups and nested templates</li> </ol> <h3 id="using-a-script-1">Using a script (#1)</h3> <p>This is by far the simplest solution, however it is also the most error-prone. You will have to code features that the Azure deployment system would otherwise handle for you, like dependencies, failures, and ordering. Most likely need a script, however it is best to keep it as simple as possible, adding all of the configuration into the ARM Template.</p> <h3 id="resource-group-deploying-other-resource-groups-2">Resource Group deploying other Resource Groups (#2)</h3> <p>This is accomplished using the <code>&quot;resourceGroup&quot;</code> property which you can set on the <code>&quot;Microsoft.Resources/deployments&quot;</code> type, otherwise known as a nested template. Overall this is a minimal change if you are already using nested templates.</p> <p>You can also deploy to multiple subscriptions using the <code>&quot;subscriptionId&quot;</code> property.</p> <p>There are a couple of gotchas here, one is that the child Resource Groups need to exist before the nested deployment (just like how you need to define an existing RG when executing a template deployment). You can either script the creation of all of the RGs before running the deployment on the &quot;primary&quot; RG, or use the <code>&quot;Microsoft.Resources/resourceGroups&quot;</code> resource type, with the <code>dependsOn</code> property on the nested template.</p> <p>Here is an example</p> <pre><code class="language-json">{ &quot;type&quot;: &quot;Microsoft.Resources/resourceGroups&quot;, &quot;apiVersion&quot;: &quot;2018-05-01&quot;, &quot;location&quot;: &quot;[parameters('location')]&quot;, &quot;name&quot;: &quot;[parameters('msiResourceGroup')]&quot;, &quot;properties&quot;: {} }, { &quot;name&quot;: &quot;msiDeployment&quot;, &quot;type&quot;: &quot;Microsoft.Resources/deployments&quot;, &quot;apiVersion&quot;: &quot;2017-05-10&quot;, &quot;resourceGroup&quot;: &quot;[parameters('msiResourceGroup')]&quot;, &quot;dependsOn&quot;: [ &quot;[resourceId('Microsoft.Resources/resourceGroups/', parameters('msiResourceGroup'))]&quot; ], &quot;properties&quot;: { ... } } </code></pre> <p>Also, depending on how you nest templates, the <code>resourceGroup()</code> function will behave differently. If you have an embedded template <code>&quot;template&quot;: {}</code> the <code>resourceGroup()</code> function will refer to the parent RG. Alternatively, if you have a linked template <code>&quot;templateLink&quot;: { &quot;uri&quot;: &quot;...&quot;}</code> the <code>resourceGroup()</code> function will refer to the child RG. The same applies to the <code>subscription()</code> function.</p> <h3 id="subscription-level-templates-3">Subscription-level Templates (#3)</h3> <p>This may be my preferred method of deploying complex, multi-RG solutions. Most of the concepts are the same as cross-RG deployments, however there is no &quot;primary&quot; RG. With this method you can deploy to a completely blank Subscription, which is why this is often used in combination with <a href="https://docs.microsoft.com/en-us/azure/governance/blueprints/overview" title="Overview of the Azure Blueprints service">Azure Blueprints</a> as a &quot;Subscription Factory&quot; pattern.</p> <p>To author Subscription Templates, you need to use a different template schema <code>https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#</code> and execute the deployment using the <code>New-AzDeployment</code> or <code>az deployment create</code> command.</p> <p>Here is an Azure docs article for the details: <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/deploy-to-subscription" title="Create resource groups and resources at the subscription level">Create resource groups and resources at the subscription level</a></p> <p>The Subscription template will be fairly light, with most of the heavy lifting in the nested templates. There are a few functions that are not available in the Subscription Template, like <code>resourceGroup()</code> which means you can't use <code>resourceGroup().location</code> as a default deployment location.</p> <p>You will need to add a <code>&quot;location&quot;</code> parameter to the template, and use the value when creating the Resource Groups.</p> <p>Here is an example:</p> <pre><code class="language-json">{ &quot;$schema&quot;: &quot;https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#&quot;, &quot;contentVersion&quot;: &quot;1.0.0.1&quot;, &quot;parameters&quot;: { &quot;hdiResourceGroup&quot;: { &quot;type&quot;: &quot;string&quot;, &quot;defaultValue&quot;: &quot;DL-HDI&quot; }, &quot;msiResourceGroup&quot;: { &quot;type&quot;: &quot;string&quot;, &quot;defaultValue&quot;: &quot;DL-MSI&quot; }, &quot;location&quot;: { &quot;type&quot;: &quot;string&quot;, &quot;defaultValue&quot;: &quot;westus2&quot; } ... }, &quot;variables&quot;: {...}, &quot;resources&quot;: { { &quot;type&quot;: &quot;Microsoft.Resources/resourceGroups&quot;, &quot;apiVersion&quot;: &quot;2018-05-01&quot;, &quot;location&quot;: &quot;[parameters('location')]&quot;, &quot;name&quot;: &quot;[parameters('hdiResourceGroup')]&quot;, &quot;properties&quot;: {} }, } .... } </code></pre> <h2 id="extra-tip-using-the-templatelink.uri-property">Extra Tip: Using the <code>templateLink.uri</code> property</h2> <p>I am not a big fan of using additional parameters for Nested Template URLs and SAS Tokens. You may have seen them in examples with underscores in front, like <code>&quot;_sasToken&quot;</code> or <code>&quot;_templateRoot&quot;</code></p> <p>When you create a deployment using a template link URL (on <code>raw.githubusercontent.com</code> or Azure Blob Storage) you have access to a <code>templateLink</code> property on <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-template-functions-deployment#deployment" title="Deployment functions for Azure Resource Manager templates">the Deployment model</a></p> <p>If you are using public urls, you can just use the <code>uri()</code> function for nested templates.</p> <p><code>&quot;msiTemplate&quot;: &quot;[uri(deployment().properties.templateLink.uri, 'dl-msi.json')]</code></p> <p>If you want to <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-manager-powershell-sas-token" title="Deploy private Resource Manager template with SAS token and Azure PowerShell">secure the templates using Azure Blob Storage SAS Tokens</a>, you can use some String functions to pull the SAS token out of the TemplateLink property.</p> <p>For example:</p> <pre><code class="language-json">&quot;variables&quot;: { &quot;templateRoot&quot;:&quot;[deployment().properties.templateLink.uri]&quot;, &quot;hasToken&quot;:&quot;[not(equals(indexOf(variables('templateRoot'),'?'), -1))]&quot;, &quot;sasToken&quot;:&quot;[if(variables('hasToken'),substring(variables('templateRoot'),indexOf(variables('templateRoot'),'?')),'')]&quot;, &quot;msiTemplate&quot;: &quot;[concat(uri(deployment().properties.templateLink.uri, 'dl-msi.json'), variables('sasToken'))]&quot;, } </code></pre> <p>Note that this example supports both public and access token URLs, which adds complexity with conditional statements. I tried to keep it as simple as possible.</p> <p>This practice assumes that you are deploying the templates before running any deployments. This does not work with local files or inline JSON deployments.</p> <p>Azure Resource Manager (ARM) templates provide an excellent, built-in resource configuration and deployment solution. You can find a wealth of templates for deploying anything from a <a href="https://github.com/Azure/azure-quickstart-templates/tree/master/wordpress-app-service-mysql-inapp">Wordpress site on Azure App Service</a>, to a full <a href="https://github.com/Azure/azure-quickstart-templates/tree/master/101-hdinsight-secure-vnet">HDInsight cluster on a private VNET</a>.</p> http://blog.tylerdoerksen.ca/posts/2018/12/auth-azure-management-sdk.html Authentication using Azure Management SDK 2018-12-27T00:00:00Z <p>If you want to programmatically update Azure Resource configurations you have a number of options.</p> <ol> <li>Use the <a href="https://docs.microsoft.com/en-us/powershell/azure/install-az-ps?view=azps-1.0.0" target="_blank"><strong>PowerShell</strong></a> or <a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest" target="_blank"><strong>Python</strong></a> command line tools</li> <li>Use the <a href="https://github.com/Azure/azure-libraries-for-net" target="_blank"><strong>.NET Fluent libraries</strong></a></li> <li>Use the <a href="https://github.com/Azure/azure-sdk-for-net" target="_blank"><strong>.NET Management SDK</strong></a></li> <li>Call the <a href="https://docs.microsoft.com/en-us/rest/api/azure/" target="_blank"><strong>REST API directly</strong></a></li> </ol> <p>Each of those options have pros and cons depending on how you are using them. Overall I would suggest using the <strong>PowerShell</strong> module if possible.</p> <p>However, you may need to integrate the Azure SDK directly into you application or tool with the Management SDK.</p> <h1 id="getting-started-with-the.net-management-sdk">Getting Started with the .NET Management SDK</h1> <p>Like other SDK libraries, the Azure Management SDK is meant to be at the &quot;core&quot; of the tool or system you are building. As such, the libraries are highly configurable and not very prescriptive. Also, there is very little documentation on how to use this library. Most articles I have seen assume you have created an application in Azure AD and generated an access token somehow.</p> <h2 id="packages">Packages</h2> <p>Rather than one large library or package for all of the Azure services, the Management SDK has a package per resource type.</p> <p>Here is a full list of the <a href="https://github.com/Azure/azure-sdk-for-net/blob/psSdkJson6/Documentation/sdk-for-net-packages.md" target="_blank">NuGet Packages</a></p> <p>Along with the specific resource package, you should also install the following common packages.</p> <p><a href="https://www.nuget.org/packages/Microsoft.Rest.ClientRuntime.Azure" target="_blank"><strong>Microsoft.Rest.ClientRuntime.Azure</strong></a></p> <p><a href="https://www.nuget.org/packages/Microsoft.Rest.ClientRuntime.Azure.Authentication" target="_blank"><strong>Microsoft.RestClientRuntime.Azure.Authentication</strong></a></p> <h2 id="logging-in">Logging In</h2> <p>Each library will contain one or many &quot;Client&quot; classes. Instantiating the client class will require an implementation of the <code>ServiceClientCredentials</code> abstract class.</p> <p>Rather than implement that class yourself, you can find a few implementations in the <code>Microsoft.Rest.Azure.Authentication</code> namespace. Let's go over a few of the Providers in that namespace.</p> <p><strong>Add Using:</strong></p> <pre><code>using Microsoft.Rest.Azure.Authentication </code></pre> <h3 id="application-token">Application Token</h3> <p>You can use the <code>ApplicationTokenProvider</code> class when your application interacts with the Azure API directly as an application, without user context.</p> <p><strong>Setup</strong></p> <p>For this token provider you need to go to <a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-v1-add-azure-ad-app" target="_blank">Azure AD</a> and create an application. After creating that application you can either generate a Secret Key or upload a certificate.</p> <p>There are two different sets of Static methods on the <code>ApplicationTokenProvider</code> class. <code>LoginSilentAsync</code> and <code>LoginSilentWithCertificateAsync</code></p> <p><strong>LoginSilentAsync</strong></p> <pre><code>ServiceClientCredentials creds = ApplicationTokenProvider.LoginSilentAsync(&quot;mydomain.onmicrosoft.com&quot;, &quot;&lt;appId/clientId guid&gt;&quot;, &quot;&lt;secret&gt;&quot;); </code></pre> <p><strong>LoginSilentWithCertificateAsync</strong></p> <pre><code>X509Certificate2 localCert = ... ClientAssertionCertificate certAssertion = new ClientAssertionCertificate(&quot;&lt;appId/clientId guid&gt;&quot;, localCert); ServiceClientCredentials creds = ApplicationTokenProvider.LoginSilentWithCertificateAsync(&quot;mydomain.onmicrosoft.com&quot;, certAssertion); </code></pre> <h3 id="interactive-login">Interactive Login</h3> <p>If you are building a .NET Full Framework application (using .NET 452 or above) you can use the <code>UserTokenProvider.LoginWithPromptAsync</code> static method.</p> <p>Again this requires that you have registered an <a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-v1-dotnet" target="_blank">Azure AD Application</a></p> <p><strong>LoginWithPromptAsync</strong></p> <pre><code>var settings = ActiveDirectoryClientSettings.UsePromptOnly(&quot;&lt;clientId&gt;&quot;, new Uri(&quot;http://myRedirectUri&quot;)); var cred = UserTokenProvider.LoginWithPromptAsync(settings); </code></pre> <p>That is the simplest signature, which uses the <code>common</code> tenant. If know which Tenant the user is logging into and want to reduce the redirects you can use a method with the <code>TenantId</code> parameter.</p> <p>If you want to programmatically update Azure Resource configurations you have a number of options.</p> http://blog.tylerdoerksen.ca/posts/2018/07/Elevate-Access-to-Root-Management-Group.html Elevate Access to Root Management Group 2018-07-03T00:00:00Z <h2 id="management-groups">Management Groups</h2> <p>Recently a new Azure resource type was introduced called Management Groups, which allows users to group Azure Subscriptions under the same Azure AD Directory (aka. Tenant) for ease of access and policy management.</p> <blockquote class="blockquote"> <p><em>Azure Docs Article: <a href="https://docs.microsoft.com/en-us/azure/azure-resource-manager/management-groups-overview">Organize your resources with Azure management groups</a></em></p> </blockquote> <h2 id="root-management-group">Root Management Group</h2> <p>By default all of the subscriptions attached to the Directory (your_organization.onmicrosoft.com) will be under the &quot;Tenant Root Group&quot;. However, when you first enable Management Groups you will not have access to the Root Group. To get full Owner access to the group you need to use a Directory Global Admin to assign the Owner role to a user.</p> <p><a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/elevate-access-global-admin">This article</a> generically outlines how to <strong>elevate access for a Global Administrator</strong>. Once you follow the first set of steps you can run the following PowerShell commands to setup your permissions.</p> <p>Only a <strong>Global Administrator</strong> will be able to get elevated access.</p> <h2 id="owner-role-assignment">Owner Role Assignment</h2> <blockquote class="blockquote"> <p><em>Note: This requires AzureRM.Resources Module version 6.1.0 or above</em></p> </blockquote> <ol> <li><p>Login to Azure PowerShell using <code>Connect-AzureRmAccount</code></p> </li> <li><p>Verify that you have <strong>User Access Administrator</strong> permissions</p> <pre><code class="language-powershell">Get-AzureRmRoleAssignment | where {$_.RoleDefinitionName -eq &quot;User Access Administrator&quot; ` -and $_.SignInName -eq &quot;&lt;username&#64;example.com&gt;&quot; ` -and $_.Scope -eq &quot;/&quot;} </code></pre> </li> <li><p>Get the <strong>&quot;Tenant Root Group&quot; Id property</strong> using <code>Get-AzureRmManagementGroup</code></p> <p>It will be of the form <code>/providers/Microsoft.Management/managementGroups/94c40a73-c82f-47f0-8244-aed167ae33a0</code> where the GUID is the Directory ID of the Azure AD Directory.</p> </li> <li><p>Create a new <strong>Owner</strong> role assignment</p> <pre><code class="language-powershell">New-AzureRmRoleAssignment ` -ObjectId $userObjectId ` -RoleDefinitionName &quot;Owner&quot; ` -Scope $rootManagementGroupId </code></pre> </li> </ol> <h2 id="clean-up">Clean Up</h2> <p>Once you have verified access to the Root Management Group, go back to Azure Active Directory and disable the &quot;User Access Administrator&quot; role assignment by setting the directory property to <strong>No</strong> or running the following script</p> <pre><code class="language-powershell">Remove-AzureRmRoleAssignment ` -SignInName &quot;&lt;username&#64;example.com&gt;&quot; ` -RoleDefinitionName &quot;User Access Administrator&quot; ` -Scope &quot;/&quot; </code></pre> <p>Recently a new Azure resource type was introduced called Management Groups, which allows users to group Azure Subscriptions under the same Azure AD Directory (aka. Tenant) for ease of access and policy management.</p> http://blog.tylerdoerksen.ca/posts/2018/03/AppInsights-Static-Content.html Azure Application Insights and Static Content 2018-03-20T00:00:00Z <p>As you may have noticed, this site uses <a href="https://wyam.io" title="Wyam">Wyam</a> as a static site generator to produce what you see here from a set of .md Markdown files checked into a Git repository.</p> <p>The site is hosted on Azure Web Apps which is basically IIS under-the-hood.</p> <p>There are some little tricks in the web.config file to make this work properly. Which you can find more info on the <a href="https://wyam.io/docs/deployment/azure" title="Wyam Documentation - Azure">Azure hosting Wyam documentation page</a>.</p> <p>I noticed that even after instrementing Application Insights into the client side JavaScript I was not getting any server side telemetry. The reason for that is that the default Web App extension assumes that you are using ASP.NET which with a Static Site you are not.</p> <h2 id="enabling-application-insights-for-static-content">Enabling Application Insights for Static Content</h2> <ol> <li><p>If you are using Azure Web Apps. <a href="https://docs.microsoft.com/en-us/azure/application-insights/app-insights-monitor-performance-live-website-now" title="Instrument web apps at runtime with Application Insights">Add the Applications Insights Extension to the Web App</a>. This will add the proper DLLs to the Bin directory of your site.</p> </li> <li><p>Add the following code to your <code>web.config</code> file</p> <pre><code> &lt;configuration&gt; &lt;system.webServer&gt; &lt;modules runAllManagedModulesForAllRequests=&quot;true&quot;&gt; &lt;remove name=&quot;ApplicationInsightsWebTracking&quot;/&gt; &lt;add name=&quot;ApplicationInsightsWebTracking&quot; type=&quot;Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web&quot; preCondition=&quot;managedHandler&quot;/&gt; &lt;/modules&gt; &lt;/system.webServer&gt; &lt;/configuration&gt; </code></pre> <p>The key difference in this code compared to the Application Insights default settings is the <code>runAllManagedModulesForAllRequests=&quot;true&quot;</code> flag on the Modules configuration.</p> </li> </ol> <p>And you are done! You should now see some server side telemetry for .png or .js requests in your Application Insights portal.</p> <p>Thanks for reading.</p> <p>As you may have noticed, this site uses <a href="https://wyam.io" title="Wyam">Wyam</a> as a static site generator to produce what you see here from a set of .md Markdown files checked into a Git repository.</p> http://blog.tylerdoerksen.ca/posts/2016/12/azure-keyvault-your-asp-net.html Azure KeyVault your ASP.NET 2016-12-02T00:00:00Z <p>I am sure there are many projects with protected secrets and keys, and many more that should. One of the main hindrances of key protection is ease of use. Often teams skip over security features because of the time it would take away from building functionality.</p> <p>With that I wanted to outline a very quick and easy way to start consuming secrets in a KeyVault store.</p> <p><em>Note: The regular documentation for using KeyVault in an ASP.NET page can be found <a href="https://docs.microsoft.com/en-us/azure/key-vault/key-vault-use-from-web-application" title="Use Azure Key Vault from a Web Application">here</a>.</em></p> <h3 id="microsoft-extensions-configuration">Microsoft Extensions Configuration</h3> <p>Microsoft.Extensions.Configuration (<a href="https://github.com/aspnet/Configuration" title="github aspnet Configuration">GitHub</a>) is a .NET Core project to help users manage configuration settings from a variety of sources. You can load JSON, XML, INI, and even Cmdline Args.</p> <p>Fortunately the libraries target both .NETStandard 1.5 and .NETFramework 4.5.1, so they can be used in your existing ASP.NET projects.</p> <p>Microsoft.Extensions.Configuration.AzureKeyVault (<a href="https://www.nuget.org/packages/Microsoft.Extensions.Configuration.AzureKeyVault">NuGet</a>) adds a <code>UseAzureKeyVault</code> extension method to the base library.</p> <p>Implementing this is very easy.</p> <pre><code>var builder = new ConfigurationBuilder(); builder.AddAzureKeyVault( ConfigurationManager.AppSettings[&quot;Vault&quot;], ConfigurationManager.AppSettings[&quot;ClientId&quot;], ConfigurationManager.AppSettings[&quot;ClientSecret&quot;]); config = builder.Build(); </code></pre> <p>Then to access the secret.</p> <pre><code>config[&quot;ConnectionStringKey&quot;]; </code></pre> <p><code>Web.config</code></p> <pre><code>&lt;add key=&quot;ClientId&quot; value=&quot;&quot; /&gt; &lt;add key=&quot;ClientSecret&quot; value=&quot;&quot; /&gt; &lt;add key=&quot;Vault&quot; value=&quot;https://{name}.vault.azure.net&quot; /&gt; </code></pre> <p>Where <code>ClientId</code> is the Guid for the Azure AD Application with authorized access to the Azure KeyVault. <code>ClientSecret</code> is the secret key generated by the AD Application for service level authentication.</p> <p><em>More Details on KeyVault access setup <a href="https://docs.microsoft.com/en-us/azure/key-vault/key-vault-get-started" title="Get started with Azure Key Vault">here</a>.</em></p> <p><strong>Resources</strong></p> <ul> <li><a href="https://github.com/tylerd/storage-blobs-dotnet-webapp/tree/keyvault">Source Code</a></li> <li><a href="https://blogs.msdn.microsoft.com/cclayton/2016/11/25/ronin-building-blocks-configuration/">Ronin Building Blocks – Configuration</a> blog post by <a href="https://www.linkedin.com/in/chris-clayton-974a284">Chris Clayton</a></li> </ul> <p>I am sure there are many projects with protected secrets and keys, and many more that should. One of the main hindrances of key protection is ease of use. Often teams skip over security features because of the time it would take away from building functionality.</p> http://blog.tylerdoerksen.ca/posts/2016/08/azure-cli-on-bash-windows-10.html azure-cli on Bash Windows 10 2016-08-10T00:00:00Z <p>Once you get the Anniversary Update for Windows 10 you will be able to run Bash on Windows provided by Ubuntu. Very excited about this! It will make managing Linux machines that much easier.</p> <h3 id="installing-azure-cli">Installing azure-cli</h3> <ol> <li><p><a href="http://https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions">Install NPM</a> - <code>sudo apt-get install -y nodejs</code></p> </li> <li><p>Install azure-cli - <code>npm install -g azure-cli</code></p> </li> <li><p>Create symbolic link between nodejs and node - <code>sudo ln -s /usr/bin/nodejs /usr/bin/node</code></p> <blockquote class="blockquote"> <p>Note: The reason for step 3 is that Ubuntu installs nodejs rather than node, since the azure-cli is programmed to use node, you will get an error without this link</p> </blockquote> </li> </ol> <p>And you are done. After running <code>azure</code> you should see this...</p> <p><img src="/content/images/2016/08/azure-cli.png" class="img-fluid" alt="azure-cli start screen" /></p> <p>Once you get the Anniversary Update for Windows 10 you will be able to run Bash on Windows provided by Ubuntu. Very excited about this! It will make managing Linux machines that much easier.</p> http://blog.tylerdoerksen.ca/posts/2016/07/aspnetcore-get-current-access-token.html AspNetCore - Get current access token 2016-07-14T00:00:00Z <p>Recently I was doing some fiddling with Fitbit authentication using the <a href="https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers">AspNet Security OAuth Providers</a> to see if I could authenticate a website user with a Fitbit OAuth token and then use that access key to display some statistics on the amount of steps they have in a given work week.</p> <p>The authentication component was relatively easy, just adding the dependency to the <a href="https://www.nuget.org/packages/AspNet.Security.OAuth.Fitbit/">Fitbit security provider from NuGet</a> and it worked. However, normally in the OWIN providers the code would add the Access Token to the current set of Claims in the ClaimsIdenitity object. In AspNetCore that was not the case.</p> <pre><code>app.UseFitbitAuthentication(options =&gt; { options.ClientId = &quot;&quot;; options.ClientSecret = &quot;&quot;; options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.Scope.Add(&quot;profile&quot;); options.Scope.Add(&quot;activity&quot;); options.SaveTokens = true; }); </code></pre> <p>So long story short, this is a basic HttpContext extension method to retrieve the Access Token from the AuthenticationManager</p> <pre><code>public static string GetFitbitUserAccessToken(this HttpContext context) { var authInfo = context.Authentication.GetAuthenticateInfoAsync(&quot;Fitbit&quot;).Result; var tokens = authInfo.Properties.GetTokens(); var accessToken = tokens.FirstOrDefault(t =&gt; t.Name == &quot;access_token&quot;); return accessToken.Value; } </code></pre> <p><em>Error handling removed for length</em></p> <p>The key component here is the <code>GetAuthenticateInfoAsync</code> call. In a security configuration there could be multiple Auth &quot;Schemes&quot; you need to specify the one you are retrieving, some basic debugging will allow you to find the right one.</p> <p>Hope this helps.</p> <p>Thanks for reading.</p> <p>Recently I was doing some fiddling with Fitbit authentication using the <a href="https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers">AspNet Security OAuth Providers</a> to see if I could authenticate a website user with a Fitbit OAuth token and then use that access key to display some statistics on the amount of steps they have in a given work week.</p> http://blog.tylerdoerksen.ca/posts/2015/12/harp-on-azure-web-apps.html Harp on Azure Web Apps 2015-12-31T00:00:00Z <p>Recently I have been trying out different frameworks like <a href="/posts/2015/12/ghost-on-azure-web-apps" title="Ghost on Azure Web Apps">Ghost</a> running on Azure Web Apps. I was trying to get away from just the standard ASP.NET or PHP solutions, branching out to Node.js or static site generators (more to come on that).</p> <h2 id="harp">Harp</h2> <p>Harp is a Node.js / npm web platform that uses common template formats like Jade and Markdown to make it easier to author pages. Rather than providing a user interface for authoring, the process flow includes editing local files for content and layout.</p> <p>Harp seems to be both a Static Site Generator and a Node.js hosting platform. For the purposes of this post I will be going through how to run Harp as a hosting platform.</p> <ol> <li><p>Initialize Harp directory</p> <pre><code> harp init my-harp-app cd my-harp-app </code></pre> </li> <li><p>Initialize your app as a Git repo</p> <pre><code> git init git commit -am &quot;initial commit&quot; </code></pre> </li> <li><p>Create a new Azure Web App</p> </li> <li><p>Enable Continuous Deployment with a <a href="https://azure.microsoft.com/en-us/documentation/articles/web-sites-publish-source-control/" title="Continuous deployment using GIT in Azure App Service">Local Git Repository</a></p> </li> <li><p>Copy the repository clone url and add it as a remote repository</p> <pre><code> git remote add azure https://user&#64;my-harp-app.scm.azurewebsites.net:443/my-harp-app.git </code></pre> <p><em>Note: <code>my-harp-app</code> will be replaced by your site name.</em></p> </li> <li><p>Add <code>package.json</code> and <code>server.js</code></p> <pre><code> { &quot;name&quot;: &quot;harpapp&quot;, &quot;version&quot;: &quot;0.0.0&quot;, &quot;private&quot;: true, &quot;dependencies&quot;: { &quot;harp&quot;: &quot;0.19.0&quot; }, &quot;engines&quot;: { &quot;node&quot;: &quot;4.1.x&quot;, &quot;npm&quot;: &quot;3.5.1&quot; } } </code></pre> </li> <li><p>Then, use Node Package Manager to install the dependencies:</p> <pre><code> npm install </code></pre> </li> <li><p>Next, create <code>server.js</code>, which should contain the following:</p> <pre><code> require('harp').server(__dirname, { port: process.env.PORT || 5000 }) </code></pre> </li> <li><p>Create a <code>iisnode.yaml</code> file which should contain the following</p> <pre><code> node_env: production </code></pre> </li> <li><p>Commit any changes to Git</p> <pre><code> git commit -am &quot;adding node files&quot; </code></pre> </li> <li><p>Deploy your Harp app to Azure</p> <pre><code> git push azure master </code></pre> </li> </ol> <p>At this point your site should be running on Azure at <code>http://my-harp-app.azurewebsites.net</code>, but with the subdomain you specifed instead of <code>my-harp-app</code>.</p> <blockquote class="blockquote"> <p><a href="http://harpjs.com/docs/deployment/azure" title="Deploying Harp to Azure">This article</a> shows you how to create and deploy your Harp application to Azure using the Azure Command Line Interface (<code>azure-cli</code>) tool.</p> </blockquote> <p>Stay tuned for more articles on web platforms and static site generators like middleman, Jekyll, Hexo, and more.</p> <p>Thanks for reading.</p> <p>Recently I have been trying out different frameworks like <a href="/posts/2015/12/ghost-on-azure-web-apps" title="Ghost on Azure Web Apps">Ghost</a> running on Azure Web Apps. I was trying to get away from just the standard ASP.NET or PHP solutions, branching out to Node.js or static site generators (more to come on that).</p> http://blog.tylerdoerksen.ca/posts/2015/12/web-apps-tools-and-tips.html Web Apps - Tools and Tips 2015-12-20T00:00:00Z <p>After doing some tinkering with Azure Web Apps I thought I would write a quick post outlining some quick tips. This will be mostly related to NodeJS as that was the platform I was working with.</p> <h2 id="kudu">Kudu</h2> <p>Kudu is the <a href="https://github.com/projectkudu/kudu" target="_blank">open source</a> platform that powers deployments, configuration, logging, and extensions for Azure Web Apps. You can access it via a link in the tools menu of the new portal or by adding &quot;.scm.&quot; in the middle of your URL.</p> <blockquote class="blockquote"> <p>yoursite.<strong>scm</strong>.azurewebsites.net</p> </blockquote> <p>Some of the tasks that I use Kudu for:</p> <ul> <li>Browsing and editing files on the site</li> <li>Command Line (CMD or PowerShell)</li> <li>Checking Environment Variables</li> <li>Streaming Logs</li> </ul> <h2>Visual Studio Online [VSO]</h2> Not to be confused with TFS-as-a-Service which has now been renamed to Visual Studio Team Services (VSTS), VSO is an online, web-based, programming IDE. You can install it on your site using Site Extensions either through the portal or Kudu. If this tool reminds you of Visual Studio Code it is because they use the same underlying JavaScript visual engine. <p>Once you setup the extension you can access VSO by adding /dev to the Kudu sub-domain.</p> <blockquote class="blockquote"> <p>your site.scm.azurewebsites.net**/dev**</p> </blockquote> <p>For the project that I was working on I did not bother installing/upgrading different versions of Node and NPM on my machine but rather created a development site and used VSO for editing.</p> <p>Some of the tasks I use VSO for:</p> <ul> <li>File editing and debugging</li> <li>Committing changes to the Git repository</li> <li>Running commands (NPM, Git, static site gen)</li> </ul> <h2 id="iisnode.yml">iisnode.yml</h2> <p>This is the configuration file for the IIS Node module. This file complements the normal web.config with node-specific settings. Normally you would configure items like &quot;node_env&quot; in this file rather than the web.config so it can be easily checked into source control and maintain more human-readability. The web.config file will be generated by the Kudu deployment process when you sync changes, so most of the time there is no need to add it to the Git repo.</p> <p>Occasionally you will find a node project, like Ghost Blog, where the log output will not be picked up by the normal log streaming feature of Azure Web Apps. In this instance I have added entries to iisnode.yml to enable alternate logging directly from IIS Node.</p> <p>Here is an example iisnode.yaml file</p> <pre><code>node_env: production loggingEnabled: true logDirectory: iisnode </code></pre> <p><a href="https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/iisnode.yml">This example config file</a> gives a description of the possible settings.</p> <p>I hope some of this information proves useful, I may be adding some tips as I write out further blog posts so check back for more later on.</p> <p>Thanks for reading.</p> <p>After doing some tinkering with Azure Web Apps I thought I would write a quick post outlining some quick tips. This will be mostly related to NodeJS as that was the platform I was working with.</p> http://blog.tylerdoerksen.ca/posts/2015/12/ghost-on-azure-web-apps.html Ghost on Azure Web Apps 2015-12-15T00:00:00Z <p>Every so often I like to try out different blogging platforms and Ghost is one that I have looked at multiple times since the project started. Even though it has been getting easier, the experience is not great when running Ghost on Azure.</p> <p>There are a number of ways you can accomplish this, everything from forking the Ghost repo and building it to hosting Ghost on a Docker container.</p> <p>I decided to <a href="https://github.com/TryGhost/Ghost/wiki/Using-Ghost-as-an-NPM-module">deploy Ghost as an NPM module</a> for a few reasons.</p> <ul> <li>The ability to update a version number and re-deploy without dealing with Git forks, pulls, or commits from any other repos</li></li> <li>I was not going to edit the Ghost platform itself, the only changes to the site would be related to content, themes, and configuration</li></li> </ul> <p>For some of the other ways you can host Ghost on Azure, check out <a href="http://www.andrewzey.com/hosting-ghost-on-azure/">this post by Andrew Zay</a>.</p> <p>Now here is the step by step guide to creating a Ghost site on Azure using NPM.</p> <h3 id="prerequisites">Prerequisites</h3> <ul> <li><p>Install NPM</p> </li> <li><p>Install Git</p> </li> <li><p>Install Azure CLI - <code>npm install -g azure-cli</code></p> </li> <li><p>(Optional) Install <a href="http://code.visualstudio.com">Visual Studio Code</a></p> </li> </ul> <h3 id="setup-local-environment">Setup Local Environment</h3> <ol> <li><p>Create a new directory for your Ghost app</p> </li> <li><p>Initialize an npm package with <code>npm init</code></p> </li> <li><p>Fill in the require information</p> </li> <li><p>Add the following to <strong>package.json</strong></p> <pre><code>&quot;engines&quot;: { &quot;node&quot;: &quot;0.10.32&quot; }, &quot;dependencies&quot;: { &quot;ghost&quot;: &quot;0.7.4&quot; } </code></pre> </li> <li><p>Create a <strong>server.js</strong> file</p> </li> <li><p>Add the following</p> <pre><code> var ghost = require('ghost'); var path = require('path'); ghost({ config: path.join(__dirname, 'config.js') }).then(function (ghostServer) { ghostServer.start(); }); </code></pre> </li> <li><p>Create an <strong>iisnode.yml</strong> file</p> </li> <li><p>Add the following to iisnode.yml</p> <pre><code> node_env: production loggingEnabled: true logDirectory: iisnode </code></pre> </li> <li><p>Initialize a Git repository</p> </li> </ol> <h3 id="create-local-content-and-config">Create Local Content and Config</h3> <ol> <li><p>Create <strong>config.js</strong> file based on the content <a href="https://github.com/TryGhost/Ghost/blob/master/config.example.js">here</a></p> </li> <li><p>Update production &gt; url to your Azure Web App url</p> </li> <li><p>Update production &gt; server &gt; port to <code>process.env.PORT</code></p> </li> <li><p>Add the content path after the server config</p> <pre><code> paths: { contentPath: path.join(__dirname, '/content/') } </code></pre> </li> <li><p>Copy <strong>/content/</strong> directory from <a href="https://github.com/TryGhost/Ghost/tree/master/conten">here</a> to the root directory</li></p> </li> <li><p>Copy the casper theme from <a href="https://github.com/TryGhost/Casper">here</a> to the <strong>/content/themes/casper</strong> directory (this was a sub-module so it was not included on the github zip download)</p> </li> <li><p>Commit to Git repository</li></p> </li> </ol> </ol> <h3 id="deploy-to-azure">Deploy to Azure</h3> <ol> <li><p>Using the Azure CLI tool create a new Azure Web App</p> <pre><code> azure site create --location &quot;West US&quot; my-ghost-app --git </code></pre> </li> <li><p>Commit the new .gitignore file to your repository</li></p> </li> <li><p>Push changes to Azure</p> <pre><code> git push azure master </code></pre> </li> </ol> <p>At this point the deployment script should output to the console.</p> <p>The first time you hit the site, node will be running some db migrations to initialize the data store. You should be able to see the stdout or stderr logging in the site/wwwroot/iisnode sub-directory.</p> <p>Note: I chose the node version and ghost version specifically. I have had issues related to node, npm, ghost, and other dependencies in the past.</p> <p>Thanks for reading.</p> <p>Every so often I like to try out different blogging platforms and Ghost is one that I have looked at multiple times since the project started. Even though it has been getting easier, the experience is not great when running Ghost on Azure.</p> http://blog.tylerdoerksen.ca/posts/2015/11/app-services-vs-cloud-services.html App Services vs Cloud Services 2015-11-30T00:00:00Z <blockquote class="blockquote"> <p>This blog article has been migrated from my old blog and updated. You can read the original post <a href="https://tylerazure.wordpress.com/2013/11/01/azure-websites-vs-cloud-services" title="Azure Websites vs Cloud Services">here</a></p> </blockquote> <blockquote class="blockquote"> <p><strong>Update 2015:</strong> Cloud Services as it exists today is undergoing a significant change. If you want to deploy to stateless VMs like Cloud Services you can use <strong>VM Scale Sets</strong></p> </blockquote> <p>The question of the week is. When do you use Azure Web Apps as your web platform and when do you use Cloud Services. These two platforms provide similar functionality in that you can deploy your ASP.NET or other IIS based web application projects to either of these platforms. There are some general cases of when to use one over the other and some specific differences that may help in making that decision. In this post I am going to go through these differences and attempt to give some guidance on what to use when.</p> <h2>When to use Web Apps</h2> <img class="wp-image-3651 alignright" style="border:0;" src="http://tylerazure.files.wordpress.com/2013/10/websites-vs-cloudservices.png?w=300&amp;h=210" alt="Websites-vs-CloudServices" width="300" height="210" /> <p><strong>You Are Just Starting</strong> - Compared to Cloud Services, Web Apps may not be as flexible but it is definitely easier. You can build your website using Visual Studio, WebMatrix, or any other IDE of your choice without the need for an SDK or any other additional software.</p> <p>You can deploy to Azure Web Apps using WebDeploy, FTP, or even DropBox. You can sync your site code straight from GitHub, BitBucket, Codeplex, or TFS Online. It is incredibly easy and require little to know buy-in to Azure if you want to create an IIS website.</p> <p><strong>You Have a Single Compute Tier</strong> - If you are running an application that does not require internal communication then it would be much easier to use Web Apps . Again, the stance that I usually take is use the easiest option until you are required to change. If you need multiple machines that talk to each other over a private network, then you cannot use Web Apps and you need to use Cloud Services (or Virtual Machines).</p> <p>With Web Apps you can have multiple servers handling requests if you have a high load, however those servers know nothing of each other and do not have internal addresses or endpoints.</p> <p><strong>Your Site is Written in PHP, Python, or Node.js</strong> - This point is not to say that you cannot use these platforms on Cloud Services, it is just easier with Web Apps because the machines are configured beforehand. With Cloud Services you get a base Azure Image to deploy onto. The Azure Website system uses that same base image however extra software has been installed to IIS for your convenience.</p> <h2>When to use Cloud Services</h2> <strong>You Need Machine Level Access</strong> - If you compare the underlying platform of Web Apps and Cloud Services, Cloud Services provides you with a completely provisioned, unique, stateless virtual machine whereas Web Apps provides pre-configured IIS application pool, and you may be on the same machine as other sites. With IIS there are many restrictions, not the least of them is machine level access. This restriction could affect the base functionality of .NET like <a href="http://tylerazure.wordpress.com/2013/08/23/pfx-certificate-files-and-windows-azure-websites/">using PFX certificates to sign network tokens</a>, or accessing local user profile data. <p>When deploying to Cloud Services there is no shared option, this deployment owns the entire virtual machine for its lifetime (which could vary, it is not a state-full instance). This gives you much more control over the deployment environment compared to Web Apps .</p> <p><strong>You Perform Background Processing</strong> - The Cloud Services platform has two different Role Types, a Web Role, and a Worker Role. If you are familiar with on-premise architectures you can compare the two to an IIS Application and a Windows Service. Azure Web Apps is all IIS, the web server provides the entire platform, there is no room for long running processes or threads that can sit and wait for communication on another port outside of IIS.</p> <p><em><strong>Note:</strong> For regularly scheduled or triggered operations you can use Azure Web Jobs which run as a sub-set of an Azure Web App.</em></p> <p>If those Windows Service type scenarios are sounding familiar to you, you may need to consider using Cloud Services for the Worker Role capabilities.</p> <p><strong>Your Application Requires Internal Communication</strong> - With Windows Azure services there is a general level of scaleability. Both Cloud Services and Azure Web Apps can scale up and down as needed, even automatically. However, if you want to use 2 web front-end machines and they need to communicate to each other, you need to use Cloud Services Roles and Instances. Azure Web Apps take routed requests in a farm of IIS hosting servers, they have no knowledge of other machines in the same site.</p> <p>Cloud Services however runs as an overall deployment with multiple Roles and each of those Roles can contain multiple Instances. You can scale different components of your system separate from others. Cloud Service deployments also have an internal network all to themselves to use to communicate between the Roles and Instances. The Azure SDK contains .NET Libraries to determine which machine is the current instance and where to contact the others.</p> <h2>Feature Breakdown</h2> For those more specific features that may sway your decision one way or the other, here is a quick table comparing the two. <table border="1" cellspacing="0"> <tbody> <tr> <th align="left" valign="top">Feature</th> <th align="left" valign="top">Web Apps</th> <th align="left" valign="top">Cloud Services</th> </tr> <tr> <td valign="top">Scale Out to Multiple Instances Without Redeploy</td> <td valign="top">Yes</td> <td valign="top">Yes</td> </tr> <tr> <td valign="top">SSL</td> <td valign="top">Yes</td> <td valign="top">Yes</td> </tr> <tr> <td valign="top">Visual Studio Integration</td> <td valign="top">Yes</td> <td valign="top">Yes</td> </tr> <tr> <td valign="top">Deploy from TFS On-Prem or Online</td> <td valign="top">Yes</td> <td valign="top">Yes</td> </tr> <tr> <td valign="top">WebMatrix Support</td> <td valign="top">Yes</td> <td valign="top">No</td> </tr> <tr> <td valign="top">Fast Deployment</td> <td valign="top">Yes</td> <td valign="top">No</td> </tr> <tr> <td valign="top">Instances Share Content and Configuration</td> <td valign="top">Yes</td> <td valign="top">No</td> </tr> <tr> <td valign="top">Multiple Deployment Environments (Production and Staging)</td> <td valign="top">Yes</td> <td valign="top">Yes</td> </tr> <tr> <td valign="top">Network Isolation</td> <td valign="top">No</td> <td valign="top">Yes</td> </tr> <tr> <td valign="top">Support for Windows Azure Traffic Manager</td> <td valign="top">Yes</td> <td valign="top">Yes</td> </tr> <tr> <td valign="top">Support for CDN</td> <td valign="top">Yes</td> <td valign="top">Yes</td> </tr> <tr> <td valign="top">Remote Desktop Access</td> <td valign="top">No</td> <td valign="top">Yes</td> </tr> <tr> <td valign="top">Execute Start-Up Tasks</td> <td valign="top">No</td> <td valign="top">Yes</td> </tr> </tbody> </table> <h2>Summary</h2> If the above information has just left you more confused, here are some basic guidelines that I use for many Azure service match-ups. <p>Use what you need, until you need more, then switch.</p> <p>That said, start by creating an Azure Website (hey, it's free right), get your application out into the world. If you find that you require more complexity and you are considering a multi-tier scenario, consider switching to Cloud Services.</p> <p>As always, thanks for reading!</p> <p>This blog article has been migrated from my old blog and updated. You can read the original post <a href="https://tylerazure.wordpress.com/2013/11/01/azure-websites-vs-cloud-services" title="Azure Websites vs Cloud Services">here</a></p> http://blog.tylerdoerksen.ca/posts/2015/11/pfx-certificate-files-and-azure-web-apps.html PFX certificate files and Azure Web Apps 2015-11-29T00:00:00Z <blockquote class="blockquote"> <p>This blog article has been migrated from my old blog and updated. You can read the original post <a href="https://tylerazure.wordpress.com/2013/08/23/pfx-certificate-files-and-windows-azure-websites/" title="PFX certificate files and Windows Azure Websites">here</a></p> </blockquote> <h2>How I got burned today ...</h2> I needed to write a simple SAML 1.1 provider that would generate a SAML token and sign it using a .pfx certificate. <p>So I wrote this code in my MVC4 Controller ...</p> <pre><code>var cert = new X509Certificate2(pfxFile, "myPassword"); var privateKey = cert.PrivateKey; </code></pre> <p>Used the private key to sign the token, ran it locally with no issue. However, once I published the site to Azure Web Apps I get this error.</p> <pre> [CryptographicException: The system cannot find the file specified.] System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr) +33 System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromFile(String fileName, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle&amp; pCertCtx) +0 System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromFile(String fileName, Object password, X509KeyStorageFlags keyStorageFlags) +218 System.Security.Cryptography.X509Certificates.X509Certificate..ctor(String fileName, String password) +63 System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(String fileName, String password) +58 WAWSPfxTest.Controllers.HomeController.Index() +180 </pre> <p>I confirmed that the file did in fact exist.</p> <h2>What happened ??</h2> Well it turns out that when you load certificates the system will use a local directory to store the key (??) <p>The default location for the key is the under the local user profile, and with Azure Web Apps, there is no local user profile directory.</p> <h2>Key Storage Flags to the rescue</h2> With some trial and error I found that the <strong>MachineKeySet</strong> flag worked on my Azure Web App. So with a quick change to the code it was working again. <pre><code>var cert = new X509Certificate2(pfxFile, &quot;myPassword&quot;, X509KeyStorageFlags.MachineKeySet); var privateKey = cert.PrivateKey; </code></pre> <blockquote class="blockquote"> <p><strong>Note:</strong> <a href="https://azure.microsoft.com/en-us/blog/using-certificates-in-azure-websites-applications/" title="Using Certificates in Azure Websites Applications">This Azure Blog Article</a> outlines how to upload and use certificates with Azure Web Apps.</p> </blockquote> <p>I hope this helps someone.</p> <p>This blog article has been migrated from my old blog and updated. You can read the original post <a href="https://tylerazure.wordpress.com/2013/08/23/pfx-certificate-files-and-windows-azure-websites/" title="PFX certificate files and Windows Azure Websites">here</a></p> http://blog.tylerdoerksen.ca/posts/2015/11/old-blog-posts.html Old Blog Posts 2015-11-28T00:00:00Z <p>This new blog is running on Azure and generated by Wyam. Previously I was running Ghost on Azure also. If you would like to view all my posts from 2010 up to 2014 please follow this link.</p> <h2 id="tylers-azure-blog-wordpress.com"><a href="https://tylerazure.wordpress.com" title="Tyler's Azure Blog">Tyler's Azure Blog - Wordpress.com</a></h2> <p>This new blog is running on Azure and generated by Wyam. Previously I was running Ghost on Azure also. If you would like to view all my posts from 2010 up to 2014 please follow this link.</p>