update route_create.sh
This commit is contained in:
1 parent
e54e57436b
commit
a0315401e8
1 file changed
+146
@@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ADMIN_API_URL="${ADMIN_API_URL:-http://localhost:9180}"
|
||||
ADMIN_API_KEY="${ADMIN_API_KEY:-edd1c9f034335f136f87ad84b625c8f1}"
|
||||
TENANT_ID="${TENANT_ID:-2081a403-c773-427a-86a4-543f0983d921}"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
./route_create.sh <route-prefix> <dataverse-host> <client-id> <client-secret>
|
||||
|
||||
Params:
|
||||
route-prefix APISIX public route prefix, for example: ssm-vn-dev
|
||||
dataverse-host Dataverse host without scheme, for example: tngredev.crm5.dynamics.com
|
||||
client-id Microsoft Entra application client id
|
||||
client-secret Microsoft Entra application client secret
|
||||
|
||||
Derived values:
|
||||
route id <route-prefix>-route
|
||||
route uri /<route-prefix>/*
|
||||
token cache key dataverse_token_<route-prefix with '-' replaced by '_'>
|
||||
upstream https://<dataverse-host>
|
||||
token scope https://<dataverse-host>/.default
|
||||
|
||||
Example:
|
||||
./route_create.sh ssm-vn-dev tngredev.crm5.dynamics.com 2f680fb4-35b8-4be2-99ee-a3d183b607c9 'YOUR_CLIENT_SECRET'
|
||||
|
||||
Optional env:
|
||||
ADMIN_API_URL Default: http://localhost:9180
|
||||
ADMIN_API_KEY Default: edd1c9f034335f136f87ad84b625c8f1
|
||||
TENANT_ID Default: 2081a403-c773-427a-86a4-543f0983d921
|
||||
EOF
|
||||
}
|
||||
|
||||
if [ "$#" -ne 4 ]; then
|
||||
echo "ERROR: Missing required params. Expected 4 params, got $#." >&2
|
||||
echo >&2
|
||||
usage >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ROUTE_PREFIX="$1"
|
||||
DATAVERSE_HOST="$2"
|
||||
CLIENT_ID="$3"
|
||||
CLIENT_SECRET="$4"
|
||||
|
||||
if ! [[ "$ROUTE_PREFIX" =~ ^[A-Za-z0-9][A-Za-z0-9_-]*$ ]]; then
|
||||
echo "ERROR: route-prefix is invalid: $ROUTE_PREFIX" >&2
|
||||
echo "Use only letters, numbers, hyphen, and underscore. Example: ssm-vn-dev" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$DATAVERSE_HOST" == http://* || "$DATAVERSE_HOST" == https://* || "$DATAVERSE_HOST" == */* ]]; then
|
||||
echo "ERROR: dataverse-host must be host only, without scheme/path." >&2
|
||||
echo "Example: tngredev.crm5.dynamics.com" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
json_escape() {
|
||||
sed \
|
||||
-e 's/\\/\\\\/g' \
|
||||
-e 's/"/\\"/g' \
|
||||
-e ':a;N;$!ba;s/\n/\\n/g'
|
||||
}
|
||||
|
||||
lua_escape() {
|
||||
sed \
|
||||
-e 's/\\/\\\\/g' \
|
||||
-e 's/"/\\"/g' \
|
||||
-e ':a;N;$!ba;s/\n/\\n/g'
|
||||
}
|
||||
|
||||
ROUTE_ID="${ROUTE_PREFIX}-route"
|
||||
TOKEN_SUFFIX="${ROUTE_PREFIX//-/_}"
|
||||
TOKEN_CACHE_KEY="dataverse_token_${TOKEN_SUFFIX}"
|
||||
ROUTE_URI="/${ROUTE_PREFIX}/*"
|
||||
REWRITE_REGEX="^/${ROUTE_PREFIX}(/.*)$"
|
||||
UPSTREAM_NODE="${DATAVERSE_HOST}:443"
|
||||
TOKEN_SCOPE="https://${DATAVERSE_HOST}/.default"
|
||||
|
||||
TOKEN_CACHE_KEY_LUA="$(printf '%s' "$TOKEN_CACHE_KEY" | lua_escape)"
|
||||
TENANT_ID_LUA="$(printf '%s' "$TENANT_ID" | lua_escape)"
|
||||
CLIENT_ID_LUA="$(printf '%s' "$CLIENT_ID" | lua_escape)"
|
||||
CLIENT_SECRET_LUA="$(printf '%s' "$CLIENT_SECRET" | lua_escape)"
|
||||
TOKEN_SCOPE_LUA="$(printf '%s' "$TOKEN_SCOPE" | lua_escape)"
|
||||
|
||||
LUA_FUNCTION="return function(conf, ctx) local core = require(\"apisix.core\"); local http = require(\"resty.http\"); local cache = ngx.shared.oauth_cache; if not cache then core.log.error(\"oauth_cache not defined in config.yaml\"); return end; local token = cache:get(\"${TOKEN_CACHE_KEY_LUA}\"); if not token then local httpc = http.new(); httpc:set_timeout(5000); local tenant_id = \"${TENANT_ID_LUA}\"; local client_id = \"${CLIENT_ID_LUA}\"; local client_secret = \"${CLIENT_SECRET_LUA}\"; local scope = \"${TOKEN_SCOPE_LUA}\"; local body = \"grant_type=client_credentials&client_id=\" .. ngx.escape_uri(client_id) .. \"&client_secret=\" .. ngx.escape_uri(client_secret) .. \"&scope=\" .. ngx.escape_uri(scope); local res, err = httpc:request_uri(\"https://login.microsoftonline.com/\" .. tenant_id .. \"/oauth2/v2.0/token\", { method = \"POST\", body = body, headers = { [\"Content-Type\"] = \"application/x-www-form-urlencoded\" }, ssl_verify = false }); if not res or res.status ~= 200 then core.log.error(\"Failed to fetch Azure AD token: \", err or (res and res.body)); return core.response.exit(500, { error = \"Auth failed to upstream provider\" }) end; local data, decode_err = core.json.decode(res.body); if not data or not data.access_token then core.log.error(\"Failed to decode token response\"); return core.response.exit(500, { error = \"Invalid token response\" }) end; token = data.access_token; local expires_in = data.expires_in or 3600; cache:set(\"${TOKEN_CACHE_KEY_LUA}\", token, expires_in - 60) end; ngx.req.set_header(\"Authorization\", \"Bearer \" .. token) end"
|
||||
|
||||
ROUTE_ID_JSON="$(printf '%s' "$ROUTE_ID" | json_escape)"
|
||||
ROUTE_URI_JSON="$(printf '%s' "$ROUTE_URI" | json_escape)"
|
||||
REWRITE_REGEX_JSON="$(printf '%s' "$REWRITE_REGEX" | json_escape)"
|
||||
UPSTREAM_NODE_JSON="$(printf '%s' "$UPSTREAM_NODE" | json_escape)"
|
||||
LUA_FUNCTION_JSON="$(printf '%s' "$LUA_FUNCTION" | json_escape)"
|
||||
|
||||
PAYLOAD_FILE="$(mktemp)"
|
||||
trap 'rm -f "$PAYLOAD_FILE"' EXIT
|
||||
|
||||
cat > "$PAYLOAD_FILE" <<EOF
|
||||
{
|
||||
"uri": "${ROUTE_URI_JSON}",
|
||||
"name": "${ROUTE_ID_JSON}",
|
||||
"plugins": {
|
||||
"key-auth": {},
|
||||
"proxy-rewrite": {
|
||||
"regex_uri": [
|
||||
"${REWRITE_REGEX_JSON}",
|
||||
"\$1"
|
||||
]
|
||||
},
|
||||
"serverless-pre-function": {
|
||||
"phase": "access",
|
||||
"functions": [
|
||||
"${LUA_FUNCTION_JSON}"
|
||||
]
|
||||
},
|
||||
"limit-count": {
|
||||
"count": 100,
|
||||
"time_window": 60,
|
||||
"rejected_code": 429
|
||||
}
|
||||
},
|
||||
"upstream": {
|
||||
"type": "roundrobin",
|
||||
"nodes": {
|
||||
"${UPSTREAM_NODE_JSON}": 1
|
||||
},
|
||||
"pass_host": "node",
|
||||
"scheme": "https"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "Creating/updating APISIX route:"
|
||||
echo " route id: ${ROUTE_ID}"
|
||||
echo " public uri: ${ROUTE_URI}"
|
||||
echo " upstream: https://${DATAVERSE_HOST}"
|
||||
echo " rewrite: /${ROUTE_PREFIX}/... -> /..."
|
||||
echo " token cache key: ${TOKEN_CACHE_KEY}"
|
||||
echo
|
||||
|
||||
curl -i "${ADMIN_API_URL}/apisix/admin/routes/${ROUTE_ID}" \
|
||||
-H "X-API-KEY: ${ADMIN_API_KEY}" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-X PUT \
|
||||
--data-binary "@${PAYLOAD_FILE}"
|
||||
Reference in new issue
Block a user