Skip to content

Commit 74be247

Browse files
English redirect
1 parent 7644655 commit 74be247

File tree

113 files changed

+15739
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+15739
-0
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
---
2+
layout: page
3+
title: 'Securing Azure Functions: API Management Policies'
4+
hero_image: '/img/IMG_20220521_140146.jpg'
5+
show_sidebar: false
6+
hero_height: is-small
7+
date: '2024-01-27'
8+
---
9+
10+
11+
<h1>API Management Policies</h1>
12+
13+
Azure API Management is a hybrid, multi-cloud management platform for APIs across all environments. As a platform-as-a-service, API Management supports the complete API lifecycle. The inbound processing rules allow you to configure a JWT validation policy to pre-authorize requests:
14+
15+
<img src="/articles/images/SecureAzFunc/Github-SecAzFunc14.png" width="400">
16+
17+
18+
Validating JWT token is one of the many access restrictions policies that API Management allows you to configure.
19+
Check out [API Management access restriction policies documentation](https://learn.microsoft.com/en-us/azure/api-management/api-management-access-restriction-policies) for more options.
20+
21+
22+
<h3>JWT validation policy</h3>
23+
24+
Sample inbound policy.
25+
26+
<inbound>
27+
<base />
28+
<set-backend-service id="apim-generated-policy" backend-id="provisionierungacco" />
29+
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Invalid token.">
30+
<openid-config url="https://login.microsoftonline.com/0da700fe-a3a7-4aaa-a43f-48a79eefc326/v2.0/.well-known/openid-configuration Jump " />
31+
<issuers>
32+
<issuer>https://login.microsoftonline.com/0da700fe-a3a7-4aaa-a43f-48a79eefc326/v2.0< Jump /issuer>
33+
</issuers>
34+
<required-claims>
35+
<claim name="aud" match="any">
36+
<value>7e5ff242-8d3a-46a9-8890-45722c2f3d27</value>
37+
</claim>
38+
</required-claims>
39+
</validate-jwt>
40+
</inbound>
41+
42+
43+
Let us analyze the values:
44+
* backend-id="provisionierungacco"
45+
46+
This should point to your Azure Function.
47+
48+
* openid-config url="https://login.microsoftonline.com/0da700fe-a3a7-4aaa-a43f-48a79eefc326/v2.0/.well-known/openid-configuration"
49+
50+
Every app registration in Azure AD is provided a publicly accessible endpoint that serves its OpenID configuration document.
51+
52+
To find the configuration document for your app, navigate to the Azure portal and then: Select Azure Active Directory >> App registrations >> YourApp >> Endpoints. Locate the URI under OpenID Connect metadata document. It should look something like this:
53+
https://login.microsoftonline.com/YOURTENANTID/v2.0/.well-known/openid-configuration <br/>
54+
where
55+
<br/>
56+
path is: /.well-known/openid-configuration <br/>
57+
and authority URL is: https://login.microsoftonline.com/{tenant}/v2.0
58+
59+
For more information go to [OpenID Connect on the Microsoft identity platform](https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc).
60+
61+
<h3> required-claims</h3>
62+
63+
<h4>aud</h4>
64+
65+
It's up to you to decide which claims will be checked. One of the more common ones is the aud which in our case will be identical with the guid in our scope.
66+
As per[ RFC definition ](https://www.rfc-editor.org/rfc/rfc7519#section-4.1.3) aud claim refers to the recipient of the access token:
67+
<br/>
68+
69+
> The "aud" (audience) claim identifies the recipients that the JWT is intended for. Each principal intended to process the JWT MUST identify itself with a value in the audience claim. If the principal processing the claim does not identify itself with a value in the "aud" claim when this claim is present, then the JWT MUST be rejected. In the general case, the "aud" value is an array of case- sensitive strings, each containing a StringOrURI value. In the special case when the JWT has one audience, the "aud" value MAY be a single case-sensitive string containing a StringOrURI value. The interpretation of audience values is generally application specific. Use of this claim is OPTIONAL.
70+
71+
<br/>
72+
In our case the recipient, or the audience, will be Azure Function.
73+
74+
75+
<h4>azp</h4>
76+
[IANA](https://www.iana.org/assignments/jwt/jwt.xhtml) defines azp as <i>Authorized party - the party to which the ID Token was issued</i>.
77+
78+
[Open ID specification](https://openid.net/specs/openid-connect-core-1_0.html) gives the following definition:
79+
<br/>
80+
81+
>OPTIONAL. Authorized party - the party to which the ID Token was issued. If present, it MUST contain the OAuth 2.0 Client ID of this party. This Claim is only needed when the ID Token has a single audience value and that audience is different than the authorized party. It MAY be included even when the authorized party is the same as the sole audience. The azp value is a case sensitive string containing a StringOrURI value.
82+
83+
<br/>
84+
85+
I like to check this claim, because it helps to avoid the required assignment issue. Instead of (or additionally to) granting permissions for your client to your backend app you can check in the JWT who sends the request. If needed, several values can be accepted, e.g. in the scenario where 2 or more apps call your Azure Function:
86+
87+
<required-claims>
88+
<claim name="aud" match="any">
89+
<value>7e5ff242-8d3a-46a9-8890-45722c2f3d27</value>
90+
</claim>
91+
<claim name="azp" match="any">
92+
<value>a1888df2-84c2-4379-8d53-7091dd630ca7</value>
93+
<value>f1d55d9b-b116-4f54-bc00-164a51e7e47f</value>
94+
95+
<value>d5dfkae9-4f54-bc00-8d53-164a5130ca7b</value>
96+
</claim>
97+
</required-claims>
98+
99+
100+
101+
102+
<h1>See Also</h1>
103+
104+
[Securing Azure Functions: Design Considerations](https://powershellscripts.github.io/articles/en/Azure/Securing%20Azure%20Functions%20-%20Design/)
105+
106+
[Securing Azure Functions: Scope](https://powershellscripts.github.io/articles/en/Azure/Securing%20Azure%20Functions%20-%20Scope/)
107+
108+
[Securing Azure Functions: Tooling](https://powershellscripts.github.io/articles/en/Azure/Securing%20Azure%20Functions-Tooling/)
109+
110+
111+
112+
<!-- Default Statcounter code for Azure - API
113+
https://powershellscripts.github.io/articles/en/Azure/Securing%20Azure%20Functions%20-%20API/
114+
-->
115+
<script type="text/javascript">
116+
var sc_project=12962355;
117+
var sc_invisible=0;
118+
var sc_security="042aeb11";
119+
var scJsHost = "https://";
120+
document.write("<sc"+"ript type='text/javascript' src='" +
121+
scJsHost+
122+
"statcounter.com/counter/counter.js'></"+"script>");
123+
</script>
124+
<noscript><div class="statcounter"><a title="Web Analytics"
125+
href="https://statcounter.com/" target="_blank"><img
126+
class="statcounter"
127+
src="https://c.statcounter.com/12962355/0/042aeb11/0/"
128+
alt="Web Analytics"
129+
referrerPolicy="no-referrer-when-downgrade"></a></div></noscript>
130+
<!-- End of Statcounter Code -->
131+
132+
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
---
2+
layout: page
3+
title: 'Securing Azure Functions: Design Considerations'
4+
hero_image: '/img/IMG_20220521_140146.jpg'
5+
show_sidebar: true
6+
hero_height: is-small
7+
date: '2024-01-25'
8+
---
9+
10+
11+
12+
<h1>Design</h1>
13+
14+
Which app calls which? One of the first things to consider is the [design](https://learn.microsoft.com/en-us/azure/api-management/authentication-authorization-overview#oauth-20-authorization-scenarios) you want to follow. The authentication flow you choose will decide what is authorised to what. Consider these two scenarios:
15+
16+
<img src="/articles/images/SecureAzFunc/Github-SecureAzFunc1.PNG" width="600" alt="Diagram showing OAuth communication where audience is the backend.Diagram showing OAuth communication where audience is the API Management gateway.">
17+
18+
19+
20+
<br/><br/>
21+
22+
<h1>Authorization Flow</h1>
23+
24+
Make sure you understand [authorization flow](https://learn.microsoft.com/en-us/azure/api-management/authorizations-overview#process-flow-for-runtime).
25+
26+
<img src="/articles/images/SecureAzFunc/Github-secureayfunc2.svg" width="600" alt="Diagram that shows the process flow for creating runtime.">
27+
28+
29+
The client app needs to call API Management. If you can call your Azure Function directly, using only function code - it's not secured with OAuth.
30+
31+
<br/><br/>
32+
<h1>JSON Web Token (JWT)</h1>
33+
34+
Per the OAuth specification, access tokens are opaque strings without a set format.
35+
36+
JSON Web Tokens are split into three parts:
37+
* Header - Provides information about how to validate the token including information about the type of token and how it was signed.
38+
* Payload - Contains all of the important data about the user or application that's attempting to call the service.
39+
* Signature - Is the raw material used to validate the token. Each piece is separated by a period (.) and separately Base64 encoded.
40+
41+
Useful resources:
42+
* [List of token claims and their description](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens#claims-in-access-tokens)
43+
* [Options for validating a token](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens#validate-tokens)
44+
45+
<h3>Token formats</h3>
46+
47+
There are two different versions of JSON Web Tokens (JWTs) called v1.0 and v2.0 available on the Microsoft identity platform. Custom APIs registered by developers in Azure Active Directory can choose either of them. Microsoft-developed APIs like Microsoft Graph or APIs in Azure use other, proprietary token formats.
48+
49+
v1.0 is selected as a default for Azure AD-only applications.
50+
51+
v2.0 is selected as a default for applications that support consumer accounts.
52+
53+
The contents of the token are not decoded directly in applications and are intended for the API only, however, for troubleshooting purposes you can decode your tokens using [https://jwt.ms/](https://jwt.ms/) or [https://jwt.io/](https://jwt.ms/)https://jwt.ms/ sites.
54+
55+
56+
V1.0
57+
58+
Decoded v1.0 token example (the token value comes from [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens) ):
59+
60+
<img src="/articles/images/SecureAzFunc/Github-SecureAzFunc3.PNG" width="600">
61+
62+
63+
64+
V2.0
65+
66+
Decoded v2.0 token example (the token value comes from [learn.microsoft.com](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens) ):
67+
68+
<img src="/articles/images/SecureAzFunc/Github-SecAzFunc4.png" width="600">
69+
70+
71+
The site [https://jwt.ms/](https://jwt.ms/) also helps to interpret the claims included in the token:
72+
73+
<img src="/articles/images/SecureAzFunc/Github-SecAzFunc5.png" width="400">
74+
75+
76+
! Notice the difference in the issuers between the two versions.
77+
Token version is one of the common issues while configuring authentication between apps!
78+
79+
80+
<h3>What does it mean that the token version is wrong?</h3>
81+
82+
* If there is a mismatch between issuers, i.e. in the decoded token you see sts.windows.net and APIM policy requires login.microsoftonline.com
83+
* When you receive "Invalid token" error
84+
85+
86+
<h3>How to "fix" token version?</h3>
87+
88+
Go to manifest in your app registration and set accessTokenAcceptedVersion
89+
to 2:
90+
91+
<img src="/articles/images/SecureAzFunc/Github-SecAzFunc6.png" width="400">
92+
93+
94+
95+
It may take a few minutes to apply the changes.
96+
97+
<br/><br/>
98+
99+
<h1>See Also</h1>
100+
101+
[Securing Azure Functions: Scope](https://powershellscripts.github.io/articles/en/Azure/Securing%20Azure%20Functions%20-%20Scope/)
102+
103+
[Securing Azure Functions: API Management Policies](https://powershellscripts.github.io/articles/en/Azure/Securing%20Azure%20Functions%20-%20API/)
104+
105+
[Securing Azure Functions: Tooling](https://powershellscripts.github.io/articles/en/Azure/Securing%20Azure%20Functions-Tooling/)
106+
107+
108+
109+
<!-- Default Statcounter code for Azure - Design
110+
https://powershellscripts.github.io/articles/en/Azure/Securing%20Azure%20Functions%20-%20Design
111+
-->
112+
<script type="text/javascript">
113+
var sc_project=12962353;
114+
var sc_invisible=0;
115+
var sc_security="a2726073";
116+
var scJsHost = "https://";
117+
document.write("<sc"+"ript type='text/javascript' src='" +
118+
scJsHost+
119+
"statcounter.com/counter/counter.js'></"+"script>");
120+
</script>
121+
<noscript><div class="statcounter"><a title="Web Analytics
122+
Made Easy - Statcounter" href="https://statcounter.com/"
123+
target="_blank"><img class="statcounter"
124+
src="https://c.statcounter.com/12962353/0/a2726073/0/"
125+
alt="Web Analytics Made Easy - Statcounter"
126+
referrerPolicy="no-referrer-when-downgrade"></a></div></noscript>
127+
<!-- End of Statcounter Code -->
128+
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
layout: page
3+
title: 'Securing Azure Functions: Scope'
4+
hero_image: '/img/IMG_20220521_140146.jpg'
5+
show_sidebar: false
6+
hero_height: is-small
7+
date: '2024-01-28'
8+
---
9+
10+
11+
<h1>Scope</h1>
12+
When setting scope for your application permissions, mind the different access scenarios:
13+
14+
<img src="/articles/images/SecureAzFunc/Github-SecAzFunc7.png" width="400">
15+
16+
<sup>Image source: https://learn.microsoft.com/en-us/azure/active-directory/develop/permissions-consent-overview</sup>
17+
18+
For more details on delegated vs app-only access see [Permissions and consent](https://learn.microsoft.com/en-us/azure/active-directory/develop/permissions-consent-overview).
19+
20+
To simplify it though, let us say that if you need a user to click consent to a particular resource, then you should go here in the Azure portal:
21+
22+
<img src="/articles/images/SecureAzFunc/Github-SecAzFunc8.png" width="500">
23+
24+
25+
But in the client app and Backend API scenario describe above, you would rather use app-only permissions, and start from Enterprise Applications, where you set **Assignment Required** to **True**.
26+
27+
<img src="/articles/images/SecureAzFunc/Github-SecAzFunc9.png" width="500">
28+
29+
30+
If this option is set to yes, then users and other apps or services must first be assigned this application before being able to access it.
31+
32+
<h3>Why is it important?</h3>
33+
Because if you do not enable required assignment, **any app** registration can request the default scope of your app. This is the default setting. **Unless you are doing further checking of the token scopes in code, this leaves your app open** to being called by clients which haven’t been explicitly granted permission. Check out [these cool tests](https://medium.com/airwalk/azure-app-service-easy-auth-and-the-default-scope-1fb0b65b4d26) proving how that happens.
34+
35+
36+
<h3>Application is not assigned to a role for the application</h3>
37+
38+
Once you have enabled the required assignment setting, but before you assigned any roles, you should get an *invalid_grant* error., e.g.
39+
40+
AADSTS501051: Application '1df771d6-ef9c-473e-af87-cafa8928e024'(testClient)
41+
is not assigned to a role for the application '8d138478-d3a3-47f5-a233-1408cd6baae4'(testBackend2)
42+
43+
<img src="/articles/images/SecureAzFunc/Github-SecAzFunc10.png" width="600">
44+
45+
If you receive **Application is not assigned to a role for the application** error, go to App Registrations >> Choose your client app >> API Permissions:
46+
47+
<img src="/articles/images/SecureAzFunc/Github-SecAzFunc11.png" width="400">
48+
49+
Add the required permission and verify that the admin consent has been granted. When you click on **Add a permission**, you can easily navigate to the right API, by selecting **my APIs** or **APIs my organization uses**:
50+
51+
<img src="/articles/images/SecureAzFunc/Github-SecAzFunc12.png" width="400">
52+
53+
54+
If you do not see the right API there, go to Azure Portal >> App Registrations >> Select your backend app (representing Azure Function) >> App roles (for app-only access scenario).
55+
56+
57+
<h3>Default scope</h3>
58+
59+
60+
The /.default scope has several uses:
61+
* it is a shortcut back to the Azure AD v1 behavior (e.g., static consent)
62+
* **it is required when the app is making service-to-service calls or using application-only permissions**
63+
* it is required when using the on-behalf-of (OBO) flow, where your API is making calls on behalf of the user to a different API, e.g. client app --> your API --> Graph API.
64+
65+
66+
Check out the awesome article by [John Patrick Dandison](https://dev.to/jpda) explaining in great detail [Just what *is* the /.default scope in the Microsoft identity platform & Azure AD?](https://dev.to/425show/just-what-is-the-default-scope-in-the-microsoft-identity-platform-azure-ad-2o4d) where he clarifies very well, and with examples, the difference between static and dynamic consent and where to use the ./default scope.
67+
68+
For us, the second scenario (making service-to-service calls or using application-only permissions) is the most relevant. That's why our scope will look like this:
69+
{BackendID}/.default.
70+
71+
For a backend app (our Azure Function) with the following data:
72+
73+
<img src="/articles/images/SecureAzFunc/Github-SecAzFunc13.png" width="400">
74+
75+
the scope will look like this: *8d138478-d3a3-47f5-a233-1408cd6baae4/.default*
76+
77+
78+
<br/><br/>
79+
80+
<h1>See Also</h1>
81+
82+
[Securing Azure Functions: Design Considerations](https://powershellscripts.github.io/articles/en/Azure/Securing%20Azure%20Functions%20-%20Design/)
83+
84+
[Securing Azure Functions: API Management Policies](https://powershellscripts.github.io/articles/en/Azure/Securing%20Azure%20Functions%20-%20API/)
85+
86+
[Securing Azure Functions: Tooling](https://powershellscripts.github.io/articles/en/Azure/Securing%20Azure%20Functions-Tooling/)
87+
88+
89+
<!-- Default Statcounter code for Azure - Scope
90+
https://powershellscripts.github.io/articles/en/Azure/Securing%20Azure%20Functions%20-%20Scope/
91+
-->
92+
<script type="text/javascript">
93+
var sc_project=12962354;
94+
var sc_invisible=1;
95+
var sc_security="7644b0bc";
96+
</script>
97+
<script type="text/javascript"
98+
src="https://www.statcounter.com/counter/counter.js"
99+
async></script>
100+
<noscript><div class="statcounter"><a title="free web stats"
101+
href="https://statcounter.com/" target="_blank"><img
102+
class="statcounter"
103+
src="https://c.statcounter.com/12962354/0/7644b0bc/1/"
104+
alt="free web stats"
105+
referrerPolicy="no-referrer-when-downgrade"></a></div></noscript>
106+
<!-- End of Statcounter Code -->
107+

0 commit comments

Comments
 (0)