Skip to main content

15 - Migration Patterns

Migrating to Azure APIM from Kong, Apigee, AWS API Gateway, and legacy gateways


🎯 Migration Overview


📊 Feature Mapping Matrix

FeatureKongApigeeAWS API GWAPIM Equivalent
Rate Limitingrate-limiting pluginSpike ArrestUsage Plansrate-limit, rate-limit-by-key
JWT Validationjwt pluginVerifyJWTCognito/Customvalidate-jwt, validate-azure-ad-token
API Keyskey-auth pluginAPI KeyAPI KeysSubscription keys
Cachingproxy-cache pluginResponseCacheBuilt-in cachingcache-lookup, cache-store
Request Transformrequest-transformerAssignMessageMapping templatesset-header, set-body, rewrite-uri
Response Transformresponse-transformerAssignMessageMapping templatesset-header, set-body
Load Balancingupstream targetsTarget ServersVPC LinkBackend pools
Circuit BreakerCustom/Kong GatewayN/AN/Aretry, circuit-breaker in backends
OAuth 2.0oauth2 pluginOAuthCognitoOAuth 2.0 authorization servers
IP Filteringip-restriction pluginAccessControlResource policiesip-filter
CORScors pluginCORSCORS configcors policy
LoggingVarious pluginsMessageLoggingCloudWatchApplication Insights, Event Hub
Quotarate-limiting pluginQuotaUsage Plansquota, quota-by-key

🐒 Kong Migration

Kong to APIM Mapping

Kong ConceptAPIM Equivalent
ServiceBackend
RouteAPI Operation
Plugin (global)Global Policy
Plugin (service)API Policy
Plugin (route)Operation Policy
ConsumerUser/Subscription
UpstreamBackend Pool

Kong Plugin to APIM Policy

# Kong rate-limiting plugin
plugins:
- name: rate-limiting
config:
minute: 100
policy: local
<!-- APIM equivalent -->
<inbound>
<rate-limit calls="100" renewal-period="60" />
</inbound>
# Kong jwt plugin
plugins:
- name: jwt
config:
key_claim_name: iss
secret_is_base64: false
<!-- APIM equivalent -->
<inbound>
<validate-jwt header-name="Authorization" require-signed-tokens="true">
<openid-config url="https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration"/>
<issuers>
<issuer>https://login.microsoftonline.com/{tenant}/v2.0</issuer>
</issuers>
</validate-jwt>
</inbound>

Kong Export Script

#!/bin/bash
# Export Kong configuration for migration analysis

# Export services
curl -s http://kong-admin:8001/services | jq '.' > kong-services.json

# Export routes
curl -s http://kong-admin:8001/routes | jq '.' > kong-routes.json

# Export plugins
curl -s http://kong-admin:8001/plugins | jq '.' > kong-plugins.json

# Export consumers
curl -s http://kong-admin:8001/consumers | jq '.' > kong-consumers.json

# Export upstreams
curl -s http://kong-admin:8001/upstreams | jq '.' > kong-upstreams.json

echo "Kong configuration exported. Review files for migration planning."

🌐 Google Apigee Migration

Apigee to APIM Mapping

Apigee ConceptAPIM Equivalent
API ProxyAPI
ProxyEndpointFrontend
TargetEndpointBackend
FlowPolicy section
PolicyPolicy element
ProductProduct
Developer AppSubscription
EnvironmentAPIM instance or tags

Apigee Policy Conversions

<!-- Apigee: AssignMessage -->
<AssignMessage name="SetHeaders">
<Set>
<Headers>
<Header name="X-Custom-Header">value</Header>
</Headers>
</Set>
</AssignMessage>
<!-- APIM equivalent -->
<set-header name="X-Custom-Header" exists-action="override">
<value>value</value>
</set-header>
<!-- Apigee: SpikeArrest -->
<SpikeArrest name="SpikeArrest">
<Rate>100pm</Rate>
</SpikeArrest>
<!-- APIM equivalent -->
<rate-limit calls="100" renewal-period="60" />
<!-- Apigee: Quota -->
<Quota name="CheckQuota">
<Interval>1</Interval>
<TimeUnit>day</TimeUnit>
<Allow count="1000"/>
</Quota>
<!-- APIM equivalent -->
<quota calls="1000" renewal-period="86400" />
<!-- Apigee: VerifyJWT -->
<VerifyJWT name="VerifyJWT">
<Algorithm>RS256</Algorithm>
<Source>request.header.Authorization</Source>
<Issuer>https://issuer.example.com</Issuer>
</VerifyJWT>
<!-- APIM equivalent -->
<validate-jwt header-name="Authorization" require-signed-tokens="true">
<issuers>
<issuer>https://issuer.example.com</issuer>
</issuers>
<required-claims>
<claim name="iss" match="all">
<value>https://issuer.example.com</value>
</claim>
</required-claims>
</validate-jwt>

