Skip to content

Instantly share code, notes, and snippets.

@kevinhillinger
Last active April 1, 2019 19:16
Show Gist options
  • Save kevinhillinger/630bd1089aff2fbd83bed39205e30f9e to your computer and use it in GitHub Desktop.
Save kevinhillinger/630bd1089aff2fbd83bed39205e30f9e to your computer and use it in GitHub Desktop.
Azure API Management to Key Vault Integration - Client Certificate Authentication
rg=apim
location=eastus2
vnet=apim-vnet
az group create --name $rg --location $location
az network vnet create -n $vnet -g $rg -l $location \
--address-prefixes 10.0.0.0/16 \
--subnet-name default \
--subnet-prefixes 10.0.0.0/24
# there is no cli support for azure APIM :(
# create it from the portal with developer tier, join to vnet
keyvault=apim-vault-$((1 + RANDOM % 10000))
az keyvault create --name $keyvault -g $rg -l $location
# secure the key vault
az network vnet subnet update --resource-group $rg \
--vnet-name $vnet \
--name default \
--service-endpoints "Microsoft.KeyVault"
subnetid=$(az network vnet subnet show --resource-group $rg --vnet-name $vnet --name default --query id --output tsv)
az keyvault network-rule add --resource-group $rg --name $keyvault --subnet $subnetid
az keyvault network-rule add --resource-group $rg --name $keyvault --ip-address "10.0.0.0/16"
# azure services allow
az keyvault update --resource-group $rg --name $keyvault --bypass AzureServices
# enable the service endpoint rules
az keyvault update --resource-group $rg --name $keyvault --default-action Deny
# Resources
# https://docs.microsoft.com/en-us/azure/key-vault/key-vault-manage-with-cli2
keyvault=$(az keyvault list -g $rg --query '[?name.starts_with(@, `apim`)].name' --output tsv)
# create the service principal
sp_name="apim-${keyvault}"
sp=$(az ad sp create-for-rbac -n $sp_name --skip-assignment --output json)
sp_id=$(echo $sp | jq .appId -r)
# assign the service principal to the vault to allow read permission on the certificates
az keyvault set-policy --name $keyvault \
--spn $sp_id \
--certificate-permissions get \
--secret-permissions get
# references
# https://www.noelbundick.com/posts/importing-certificates-to-key-vault/
keyvault=$(az keyvault list -g $rg --query '[?name.starts_with(@, `apim`)].name' --output tsv)
cert=cert1
pfx=cert1.pfx
# Tell Key Vault to create a certificate with the default policy
az keyvault certificate create --vault-name $keyvault -n $cert -p "$(az keyvault certificate get-default-policy -o json)"
# Download the secret (private key information) associated with the cert
az keyvault secret download --vault-name $keyvault -n $cert -e base64 -f $pfx
<!--
Create the following named values in APIM:
- aad-endpoint
- aad-clientid
- aad-clientsecret
- aad-scope
-->
<policies>
<inbound>
<base />
<!-- to get a request to AAD, use https://login.microsoftonline.com/<tenant id>/oauth2/token -->
<send-request ignore-error="true" timeout="20" response-variable-name="bearerToken" mode="new">
<set-url>{{aad.endpoint}}</set-url>
<set-method>POST</set-method>
<set-header name="Content-Type" exists-action="override">
<value>application/x-www-form-urlencoded</value>
</set-header>
<set-body>
@{
return "client_id={{aad.clientid}}&resource={{aad.scope}}&client_secret={{aad.clientsecret}}&grant_type=client_credentials";
}
</set-body>
</send-request>
<set-variable name="keyVaultToken"
value="@((String)((IResponse)context.Variables["bearerToken"]).Body.As<JObject>()["access_token"])" />
<!-- get certificate from key vault
https://docs.microsoft.com/en-us/azure/key-vault/authentication-requests-and-responses
https://docs.microsoft.com/en-us/rest/api/keyvault/getcertificate/getcertificate
{vaultBaseUrl}/certificates/{certificate-name}/{certificate-version}?api-version=7.0
-->
<send-request ignore-error="true" timeout="20" response-variable-name="clientCertificate" mode="new">
<set-url>{{keyvault.url}}/certificates/{{keyvault.cert.name}}?api-version=7.0</set-url>
<set-method>GET</set-method>
<set-header name="Content-Type" exists-action="override">
<value>application/json</value>
</set-header>
<set-header name="Authorization" exists-action="override">
<value>@("Bearer" + context.Variables["bearerToken"])</value>
</set-header>
</send-request>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
<set-header name="x-client-cert" exists-action="override">
<value>@(context.Variables["clientCertificate"])</value>
</set-header>
<set-body>
@{
string cert = context.Variables["clientCertificate"];
return "x-client-cert: " + cert;
}
</set-body>
</outbound>
<on-error>
<base />
</on-error>
</policies>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment