Before you read on, I want to be clear: I appreciate security engineers and value building secure applications. But I also believe we should start addressing security in larger organizations differently.

Imagine a large organization, not necessarily an IT organization, but one that does have at least a few in-house developed software products. Thousands of users and an IT department of only a few dozen people managing mostly off-the-shelf applications. Alongside this, a few software development teams work on the in-house developed applications. Now imagine you’re an architect working with those development teams.

What I see happening again and again

As an architect working with those teams, it’s my job to surface the trade-offs involved in building a new application. Performance vs. complexity, cost versus security, and so on. I bring in SMEs to help articulate the pros/cons of a design and the consequences of alternatives under consideration. In other words, I help formulate trade-offs for decision making.

Once these trade-offs are clear, I bring them to the responsible product owner, asset owner, or manager. I ensure they understand the implications and consequences and then let them decide how to proceed. Ultimately, it is their responsibility to decide which risks, including security risks, to accept, reduce, or fully mitigate. Based on those decisions, a design is finalized and implementation starts.

Notably, in most cases this only happens after repeatedly asking security teams for guidelines or policies that often never arrive.

Then, halfway through implementation, security suddenly enters the stage. They want to review the designs and start recommending extra security measures to be implemented. These statements are usually disconnected from the actual context of the application, the phase it is in, and the risk appetite at that time. Even more frustrating, they are often presented as absolutes (“you must never do this” or “you must always do that”) rather than as trade-offs to be decided on by the product owner. Or sometimes it’s just a simple NO as part of a change approval board, no explanation given, no conversation about the trade-off possible.

What causes this?

It’s not that security teams want to block progress. The problem is organizational: security is separated from product development and rewarded for reducing security risk, not for enabling successful delivery. But organizations make a profit by taking calculated risks, not by overinvesting in risk reduction. And for that reason a team responsible only for minimizing security risk can never make the right decision for the whole product.

Or in other words: a team with one side of the trade-off in the name, can never make the right decision on behalf of the whole.

This is not a new idea. We have seen similar things when parts of the organization were optimized either for development or operations and were not collaborating effectively to achieve the larger, overarching goal of producing constant, reliable change.

Analogous to the DevOps movement, I believe security teams should stop positioning themselves as a separate team of gatekeepers.

So, what should we do instead?

Product leadership should define the risk appetite per product and. Security teams should write clear policies, advise architects and product owners, but leave individual trade-offs to the product owner.

Product owners may get it wrong. But if that happens, it is their responsibility, not that of the security team.

Now, I recognize that a safety net is still needed to protect the organization against excessive risk-taking. But this can also be achieved without security teams involving themselves in individual decisions. Instead, they can report to senior management on how teams and products align with the agreed risk appetite, allowing management to intervene when necessary. In that model, security is no longer on the critical path and no longer responsible for every individual decision. Their responsibility becomes delivering high-quality advice at the right time and escalating systemic risk trends, rather than blocking individual implementations.

Conclusion

Separating security into a standalone responsibility creates friction and consistently undermines good risk decisions. Security decisions should be made within the product context by the product owner, advised by the architect, the security team, and other relevant SMEs. Security teams should act as trusted advisors, not gatekeepers or veto holders. As a safety net, they can report how products align with the agreed risk appetite to senior management, enabling intervention when necessary. To change the interaction between security and product teams, management must empower product owners to take decisions around security risk, scoped to their product, and reposition security teams as advisors, not deciders.

 

If you have been reading my previous two posts (part I & part II) on this subject, you might have noticed that neither solution I presented is perfect. Both solutions still suffer from storing secrets for local development in source control. Also combining configuration from multiple sources, can be be difficult. Luckily, in the newest versions of the .NET Framework and .NET Core there is a solution available that allows you to store your local development secrets outside of source control: user secrets.

User secrets are contained in a JSON file that is stored in your user profile and which contents can be applied to your runtime App Settings. Adding user secrets to you project is done by rightclicking on the project and selecting manage user secrets:

The first time you do this, an unique GUID is generated for the project which links this specific project to an unique file in your users folder. After this, the file is automatically opened up for editting. Here you can provide overrides for app settings:

When starting the project now, these user secrets are loaded using config builders and available as AppSettings. So let’s take a closer look at these config builders.

Config builders