☁️ AWS API Gateway Migration

AWS to APIM Mapping

AWS ConceptAPIM Equivalent
REST APIAPI
ResourceAPI path
MethodOperation
StageTags, Named values
Usage PlanProduct
API KeySubscription key
AuthorizerPolicy (validate-jwt)
IntegrationBackend
Mapping TemplatePolicies (set-body)

AWS Authorizer to APIM

// AWS Lambda Authorizer (conceptual)
{
"type": "TOKEN",
"identitySource": "method.request.header.Authorization",
"authorizerUri": "arn:aws:lambda:..."
}
<!-- APIM: JWT validation (replaces Lambda authorizer) -->
<validate-jwt header-name="Authorization"
failed-validation-httpcode="401">
<openid-config url="https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/openid-configuration"/>
<audiences>
<audience>{app-client-id}</audience>
</audiences>
</validate-jwt>

AWS Mapping Template to APIM

## AWS Request Mapping Template
{
"userId": "$input.params('id')",
"body": $input.json('$')
}
<!-- APIM equivalent -->
<set-body>@{
var id = context.Request.MatchedParameters["id"];
var body = context.Request.Body.As<JObject>();
return new JObject(
new JProperty("userId", id),
new JProperty("body", body)
).ToString();
}</set-body>

AWS Export Script

#!/bin/bash
# Export AWS API Gateway configuration

API_ID="your-api-id"
STAGE="prod"

# Export API definition
aws apigateway get-export \
--rest-api-id $API_ID \
--stage-name $STAGE \
--export-type oas30 \
aws-api-export.json

# Export usage plans
aws apigateway get-usage-plans > aws-usage-plans.json

# Export API keys
aws apigateway get-api-keys --include-values > aws-api-keys.json

echo "AWS API Gateway exported. Import OpenAPI to APIM."

📋 Migration Methodology

Phase 1: Discovery & Assessment

TaskOutput
InventoryList of all APIs, endpoints, consumers
Dependency MapBackend services, auth providers
Traffic AnalysisRequest volumes, patterns
Policy AuditCustom plugins, complex logic
Risk AssessmentBreaking changes, downtime impact

Phase 2: Parallel Running

Canary Migration Pattern:

  1. Deploy API to APIM
  2. Route 10% traffic to APIM
  3. Compare responses, latency
  4. Gradually increase to 100%
  5. Decommission legacy

Phase 3: Cutover Checklist

  • All APIs deployed to APIM
  • Policies tested and validated
  • Developer portal configured
  • Subscriptions migrated
  • DNS updated
  • Monitoring configured
  • Runbooks updated
  • Team trained
  • Rollback plan tested

🔄 OpenAPI Import Workflow

Import API from OpenAPI

resource api 'Microsoft.ApiManagement/service/apis@2023-05-01-preview' = {
name: 'migrated-api'
parent: apim
properties: {
format: 'openapi+json'
value: loadTextContent('./openapi-export.json')
path: 'v1/migrated'
protocols: ['https']
subscriptionRequired: true
apiType: 'http'
}
}

Post-Import Enhancements

<!-- Add APIM-specific policies after import -->
<policies>
<inbound>
<base />
<!-- Add authentication -->
<validate-azure-ad-token tenant-id="{{tenant-id}}">
<audiences>
<audience>api://{{app-id}}</audience>
</audiences>
</validate-azure-ad-token>
<!-- Add rate limiting -->
<rate-limit calls="100" renewal-period="60" />
</inbound>
<backend>
<base />
<!-- Configure backend pool -->
<set-backend-service backend-id="backend-pool" />
</backend>
<outbound>
<base />
<!-- Add correlation headers -->
<set-header name="X-Request-Id" exists-action="override">
<value>@(context.RequestId.ToString())</value>
</set-header>
</outbound>
</policies>

⚠️ Common Migration Pitfalls

PitfallMitigation
Custom plugin logicMay need Azure Functions for complex logic
Different auth modelsMap to Entra ID where possible
Performance differencesLoad test before cutover
Policy syntax errorsValidate in dev environment first
Consumer migrationCommunicate changes, provide migration period
Missing featuresUse workarounds or accept limitations

📊 Migration Effort Estimation

API ComplexityCharacteristicsEffort
SimpleCRUD, no transforms, basic auth2-4 hours
MediumCustom policies, JWT, caching1-2 days
ComplexExtensive transforms, custom logic3-5 days
Very ComplexMultiple backends, orchestration1-2 weeks

DocumentDescription
01-ArchitectureTarget architecture
04-PoliciesPolicy reference
05-DevOps-APIOpsIaC deployment

Next: 16-Production-Checklist - Go-live readiness checklist

📖Learn