I am writing a terraform code where I have to add a XML as well. I also want to add condition to xml for filtering with basepath. My substring will be a basepath. I am adding it like a below code
resource "azurerm_api_management_api_policy" "auth-policy" {
for_each = azurerm_api_management_api.api
xml_content = <<XML
<policies>
<inbound>
<cors allow-credentials="true">
<allowed-methods>
<method>*</method>
</allowed-methods>
</cors>
<base />
<set-header name="ApiKey" exists-action="skip">
<value>Default</value>
</set-header>
<choose>
<when condition='@(context.Request.Headers.ContainsKey("X-Forwarded-Host"))'>
<set-header name="X-Forwarded-Host" exists-action="override">
<value>@(context.Request.OriginalUrl.ToUri().Host)</value>
</set-header>
</when>
</choose>
<choose>
<when condition="@contains(${each.value.name}, 'substring')">
<rate-limit-by-key calls="100" renewal-period="60" counter-key="@(context.Request.Headers.GetValueOrDefault("Authorization","").AsJwt()?.Subject)" />
</when>
<otherwise>
<rate-limit-by-key calls="100000" renewal-period="60" counter-key="@(context.Subscription.Id)" />
</otherwise>
</choose>
<validate-jwt header-name="Authorization" require-scheme="Bearer"
failed-validation-httpcode="401"
failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
<openid-config url="https://*******************" />
<audiences>
...........
</audiences>
<issuers>
...............
</issuers>
</validate-jwt>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
XML
}
but it throws error
Code="ValidationError" Message="One or more fields contain incorrect values:" Details=[{"code":"ValidationError","message":"Error in element 'choose' on line 28, column 10: The 'condition' attribute is invalid - The value '@contains(string, 'sunstring')' is not within allowed values range."
Is my condition correct, or do we get basepath with a request where I can use it directly instead of each.value.name
(I get the names of the APIs) ?
I am new to xml and APIM, Thanks in advance!
What I would suggest in a case like this is to use the built-in templatefile
function. This way, you do not have to specify the XML file inline, rather as a file with some placeholder variable names. For example, you could create a file in the same directory with the name api_policy.xml.tftpl
. The tftpl
suffix is just a sign it is a terraform template file. The content of the file would then be:
<policies>
<inbound>
<cors allow-credentials="true">
<allowed-methods>
<method>*</method>
</allowed-methods>
</cors>
<base />
<set-header name="ApiKey" exists-action="skip">
<value>Default</value>
</set-header>
<choose>
<when condition='@(context.Request.Headers.ContainsKey("X-Forwarded-Host"))'>
<set-header name="X-Forwarded-Host" exists-action="override">
<value>@(context.Request.OriginalUrl.ToUri().Host)</value>
</set-header>
</when>
</choose>
<choose>
<when condition="@contains(${api_name}, 'substring')">
<rate-limit-by-key calls="100" renewal-period="60" counter-key="@(context.Request.Headers.GetValueOrDefault("Authorization","").AsJwt()?.Subject)" />
</when>
<otherwise>
<rate-limit-by-key calls="100000" renewal-period="60" counter-key="@(context.Subscription.Id)" />
</otherwise>
</choose>
<validate-jwt header-name="Authorization" require-scheme="Bearer"
failed-validation-httpcode="401"
failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
<openid-config url="https://*******************" />
<audiences>
...........
</audiences>
<issuers>
...............
</issuers>
</validate-jwt>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Note that the condition
line now has this:
when condition="@contains(${api_name}, 'substring')"
The ${api_name}
syntax tells terraform to look for values assigned to the variable with the same name which is provided when calling the templatefile
function:
resource "azurerm_api_management_api_policy" "auth-policy" {
for_each = azurerm_api_management_api.api
xml_content = templatefile("${path.root}/api_policy.xml.tftpl", {
api_name = each.value.name
})
}