Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Under which account a .net console application which is hosted inside Azure Function app, will be running

I have developed a .net console application which have these main characteristics :-

  1. Integrate with SharePoint online REST API, to retrieve some list items, and modify the items fields.
  2. Will run daily @1 am for example.
  3. I will host this console application inside Azure Function app.
  4. The Azure account does not have any permission on the sharepoint tenant, as the Azure account and the sharepoint online are on different domains.

so i am not sure under which account the console application will be running?

  • Will it runs under the current Azure account? if this is the case, then this will not work as the azure account is on different domain and does not have any permission on the sharepoint (and it shouldn't have)?

OR

  • I can define a service account for the Azure function app to run under it, where in this case i can define the service account to be an authorized account inside sharepoint online?

OR

  • i need to define the username/password inside the console application itself? i do not like to approach, as i will be exposing the password inside the console application. also changing the password for the username, means that we will need to update the console application accordingly..

so can anyone advice on this please? Thanks

EDIT

code for managing the console application authentication :-

using System; 

using System.Collections.Generic; 

using System.Linq; 

using System.Text; 

using Microsoft.SharePoint.Client; 



namespace O365SPProject 

{ 

    class Program 

    { 





     private class Configuration 

        { 

                public static string ServiceSiteUrl = "https://<tenant>.sharepoint.com"; 

                public static string ServiceUserName = "<user>@<tenant>.onmicrosoft.com"; 

                public static string ServicePassword = "xxxxxxxxxx"; 

        } 



                 static ClientContext GetonlineContext() 

                          { 

                                    var securePassword = new SecureString(); 

                                    foreach (char c in Configuration.ServicePassword) 

                                    { 

                                        securePassword.AppendChar(c); 

                                    } 

                                    var onlineCredentials = new SharePointOnlineCredentials(Configuration.ServiceUserName, securePassword); 

                                    var context = new ClientContext(Configuration.ServiceSiteUrl); 

                                    context.Credentials = onlineCredentials; 

                                    return context; 

                          } 





        static void Main(string[] args) 

        { 

            var ClientContext=GetonlineContext(); 

            Web web = clientContext.Web;  

            // do somethings            

        } 

    } 

}
like image 305
john Gu Avatar asked Sep 10 '18 23:09

john Gu


Video Answer


2 Answers

There are multiple parts to your question, so I'll answer it accordingly.

1. Which option out of the 3 you mentioned (or if there is a different better option :)), should you use to manage your configuration data/service account identity

OPTION 4 (similar to your option 2 with subtle difference): You should take your service account identity and configuration data out of your console application completely and pass them in through "Application Settings" for your Azure Function App.

This option is similar to the option 2 you had in your question, as you keep the information outside of console app code

I can define a service account for the Azure function app to run under it, where in this case i can define the service account to be an authorized account inside sharepoint online?

