|
| 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 | + |
0 commit comments