<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Winterdom</title>
		<description>by d&#230;mons be driven - a site by Tomas Restrepo</description>
		<link>https://winterdom.com/</link>
		<atom:link href="https://winterdom.com/feed.xml" rel="self" type="application/rss+xml" />
		
			<item>
				<title>Azure File Storage and Billing Transparency</title>
				<description>&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/storage/files/?toc=%2fazure%2fstorage%2ffiles%2ftoc.json&quot;&gt;Azure Files&lt;/a&gt;
is an excellent service, providing file-system (SMB) based storage on the cloud. It has been
very useful for us together with Azure Kubernetes Service.&lt;/p&gt;

&lt;p&gt;Functionality-wise, I have no complaints. While there are a few things that could be better, the
service overall provides good value, and the addition of Premium File Storage is definitely
a very interesting and exciting option.&lt;/p&gt;

&lt;p&gt;I have been, however, dissatisfied with the Billing experience.&lt;/p&gt;

&lt;h2 id=&quot;cloud-billing-transparency&quot;&gt;Cloud Billing Transparency&lt;/h2&gt;

&lt;p&gt;I’m a strong believer that Cloud-based offerings need to have a clear set of billing rules
that customers can clearly understand and use to budget their cloud costs. There are 4 key
elements that I believe contribute to having clear and transparent cloud billing for
usage-based services:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The publicly available pricing information should clearly document what
&lt;strong&gt;billing meters&lt;/strong&gt; are used and how these relate to the prices listed.&lt;/li&gt;
  &lt;li&gt;For services that charge for communication, any related billing meters should have
a clear relation to the &lt;strong&gt;underlying protocol&lt;/strong&gt; operations and semantics.&lt;/li&gt;
  &lt;li&gt;The service should provide &lt;strong&gt;metrics&lt;/strong&gt; that allow customers to understand their usage.&lt;/li&gt;
  &lt;li&gt;Any metrics should clearly &lt;strong&gt;relate&lt;/strong&gt; to the corresponding billing meters, so that
the customer can audit their bills for accuracy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A customer that understands how your service is billed, budget properly for it,
and also audit the usage is a happy customer.&lt;/p&gt;

&lt;h2 id=&quot;the-azure-files-billing-conundrum&quot;&gt;The Azure Files Billing Conundrum&lt;/h2&gt;

&lt;p&gt;Why am I generally unhappy about how Azure Files are billed? It’s not so much that I object
to the actual cost of the service (which is generally reasonable for most scenarios), but that
I believe that Azure Files breaks several of the rules above.&lt;/p&gt;

&lt;p&gt;Let me explain why.&lt;/p&gt;

&lt;h3 id=&quot;pricing-information-vs-billing-meters&quot;&gt;Pricing Information vs. Billing Meters&lt;/h3&gt;

&lt;p&gt;The first issue I have with Azure Files is how &lt;a href=&quot;https://azure.microsoft.com/en-us/pricing/details/storage/files/&quot;&gt;pricing information&lt;/a&gt;
is presented. There are two separate components: Storage and Operations.&lt;/p&gt;

&lt;p&gt;Storage pricing is very clearly presented, but Operation pricing is &lt;strong&gt;very deceptive&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Billing meters are only partially related to how pricing is presented. While pricing talks about
“Put, Create Container Operations” or “List Operations”, billing meters include things such
as “protocol operations”, and “lrs write operations”. You can guess about how they are mapped
in some cases, but not all of them.&lt;/p&gt;

&lt;p&gt;I would much rather the pricing information was presented by outlining the meters used and
what each one measures exactly.&lt;/p&gt;

&lt;h3 id=&quot;billing-and-protocols&quot;&gt;Billing and Protocols&lt;/h3&gt;

&lt;p&gt;Azure Files operation pricing is stated in terms of the underlying operations on the REST API. This
is fine if you’re accessing the service over the HTTP interface, but that’s not really the common usage
for Azure Files.&lt;/p&gt;

&lt;p&gt;Instead, you’ll mostly be accessing the service over SMB from Windows or Linux machines, and so there’s
no clear relationship of how a File-System-based operation (such as &lt;code class=&quot;highlighter-rouge&quot;&gt;Open File&lt;/code&gt;) maps to an operation
on the REST API. This leads to significant confusion and makes it easy to budget incorrectly for the service,
understimating the actual costs.&lt;/p&gt;

&lt;p&gt;For example, I ran into a case where a service would often open a file, read from it, and then close it.
I was pretty surprised that my Azure Files bill was primarily composed of &lt;strong&gt;“Write Operations”&lt;/strong&gt;. Well,
surprise-surprise, turns out that the file-system  &lt;em&gt;open a file&lt;/em&gt; operation is considered a write operation for
billing purposes. There was absolutely no way for me to figure that out before I wasted a lot of time
and a few support cases (which went nowhere) on it.&lt;/p&gt;

&lt;h3 id=&quot;meters-and-metrics&quot;&gt;Meters and Metrics&lt;/h3&gt;

&lt;p&gt;Azure Files supports some basic metrics, which get stored in Azure Storage Tables on the same
storage account. While these are useful in general, they are not very useful to audit your usage costs.&lt;/p&gt;

&lt;p&gt;This is because the metrics, again, bear no direct relationship to the billing meters. For example, you will
see things like this in your storage metrics:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;user;Create&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;user;SessionSetup&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;user;Write&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;user;GetFile&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;user;QueryInfo&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;… and more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These bear a little bit more relationship to the file-system semantics of Azure Files access over SMB
(but still only partially). The big problem is that there’s no obvious way to relate the metric values
to the corresponding Billing Meters being used. We can guess about what some of it means, but
since it’s essentially undocumented, it does not provide a base that’s stable enough to actually
audit your bill.&lt;/p&gt;

&lt;p&gt;It also clearly doesn’t relate very clearly to the public pricing information, either.&lt;/p&gt;

&lt;p&gt;But beyond the obvious disconnect with pricing/meters, there’s an even more annoying issue with
Azure Files metrics: They don’t provide enough information to actually troubleshoot billing issues,
because there are no corresponding access logs for Azure Files.&lt;/p&gt;