but difference is that I am not saying that you will be able to define a service account for your Azure function app to run under (because you can't control the account that Azure function will run under, Microsoft infrastructure takes care of it), instead you will pass it to your console app as a secure configuration data and your console app will use it. More on security/encryption later while comparing the options.

I actually took your console application code from question, created a console app and used it in a timer triggered Azure function to get it working. So these steps are from a working sample. I used the "Microsoft.SharePointOnline.CSOM" nuget package in my console app, and had to upload some of the dependency dlls along with exe in order for it to run. Feel free to ask for more details on doing this part if you run into issues.

Adding Application Settings - Navigate your Azure Function App and Click on "Application Settings"

enter image description here

Add Settings for all items that you want to take out of your console application and control from outside. I did it for all 3 items I saw, but this is up to you.

enter image description here

Then change your code to use these settings. I have shown the exact code changes at the end.

OPTION 5 Registering a new application in Azure AD to represent your Azure function.

  • You should register a new application in your Azure AD and use this identity to access SharePoint online.
  • You will need to grant permissions to SharePoint online for this application (NOTE: permission assignment will not be as granular or detailed as in case of your service account approach, I'll explain more while comparing the options)
  • You will need to associate a certificate with your AzureAD application to help in authentication.
  • While authenticating to SharePoint online, you will not be directly able to use the SharePointOnlineCredentials class as in your code today, but instead send the bearer token in 'Authorization' header for the http request.

Here is blog post that walks through detailed steps involved in this option 5. NOTE: This blog still leaves out the certificate details like password in function code at the end, which will not be ideal and you will need to move it out to App Settings or Azure Key Vault ideally.

2. Which account will the .NET console application run under and a Quick Comparison of all options

It's an arbitrary IIS App Pool account, as pointed out by @Mitch Stewart, other SO posts and is evident in the output I get for my function, it's exact value in my run came out to be "IIS APPPOOL\mawsFnPlaceholder0_v1 ". See the image at the bottom. You already have some good info shared on this, so I'll not repeat. Only thing I'll add is that this account will be controlled by the infrastructure hosting your function app and will be designed more towards taking care of isolation/other concerns in a shared infrastructure where many function apps can run, so trying to control/change it may not be the way to go right now.

Option 1 (from your question) - Giving permissions to an IIS app pool account for your SharePoint Online site, especially when you don't control the account may not be a good idea.

Option 2 (from your question) - It would have been better than the other 2 options you mentioned, but you can't really control this account.

Option 3 (from your question)- Embedding this information deep into your console application will be a maintenance issue as well as not the most secure option unless you start reading form a vault etc. Maintenance issues will remain no matter what you do because it's embedded in compiled code, which it shouldn't be.

Option 4 - This is better than previous 3 options, because it separates the concern of code from configuration and identity information, no recompilation needed for updates. Also note that whatever you store in App Settings configurations is encrypted by default (with good governance of key rotation) and is the recommended way. These values are decrypted only just before execution of your app and loaded into process memory. Look detailed discussion in this link, I have also given a small relevant excerpt below -

Provide documentation about encrypt/decrypt settings

enter image description here

Even with this option you could store them in a key vault and then your setting would be the URL of the key vault secret that has the actual information.

Option 5 - This option makes use of Azure AD based identity to authenticate with SharePoint Online which is good part. It does come with some additional effort and some limitations though, so you will need to consider if these limitations are acceptable or not in your scenario:

  • Permissions for SharePoint online will not be as granular/detailed as a user being given permissions from inside SharePoint Users/Groups interfaces (no site/list/folder/item level specific permissions etc). In this approach, you will give the permissions as part of setting up Azure AD application and you will only get generic options like these (shown in screenshot below) enter image description here

  • Microsoft has some well documented limitations in this scenario, which you can read here: What are the limitations when using app-only enter image description here

So overall, I would suggest you choose option 4 or option 5, or a combination of both for your implementation depending on which limitations are acceptable in your scenario.

3. Code Changes to use App Settings

Just the important Change

public static string ServiceSiteUrl = Environment.GetEnvironmentVariable("ServiceSiteUrl");
public static string ServiceUserName = Environment.GetEnvironmentVariable("ServiceUserName");
public static string ServicePassword = Environment.GetEnvironmentVariable("ServicePassword");

Full Code in a working Sample (I replaced do something with reading the title and Url for SharePoint Web object):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Client;
using System.Security;
using System.Security.Principal;

namespace O365SPProject
{
    class Program
    {
        private class Configuration
        {
            public static string ServiceSiteUrl = Environment.GetEnvironmentVariable("ServiceSiteUrl");
            public static string ServiceUserName = Environment.GetEnvironmentVariable("ServiceUserName");
            public static string ServicePassword = Environment.GetEnvironmentVariable("ServicePassword");
        }

        static ClientContext GetonlineContext()
        {
            var securePassword = new SecureString();
            foreach (char c in Configuration.ServicePassword)
            {
                securePassword.AppendChar(c);
            }

            var onlineCredentials = new SharePointOnlineCredentials(Configuration.ServiceUserName, securePassword);
            var context = new ClientContext(Configuration.ServiceSiteUrl);
            context.Credentials = onlineCredentials;
            return context;
        }

        static void Main(string[] args)
        {
            var ClientContext = GetonlineContext();
            ClientContext.Load(ClientContext.Web);
            ClientContext.ExecuteQuery();

            Console.WriteLine("This app found web title as: {0} and URL as: {1}", 
                ClientContext.Web.Title, ClientContext.Web.Url);

            Console.WriteLine("Console app is running with identity {0}", WindowsIdentity.GetCurrent().Name);
        }
    }
}

OUTPUT on executing Azure Function enter image description here

like image 163
Rohit Saigal Avatar answered Oct 13 '22 20:10

Rohit Saigal


The SharePoint REST API supports OAuth. Here's a promising article. Although, this might be a bit much for you intentions. Alternatively, you can try using basic auth (username + password). To guard against plain text passwords, you can store them in Azure Key Vault.

Edit The current user of an Azure function is the identity of the IIS app pool.

Code Logs

like image 40
Mitch Stewart Avatar answered Oct 13 '22 18:10

Mitch Stewart