Config builders are new in .NET Framework 4.7.1 and .NET Core 2.0 and allow for pulling settings from one ore more other sources than just your app.config. Config builders support a number of different sources like user secrets, environment variables and Azure Key Vault (full list on MSDN). Even better: you can create your own config builder, to pull in configuration from your own configuration management system / keychain

The way config builders are used, differs between .NET Core and the Full Framework. In this example, I will be using the full framework. In the full framework config builders are added to your app.settings file. If you have added user secrets to your project, you will find an UserSecretsConfigBuilder in your Web.config already:


  
    
  


  ..
  

Important: If you add or edit this configuration by hand, do make sure that the configBuilders section is BEFORE the appSettings section.

Config builders and Azure KeyVault

Now let’s make this more realistic. When running locally, user secrets are fine. However, when running in Azure we want to use our Key Vault in combination with Manged Identity again. The full example is on GitHub and as in my previous posts, this example is based on first deploying an ARM template to set up the required infrastructure. With this in place, we can have our application read secrets from KeyVault on startup automatically.

Important: Your managed identity will need both list and get access to your Key vault. If not, you will get hard to debug errors.

As a first step, we have to install the config builder for Key Vault by adding the NuGET package Microsoft.Configuration.ConfigurationBuilders.Azure. After that, add an Web.config transformation for the Release configuration as follow:



  
    
      
    
  

Now we just have to deploy and enjoy the result:

Happy coding!

In my previous post (secret management part 1: using azurekey vault and azure managed identity) I showed an example of storing secrets (keys, passwords or certificates) in an Azure Key Vault and how to retrieve them securely. Now, this approach has one downside and that is this indirection via the Key Vault.

In the previous implementation, service X creates an key to access it and we store it in the Key Vault. After that, service Y that needs the key, authenticates to the Azure Active Directory to access the Key Vault, retrieve the secret and use it to access service X. Why can’t we just access service X, after authenticating to the Azure Active Directory, as shown below?

In this approach we completely removed the need for Azure Key Vault, reducing the amount of hassle. Another benefit is that we are no longer creating extra secrets, which means we can also not loose them. Just another security benefit. Now let’s build an example and see how this works.

Infrastructure

Again we start by creating an ARM Template to deploy our infrastructure. This time we are using a feature of the Azure SQL DB Server to have an AAD identity be appointed as an administrator on that server, in the following snippet.

{
  "type": "administrators",
  "name": "activeDirectory",
  "apiVersion": "2014-04-01-preview",
  "location": "[resourceGroup().location]",
  "properties": {
    "login": "MandatorySettingValueHasNoFunctionalImpact", 
    "administratorType": "ActiveDirectory",
    "sid": "[reference(concat(resourceId('Microsoft.Web/sites', parameters('appServiceName')),'/providers/Microsoft.ManagedIdentity/Identities/default'), '2015-08-31-preview').principalId]",
    "tenantId": "[subscription().tenantid]"
  },
  "dependsOn": [
    "[concat('Microsoft.Sql/servers/', parameters('sqlServerName'))]"
  ]
}

We are using the same approach as earlier, but now to set the objectId for the AAD admin of the Azure SQL DB Server. One thing that is also important is that the property for ‘login’ is just a placeholder of the principals name. Since we do not know it, we can set it to anything we want. If we would ever change the user through the portal (which we shouldn’t), this property will reflect the actual username.

Again, the full template can be found on GitHub.

Code

With the infrastructure in place, let’s write some passwordless code to have our App Service access the created Azure SQL DB:

if (isManagedIdentity)
{
  var azureServiceTokenProvider = new AzureServiceTokenProvider();
  var accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("https://database.windows.net/");

  var builder = new SqlConnectionStringBuilder
  {
    DataSource = ConfigurationManager.AppSettings["databaseServerName"] + ".database.windows.net",
    InitialCatalog = ConfigurationManager.AppSettings["databaseName"],
    ConnectTimeout = 30
  };

  if (accessToken == null)
  {
    ViewBag.Secret = "Failed to acuire the token to the database.";
  }
  else
  {
    using (var connection = new SqlConnection(builder.ConnectionString))
    {
      connection.AccessToken = accessToken;
      connection.Open();

      ViewBag.Secret = "Connected to the database!";
    }
  }
}

First we request a token and specify a specific resource “https://database.windows.net/” as the type of resource we want to use the token for. Next we start building a connection string, just as we would do normally. However, we leave out anything related to authentication. Next (and this is only available in .NET Framework 4.6.1 or higher), just before opening the SQL Connection we set the acquired token on the connection object. From there on, we can again work normally as ever before.

