Basic authentication in API Management using Key Vault.
This post will provide an example of how to integrate Azure API Management, Key Vault and Managed
Identities to securely retrieve and use a secret within
an API.
Enable Managed Identity
Before we jump into the policy itself, we first need to do some
groundwork. As we are going to retrieve the secret from Key Vault, we will
assign a managed identity to API Management, which we then give permission to
get the secrets. First, enable managed identity on your API Management.
Assign permissions
Once enabled, the next step is to assign the required
permissions to this new identity in Key Vault, which has the name of our
resource. We do this in the Access policies blade,
where we provide Get permissions
for the secrets. Important to note, this does give the identity access to all
the secrets in this Key Vault. As such, it is important to have a good Key
Vault policy around separation of secrets.
Next Add access policy with
the below of below screen shot.
Once done above steps we can
see in access policy api management will added, refer below screen shot.
Next Generating secrets Value
in azure key vault refer below screen shots.
Create policy
Now that we have everything in place, we are going to create the
policy. In this scenario, we will send the secret as part of our basic
authentication header. The endpoint we are using is on Request
Bin, which allows us to easily inspect the call. Refer below screen
shot.
Add below xml in policy.
<!--
IMPORTANT:
- Policy elements can appear only within
the <inbound>, <outbound>, <backend> section elements.
- To apply a policy to the incoming request
(before it is forwarded to the backend service), place a corresponding policy
element within the <inbound> section element.
- To apply a policy to the outgoing
response (before it is sent back to the caller), place a corresponding policy
element within the <outbound> section element.
- To add a policy, place the cursor at the
desired insertion point and select a policy from the sidebar.
- To remove a policy, delete the
corresponding policy statement from the policy document.
- Position the <base> element within
a section element to inherit all policies from the corresponding section
element in the enclosing scope.
- Remove the <base> element to
prevent inheriting policies from the corresponding section element in the
enclosing scope.
- Policies are applied in the order of
their appearance, from the top down.
- Comments within policy elements are not
supported and may disappear. Place your comments between policy elements or at
a higher level scope.
-->
<policies>
<inbound>
<choose>
<when
condition="@(!context.Request.Headers.ContainsKey("Authorization"))">
<return-response>
<set-status
code="401" reason="Unauthorized" />
</return-response>
</when>
</choose>
<!-- check the cache for secret
first -->
<cache-lookup-value key="@(context.Request.Headers.GetValueOrDefault("Authorization").AsBasic().UserId)"
variable-name="keyvaultsecretResponse" />
<!-- call Key Vault if not found in
cache -->
<choose>
<when
condition="@(!context.Variables.ContainsKey("keyvaultsecretResponse"))">
<send-request
mode="new" response-variable-name="keyvaultsecret"
timeout="20" ignore-error="false">
<set-url>@{
return "https://*******.vault.azure.net/secrets/"
+ context.Request.Headers.GetValueOrDefault("Authorization").AsBasic().UserId
+ "/?api-version=7.0";
}</set-url>
<set-method>GET</set-method>
<authentication-managed-identity resource="https://vault.azure.net"
/>
</send-request>
<!-- transform response to
string and store in cache -->
<set-variable
name="keyvaultsecretResponse"
value="@((string)((IResponse)context.Variables["keyvaultsecret"]).Body.As<JObject>()["value"])"
/>
<cache-store-value
key="@(context.Request.Headers.GetValueOrDefault("Authorization").AsBasic().UserId)"
value="@((string)context.Variables["keyvaultsecretResponse"])"
duration="3600" />
</when>
</choose>
<!--Check if password from the
Authorization header matches the secret value from the Key Vault -->
<choose>
<when
condition="@(context.Request.Headers.GetValueOrDefault("Authorization").AsBasic().Password!=
(string)context.Variables["keyvaultsecretResponse"])">
<return-response>
<set-status
code="401" reason="Not authorized" />
</return-response>
</when>
</choose>
<!--Delete the Authorization header,
because it can cause problems at the backend-->
<set-header
name="Authorization" exists-action="delete" />
<base />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Reference Link:
https://aztoso.com/posts/apim-basic-auth-keyvault/
https://blog.eldert.net/retrieve-azure-key-vault-secrets-from-api-management-policies/
https://madeofstrings.com/2019/06/13/azure-api-management-key-vault-and-managed-identities/
https://vincentlauzon.com/2019/11/19/accessing-azure-key-vault-from-within-azure-api-management/
Comments
Post a Comment