&lt;p&gt;So if my Azure Files bill grows 10x in write operations, there doesn’t appear to be a way to figure out
what shares, folders, or files are actually getting accessed and thus triggering the usage increase. Even
Microsoft Support appears unable to obtain this information, which means that if you run into such a case,
you’re stuck trying to figure things out by trial and error.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;While Azure Files provides an excellent platform for cloud services, make sure you understand exactly
what your usage patterns are and keep in mind that the file-system nature of the service seems to be
very much at odds with how the pricing information is presented. Expecting some surprises in your bill
while you understand your usage patterns better might be a good idea, too.&lt;/p&gt;
</description>
				<pubDate>Wed, 11 Dec 2019 00:00:00 +0000</pubDate>
				<link>https://winterdom.com/2019/12/11/azure-files-and-billing-transparency</link>
				<guid isPermaLink="true">https://winterdom.com/2019/12/11/azure-files-and-billing-transparency</guid>
			</item>
		
			<item>
				<title>Importing Certificates into Azure Key Vault using the API</title>
				<description>&lt;p&gt;I spent some time the last two days figuring out how to correctly import X.509
certificates into an Azure &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/key-vault/&quot;&gt;Key Vault&lt;/a&gt; instance using 
the API (through the &lt;a href=&quot;https://www.nuget.org/packages/Microsoft.Azure.KeyVault&quot;&gt;Microsoft.Azure.KeyVault&lt;/a&gt;
NuGet package), and ran into a few issues.&lt;/p&gt;

&lt;p&gt;Unfortunately, neither the library, nor the underlying REST API are very well documented, so wanted to
write this post to document the gotchas I ran into, in case it’s useful to anyone.&lt;/p&gt;

&lt;h2 id=&quot;pem-certificate-format&quot;&gt;PEM Certificate Format&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://docs.microsoft.com/en-us/rest/api/keyvault/importcertificate/importcertificate&quot;&gt;Import Certificate&lt;/a&gt;
API (and corresponding &lt;code class=&quot;highlighter-rouge&quot;&gt;KeyVault.ImportCertificate()&lt;/code&gt; method) are documented as accepting the certificate
to import in both &lt;code class=&quot;highlighter-rouge&quot;&gt;PFX&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;PEM&lt;/code&gt; formats. It took me a while to figure out the right incantation
to use for a &lt;code class=&quot;highlighter-rouge&quot;&gt;PEM&lt;/code&gt; file, however.&lt;/p&gt;

&lt;p&gt;There are a few separate issues here you need to be very careful about:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Private Key Format&lt;/strong&gt;: A certificate with a private key in a PEM file could have the key stored
in various format. One very common one is &lt;code class=&quot;highlighter-rouge&quot;&gt;PKCS#1&lt;/code&gt;, which is identified by the key being wrapped in
&lt;code class=&quot;highlighter-rouge&quot;&gt;-----BEGIN RSA PRIVATE KEY-----&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;-----END RSA PRIVATE KEY-----&lt;/code&gt;.&lt;/p&gt;

    &lt;p&gt;If you try to import such a certificate to Key Vault, however, you will get an error. This is because
Key Vault will only accept a key in &lt;code class=&quot;highlighter-rouge&quot;&gt;PKCS#8&lt;/code&gt; format, which you will recognize because it’s wrapped
in &lt;code class=&quot;highlighter-rouge&quot;&gt;-----BEGIN PRIVATE KEY-----&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;-----END PRIVATE KEY-----&lt;/code&gt;.&lt;/p&gt;

    &lt;p&gt;You can easily use the &lt;code class=&quot;highlighter-rouge&quot;&gt;openssl pkcs8 -topk8&lt;/code&gt; command to convert the private key once you know to do this.&lt;/p&gt;

    &lt;p&gt;This aspect is not documented on the API, but it is mentioned in passing in the
