9

I'm attempting to retrieve a file out of Azure File Storage to be used by an .exe that is executed within an Azure Function and can't seem to get pass the UNC credentials.

My app gets the UNC file path out of an Azure SQL database and then attempts to navigate to that UNC path (in Azure File Storage) to import the contents of the file. I can navigate to the file location from my PC in windows explorer but am prompted for the credentials.

I've tried using a "net use" command prior to executing the app but it doesn't seem to authenticate.

net use \\<storage account>.file.core.windows.net\<directory>\ /u:<username> <access key>

MyApp.exe 

Azure Function Log error:

Unhandled Exception: System.UnauthorizedAccessException: Access to the path '<file path>' is denied.

If possible, I'd rather not modify my C# app and do the authentication in the Azure Function (its a Batch function at the moment and will be timer based).

BamBamBeano
  • 464
  • 4
  • 13
  • 24
  • Reading this link it says you should be able to use the `NET USE` command by itself with your credentials or you can use the `CMDKEY` command to store your credentials and then use the `NET USE` command without your credentials. https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-files/#mount-the-file-share – Squashman Oct 18 '16 at 13:44
  • Good idea but the Azure Function doesn't seem to like the `CMDKEY`. `2016-10-18T15:40:22.425 CMDKEY: Credentials cannot be saved from this logon session. ` – BamBamBeano Oct 18 '16 at 15:41

2 Answers2

11

I believe it is not possible to mount an Azure File Service Share in an Azure Function as you don't get access to underlying infrastructure (same deal as WebApps).

What you could do is make use of Azure Storage SDK which is a wrapper over Azure Storage REST API and use that in your application to interact with files in your File Service Share.

Community
  • 1
  • 1
Gaurav Mantri
  • 128,066
  • 12
  • 206
  • 241
  • thanks for the quick reply. I was hoping to not have to modify my app to access Azure File Storage from an Azure Function but I'll look into the Azure Storage SDK. – BamBamBeano Oct 18 '16 at 13:25
  • Unfortunately, that's the only option available right now. – Gaurav Mantri Oct 18 '16 at 13:27
  • 2
    We do have an open issue to add Azure Files support to WebJobs SDK and Functions (see [here](https://github.com/Azure/azure-webjobs-sdk-extensions/issues/14)). No ETA on that. – mathewc Oct 18 '16 at 15:17
  • Using the examples here: https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-files/#develop-with-file-storage I still can't get around the "user name or password is incorrect" error. If I use "net use" to mount the drive locally it works fine. But within the context of an Azure Function I can not mount the drive. `if (file.Exists())` returns true, but `Closed.XML.Excel.XLWorkbook MyWorkbook = new XLWorkbook();` will produce the username/password incorrect error. – BamBamBeano Oct 18 '16 at 20:36
1

You cannot use SMB (445/TCP). Functions run inside the App Service sandbox.

From https://github.com/projectkudu/kudu/wiki/Azure-Web-App-sandbox#restricted-outgoing-ports:

Restricted Outgoing Ports

Regardless of address, applications cannot connect to anywhere using ports 445, 137, 138, and 139. In other words, even if connecting to a non-private IP address or the address of a virtual network, connections to ports 445, 137, 138, and 139 are not permitted.

Use the Azure Storage SDK to talk to your Azure File endpoint:

using Microsoft.Azure;  // Namespace for CloudConfigurationManager
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.File;

// Parse the connection string and return a reference to the storage account.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
    CloudConfigurationManager.GetSetting("StorageConnectionString"));

// Create a CloudFileClient object for credentialed access to File storage.
CloudFileClient fileClient = storageAccount.CreateCloudFileClient();

// Get a reference to the file share we created previously.
CloudFileShare share = fileClient.GetShareReference("logs");

// Ensure that the share exists.
if (share.Exists())
{
    // Get a reference to the root directory for the share.
    CloudFileDirectory rootDir = share.GetRootDirectoryReference();

    // Get a reference to the directory we created previously.
    CloudFileDirectory sampleDir = rootDir.GetDirectoryReference("CustomLogs");

    // Ensure that the directory exists.
    if (sampleDir.Exists())
    {
        // Get a reference to the file we created previously.
        CloudFile file = sampleDir.GetFileReference("Log1.txt");

        // Ensure that the file exists.
        if (file.Exists())
        {
            // Write the contents of the file to the console window.
            Console.WriteLine(file.DownloadTextAsync().Result);
        }
    }
}

Sample uses CloudConfigurationManager - i think that's a bit too much for such a simple scenario. I would do this instead:

using System.Configuration;

// "StorConnStr" is the Storage account Connection String
// defined for your Function in the Azure Portal
string connstr = ConfigurationManager.ConnectionStrings["StorConnStr"].ConnectionString;
evilSnobu
  • 24,582
  • 8
  • 41
  • 71
  • Thanks for the response. Similar to the comment on the answer above. I'm trying this method and able to print the contents to a console window. I'm having trouble getting it into a DataTable though. I'm using `ClosedXML.Excel.Workbook` and `ClosedXML.Excel.WorkSheet` and previously just sent in the UNC path. That doesn't seem to be possible now because I keep receiving the "username and password incorrect". Is there a way to pass something like `file.DownloadTextAsync().Result` into `ClosedXML.Excel.XLWorkbook`? – BamBamBeano Oct 19 '16 at 13:05
  • Is there any override on the method that reads in data other than the UNC type? – evilSnobu Oct 19 '16 at 17:12
  • Do this work in Azure Functions in the portal? I get the ERROR: The type or namespace name 'File' does not exist in the namespace 'Microsoft.WindowsAzure.Storage' And the ERROR: The type or namespace name 'CloudStorageAccount' does not exist in the namespace 'Microsoft.WindowsAzure.Storage' It seems to me that the function runtime 1 and 2 (preview) doesn't allow to change the target framework and is selecting by default something that doesn't have access to storage. Or I'm just missing something :) – zurcacielos Jul 16 '18 at 15:51
  • Should work but you need a specific version of that Storage nuget. Look it up, should match whatever version Functions v1 uses. You should really use v2 if you can. – evilSnobu Jul 16 '18 at 16:10