Again, it’s that simple! The code is, yet again available on GitHub.

Supported services

Unfortunately, you can not use this approach for every service you will want to call and are dependent on the service supporting this approach. A full list of services that support token based application authentication are listed on MSDN. Also, you can support this way of authentication on your own services. Especially when you are moving to a microservices architecture, this can save you a lot of work and management of secrets.

Een van de eerste uitdagingen die ik tegenkwam toen ik begon te ontwikkelen op een Windows machine, was het creëren van een valide SSL certificaat. Er zijn veel handleidingen te vinden die je van alles met IIS laten doen of via allerlei hoepels self signed certificaten laten genereren. Uiteindelijk ben ik toch teruggevallen op wat me zo beviel onder Linux: de command line.

Omdat het mijn doel was een om echt geldig certificaat te krijgen, moest ik eerst een CSR (certificate sign request) genereren om te kunnen opsturen naar een certificate authority zodat ik een geldig certificaat krijg. Natuurlijk is het mogelijk om een certificaat te bemachtigen zonder eerst een CSR te genereren, maar dat raad ik af.

Een certificaat downloaden zonder CSR

Een certificaat bestaat altijd uit twee delen, het publieke en het privé deel. Het publieke deel kan gebruikt worden om informatie voor de houder van het certificaat te versleutelen, het privé deel om die weer te ontsleutelen. Ten overvloede, dat privé deel moet je dus voor jezelf houden. Wanneer je een volledig certificaat (publiek en privé deel) van een certificate authority krijgt betekend dus dat een of meer mensen het privé deel van je certificaat hebbben (gehad). Als je zelf een CSR genereert, dan genereer je zelf het privé deel en een gedeelte van het publieke deel van je certificaat. Deze informatie gebruikt je certificate authority om het publieke deel van je certificaat te maken. Ze krijgen dus het privé deel nooit te zien als je een CSR gebruikt. Helemaal wanneer je je certificaten bij je leverancier kan downloaden, is het dus verstandig om zelf een CSR te genereren.

Het genereren van een CSR

Zoals gezegd had ik geen zin in gedoe met IIS, domein controllers of allerlei andere onbekende software voor het genereren van een CSR, dus ik heb de OpenSSbinaries voor Windows gebruikt. Je kunt deze vinden op http://indy.fulgan.com/SSL/ of een andere bron opzoeken via www.openssl.org.

Nadat OpenSSL geinstalleerd is, kan een keypair gegeneerd worden. Dit keypair is de basis van een certificaat:

.\openssl.exe genrsa -out .\henrybeen.nl.key 4096

Ik heb gekozen voor een 4096 bit sleutel. Op dit moment zijn er veel tutorials of voorbeelden die een 1024 bit sleutel gebruiken, maar dit is echt te kort. Veel certificate authorities accepteren alleen nog maar CSR’s met een sleutel van 2048 of langer. Deze lengte zal veilig zijn tot ongeveer 2030 verwacht men. De reden dat ik 4096 gebruik, is simpelweg omdat ik kan. Na het genereren van het keypair, kunnen we dit gebruiken om een CSR te generen:

.\openssl.exe req -new -sha256 -key "henrybeen.nl.key" -out "henrybeen.nl.csr" -days 730 -nodes -x509 -subj "/C=NL/ST=xx/L=xx/O=yy/CN=henrybeen.nl"

Dit CSR kunnen we opsturen naar een certificate authority om het publieke deel van het certificaat te ontvangen. Er zijn veel certificate authorities, de enige nog duurder dan andere. Zelf gebuik ik regelmatig StartSSL, welke gratis is voor privé gebruik.

Nu nog automatiseren

Lui als ik ben, wil ik dit natuurlijk niet elke keer met de hand doen, dus ik heb een eenvoudig Powershell script geschreven dat het downloaden van OpenSSL, het genereren van een keypair en CSR automatiseert. Leuk om ook eens aan scripten onder Windows, in Powershell te ruiken. Het is niet bepaald mijn lievelings, maar het werk. Het script is natuurlijk te downloaden en kan als volgt gebruikt worden:

.\GenerateCSR.ps1 -domain henrybeen.nl -countryCode NL -city "xx"-organization "yy"

Wat uiteindelijk twee bestanden oplevert: Het keypair en de CSR