(Key Vault documentation)[https://docs.microsoft.com/en-us/azure/key-vault/certificate-scenarios#formats-of-import-we-support].&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Content Type&lt;/strong&gt;: If you’re going to import a &lt;code class=&quot;highlighter-rouge&quot;&gt;PEM&lt;/code&gt; certificate, you also need to set the &lt;code class=&quot;highlighter-rouge&quot;&gt;policy.secret_props.contentType&lt;/code&gt;
property to the right type:&lt;/p&gt;

    &lt;div class=&quot;language-cs highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;policy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CertificatePolicy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;SecretProperties&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SecretProperties&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ContentType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;application/x-pem-file&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Value Format&lt;/strong&gt;: The second confusing part I ran into here is how to actually send the &lt;code class=&quot;highlighter-rouge&quot;&gt;PEM&lt;/code&gt; data to
KeyVault. The API documentation states that the &lt;code class=&quot;highlighter-rouge&quot;&gt;value&lt;/code&gt; parameter is &lt;code class=&quot;highlighter-rouge&quot;&gt;Base64 encoded representation of the certificate object to import.&lt;/code&gt; This is only partially correct.&lt;/p&gt;

    &lt;p&gt;If you’re importing a certificate in &lt;code class=&quot;highlighter-rouge&quot;&gt;PFX&lt;/code&gt; format, this is correct. &lt;code class=&quot;highlighter-rouge&quot;&gt;PFX&lt;/code&gt; is a binary format, so you need to
base64-encode the value before providing it to Key Vault. &lt;code class=&quot;highlighter-rouge&quot;&gt;PEM&lt;/code&gt;, however, is already a text format, so
base64-encoding it will make no sense.&lt;/p&gt;

    &lt;p&gt;The result is that the &lt;code class=&quot;highlighter-rouge&quot;&gt;value&lt;/code&gt; parameter will just be the raw text contents of your &lt;code class=&quot;highlighter-rouge&quot;&gt;PEM&lt;/code&gt; file. With one
major, undocumented gotcha: The content &lt;strong&gt;must&lt;/strong&gt; use UNIX-style line separators (&lt;code class=&quot;highlighter-rouge&quot;&gt;\n&lt;/code&gt;). Attempting to
send the content using Windows-style line endings (&lt;code class=&quot;highlighter-rouge&quot;&gt;\r\n&lt;/code&gt;) will just result in a confusing error
such as &lt;code class=&quot;highlighter-rouge&quot;&gt;The specified PEM X.509 certificate content is in an unexpected format. Please check if certificate is in valid PEM format&lt;/code&gt;.&lt;/p&gt;

    &lt;p&gt;The only way I was able to figure out this little detail was by reading the &lt;a href=&quot;https://github.com/azure/azure-cli&quot;&gt;Azure CLI&lt;/a&gt;
source code.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;updating-certificates&quot;&gt;Updating Certificates&lt;/h2&gt;

&lt;p&gt;Another interesting scenario I ran into was attempting to import a new certificate version on top of an
existing certificate as a new version. The documentation for the
&lt;a href=&quot;https://docs.microsoft.com/en-us/rest/api/keyvault/importcertificate/importcertificate&quot;&gt;Import Certificate&lt;/a&gt;
API doesn’t actually say if this is possible, but since the Azure Portal actually allows you to do it,
I figured it would be a safe bet that it would work.&lt;/p&gt;

&lt;p&gt;It is, indeed, possible to do this. However, there was one surprising error I ran into while testing this out.&lt;/p&gt;

&lt;p&gt;Purely by coincidence, I tried importing a certificate that had a 4096-bit key as a new version of a previous
certificate that had a 2048-bit key. Trying this out failed with a &lt;code class=&quot;highlighter-rouge&quot;&gt;CONFLICT&lt;/code&gt; error. Digging deeper, I found
out that the actual error message was &lt;code class=&quot;highlighter-rouge&quot;&gt;Expected KeySize is 4096 but was 2048&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This made no sense at first, until I realized that Key Vault was apparently attempting to somehow reuse the key of the
current certificate version rather than the one included in the &lt;code class=&quot;highlighter-rouge&quot;&gt;Import Certificate&lt;/code&gt; call.&lt;/p&gt;

&lt;p&gt;The way to avoid this error appears to be to explicitly set the &lt;code class=&quot;highlighter-rouge&quot;&gt;policy.key_props.key_size&lt;/code&gt; parameter to the right
value when attempting to import the new certificate version on top of the old one:&lt;/p&gt;

&lt;div class=&quot;language-cs highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;policy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CertificatePolicy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Attributes&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CertificateAttributes&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Enabled&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;SecretProperties&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SecretProperties&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ContentType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;application/x-pem-file&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;KeyProperties&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;KeyProperties&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Exportable&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ReuseKey&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;KeySize&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;theCertificate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PublicKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;KeySize&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hope you find this useful!&lt;/p&gt;
</description>
				<pubDate>Thu, 31 Oct 2019 00:00:00 +0000</pubDate>
				<link>https://winterdom.com/2019/10/31/importing-keyvault-certificates-api</link>
				<guid isPermaLink="true">https://winterdom.com/2019/10/31/importing-keyvault-certificates-api</guid>
			</item>
		
			<item>
				<title>Defining RBAC Role Assignments in ARM Templates</title>
				<description>&lt;p&gt;It’s no secret I’m a big fan of Azure Resource Manager (ARM) templates. Getting
started with ARM templates is hard, but well worth the effort, and make it significantly
easier to have reproduceable, consistent deployments of your Azure resources.&lt;/p&gt;

&lt;p&gt;One thing that I had been feeling left out, however, was being able to
assign permissions to Azure resources during creation. Azure’s Role-based Access Control
(RBAC) mechanism is a powerful way to control who can manage and access your resources,
and having to do this through scripting was possible, but cumbersome at times.&lt;/p&gt;

&lt;p&gt;A few days ago, I realized that you can actually
&lt;a href=&quot;https://github.com/Azure/azure-quickstart-templates/tree/master/101-rbac-builtinrole-resourcegroup&quot;&gt;create RBAC role assignments&lt;/a&gt;
through ARM templates just like any other resource. This capability is not new by any means, I
just had missed it before!&lt;/p&gt;

&lt;h2 id=&quot;creating-an-assignment&quot;&gt;Creating an assignment&lt;/h2&gt;

&lt;p&gt;To create an assignment, you need the following information:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The ID of the role you want to assign. This is a long string that contains the
subscription id and the role identifier (both GUIDs).&lt;/li&gt;
  &lt;li&gt;The object ID of the user/group/service principal you want to grant access to.&lt;/li&gt;
  &lt;li&gt;The scope at which you want to assign the role, which is going to be either a
subscription, resource group, or resource id.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s an example of creating such an assignment:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$schema&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;contentVersion&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1.0.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;parameters&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; 
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;monitoringUsersGroup&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;metadata&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Object ID for the monitoring users group in AAD&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;variables&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;monitoringContributorRole&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[concat(subscription().Id, '/providers/Microsoft.Authorization/roleDefinitions/749f88d5-cbae-40b8-bcfc-e573ddc772fa')]&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;resources&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Microsoft.Authorization/roleAssignments&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ace492e6-ebf6-48fa-8dd4-ea762489cbf3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;apiVersion&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2017-10-01-preview&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;roleDefinitionId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[variables('monitoringContributorRole')]&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;principalId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[parameters('monitoringUsersGroup')]&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;scope&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[resourceGroup().Id]&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;outputs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we grant the members of an Azure Active Directory group the &lt;code class=&quot;highlighter-rouge&quot;&gt;Monitoring Contributor&lt;/code&gt;
built-in role to the resource group the template is deployed to.&lt;/p&gt;

&lt;p&gt;Also interesting here is that you don’t need to specify a &lt;code class=&quot;highlighter-rouge&quot;&gt;location&lt;/code&gt; property in the resource.&lt;/p&gt;

&lt;h2 id=&quot;some-gotchas&quot;&gt;Some gotchas&lt;/h2&gt;

&lt;p&gt;There are a couple of things to watch out for when doing this.&lt;/p&gt;

&lt;p&gt;The first one is that to assign a role, you need the &lt;code class=&quot;highlighter-rouge&quot;&gt;objectId&lt;/code&gt; of the AAD user/group/principal,
rather than the name. This is cumbersome because there’s no way to resolve these within
the ARM template itself, so you’ll always need to pass these as input parameters.&lt;/p&gt;

&lt;p&gt;A more significant issue, however, is the &lt;code class=&quot;highlighter-rouge&quot;&gt;name&lt;/code&gt; of the &lt;code class=&quot;highlighter-rouge&quot;&gt;roleAssignment&lt;/code&gt; resource, which
needs to be a unique GUID.&lt;/p&gt;

&lt;p&gt;This is a problem if, for example, you’re assigning role permissions at the resource group
or individual resource level, rather than globally at the subscription.&lt;/p&gt;

&lt;p&gt;For example, in my case I was creating a template that would be used to deploy multiple
copies of the same resources into different resource groups within the same subscription.&lt;/p&gt;

&lt;p&gt;If the GUID that defines the role assignment name is hardcoded in the template, then
each time I ran the template, the &lt;code class=&quot;highlighter-rouge&quot;&gt;scope&lt;/code&gt; of the role assignment would get overwritten with
the id of the last resource group it was deployed to. Clearly, this is undesirable.&lt;/p&gt;

&lt;p&gt;What we need then, is a way to ensure that each deployment to a different resource group
uses a different GUID for the role assignment, but at the same time, ensure that the same
one is used when deploying to the same resource group.&lt;/p&gt;

&lt;p&gt;Clearly, providing the assignment GUID as a parameter is an easy workaround, but very cumbersome.&lt;/p&gt;

&lt;p&gt;A better workaround comes from the &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-template-functions-string#guid&quot;&gt;guid&lt;/a&gt;
function! It takes one or more strings that are used to calculate a hash, very much
like the &lt;code class=&quot;highlighter-rouge&quot;&gt;uniquestring&lt;/code&gt; function; only this one generates a string in GUID format instead.&lt;/p&gt;

&lt;p&gt;By using the &lt;code class=&quot;highlighter-rouge&quot;&gt;guid&lt;/code&gt; function with the resource group id and some other consistent stuff as input,
we can solve our problem in an elegant way:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Microsoft.Authorization/roleAssignments&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[guid(resourceGroup().id, 'monitoringUsers')]&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
				<pubDate>Thu, 02 Aug 2018 00:00:00 +0000</pubDate>
				<link>https://winterdom.com/2018/08/02/rbac-role-assignments-in-arm-templates</link>
				<guid isPermaLink="true">https://winterdom.com/2018/08/02/rbac-role-assignments-in-arm-templates</guid>
			</item>
		
			<item>
				<title>Issues when deleting azureFile dynamic volumes in Kubernetes</title>
				<description>&lt;p&gt;I’ve been doing a lot of work lately with Kubernetes and Azure Kubernetes Service in particular. For this,
I’m using the azureFile storage provider to support providing storage folders for my pods.&lt;/p&gt;

&lt;p&gt;For one specific case, I’m using dynamic provisioning of persistent volumes, as described in the
&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/aks/azure-files-dynamic-pv&quot;&gt;documentation&lt;/a&gt;. This has been working great.
Almost.&lt;/p&gt;

&lt;p&gt;Today I noticed something odd. Some of the Persistent Volumes created were stuck on a failed state
during deletion:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://static.winterdom.com/images/2018/aks-azurefiles-1.png&quot; alt=&quot;Failed Persistent Volumes&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The error message was this:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Failed to create deleter for volume &quot;pvc-85ba62d5-902e-11e8-9771-2a03d0b14ac3&quot;: Couldn't get secret 6d07576ce8d89bd641b5/azure-storage-account-fd9063993902011e888c32e-secret
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This actually made sense. The way dynamic persistent volumes work is this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;When the Persistent Volume Claim is created, Kubernetes creates a new Secret object containing the
credentials for the Azure Storage Account. This secret is named &lt;code class=&quot;highlighter-rouge&quot;&gt;azure-storage-account-&amp;lt;namespace&amp;gt;-secret&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;When the Persistent Volume Claim is deleted, the deleter for the volume will use these credentials
to delete the Azure File Share that was dynamically created, and then delete the corresponding secret.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second part is what was biting me.&lt;/p&gt;

&lt;p&gt;I currently deploy the applications using &lt;a href=&quot;https://docs.helm.sh/&quot;&gt;Helm&lt;/a&gt;. I deploy each one into a separate Kubernetes
Namespace. This is fully supported by Helm, but has one issue: When you delete the application using
&lt;code class=&quot;highlighter-rouge&quot;&gt;helm delete&lt;/code&gt;, the original namespace created remains behind. I wanted to clean these up, and so
was aggressively deleting them using &lt;code class=&quot;highlighter-rouge&quot;&gt;kubectl delete namespace&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The problem here is that the secret that gets automatically created by the azureFiles provider when
the Persistent Volume Claim is created, goes into the same namespace as the PVC. That meant that when I was
aggressively removing the namespace, I was also deleting the secret before the volume deleter could get to it.&lt;/p&gt;

&lt;p&gt;This isn’t very clearly documented (or at least I found no mention of this), so it might be something to watch out for.&lt;/p&gt;
</description>
				<pubDate>Thu, 26 Jul 2018 00:00:00 +0000</pubDate>
				<link>https://winterdom.com/2018/07/26/kubernetes-azureFile-dynamic-volumes-deleting</link>
				<guid isPermaLink="true">https://winterdom.com/2018/07/26/kubernetes-azureFile-dynamic-volumes-deleting</guid>
			</item>
		
			<item>
				<title>AzureFile Persistent Volumes Retain Issue</title>
				<description>&lt;p&gt;A bit ago, I &lt;a href=&quot;/2018/07/23/aks-azure-files-permissions&quot;&gt;posted&lt;/a&gt; about some issues around permissions
when using static provisioning of Azure File volumes in Azure Kubernetes Service (AKS). In there, I mentioned that the
workaround was to use explicit Persistent Volumes so that the right mount options could be created.&lt;/p&gt;

&lt;p&gt;Since then, I’ve run into a separate, but related, issue. I started noticing that sometimes, my Persistent Volume Claims
would get stuck on the &lt;code class=&quot;highlighter-rouge&quot;&gt;PENDING&lt;/code&gt; state:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://static.winterdom.com/images/2018/aks-azurefiles-2.png&quot; alt=&quot;Pending Persistent Volume Claims&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The notes for the PVCs would not contain any useful information. But looking at the Persistent Volumes, I noticed
they would get stuck in the &lt;code class=&quot;highlighter-rouge&quot;&gt;RELEASED&lt;/code&gt; state:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://static.winterdom.com/images/2018/aks-azurefiles-3.png&quot; alt=&quot;Released Persistent Volumes&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I could not figured out exactly what was happening until I noticed the pattern that led to it:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;I’d create the Persistent Volumes&lt;/li&gt;
  &lt;li&gt;Then I’d deploy an application on the cluster that would create Persistent Volume Claims on the volumes&lt;/li&gt;
  &lt;li&gt;I’d update the application. This worked just fine and stuff continued to run.&lt;/li&gt;
  &lt;li&gt;I’d remove the application (thus deleting the Persistent Volume Claims)&lt;/li&gt;
  &lt;li&gt;I’d deploy the application again, and now the PVCs would get stuck in &lt;code class=&quot;highlighter-rouge&quot;&gt;Pending&lt;/code&gt; state.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The issue of course, happened in step (4) above. Once the Persistent Volume Claim was deleted, the Persistent Volume
would transitioned to the &lt;code class=&quot;highlighter-rouge&quot;&gt;Released&lt;/code&gt; status. These volumes all had a default
&lt;a href=&quot;https://kubernetes.io/docs/tasks/administer-cluster/change-pv-reclaim-policy/&quot;&gt;reclaim policy&lt;/a&gt; of &lt;code class=&quot;highlighter-rouge&quot;&gt;Retain&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Based on my understanding, I would have expected that taking a new claim on the volumes would work. But unfortunately,
this does not appear to be the case (either I’m misunderstanding the Kubernetes documentation, or there’s an issue
here in the volume provider).&lt;/p&gt;

&lt;p&gt;I also thought that maybe making this work would involve setting the retain policy to &lt;code class=&quot;highlighter-rouge&quot;&gt;Recycle&lt;/code&gt;, but this appears
to be unimplemented as of yet for the azureFile provider.&lt;/p&gt;

&lt;p&gt;In any case, once this happens, the only way to get this working again is to manually delete the Persistent Volumes
and recreate them again from scratch.&lt;/p&gt;

&lt;p&gt;This is unexpected (not explicitly documented), not obvious, and certainly annoying.:w&lt;/p&gt;
</description>
				<pubDate>Thu, 26 Jul 2018 00:00:00 +0000</pubDate>
				<link>https://winterdom.com/2018/07/26/azurefile-persistent-volumes-retain-issue</link>
				<guid isPermaLink="true">https://winterdom.com/2018/07/26/azurefile-persistent-volumes-retain-issue</guid>
			</item>
		
			<item>
				<title>AKS Service Principal Credentials</title>
				<description>&lt;p&gt;When creating a new Azure Kubernetes Service (AKS) cluster, you must define
a Service Principal in your Azure Active Directory Tenant that will
be used by the cluster to do operations on the Azure infrastructure later on.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/aks/kubernetes-service-principal&quot;&gt;documentation&lt;/a&gt; states:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;On the master and node VMs in the Kubernetes cluster, the service principal
credentials are stored in the file &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc/kubernetes/azure.json&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I was curious how this worked, so I set out to take a look at the file. An easy way to do this
was to spawn a new &lt;code class=&quot;highlighter-rouge&quot;&gt;busybox&lt;/code&gt; pod on the cluster with the &lt;code class=&quot;highlighter-rouge&quot;&gt;azure.json&lt;/code&gt; file
mounted as a volume into the container.&lt;/p&gt;

&lt;p&gt;I used the following YAML template to create the pod using &lt;code class=&quot;highlighter-rouge&quot;&gt;kubectl apply&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;v1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Pod&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;test&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;containers&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;test&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;busybox&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;sleep&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;3600&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumeMounts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;mountPath&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/etc/kubernetes/azure.json&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;azure-secret&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;azure-secret&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;hostPath&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/etc/kubernetes/azure.json&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;File&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once the pod is up and running, I went spelunking into it by opening a new interactive session
using &lt;code class=&quot;highlighter-rouge&quot;&gt;kubectl exec -it test -- sh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, let’s look at the contents of the file through &lt;code class=&quot;highlighter-rouge&quot;&gt;cat /etc/kubernetes/azure.json&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cloud&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;AzurePublicCloud&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;tenantId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*********&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;subscriptionId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*********&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;aadClientId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;**********&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;aadClientSecret&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*********&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;resourceGroup&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;MC_dev-k-eastus-2-rg_dev-k-eastus-2_eastus&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;location&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;eastus&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;vmType&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;standard&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;subnetName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;aks-subnet&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;securityGroupName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;aks-agentpool-22088002-nsg&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;vnetName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;aks-vnet-22088002&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;vnetResourceGroup&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;routeTableName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;aks-agentpool-22088002-routetable&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;primaryAvailabilitySetName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;agentpool-availabilitySet-22088002&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;primaryScaleSetName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cloudProviderBackoff&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cloudProviderBackoffRetries&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cloudProviderBackoffExponent&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cloudProviderBackoffDuration&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cloudProviderBackoffJitter&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cloudProviderRatelimit&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cloudProviderRateLimitQPS&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cloudProviderRateLimitBucket&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;useManagedIdentityExtension&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;useInstanceMetadata&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;providerVaultName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;providerKeyName&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;k8s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;providerKeyVersion&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The relevant fields containing the credentials are &lt;code class=&quot;highlighter-rouge&quot;&gt;aadClientId&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;aadClientSecret&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I was curious, however, as to the permissions on the file:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/ # ls -l /etc/kubernetes
total 4
-rw-------    1 root     root          1173 Jul 24 19:13 azure.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As suspected, the file is only readable by containers running as root.&lt;/p&gt;
</description>
				<pubDate>Tue, 24 Jul 2018 00:00:00 +0000</pubDate>
				<link>https://winterdom.com/2018/07/24/aks-service-principal-credentials</link>
				<guid isPermaLink="true">https://winterdom.com/2018/07/24/aks-service-principal-credentials</guid>
			</item>
		
			<item>
				<title>AKS and Azure Files Permissions</title>
				<description>&lt;p&gt;Saving this here for my own recollection later on. Warning, a bit of ranting ahead.&lt;/p&gt;

&lt;p&gt;Recently, I’ve been running a lot of trials on top of the Azure managed Kubernetes
Service (AKS). One key feature that I needed was the ability to provide services
deployed to an AKS cluster with external storage. Since I needed the option
to mount the storage shared between multiple pod instances, Azure Files was the way to go.&lt;/p&gt;

&lt;p&gt;My first attempt to do this leveraged using automated static volume provisioning,
as defined in the &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/aks/azure-files-volume&quot;&gt;documentation&lt;/a&gt;.
&lt;em&gt;Static&lt;/em&gt; just means that you first create the Azure File Share on your own,
and then provide the pod with the necessary information to reach it, such as the
account name and key, and the file share name.&lt;/p&gt;

&lt;p&gt;This worked, sort of. There’s a big gotcha that’s not included in the documentation, and
that takes a bit of search-fu to &lt;a href=&quot;http://unethicalblogger.com/2017/12/01/aks-storage-research.html&quot;&gt;find it&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The problem is &lt;em&gt;file permissions&lt;/em&gt;. When using static provisioning, the Azure Files plugin
in Kubernetes will default the share permissions to &lt;code class=&quot;highlighter-rouge&quot;&gt;0750&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;0700&lt;/code&gt; depending on the version
of Kubernetes in use.&lt;/p&gt;

&lt;p&gt;What this means is that static provisioning, as described in the AKS documentation,
is &lt;em&gt;completely useless&lt;/em&gt; if the following conditions are met:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Your container is configured to run as a non-root user (which is generally the recommended
approach for security), and&lt;/li&gt;
  &lt;li&gt;You need to write to the mounted file share.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you just need to read data from the share, then this is not a problem. If you need to write to it,
however, this really throws a wrench into your plans, and the documentation doesn’t tell you
how to work around it.&lt;/p&gt;

&lt;h2 id=&quot;the-workaround&quot;&gt;The workaround&lt;/h2&gt;

&lt;p&gt;The workaround is described in more detail on &lt;a href=&quot;https://github.com/andyzhangx/Demo/blob/master/linux/azurefile/azurefile-mountoptions.md#set-mountoptions-in-static-provisioning-for-azure-file-support-from-v150&quot;&gt;this sample&lt;/a&gt;
by Andy Zhang.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Create a new Kubernetes Persistent Volume for your Azure Files Share, and override the
default file and directory permissions for the file share.
    &lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;v1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;PersistentVolume&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;pv-azurefile&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;capacity&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;storage&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;5Gi&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;accessModes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ReadWriteMany&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;azureFile&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;secretName&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;azure-secret&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;shareName&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;k8stest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;readOnly&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;mountOptions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dir_mode=0777&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;file_mode=0777&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;uid=10000&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;gid=10000&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;mfsymlinks&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nobrl&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Create a new Persistent Volume Claim for your service to request access to the
Persistent Volume created in the previous step
    &lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;PersistentVolumeClaim&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;v1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;pvc-azurefile&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;accessModes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ReadWriteMany&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;mountOptions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;storage&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;5Gi&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;storageClassName&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;volumeName&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;pv-azurefile&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Create a volume for your pod out of the PVC.&lt;/p&gt;

    &lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;azurefile01&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;claimName&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;pvc-azurefile&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice that the storage capacity is required on both the Persistent Volume and the Claim, and should be
equal or smaller to your Azure File Share size.&lt;/p&gt;

&lt;h2 id=&quot;the-disadvantages&quot;&gt;The disadvantages&lt;/h2&gt;

&lt;p&gt;The documented workaround works just fine. However, the whole issue is frustrating on many levels.&lt;/p&gt;

&lt;p&gt;First of all, making it hard to follow the recommended practice of running containers
as non-privileged users makes no sense to me. This should be easy, and work right away without
having to result to these complicated steps.&lt;/p&gt;

&lt;p&gt;Second, the fact that the documentation doesn’t warn you about the issue, and doesn’t provide a link
to the solution, is very frustrating, and causes you to lose a few hours for no good reason.&lt;/p&gt;

&lt;p&gt;While I can sort of understand why restricting the default Unix permissions on the file share,
it seems to me this is just a very leaky abstraction, than on a platform like AKS doesn’t make
a lot of sense.&lt;/p&gt;

&lt;p&gt;The most frustrating aspect for me, however, is the fact that using Persistent Volumes forces you
to have to create those manually before you can deploy applications. If you just need
to reference a single Azure File Share, then it’s sort of OK, but if you need to reference
several, it quickly adds to a lot of work. You need to manually create at least 2 Kubernetes objects
(a Secret, and the Persistent Volume) for each share.&lt;/p&gt;

&lt;p&gt;I’m using &lt;a href=&quot;https://docs.helm.sh/&quot;&gt;Helm&lt;/a&gt; to deploy my application, and now I can’t simply
deploy the helm chart. I need to manually create stuff, ensure it’s correct, and only then can I
deploy it. This is just cumbersome.&lt;/p&gt;

&lt;p&gt;I wish you could just adjust default permissions directly when creating the volume, but alas,
apparently this is not possible with the Kubernetes model (or simply unsupported by the Azure Files plugin).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Posted some additional findings &lt;a href=&quot;/2018/07/26/azurefile-persistent-volumes-retain-issue&quot;&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;getting-fixed&quot;&gt;Getting fixed!&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Update 2018-11-15&lt;/strong&gt;: Looks like this issue is &lt;a href=&quot;https://github.com/kubernetes/kubernetes/pull/69854&quot;&gt;finally fixed&lt;/a&gt;
in Kubernetes &lt;code class=&quot;highlighter-rouge&quot;&gt;v1.11.4&lt;/code&gt; with the default permissions for Azure Files reverting to &lt;code class=&quot;highlighter-rouge&quot;&gt;0777&lt;/code&gt;.
Great news.&lt;/p&gt;
</description>
				<pubDate>Mon, 23 Jul 2018 00:00:00 +0000</pubDate>
				<link>https://winterdom.com/2018/07/23/aks-azure-files-permissions</link>
				<guid isPermaLink="true">https://winterdom.com/2018/07/23/aks-azure-files-permissions</guid>
			</item>
		
			<item>
				<title>AKS Node Troubles</title>
				<description>&lt;p&gt;I’ve been having lots of fun this past week running some interesting experiments
on &lt;a href=&quot;https://kubernetes.io/&quot;&gt;Kubernetes&lt;/a&gt;. For simplicity, I created a single-node
&lt;a href=&quot;https://azure.microsoft.com/en-us/services/kubernetes-service/&quot;&gt;AKS&lt;/a&gt;
(Azure Kubernetes Cluster) using a B2S instance on Azure.&lt;/p&gt;

&lt;p&gt;Everything worked perfectly until Friday afternoon. At some point, I noticed that
every operation on the cluster appeared to be very slow. Even browsing
the Kubernetes admin portal was an exercise in frustration. The worker node, however
never went above 20% CPU.&lt;/p&gt;

&lt;p&gt;I then tried restarting the node, which proved to be…. a mistake, as it never
came back up completely.&lt;/p&gt;

&lt;p&gt;After a while, I started noticing that when running &lt;code class=&quot;highlighter-rouge&quot;&gt;kubectl get nodes&lt;/code&gt;, the node
was being reported as NotReady. I didn’t have time to troubleshoot it further, so
left it like that and tried again today, without much more luck.&lt;/p&gt;

&lt;p&gt;After searching for a bit, tried doing a &lt;code class=&quot;highlighter-rouge&quot;&gt;kubectl describe node &amp;lt;node&amp;gt;&lt;/code&gt;, and noticed
it was reporting:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;KubeletNotReady           PLEG is not healthy....
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Of course, trying to find out what &lt;code class=&quot;highlighter-rouge&quot;&gt;PLEG&lt;/code&gt; was supposed to be was next to impossible.
I did, however, looked up the &lt;code class=&quot;highlighter-rouge&quot;&gt;kubelet&lt;/code&gt; logs using &lt;code class=&quot;highlighter-rouge&quot;&gt;journalctl -u kubelet&lt;/code&gt;, but didn’t
see anything noteworthy there.&lt;/p&gt;

&lt;p&gt;I then tried restarting the &lt;code class=&quot;highlighter-rouge&quot;&gt;kubelet&lt;/code&gt; service which sort of worked! After about 5 mninutes
the node transitioned to the &lt;code class=&quot;highlighter-rouge&quot;&gt;Ready&lt;/code&gt; status, and about 3 pods came up to &lt;code class=&quot;highlighter-rouge&quot;&gt;Running&lt;/code&gt; status.
Unexpectedly, all 3 were user pods, and not a single one of the &lt;code class=&quot;highlighter-rouge&quot;&gt;kube-system&lt;/code&gt; pods came
up before the node went back to &lt;code class=&quot;highlighter-rouge&quot;&gt;NotReady&lt;/code&gt; status. Again, the reported failure was
&lt;code class=&quot;highlighter-rouge&quot;&gt;PLEG is not healthy&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;So far, I have failed to figure out exactly what triggered this issue, and how to solve
the underlying issue. Heck, I’m still trying to figure out what PLEG is.&lt;/p&gt;

&lt;p&gt;The logical thing to do would have been to nuke the node, and create a new one from scratch.&lt;/p&gt;

&lt;p&gt;However, I couldn’t figure out an obvious way to do that with AKS. While you can easily
scale your cluster to add additional nodes, it’s not obvious how to replace an unhealthy node
with a new one. I’m sure it might be possible, but I didn’t spend much trying to look for it.&lt;/p&gt;

&lt;p&gt;What did worked was upgrading the cluster. I originally created it using Kubernetes
&lt;code class=&quot;highlighter-rouge&quot;&gt;1.10.3&lt;/code&gt;, and then noticed that &lt;code class=&quot;highlighter-rouge&quot;&gt;1.10.5&lt;/code&gt; was available.&lt;/p&gt;

&lt;p&gt;Kubernetes upgrades in AKS work by provisioning a new node, then removing the old one, and so
it proved an indirect way to do exactly what I wanted, resulting in a healthy cluster again.
However, I’m still scratching my head as to what happened and what exactly was failing…&lt;/p&gt;
</description>
				<pubDate>Sat, 14 Jul 2018 00:00:00 +0000</pubDate>
				<link>https://winterdom.com/2018/07/14/aks-node-troubles</link>
				<guid isPermaLink="true">https://winterdom.com/2018/07/14/aks-node-troubles</guid>
			</item>
		
			<item>
				<title>Viasfora v4.0 Update</title>
				<description>&lt;p&gt;For the past few months, I’ve been slowly improving my Visual Studio Extension, &lt;a href=&quot;https://viasfora.com&quot;&gt;Viasfora&lt;/a&gt;.
Version 4.0 was recently released, and besides regular bug fixes and some much needed refactoring,
I also implemented a brand new feature: &lt;strong&gt;Rainbow Lines&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://static.winterdom.com/images/2018/rainbow-lines.gif&quot; alt=&quot;Rainbow Lines&quot; /&gt;&lt;/p&gt;

&lt;p&gt;For now, this feature is disabled by default, while I iron out all kinks and ensure it has the
best possible performance. If you’re a Viasfora user, and like the feature, please do give it
a try and let me know any feedback!&lt;/p&gt;

&lt;p&gt;Implementing this feature was interesting. Getting the right locations and handling caret movement
was relatively straightforward, particularly since it relies on the same logic that was already present
to support the Rainbow Highlight feature. Drawing the lines, however, was far trickier.&lt;/p&gt;

&lt;p&gt;The largest complexity here is the fact that the Visual Studio Text Editor doesn’t have layout information
for all lines; just for those that are currently visible. So when the line containing the opening brace
or closing brace is not visible, figuring out the right place to draw the lines can get tricky.&lt;/p&gt;

&lt;p&gt;Still, I think the end result is pretty decent, particularly considering the tricks for handling
scrolled views, such as this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://static.winterdom.com/images/2018/rainbow-lines-2.png&quot; alt=&quot;Rainbow Lines Scrolled View&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Of course, it’s not perfect. For example, since Viasfora does not do lexical analysis, sometimes
the lines will not align perfectly with Visual Studio’s structure guides:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://static.winterdom.com/images/2018/rainbow-lines-3.png&quot; alt=&quot;Rainbow Lines on wrong column&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;themes&quot;&gt;Themes&lt;/h2&gt;

&lt;p&gt;Version 3.6 introduced the concept of themes. These are simple JSON files that contain
all the color information for the text editor classifications in Viasfora.&lt;/p&gt;

&lt;p&gt;You can export your current configuration as a new theme, or import an existing one.
I don’t think many people have been using this, but if you have customized the Viasfora
color configuration extensively, I’d love to see what you’ve done with it and what works for you.&lt;/p&gt;

&lt;p&gt;In the meantime, I’ve shared the theme I’m currently using for Rainbow Braces
&lt;a href=&quot;https://github.com/tomasr/viasfora/blob/master/themes/dark-light-braces.json&quot;&gt;here&lt;/a&gt;, and it
works pretty nicely on the Visual Studio dark theme:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://static.winterdom.com/images/2018/rainbow-dark-theme.png&quot; alt=&quot;Rainbow dark-light-braces theme&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;version-41&quot;&gt;Version 4.1&lt;/h2&gt;

&lt;p&gt;Since the v4.0 release, I’ve continued improving Viasfora, and version 4.1 should be coming up soon. It
contains a few improvements to Rainbow Lines, but the biggest change by far was required to support
changes in how Visual Studio loads extension packages.&lt;/p&gt;

&lt;p&gt;Recently, the product team announced that Visual Studio 2017 version 15.8, Visual Studio would start
alerting users when loading synchronous packages that are configured to auto load (via the &lt;code class=&quot;highlighter-rouge&quot;&gt;[ProvideAutoLoad]&lt;/code&gt;
attribute), and a later version would completely disable support for this.&lt;/p&gt;

&lt;p&gt;Of course, Viasfora was one of the affected extensions, since it was configured to auto-load when
the Text Editor is displayed the first time. Though the Viasfora package did very little initialization and
was generally quite fast, it would be subject to the same rules as any other package.&lt;/p&gt;

&lt;p&gt;Not wanting this to cause any issues, I set up to change this, which lead to a
significant &lt;a href=&quot;https://github.com/tomasr/viasfora/commit/975524186044ce5ef07b3755f5114476f55d6255&quot;&gt;refactoring&lt;/a&gt;
of the code. Converting the package to an &lt;code class=&quot;highlighter-rouge&quot;&gt;AsyncPackage&lt;/code&gt; did not seem possible
without dropping support for VS2012, but I was able to completely remove the need to auto-load
the package with only a minor loss of functionality.&lt;/p&gt;
</description>
				<pubDate>Mon, 04 Jun 2018 00:00:00 +0000</pubDate>
				<link>https://winterdom.com/2018/06/04/viasfora-updates</link>
				<guid isPermaLink="true">https://winterdom.com/2018/06/04/viasfora-updates</guid>
			</item>
		
			<item>
				<title>API Management Sign-in Tenant</title>
				<description>&lt;p&gt;Azure API Management supports multiple identity providers for the Developer Portal. One of these
is &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/api-management/api-management-howto-aad&quot;&gt;Azure Active Directory&lt;/a&gt;.
A common complaint, however, was that when enabling AAD authentication on the developer portal, the
sign-in experience would use the default look-and-feel of AAD rather than your organization’s customized
sign-in pages.&lt;/p&gt;

&lt;p&gt;The reason for this is that unlike many other products and services, API Management always works as a
multi-tenant application allowing users from multiple AAD tenants (the ones you configure). Because of this
it always uses the common AAD sign-in URL &lt;code class=&quot;highlighter-rouge&quot;&gt;https://login.microsoftonline.com/common&lt;/code&gt; rather than
the tenant-specific sign-in URL &lt;code class=&quot;highlighter-rouge&quot;&gt;https://login.microsoftonline.com/{tenant_name_or_id}&lt;/code&gt;. You can read
more about the common endpoint in the &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-devhowto-multi-tenant-overview&quot;&gt;AAD documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This changed a few weeks ago on the API Management side. Looking at the
&lt;a href=&quot;https://blogs.msdn.microsoft.com/apimanagement/2018/03/28/release-notes-march-28-2018/&quot;&gt;release notes&lt;/a&gt;, we
find this little note:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;When configuring Azure AD as an identity provider, it is now possible to designate one of
the allowed tenants as a sign-in tenant. All developer portal users will be redirected to
that tenant when logging in (instead of the “common” tenant)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The new configuration property on the AAD identity provider is called &lt;code class=&quot;highlighter-rouge&quot;&gt;signinTenant&lt;/code&gt;, and can be configured
in the Azure Portal experience when adding (or editing) an AAD identity provider:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://static.winterdom.com/images/2018/apim-aad-1.png&quot; alt=&quot;AAD identity provider configuration&quot; /&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; When configuring a new provider, you need to both &lt;em&gt;add&lt;/em&gt; the tenant ID to
the allowed tenant list, and provide it in the sign-in tenant field if you want it to work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is also a nice side-effect from configuring the &lt;code class=&quot;highlighter-rouge&quot;&gt;signinTenant&lt;/code&gt; property: Before this, using guest accounts
in AAD directories, such as Microsoft Accounts (MSA) or guest B2B accounts to sign in to the API
Management Developer Portal was not supported. The reason for this is that when using the &lt;code class=&quot;highlighter-rouge&quot;&gt;common&lt;/code&gt; endpoint,
AAD has no way to know the target directory to sign the user into.&lt;/p&gt;

&lt;p&gt;If you set the &lt;code class=&quot;highlighter-rouge&quot;&gt;signinTenat&lt;/code&gt; property, however, this now works for both MSA and B2B guest accounts on the
that specific tenant. This enables a lot of useful scenarios for API Management users.&lt;/p&gt;
</description>
				<pubDate>Fri, 20 Apr 2018 00:00:00 +0000</pubDate>
				<link>https://winterdom.com/2018/04/20/apimanager-signin-tenant</link>
				<guid isPermaLink="true">https://winterdom.com/2018/04/20/apimanager-signin-tenant</guid>
			</item>
		
	</channel>
</rss>
