Repository: Azure/azure-linux-extensions

Issue:
LAD 3.0 returns unhelpful error if storage SAS token not passed in protected settings
If storageAccountSasToken is not specified in the protected settings, or if it's an empty string, LAD 3.0 returns a singularly unhelpful error message:
```
2017/09/05 21:52:14 [Microsoft.Azure.Diagnostics.LinuxDiagnostic-3.0.109] Invalid config settings given: Unknown exception occurred from generate_all_configs(). Msg: string index out of range. Can't proceed, but this will be still considered a success as it's an external error.
2017/09/05 21:52:14 [Microsoft.Azure.Diagnostics.LinuxDiagnostic-3.0.109] Daemon,success,0,Invalid config settings given: Unknown exception occurred from generate_all_configs(). Msg: string index out of range. Can't proceed, but this will be still considered a success as it's an external error.
```



Discussion:

Resolving patch:
diff --git a/Diagnostic/Utils/lad_ext_settings.py b/Diagnostic/Utils/lad_ext_settings.py
--- a/Diagnostic/Utils/lad_ext_settings.py
+++ b/Diagnostic/Utils/lad_ext_settings.py
@@ -89,6 +89,9 @@ def redacted_handler_settings(self):
         # The logic below could have been a general-purpose JSON tree walker, but since the specific
         # knowledge of where secrets are needs be applied anyway, it's coded for this specific schema anyway.
         # Secrets are stored only in the following paths: .storageAccountSasToken, and .sinksConfig.sink[].sasURL.
+        # LAD 2.3 used to support storageAccountKey; although LAD 3.0 does not support it, some users might mistakenly
+        # supply it. We redact it, if present, even though we're going to throw an error later on; the protected
+        # settings are logged before we inspect them to pull out the credentials.
 
         # Get and work on a copy of the handler settings dict. Note that it must be a deep copy!
         # dict(self.get_handler_settings()) doesn't work!
@@ -97,6 +100,8 @@ def redacted_handler_settings(self):
         if protected_settings:
             if 'storageAccountSasToken' in protected_settings:
                 protected_settings['storageAccountSasToken'] = 'REDACTED_SECRET'
+            if 'storageAccountKey' in protected_settings:
+                protected_settings['storageAccountKey'] = 'REDACTED_SECRET'
             if 'sinksConfig' in protected_settings and 'sink' in protected_settings['sinksConfig']:
                 for each_sink_dict in protected_settings['sinksConfig']['sink']:
                     if 'sasURL' in each_sink_dict:
diff --git a/Diagnostic/lad_config_all.py b/Diagnostic/lad_config_all.py
--- a/Diagnostic/lad_config_all.py
+++ b/Diagnostic/lad_config_all.py
@@ -452,14 +452,16 @@ def generate_all_configs(self):
 
         # 6. Actually update the storage account settings on mdsd config XML tree (based on extension's
         #    protectedSettings).
-        account = self._ext_settings.read_protected_config('storageAccountName')
+        account = self._ext_settings.read_protected_config('storageAccountName').strip()
         if not account:
-            return False, "Empty storageAccountName"
+            return False, "Must specify storageAccountName"
+        if self._ext_settings.read_protected_config('storageAccountKey'):
+            return False, "The storageAccountKey protected setting is not supported and must not be used"
         token = self._ext_settings.read_protected_config('storageAccountSasToken').strip()
+        if not token or token == '?':
+            return False, "Must specify storageAccountSasToken"
         if '?' == token[0]:
             token = token[1:]
-        if not token:
-            return False, "Empty storageAccountSasToken"
         endpoint = get_storage_endpoint_with_account(account,
                                                      self._ext_settings.read_protected_config('storageAccountEndPoint'))
         self._update_account_settings(account, token, endpoint)


Test patch: