>> In this episode of the On.NET
Show we have Chris Anderson joining us,
and he's going to talk to us about
authenticating our apps with Cosmos DB.
Welcome to another episode of the On.NET show.
My name is Cecil Phillip, and with me today
I have Chris Anderson. What's going on Chris?
>> Hey, how is it going?
>> Doing pretty good, man. So you've
come some interesting demos to show us today. Right?
>> Yes, couple of things.
>> So you have this demo you wanted to talk about doing
resource tokens authentication like
what is that? What's that about?
>> Yes. So if you want to use Cosmos DB today,
most people end up using Cosmos DB from
a well-known trusted server and using
their master key to actually talk to their server.
But one of the other options that's
available is using resource tokens.
>> Okay.
>> The challenge is that in order
to actually create a resource token,
you need to use the master key to create
a service which is well known and trusted to
create resource tokens which then issues that to
less trusted services based of what
they are should be able to access.
>> Got you.
>> So, normally you'd go ahead and
set yourself up like a web app that would do that.
But I thought Cosmos is really infinitely scalable.
Why not use then which also scales
with it and use functions?
So I went ahead and took
a couple of samples that we have for
doing token issuing and wrote a function sample with it.
>> Got you. So let's take a look at and see what you got.
>> Yes. So it's here on GitHub.
I'm going to go ahead and explore
inside a Visual Studio but if you want to you
can go ahead and find it there on this GitHub here.
I have Visual Studio opened right now and in it,
the kind of the meat and potatoes
of what's going on here is,
I've got this function
which is going through there and looking for
a couple of header properties
which indicate that "Easy Off"
has done its job and authenticated
this user who's trying to access this endpoint.
>> Got you.
>> So we only want to allow
authenticated users to get a token,
we don't want to be handing out tokens
to the entire world, technically.
>> Right. So pretty much what was happening is
that my function users authenticated,
and I wanted to use that same user
context to talk to my Cosmos DB.
>> In a certain way to try and translate
that user context into a Cosmos DB or Azure Text.
Cosmos isn't aware of like IG or
like Facebook or whatever you'd
be using to authenticate to the service.
So what we have to do is to
translate kind of application
authentication features into
the services Knowledge of Things.
So you might want your application user
to access any information about themselves.
In Cosmos, that would translate to a given collection in
a given partition key within that collection and through
issue a resource token for only that partition key.
>> Got you. Okay, cool.
>> So yes, here we grab the users information.
You can see we're passing the "Token"
we know that it's going to be JSON Web Tokens.
We can go ahead and just use the built in
JWT Security Token Library that is there in .NET.
Then if there's an error we
can go ahead and throw myself area here of
unauthorized and importantly here we're
logging a error and info warning,
and if I have app insights turned on,
this will then show up in app insights.
So when the user or third party service emails me saying,
"Hey we can't access our Cosmos," they
can give me my location ID that I have set here,
and go look it up in app insights to go figure out why
they were not able to get into the service.
>> Yes, you could see some telemetry about what
exactly happened the time, the date.
>> We might not want to leak information
about why that happened to public Internet.
So we give relatively unhelpful,
you weren't able to authorize error message.
We will make sure we don't want to lose
the reasons when we have to
debug later it's easy to look up.
>> Got it.
>> So that's a really nifty thing here of
having Azure functions and
app insights baked in together.
>> Got you.
>> Here, I'm going through there,
and in this case I'm reading the permissions that people
were allowed to access as just app settings.
So this way it's kind of a static set of permissions.
I could back this with a Cosmos DB table.
So I can have a table of permissions
that a given user was allowed to access instead.
So if you wanted to,
you could take the sample and change
this logic here where I'm basically translating.
Basically it's like a connection string type of format.
I'll show you an example here in a
second, and then that actually gets
turned into a permission object that I've
got here some adding a permission to
my permissions token, and I'm fetching it with
this resource token provider class,
and I just did this as a separate class.
This class here is
actually just a .NET full framework app,
because I'm using functions "B1" still.
But I wanted to make sure that I could
actually use the .NET standard library for Cosmos.
And so I implemented the Cosmos specific pieces,
ended up in a state library and then
reference that from .NET framework.
>> So you're using like .NET's standard
2.0 to leverage.
>> So when functions v2.0, GA's.
I can write a separate functions v2.0
sample that uses all the latest things and functions v2.0,
but obviously there's some breaking changes
between B1 and B2 so,
I wrote the samples so that way I
could have both versions around.
>> Right. So you could still pull in your DB resource
token B writer.
All you need to do is just you will change your function
app.
Make whatever updates you need to make.
But in that code like that business code so to speak,
is still like relevant,
still valid, you can still use a web.
>> The only real tricks,
the advice that I could give folks,
would be make sure that you,
if you're passing objects back and
forth between those two libraries,
go and create your own custom objects.
Don't pass "Json.NET" objects back and forth.
Because that's a really easy way to fall into
the old dependency issues gap where you're using
the different versions of your Json.NET platform they
support different types and you
have odd translation errors there,
so you can always get around
that with redirects and stuff like that,
but I find it oftentimes easier
to just create my own custom folder.
>> Right. I got you.
So one thing I wanted to ask you about.
So you are using some types here permission
token and also app permission.
So where did those come from?
Are those classes you wrote or are they part of the SDK?
>> Yes. So permission token
is both of these things are types that I created.
So basically I created the
app permission is something inside
of the function project.
As something to hand off to the .NET standard library.
Then the permission token is actually coming from
the opposite direction so that's coming
from the .NET standard library.
So these are these are types that I created.
So it was just easier for me to go and work with my data.
>> Got it.
>> These have this has
the "Json.NET" annotations on it so that way it
goes and gives me the object that I expect to when I
return it for functions and that works just fine.
>> Got it.
>> So yes. I'm going through here, I'm
basically just creating a list
of those permissions and then entering
the list and Azure functions will automatically go
ahead and transform that list into
an array of "Json Objects" to run for me.
>> So instead of that then that would
have like one of like you can get your token from there.
>> Yes. So the actual token logic
itself if we want to dive into that,
the core of it is essentially going through there
and I look to see whether or not it exists in the cache.
I keep it in memory cache that we don't have
to go ahead and ask Cosmo's each time.
If I've already looked up it, and the tokens are valid for
an hour, and so if I've already looked at this
token on this function at before in memory.
So I could have thousands of
instances of my "Function App. "
So maybe I've got thousands of it in memory still.
But you know this simplifies using like
a Redis cache and memory cache is actually
pretty effective still for a lot of these cases.
>> Great.
>> If it's not in there,
I actually go through there and I try to create it.
If it fails then it
might actually already exist because of a race condition.
So that point I go ahead and try to query it
existing through the permission feed.
>> So this is just some of
the quirks of the resource token APIs.
You know you can only create a single resource token
for a given resource.
So if you want two different users
to get access to the same resource at
the same level permissions they get the same resource
token and see if to do some kind of
hops right now this isn't ideal.
We're working on some other things
inside of the cosmos DB team to
try to improve the experience of how
you do authentication for things.
But this is the reason I wanted to
create myself my own custom class for this is
because this allows me to go ahead and kind
of compartmentalize some of
the more complex business logic away from
my application that doesn't need to care
about how I get the token it just want the token.
>> Got it. So I'm guessing on your side that
if two users with
the same resource are using the same token,
you'd have to manually do some mapping
on your side to say,
hey these users are allowed to see this resource.
Then once you get the token back here,
I'm going to let you use this tokens access Cosmos.
>> So effectively what I'm doing is inside.
>> I can show you an example of what
the actual connection string looks like
that I'm using in this model.
As you can see,
from my local debug settings,
I'm just using these local things.
So, if you copy and paste this key,
you're not going to get yourself very far, people.
>> Got it.
>> In this case,
I've got a connection string that's essentially
just the resource path in my Cosmos Studio.
So, you can see dbstes2callstest3.
>> Yes.
>> Then I print my permissions settings there for all.
I can also, in this sample,
and this is docked in the Read Me,
if anyone wants to follow along later.
I can also specify a property that's going to
be on my JSON Web Token,
that I want to use as the partition key.
So, this allows me to do
user-specific filtering for resource tokens.
>> Got it. Okay.
>> So, I can go ahead and I can set this to UPN,
which is the property on the JSON Web Token that
refers to their email address.
You have to go and look up what properties are on
the JSON Web Token in your particular
case to know which ones you can use.
But once I've done this, I can now use that key from
my JSON Web Token to filter
out which things people are allowed to access.
>> Got it.
>> So, in the case that I was just doing,
everyone can access everything on this collection.
A bunch of people
will be sharing the same resource token.
>> Yes.
>> But in the case that I was doing,
user specific partition key tokens,
each user would've been given their own unique resource
token for their partition key.
>> For their partitions, got it.
>> So, yes, it's complex.
If you are really interested in how the authentication
pieces for Cosmos works,
I'd definitely recommend just following through the code
because it can be really interesting
to see how that stuff works.
But for the most part, my goal was
to build something that you didn't have to think about.
You give it a connection string and it returns a
token of equipment permissions to that connection string.
>> Nice. What we can do too is,
we could take, you have this on GitHub, right?
So, we can always add the links to the bottom of
the show notes and people can check it out
and see what exactly you want.
>> As we add additional ways of authenticating
the Cosmos,
I plan on trying to expand
that sample with those other ways,
and I'm even thinking about trying to
add storage inside of this,
so you can use the same mechanism to
get access to a storage SAS token.
We have other samples for functions to
get a SAS token for a new blob.
>> Yes.
>> But I thought it would be really interesting to
introduce some of the same concepts for storage as well.
So, this sample will keep on getting work
on over some couple of weeks.
>> So, just before we move on, tell us again, like,
why is it a good idea or why do we have
this option of using resource tokens versus just
using the typical master key that gets
generated for us when we create
a new Cosmos DB collection?
>> Yes. I mean,
it's often times because you're being told to.
But it's really because you want to always try to
follow the principles of least privileged access.
If I'm writing, if I'm
just using an insurance company as an example,
let's say that I'm an insurance company,
that I need to share some
of this data with third parties.
Other businesses of B2B type scenarios.
Maybe I just want give them access
to my Cosmos TV but I want them
to only be able to read certain collections.
I don't want them to be able to write data,
obviously, and I don't want them to read everything.
I don't want them to read certain types of data.
>> Yes.
>> I can now issue a resource token
that gives them very specific access,
and I can go ahead and revoke
that access within
the expiration time of the resource token.
So, if I want to stop doing business with them,
I don't have to rotate all of my master keys.
>> Right.
>> I only have to just prevent
them from being able to log into my application forever.
>> So, I have more granular access partitions
in my different collections when I
use this particular way of authenticating users.
>> It's scoped and timed.
So, you don't have a token that can last for forever.
So, you don't need to worry about rotating it.
It's automatically rotated.
>> Nice. Cool.
>> So, what you
end up getting when you actually run this thing,
you can see you can run this locally by
just setting all these properties.
They won't be validated unless you're using Easy Auth.
So, just be careful that you
make sure that you turn on Easy Auth when
you end up running this thing on Azure.
Easy Auth will go through there and strip these things,
if you try to send
these things to, when you're running on Azure.
So, you don't have to worry about people trying to spoof.
>> To spoof you with some of these type of tokens.
>> Yes. But this is what ends up getting returned.
I now have this token that can get access to
my Cosmos DB for an hour.
I have this Expires title here that I can use.
You can see that I actually have
the resource, I give them access, and so,
I can easily now consume this from the Cosmos DB STKs.
If you want to learn more about how to actually
consume this from the Cosmos DB STKs,
we're not going to go into that sample here.
But there's this great article here on
the Cosmos DB documentation about securing
access to data and using resource tokens.
It describes some of
these kind of patterns of using things, and so,
with this code sample, you can now do this in
a several fashion without having to stand up
a dedicated server to issue these tokens.
>> Nice. That's great. That's awesome.
So Chris, why don't we talk a little bit about,
how can we deploy this?
So, I have this thing that's
going to issue tokens for me,
I have my function set up,
my Cosmos DB is provisioned.
You're running this locally now, right?
I want to push this in the Azure.
How can I securely push this out there?
>> So, I always
advocate for people who are building Azure applications
to make sure that they are always
having their arm template as part of
their solution in the case
that they're doing .net projects.
If you're doing something that's not .NET
you can always just have the arm template
as some directory inside of your project.
But I really love Visual Studio's arm project support.
So, I'm going to show how that works here.
This is an example arm template
that's going to go ahead and deploy myself.
You can see here the actual resources on the side here,
which is one of the reasons this is
such a great experience.
I've actually got a storage account,
I have my App Service hosting plan,
which is the dynamic hosting plan
that hosts my function Apps inside of it.
>> Yes.
>> Mostly an implementation detail for most people,
and then the actual function app itself,
and then something that I always
advocate for App Insights.
Make sure that you always have
App Insights for your function Apps.
It just makes debugging so much
simpler to monitor and manage.
Yyou can do that as part of deployment.
So, you don't need to worry about
setting it up afterwards.
>> Nice. Got it.
>> Inside of the web app
itself or the function app itself,
I have all of my settings.
You can see here I'm setting my WebJobs Dashboard,
my WebJobs storage, my local
files connection string for getting Azure files working.
I'd be changing this to either two,
if I was using the [inaudible].
In the case of V1,
we can go out and set that to one.
For those using node, that setting won't matter.
Well, it doesn't matter so much for .NET.
>> So, pretty much what we're looking at here,
these are environment variables, right,
that I could go in and I could change,
and these would be inside of
my app settings once function supports.
>> The interesting one here that I wanted
to talk about [inaudible] is something different that,
I've really never done it
before for function, so this is fairly new.
>> Okay.
>> That's the ability to Run-From-Zip.
>> Oh, so, hold on one second.
So, today, I could right click publish in Visual Studio.
I could use VSTS, right,
and you can also use GitHub or
some other source control deployment tab options.
So, why would I want to Run-From-Zip?
Tell me exactly, what are the scenarios that I'd
want to do this versus some of the others?
>> So, all of
those other mechanisms to deploy that you mentioned,
actually end up putting stuff inside of Azure files.
>> Yes.
>> The problem is that that means
pulling all those things from Azure
files every single time that you run,
and that can be a little bit slow.
>> Okay.
>> So, one of the things that
Azure Functions has come up with in order to
help alleviate this is the ability to go
ahead and have a compressed Zip package.
So, it's a lot easier to download your contents
locally and run from them
without having to download them all from Azure files
each time that we come up with a new instance.
So, with Run-From-Zip,
I'm able to just have cold start
reduced by a pretty dramatic amount,
especially if you're doing Node.js
with lots of node modules,
but it still helps for .NET where
things are a bit more sane.
>> Got you.
So, regardless of whether it's Node.js or C#
or whatever other platform that Azure Functions supports,
all I have to do is pretty much package up
my Azure Functions application,
package it up in a zip file.
I'm guessing I'll upload it somewhere and
then it'll just pull it down and just run it for me.
>> Yes.That's one of the cool things, is that,
since it's just asking
for a endpoint to download that zip from,
it's really flexible about where you put that zip.
You could structure your application in
such a way that it was just hosted on
GitHub and you used GitHub's download zip feature
and you just posted that as the URL.
You can put it inside a blob storage,
which is what I've got an example here of.
>> Okay.
>> One really cool thing is that you can actually put
that URL behind a redirect link.
So, if you have a redirect like a proxy,
you can actually go ahead and put
your zip link behind that proxy,
and then update that zip link
without ever updating the proxy.
So, now you can go ahead and do deployments without
actually pushing them everywhere.
This is really helpful for this.
I actually use this in the sample because what we
have is when you publish the sample,
I didn't want you to necessarily have to run through
the steps of building that code.
I wanted to have it already kind of package,
so it was a lot faster to deploy.
This is a lot faster because
it's already compiled for me.
So now, when you actually
deploy the sample and deploy the arm template,
it actually just runs from a zip that I have
hosted on one of Microsoft's blob storage accounts.
>> So, this was way faster than doing
a source control push because,
again, if I think about publishing versus git.
So, it's going to look at my repo.
It's going to, let's say it's node or.net or whatever.
It's going to have to restore my packages,
run my build, package it up,
and then it has to go put it under the disk over.
>> Yes.
>> With this one, it's ready built, it's ready packaged,
it's really just saying, "Hey, just go
grab this artifact and run it."
>> Yes, and the nice thing there
is that it's really easy to then roll back.
If you were to push version three out and had an issue,
you could then go ahead and rollback yourself to
v2 without having to actually rebuild v2.
As long as you have v2 sitting out there as a blob still,
you just change the setting and
point back to that v2 blob.
>> Okay, cool.
>> You can do
some of these same things with things like VSTS.
VSTS has support for basically having
your artifacts already stored inside of VSTS,
and then you just web deploy those
previous versions of artifacts back.
The main advantage of this is that
this actually runs it as a zip on
the local file system and so it can still be
faster than doing web deploy to the Azure files stuff.
That's the biggest advantage.
But because now we're able to use this public address zip,
we can do a lot of those cool things
that VSTS also enables you to
do in terms of version control and stuff.
The nice thing is VSTS can still
publish your contents to a blob,
and so you can still have some of the exact
same patterns as you do in VSTS.
This doesn't stop those from happening.
Cool. That's cool.
Let's take a look and see how this works.
>> Yes. So, in the interest
of making sure that it's actually like a live demo,
I actually only created the resource group.
There's actually nothing there to kind of prove,
there's nothing up my sleeves, so to speak,
here's my resource group and it's empty right now.
>> Got it.
>> So, the nice thing, this is,
it's really easy for me to go ahead and just hit deploy,
click on my resource group that
I'd already set up and created.
I've already got my parameters set up here
that actually have secrets and stuff in it.
So, having those separated from
your actual template is generally a good idea.
>> Okay.
>> The only reason I didn't have that storage string as
actually a parameter is
I didn't want to have to show all of my secrets.
>> Yes.
>> So, normally I'd have that as a variable.
>> So we will go ahead and run and we see here
that this is going to show up in
this "Output" here at the bottom.
So that's going to go ahead and keep on deploying.
>> Yes.
>> If we go back and we look at our resource group,
we should start to see "Services" show up in here.
So this has already created the App Insights.
It's already created the App Service plan and now
it's creating the storage account
and then it will create the Function App.
>> It's going to create the Function App.
>> So pretty much again like all of
these things where you had to define inside of
your Arm template and now
by just publishing the Arm template,
Azure is going to look at the template,
look at your parameters,
your variables, all that type of stuff.
So, it just start creating all of
these resources inside of this "Research Group".
>> Yes.
>> So, it's really repeatable and I'm sure
that everyone listening has
already had it drummed into them.
They should use Arm templates to do their deployments.
>> Yes.
>> But really, it saves you so
much time even when I'm just trying to do a demo.
So, you can see
here that everything has been created now.
>> Yes. Your Function App is there,
the Resource Group, everything is right there.
>> If everything went well,
when I click on this "Function App",
I should actually be able to see that my function now
contains my "Cosmos Token Provider".
>> Nice.
>> Anyway, I never
actually right clicked and published the Function App.
You notice that I didn't go through that step of
actually going through here and publishing this.
>> Yes.
>> This is running off of the URL that
already had there and it already had
a copy of this demo published here.
You can see Token Providers 0.0.2 was already there.
So this is running that version.
You can verify that by going to that function
and actually one just tip from me,
is if you go in your host.json you can actually
store variables that belong only to your application.
So they don't have to always be
variables that Function App knows about.
>> Okay.
>> So what I would like to do is I would like to store
my App version of my host.json so I can
always tell which version of my application I'm running.
>> Okay.
>> So just a little tip from me is,
one of the places you can store information like that.
>> Sure. I mean and is this
accessible from my Function's App
or is this just purely like a deployment artifact?
>> So this is your host.json.
You can always access host.json,
it's just there at the base of your project structure.
You can also make like
a static variable in the case of .NET,
so if you wanted to have
it as something that you could programmatically access,
I might actually just make it like
a static readonly property
that everything can access.
>> Sure.
>> But if I want to just
add a glance to be able to see things,
so JSON is a very easy way of putting it.
>> Great. Cool.
>> So, yes, now everything set up here,
of course I've got all of
my stuff like App Insights turned on,
but the one interesting thing is that if I try
to make a request to my function,
which you can't see, I don't have
the content because it's a pre-complied one,
It wont work because I haven't turned on "Easy Auth".
>> So you mention Easy Auth a few times,
and I've been meaning to ask you like,
what exactly is that? What do we do with this Easy Auth?
>> So Easy Auth is a unofficial name for
the Authentication and Authorization service.
I found that to be a mouthful, so I call it by
the internal name which I probably shouldn't, Easy Auth.
>> Easy Auth.
>> Chris going to come find me.
So I can go ahead I call it
Easy Auth and that was the code name I guessed for it.
Because it's just so easier to turn on authentication.
I can go ahead and put "AD" in front of
this Function App by just
clicking on, "Turning on Easy Auth".
You see I have a lot of providers that I can set up.
I want to go ahead and just
use the express mode where this will
create a kind of default AD application for me.
Hit "Okay", this will go off and create
that and I can go ahead and hit "Save",
and then once this kind of spinning line finishes,
I'll actually have AD in front of my applications.
You can see that took all of like five seconds,
and I can do this in an Arm template too.
In this case, since the sample I want you
to be able to choose
which authentication provider you're using.
>> Sure.
>> I have you do it this as second step,
so that you can go ahead and have your App key
and authorization token as
part of your Arm template as well.
>> Got it. Got it.
>> So, now, if I go ahead and try to
access this function by grabbing the URL,
and it's going to restart when
I change the authentication.
So there's just going to be a little bit
of spinning the stuff again.
Grab this URL right here and it will go
ahead and just do a redirect bounce
for me because I'm already logged in.
So I actually go ahead and open up an Incognito window.
You can see it gives me
that "Cannot authenticate user".
It didn't set that up.
So we're just waiting for Easy Auth to actually work
and keeps me know it's a live demo because Easy Auth-.
So the one step you have to do it
Easy Auth, honest mistake.
You can turn on Easy Auth without actually
forcing people to always use Easy Auth.
This is really helpful if you want to
have an index page that is an authenticated.
>> Yeah.
>> That then you click on "Login" button
and then now everything is authenticated from there.
To make things simple,
you can also force everyone to log in
before they ever access your content.
>> Got it.
>> So when I go ahead and if I change this from anonymous
to log in with Active Directory is
the forced action when they're not authenticated.
>> So this by default it's going
to say anytime you hit this URL,
you need to authenticate with Active Directory.
>> Yes, and you can see that this was
secure if I didn't set up Easy Auth,
it started yelling at me because I wasn't authenticated.
>> Yes.
>> But now that I set up Easy Auth and I now
force users when they try to access
my URL to authenticate,
now this should go ahead and bounce me
out to AD to log in.
>> All right.
>> As you can see, this is going to take to log
in and ask me log in.
I am just going to go ahead and
instead open that app where I've already logged in.
You don't want me to type out my password.
So just entered there.
>> So because you're authenticated in this context,
it's not asking you for username
and password, emails just whatever.
>> Exactly. Single sign on just continues to work.
>> Yes.
>> Then, now I can go ahead. It's a new application
that I've never visited before.
So it's going to of course ask me to
accept like any AD application.
>> Sure.
>> Now, the next time, this will asks me that.
It only asked me the first time I
log into the application.
You see here now I have
this empty array of permissions,
it will turn XML because we're obeying the content type.
So if I change the content type to Application JSON
as part of my request I get JSON back.
Chrome by default ask for Application XML.
So we get XML back and it's empty because I didn't set up
any permissions for my Cosmos on Azure.
So if I set up permissions,
that fancy connection string,
you'd see an array of connections here.
>> Got it, got it.
So we've seen a couple of things, right?
So you've shown us how to
use resource tokens with Cosmos DB.
And then now you're showing us how we could
have those resource tokens
generated using Azure function.
That's in itself kind of being protected by Easy Auth.
>> Yes.
>> Cool.
>> Now, you know it's really simple for you to go
ahead and start using
these tokens within your application.
So if you wanted to give
users just a little bit of access to your data,
you can now do it with
Easy Auth and the Token Provider model.
>> Cool. Thanks you for coming on man.
So if people want to learn a
little bit more about what you talked about here,
is there a repo that we can go to
and to check this stuff out?
>> Yes, so the Token Provider
is the place to grab and
learn about the Resource Token Model and
the same example of the one from Zip working.
>> Okay.
>> Then, one of the other thing that I recommend
people go ahead and do is look
under Azure App Service Announcements
for the run from the Zip Announcement.
And this is information about
any of the early stages of this preview.
So like they're working on getting more portal UI.
They're working on getting this into the CLI.
But for now, you can use this by just
setting the App setting and I said it's really,
really handy, if you are
looking to reduce Cold Start from file loading.
>> it's available today in
function's view on Apps and also V2 Apps?
>> In V2. It does not work on Linux yet.
>> Does not work on Linux.
>> Yes.
>>Got it. Okay cool.
>> Also works for App Service Web Apps too.
Well, we built this for
function specifically and this is something
that works for all of the things inside of
App Service that are the non-Linux version.
>> Cool. That's awesome.
Thanks Chris. Thank you for coming by.
>> Thanks for having me.
>> There we go.
There's another episode of the ON.NET show.
