diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..135f576d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "app/.repos/kong-plugins"] + path = app/.repos/kong-plugins + url = https://github.com/Kong/docs-plugin-toolkit.git diff --git a/Gemfile.lock b/Gemfile.lock index e799f7a9..b353e822 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ GEM remote: https://rubygems.org/ specs: - activesupport (8.0.0) + activesupport (8.0.1) base64 benchmark (>= 0.3) bigdecimal @@ -80,13 +80,13 @@ GEM listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - logger (1.6.1) + logger (1.6.3) mercenary (0.4.0) method_source (1.1.0) mini_portile2 (2.8.8) - minitest (5.25.1) + minitest (5.25.4) nio4r (2.7.4) - nokogiri (1.17.0) + nokogiri (1.17.2) mini_portile2 (~> 2.8.2) racc (~> 1.4) parallel (1.26.3) @@ -116,7 +116,7 @@ GEM regexp_parser (2.9.3) rexml (3.3.9) rouge (4.5.1) - rubocop (1.69.1) + rubocop (1.69.2) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) @@ -133,13 +133,13 @@ GEM sass-embedded (1.75.0) google-protobuf (>= 3.25, < 5.0) rake (>= 13.0.0) - securerandom (0.3.1) + securerandom (0.3.2) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.6.0) - uri (1.0.1) + uri (1.0.2) vite_ruby (3.5.0) dry-cli (>= 0.7, < 2) rack-proxy (~> 0.6, >= 0.6.1) diff --git a/Makefile b/Makefile index 1494e8d6..d1ebe96a 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ RUBY_VERSION := "$(shell ruby -v)" RUBY_VERSION_REQUIRED := "$(shell cat .ruby-version)" RUBY_MATCH := $(shell [[ "$(shell ruby -v)" =~ "ruby $(shell cat .ruby-version)" ]] && echo matched) -.PHONY: ruby-version-check +.PHONY: ruby-version-check scaffold-plugin ruby-version-check: ifndef RUBY_MATCH $(error ruby $(RUBY_VERSION_REQUIRED) is required. Found $(RUBY_VERSION). $(newline)Run `rbenv install $(RUBY_VERSION_REQUIRED)`)$(newline) @@ -48,3 +48,10 @@ kill-ports: vale: -git diff --name-only --diff-filter=d HEAD | grep '\.md$$' | xargs vale +scaffold-plugin: + @if [ -z "$(PLUGIN)" ]; then \ + echo "Error: Plugin name is required. Usage: make scaffold-plugin PLUGIN="; \ + exit 1; \ + fi + cd tools/scaffold-plugin && npm ci + node tools/scaffold-plugin/index.js $(PLUGIN) diff --git a/app/.repos/kong-plugins b/app/.repos/kong-plugins new file mode 160000 index 00000000..0000e493 --- /dev/null +++ b/app/.repos/kong-plugins @@ -0,0 +1 @@ +Subproject commit 0000e493f94bf11cf618ca528e0cf5b035c61f20 diff --git a/app/_assets/entrypoints/api_spec.js b/app/_assets/entrypoints/api_spec.js index 05cb71a9..8030b353 100644 --- a/app/_assets/entrypoints/api_spec.js +++ b/app/_assets/entrypoints/api_spec.js @@ -1,10 +1,8 @@ import { createApp } from "vue"; import APISpec from "~/javascripts/apps/APISpec.vue"; -import { BindOncePlugin } from "vue-bind-once"; import "@kong/spec-renderer-dev/dist/style.css"; if (document.getElementById("api-spec") !== null) { const app = createApp(APISpec); - app.use(BindOncePlugin); app.mount("#api-spec"); } diff --git a/app/_assets/entrypoints/application.js b/app/_assets/entrypoints/application.js index b5ef406f..26d36ea5 100644 --- a/app/_assets/entrypoints/application.js +++ b/app/_assets/entrypoints/application.js @@ -4,21 +4,21 @@ // and link to the scripts and stylesheets, and let Vite transform it. // Example: Import a stylesheet in /index.css -import '~/stylesheets/index.css' +import "~/stylesheets/index.css"; -import EntityExample from '@/javascripts/components/entity_example'; -import PluginConfigExample from '@/javascripts/components/plugin_config_example'; -import Tabs from '@/javascripts/components/tabs'; -import '@/javascripts/accordion'; -import '@/javascripts/anchor_links'; -import '@/javascripts/copy_code_snippet'; -import '@/javascripts/how_to'; -import '@/javascripts/mode'; -import '@/javascripts/releases_dropdown'; -import '@/javascripts/toc'; +import EntityExample from "@/javascripts/components/entity_example"; +import PluginConfigExample from "@/javascripts/components/plugin_config_example"; +import Tabs from "@/javascripts/components/tabs"; +import "@/javascripts/accordion"; +import "@/javascripts/anchor_links"; +import "@/javascripts/copy_code_snippet"; +import "@/javascripts/how_to"; +import "@/javascripts/mode"; +import "@/javascripts/releases_dropdown"; +import "@/javascripts/toc"; -document.addEventListener('DOMContentLoaded', function () { +document.addEventListener("DOMContentLoaded", function () { new EntityExample(); new PluginConfigExample(); new Tabs(); -}); \ No newline at end of file +}); diff --git a/app/_assets/entrypoints/hub.js b/app/_assets/entrypoints/hub.js new file mode 100644 index 00000000..390511ae --- /dev/null +++ b/app/_assets/entrypoints/hub.js @@ -0,0 +1,83 @@ +class Hub { + constructor() { + this.filters = document.getElementById("filters"); + this.plugins = document.querySelectorAll("[data-card='plugin']"); + + this.deploymentTopologies = this.filters.querySelectorAll( + 'input[name="deployment-topology"]' + ); + this.categories = this.filters.querySelectorAll('input[name="category"]'); + + this.deploymentValues = []; + this.categoryValues = []; + + this.addEventListeners(); + } + + addEventListeners() { + const checkboxes = [...this.deploymentTopologies, ...this.categories]; + checkboxes.forEach((checkbox) => { + checkbox.addEventListener("change", () => this.onChange()); + }); + } + + onChange() { + this.deploymentValues = this.getValues(this.deploymentTopologies); + this.categoryValues = this.getValues(this.categories); + + this.filterPlugins(); + } + + getValues(filterGroup) { + return Array.from(filterGroup) + .filter((checkbox) => checkbox.checked) + .map((checkbox) => checkbox.value); + } + + filterPlugins() { + this.plugins.forEach((plugin) => { + const matchesDeploymentTopology = this.filterBy( + plugin, + this.deploymentTopologies, + "deploymentTopology" + ); + const matchesCategory = this.filterBy( + plugin, + this.categories, + "category" + ); + + const showPlugin = matchesDeploymentTopology && matchesCategory; + + plugin.classList.toggle("hidden", !showPlugin); + }); + + this.toggleCategoriesIfEmpty(); + } + + toggleCategoriesIfEmpty() { + this.categories.forEach((cat) => { + const category = document.getElementById(cat.value); + const showCategory = category.querySelectorAll( + '[data-card="plugin"]:not(.hidden)' + ).length; + + category.classList.toggle("hidden", !showCategory); + }); + } + + filterBy(plugin, filterGroup, dataAttribute) { + const checkedValues = Array.from(filterGroup) + .filter((checkbox) => checkbox.checked) + .map((checkbox) => checkbox.value); + + const dataValues = plugin.dataset[dataAttribute]?.split(",") || []; + return ( + checkedValues.length === 0 || + checkedValues.some((value) => dataValues.includes(value)) + ); + } +} + +// Initialize the Hub once the DOM is fully loaded +document.addEventListener("DOMContentLoaded", () => new Hub()); diff --git a/app/_assets/entrypoints/plugin_schema.js b/app/_assets/entrypoints/plugin_schema.js new file mode 100644 index 00000000..1abf4d6f --- /dev/null +++ b/app/_assets/entrypoints/plugin_schema.js @@ -0,0 +1,8 @@ +import { createApp } from "vue"; +import PluginSchema from "~/javascripts/apps/PluginSchema.vue"; +import "@kong/spec-renderer-dev/dist/style.css"; + +if (document.getElementById("schema") !== null) { + const app = createApp(PluginSchema); + app.mount("#schema"); +} diff --git a/app/_assets/javascripts/apps/PluginSchema.vue b/app/_assets/javascripts/apps/PluginSchema.vue new file mode 100644 index 00000000..415abf80 --- /dev/null +++ b/app/_assets/javascripts/apps/PluginSchema.vue @@ -0,0 +1,16 @@ + + + \ No newline at end of file diff --git a/app/_assets/javascripts/components/tabs.js b/app/_assets/javascripts/components/tabs.js index 563ed09e..9d4dc4bd 100644 --- a/app/_assets/javascripts/components/tabs.js +++ b/app/_assets/javascripts/components/tabs.js @@ -1,20 +1,19 @@ class TabsComponent { constructor(elem) { this.elem = elem; - this.tablistNode = this.elem.querySelector('[role=tablist]'); - this.activeTabClasses = ['text-primary', 'font-semibold', 'border-brand']; - this.inactiveTabClasses = ['border-transparent']; + this.tablistNode = this.elem.querySelector("[role=tablist]"); + this.activeTabClasses = ["tab-button__horizontal--active"]; - this.tabs = Array.from(this.tablistNode.querySelectorAll('[role=tab]')); + this.tabs = Array.from(this.tablistNode.querySelectorAll("[role=tab]")); this.firstTab = this.tabs[0]; this.lastTab = this.tabs[this.tabs.length - 1]; this.tabs.forEach((tab) => { - tab.addEventListener('keydown', this.onKeydown.bind(this)); - tab.addEventListener('click', this.onClick.bind(this)); + tab.addEventListener("keydown", this.onKeydown.bind(this)); + tab.addEventListener("click", this.onClick.bind(this)); }); // Listen for the custom event to update tabs - document.addEventListener('tabSelected', this.onTabSelected.bind(this)); + document.addEventListener("tabSelected", this.onTabSelected.bind(this)); this.setSelectedTab(this.firstTab, false); } @@ -25,22 +24,22 @@ class TabsComponent { let flag = false; switch (event.key) { - case 'ArrowLeft': - selectedTab = this.getPreviousTab(tgt) + case "ArrowLeft": + selectedTab = this.getPreviousTab(tgt); flag = true; break; - case 'ArrowRight': - selectedTab = this.getNextTab(tgt) + case "ArrowRight": + selectedTab = this.getNextTab(tgt); flag = true; break; - case 'Home': + case "Home": selectedTab = this.firstTab; flag = true; break; - case 'End': + case "End": selectedTab = this.lastTab; flag = true; break; @@ -67,24 +66,26 @@ class TabsComponent { } setSelectedTab(currentTab, setFocus) { - if (typeof setFocus !== 'boolean') { + if (typeof setFocus !== "boolean") { setFocus = true; } this.tabs.forEach((tab) => { - const tabPanel = document.getElementById(tab.getAttribute('aria-controls')); + const tabPanel = document.getElementById( + tab.getAttribute("aria-controls") + ); if (currentTab === tab) { - tab.setAttribute('aria-selected', 'true'); + tab.setAttribute("aria-selected", "true"); tab.tabIndex = 0; this.toggleTabClasses(tab, true); - tabPanel.classList.remove('hidden'); + tabPanel.classList.remove("hidden"); if (setFocus) { tab.focus(); } } else { - tab.setAttribute('aria-selected', 'false'); + tab.setAttribute("aria-selected", "false"); tab.tabIndex = -1; this.toggleTabClasses(tab, false); - tabPanel.classList.add('hidden'); + tabPanel.classList.add("hidden"); } }); } @@ -108,14 +109,14 @@ class TabsComponent { } setSelectedTabBySlug(slug, setFocus = true) { - const tab = this.tabs.find(tab => tab.dataset.slug === slug); + const tab = this.tabs.find((tab) => tab.dataset.slug === slug); if (tab) { this.setSelectedTab(tab, setFocus); } } dispatchTabSelectedEvent(tabSlug) { - const event = new CustomEvent('tabSelected', { detail: { tabSlug } }); + const event = new CustomEvent("tabSelected", { detail: { tabSlug } }); document.dispatchEvent(event); } @@ -127,9 +128,7 @@ class TabsComponent { toggleTabClasses(tab, isActive) { if (isActive) { tab.classList.add(...this.activeTabClasses); - tab.classList.remove(...this.inactiveTabClasses); } else { - tab.classList.add(...this.inactiveTabClasses); tab.classList.remove(...this.activeTabClasses); } } @@ -137,14 +136,14 @@ class TabsComponent { export default class Tabs { constructor() { - document.querySelectorAll('.tabs').forEach((elem) => { + document.querySelectorAll(".tabs").forEach((elem) => { new TabsComponent(elem); }); // Check if a tab query param exists in the URL const urlParams = new URLSearchParams(window.location.search); - const tabSlug = urlParams.get('tab'); - const formatSlug = urlParams.get('format'); + const tabSlug = urlParams.get("tab"); + const formatSlug = urlParams.get("format"); if (tabSlug) { this.selectTabBySlug(tabSlug); } else if (formatSlug) { @@ -153,7 +152,7 @@ export default class Tabs { } selectTabBySlug(tabSlug) { - const event = new CustomEvent('tabSelected', { detail: { tabSlug } }); + const event = new CustomEvent("tabSelected", { detail: { tabSlug } }); document.dispatchEvent(event); } } diff --git a/app/_assets/javascripts/toc.js b/app/_assets/javascripts/toc.js index 616df0e2..bd8a2b8f 100644 --- a/app/_assets/javascripts/toc.js +++ b/app/_assets/javascripts/toc.js @@ -1,48 +1,46 @@ function toggleTocLinkClasses(link, isActive) { - const activeClasses = ['border-l-2', 'border-brand']; + const activeClasses = ["tab-button__vertical--active"]; if (isActive) { - link.classList.add('text-primary'); - link.classList.remove('text-secondary'); - link.parentElement.classList.add(...activeClasses); + link.classList.add(...activeClasses); } else { - link.classList.add('text-secondary'); - link.classList.remove('text-primary'); - link.parentElement.classList.remove(...activeClasses); + link.classList.remove(...activeClasses); } } window.addEventListener("scroll", () => { - const anchors = document.querySelectorAll("a.header-link"); - const scrollToLinks = document.querySelectorAll("a.scroll-to"); - const navHeight = document.getElementById('header-nav').offsetHeight; + const anchors = document.querySelectorAll("a.header-link"); + const scrollToLinks = document.querySelectorAll("a.scroll-to"); + const navHeight = document.getElementById("header-nav").offsetHeight; - if (!anchors.length || !scrollToLinks.length) { - return; - } + if (!anchors.length || !scrollToLinks.length) { + return; + } - let activeSet = false; + let activeSet = false; - scrollToLinks.forEach(link => toggleTocLinkClasses(link, false)); + scrollToLinks.forEach((link) => toggleTocLinkClasses(link, false)); - // Convert NodeList to Array and reverse it - const anchorsArray = Array.from(anchors).reverse(); + // Convert NodeList to Array and reverse it + const anchorsArray = Array.from(anchors).reverse(); - for (const element of anchorsArray) { - const elementTop = element.getBoundingClientRect().top + window.scrollY; + for (const element of anchorsArray) { + const elementTop = element.getBoundingClientRect().top + window.scrollY; - // window top + header section + extra padding - if (window.scrollY + navHeight + 20 >= elementTop) { - const matchingLink = document.querySelector(`a.scroll-to[href$="${element.getAttribute("href")}"]`); - if (matchingLink) { - toggleTocLinkClasses(matchingLink, true); - activeSet = true; - } - break; + // window top + header section + extra padding + if (window.scrollY + navHeight + 20 >= elementTop) { + const matchingLink = document.querySelector( + `a.scroll-to[href$="${element.getAttribute("href")}"]` + ); + if (matchingLink) { + toggleTocLinkClasses(matchingLink, true); + activeSet = true; } - }; - - if (!activeSet) { - toggleTocLinkClasses(scrollToLinks[0], true); + break; } - }); \ No newline at end of file + } + + if (!activeSet) { + toggleTocLinkClasses(scrollToLinks[0], true); + } +}); diff --git a/app/_assets/stylesheets/index.css b/app/_assets/stylesheets/index.css index 1e21e96a..b875b535 100644 --- a/app/_assets/stylesheets/index.css +++ b/app/_assets/stylesheets/index.css @@ -315,11 +315,43 @@ } path { - @apply fill-[rgb(var(--color-brand))] stroke-[rgb(var(--color-brand))] stroke-1 !important + @apply fill-[context-stroke] stroke-[rgb(var(--color-brand))] stroke-1 !important } } .badge.deprecated { @apply bg-semantic-red-secondary; } + + .tablist { + @apply list-none flex gap-4 text-sm ml-0 flex-row border-b border-primary/5 w-full items-center; + } + + .tabcolumn { + @apply list-none flex text-sm ml-0 w-full gap-0; + } + + .tab-button { + @apply flex text-sm max-h-11 box-border; + } + + .tab-button--active { + @apply text-primary font-semibold border-brand !important; + } + + .tab-button__horizontal { + @apply tab-button py-3 text-terciary hover:no-underline items-center; + + &.tab-button__horizontal--active { + @apply tab-button--active border-b-2 -mb-0.5 !important; + } + } + + .tab-button__vertical { + @apply tab-button py-2 px-5 text-terciary hover:no-underline border-l-2 border-transparent; + + &.tab-button__vertical--active { + @apply tab-button--active !important; + } + } } diff --git a/app/_data/plugin_categories.yml b/app/_data/plugin_categories.yml new file mode 100644 index 00000000..6afce132 --- /dev/null +++ b/app/_data/plugin_categories.yml @@ -0,0 +1,24 @@ +- text: AI + slug: ai + desc: Govern, secure, and control AI traffic with multi-LLM AI Gateway plugins +- text: Authentication + slug: authentication + desc: Protect your services with an authentication layer +- text: Security + slug: security + desc: Protect your services with additional security layer +- text: Traffic Control + slug: traffic-control + desc: Manage, throttle and restrict inbound and outbound API traffic +- text: Serverless + slug: serverless + desc: Invoke serverless functions in combination with other plugins +- text: Analytics & Monitoring + slug: analytics-monitoring + desc: Visualize, inspect and monitor APIs and microservices traffic +- text: Transformations + slug: transformations + desc: Transform request and responses on the fly on Kong +- text: Logging + slug: logging + desc: Log request and response data using the best transport for your infrastructure \ No newline at end of file diff --git a/app/_data/plugins/ai-proxy-advanced.yaml b/app/_data/plugins/ai-proxy-advanced.yaml new file mode 100644 index 00000000..9905b497 --- /dev/null +++ b/app/_data/plugins/ai-proxy-advanced.yaml @@ -0,0 +1,5 @@ +parameters: + provider: 'config.targets.model.provider' + route_type: 'config.targets.route_type' + options: 'config.targets.model.options' + upstream_url: 'config.targets.model.options.upstream_url' \ No newline at end of file diff --git a/app/_data/plugins/ai-proxy.yaml b/app/_data/plugins/ai-proxy.yaml new file mode 100644 index 00000000..c2613a82 --- /dev/null +++ b/app/_data/plugins/ai-proxy.yaml @@ -0,0 +1,139 @@ +providers: + - name: 'OpenAI' + formats: 'GPT-3.5, GPT-4, GPT-4o, and Multi-Modal' + url_pattern: 'https://api.openai.com:443/{route_type_path}' + min_version: '3.6' + chat: + supported: ✅ + upstream_path: '/v1/chat/completions' + route_type: 'llm/v1/chat' + model_example: 'gpt-4' + completions: + supported: ✅ + upstream_path: '/v1/completions' + route_type: 'llm/v1/completions' + model_example: 'gpt-3.5-turbo-instruct' + streaming: + supported: ✅ + - name: 'Cohere' + url_pattern: 'https://api.cohere.com:443/{route_type_path}' + min_version: '3.6' + chat: + supported: ✅ + upstream_path: '/v1/chat' + route_type: 'llm/v1/chat' + model_example: 'command' + completions: + supported: ✅ + upstream_path: '/v1/generate' + route_type: 'llm/v1/completions' + model_example: 'command' + streaming: + supported: ✅ + - name: 'Azure' + url_pattern: 'https://{azure_instance}.openai.azure.com:443/openai/deployments/{deployment_name}/{route_type_path}' + min_version: '3.6' + chat: + supported: ✅ + upstream_path: '/openai/deployments/{deployment_name}/chat/completions' + route_type: 'llm/v1/chat' + model_example: 'gpt-4' + completions: + supported: ✅ + upstream_path: '/openai/deployments/{deployment_name}/completions' + route_type: 'llm/v1/completions' + model_example: 'gpt-3.5-turbo-instruct' + streaming: + supported: ✅ + - name: 'Anthropic' + url_pattern: 'https://api.anthropic.com:443/{route_type_path}' + min_version: '3.6' + chat: + supported: ✅ + upstream_path: '/v1/complete in version 3.6, /v1/messages since version 3.7' + route_type: 'llm/v1/chat' + model_example: 'claude-2.1' + completions: + supported: ✅ + upstream_path: '/v1/complete' + route_type: 'llm/v1/completions' + model_example: 'claude-2.1' + streaming: + supported: Chat type only + - name: 'Mistral' + formats: 'mistral.ai, OpenAI, raw, and OLLAMA formats' + url_pattern: 'As defined in $UPSTREAM_URL' + min_version: '3.6' + chat: + supported: ✅ + upstream_path: 'User-defined' + route_type: 'llm/v1/chat' + model_example: 'User-defined' + completions: + supported: ✅ + upstream_path: 'User-defined' + route_type: 'llm/v1/completions' + model_example: 'User-defined' + streaming: + supported: ✅ + - name: 'Llama2' + formats: 'supports Llama2 and Llama3 models and raw, OLLAMA, and OpenAI formats' + url_pattern: 'As defined in $UPSTREAM_URL' + min_version: '' + chat: + supported: ✅ + upstream_path: 'User-defined' + route_type: 'llm/v1/chat' + model_example: 'User-defined' + completions: + supported: ✅ + upstream_path: 'User-defined' + route_type: 'llm/v1/completions' + model_example: 'User-defined' + streaming: + supported: ✅ + - name: 'Amazon Bedrock' + url_pattern: 'https://bedrock-runtime.{region}.amazonaws.com' + min_version: '3.8' + chat: + supported: ✅ + upstream_path: 'Use the LLM chat upstream path' + route_type: 'llm/v1/chat' + model_example: 'Use the model name for the specific LLM provider' + completions: + supported: ❌ + streaming: + supported: Chat type only + - name: 'Gemini' + url_pattern: 'https://generativelanguage.googleapis.com' + min_version: '3.8' + chat: + supported: ✅ + upstream_path: 'llm/v1/chat' + route_type: 'llm/v1/chat' + model_example: 'gemini-1.5-flash or gemini-1.5-pro' + completions: + supported: ❌ + streaming: + supported: Chat type only + - name: 'Hugging Face' + url_pattern: 'https://api-inference.huggingface.co' + min_version: '3.9' + chat: + supported: ✅ + upstream_path: '/models/{model_provider}/{model_name}' + route_type: 'llm/v1/chat' + model_example: 'Use the model name for the specific LLM provider' + completions: + supported: ✅ + upstream_path: '/models/{model_provider}/{model_name}' + route_type: 'llm/v1/completions' + model_example: 'Use the model name for the specific LLM provider' + streaming: + supported: ✅ + +parameters: + provider: 'config.provider' + route_type: 'config.route_type' + options: 'config.model.options' + upstream_url: 'config.model.options.upstream_url' diff --git a/app/_data/products/gateway.yml b/app/_data/products/gateway.yml index eb6c764a..154a4106 100644 --- a/app/_data/products/gateway.yml +++ b/app/_data/products/gateway.yml @@ -10,6 +10,13 @@ tiers: text: Enterprise only url: '/gateway/enterprise/' +deployment_topologies: + - slug: on-prem + text: on-prem + - slug: konnect + text: Konnect + + releases: - release: "3.7" ee-version: "3.7.1.2" diff --git a/app/_data/schemas/frontmatter/base.json b/app/_data/schemas/frontmatter/base.json index cfc3d782..0144895d 100644 --- a/app/_data/schemas/frontmatter/base.json +++ b/app/_data/schemas/frontmatter/base.json @@ -7,7 +7,7 @@ }, "content_type": { "type": "string", - "enum": ["landing_page", "how_to", "reference", "concept"] + "enum": ["landing_page", "how_to", "reference", "concept", "plugin"] }, "description": { "type": "string" diff --git a/app/_data/schemas/frontmatter/plugin.json b/app/_data/schemas/frontmatter/plugin.json new file mode 100644 index 00000000..9494e98b --- /dev/null +++ b/app/_data/schemas/frontmatter/plugin.json @@ -0,0 +1,10 @@ +{ + "$id": "schema:plugin", + "allOf": [{ "$ref": "schema:base" }], + "properties": { + "min_version": { + "type": "object" + } + }, + "required": ["content_type", "title", "description", "products", "works_on"] + } \ No newline at end of file diff --git a/app/_gateway_entities/consumer-group.md b/app/_gateway_entities/consumer-group.md new file mode 100644 index 00000000..34fd0fcd --- /dev/null +++ b/app/_gateway_entities/consumer-group.md @@ -0,0 +1,122 @@ +--- +title: Consumer Groups +content_type: reference +entities: + - consumer-group + +description: Consumer Groups let you apply common configurations to groups of Consumers, such as rate limiting policies or request and response transformation. + +tools: + - admin-api + - konnect-api + - kic + - deck + - terraform + +tier: enterprise + +related_resources: + - text: Create rate limiting tiers with {{site.base_gateway}} + url: /how-to/add-rate-limiting-tiers-with-kong-gateway/ + +api_specs: + - gateway/admin-ee + - konnect/control-planes-config + +faqs: + - q: Why aren't Consumer Group overrides working anymore? + a: | + Consumer Groups became a core Gateway entity in 3.4, which opened up a wide range of use cases for grouping Consumers. + + Before 3.4, Consumer Groups were limited to rate limiting plugins, where they were configured through overrides. This is no longer necessary. Instead, you can enable any rate limiting plugin directly on a consumer group without worrying about extra configuration. + - q: How do I enable a plugin on a Consumer Group? + a: | + First, [find out](/plugins/scopes/) if the plugin you want supports Consumer Groups. + + If it does, head over to the plugin's documentation, open the "Get Started" tab, and choose "Consumer Groups" from the dropdown for any available example. + + - q: When a Consumer is part of multiple Consumer Groups, how is precedence determined? + a: | + Currently, this is determined by the Group name, in alphabetical order. For more details, see [Plugin precedence](/plugins/scopes/#plugin-precedence). +--- + +## What is a Consumer Group? + +Consumer Groups enable the organization and categorization of [Consumers](/gateway/entities/consumer/) (users or applications) within an API ecosystem. By grouping Consumers together, you eliminate the need to manage them individually, providing a scalable, efficient approach to managing configurations. + +With Consumer Groups, you can scope plugins to specifically defined Consumer Groups and a new plugin instance will be created for each individual Consumer Group, making configurations and customizations more flexible and convenient. +For all plugins available on the consumer groups scope, see the [Plugin Scopes Reference](/plugins/scopes/). + +{:.info} +> **Note**: Consumer Groups plugin scoping is a feature that was added in {{site.base_gateway}} version 3.4. Running a mixed-version {{site.base_gateway}} cluster (3.4 control plane, and <=3.3 data planes) is not supported when using plugins scoped to Consumer Groups. + +For example, you could define two groups, Gold and Silver, assign different rate limits to them, then process each group using a different plugin: + + +{% mermaid %} +flowchart LR + A((fa:fa-user Consumers 1-5)) + + B(Consumer Group Gold + 10 requests/second + + fa:fa-user Consumer 1, fa:fa-user Consumer 2, + fa:fa-user Consumer 5 ) + + C(Consumer Group Silver + 5 requests/minute + + fa:fa-user Consumer 3, fa:fa-user Consumer 4) + + D(Rate Limiting Advanced) + E(Request Transformer Advanced) + F(Gateway Service + QR Code Generation) + G(Gateway Service + OCR) + H(QR Code Generation + service) + I(OCR service) + + A--> B & C + subgraph id1 [Kong Gateway] + direction LR + B --> D --> F + subgraph id2 [Gold route] + direction LR + D + end + C --> E --> G + subgraph id3 [Silver route] + direction LR + E + end + end + + F --> H + G --> I +{% endmermaid %} + + +## Use cases + +Common use cases for Consumer Groups: + +Use case | Description +---------|------------ +Managing permissions | You can use Consumer Groups to define different sets of users with varying levels of permissions. For example, you can create distinct Consumer Groups for regular users, premium users, and administrators. +Managing roles | Within an organization, there may be various departments or teams that interact with APIs differently. By creating Consumer Groups for these different roles, you can customize the API usage experience. For instance, an organization could have separate Consumer Groups for the marketing team, development team, and support team. +Resource quotas and rate limiting | Consumer Groups can be used to enforce resource quotas and rate limiting on different sets of Consumers. For instance, you can apply different rate limits to different Consumer Groups based on their subscription plans. +Customizing plugin configurations | With the ability to scope plugins specifically to defined groups, different Consumer Groups can have distinct plugin configurations based on their requirements. For example, one group may require additional request transformations while another may not need them at all. + +## Schema + +{% entity_schema %} + +## Set up a Consumer Group + +{% entity_example %} +type: consumer_group +data: + name: my_group +{% endentity_example %} diff --git a/app/_gateway_entities/consumer.md b/app/_gateway_entities/consumer.md index 5afd2ad0..e556ead6 100644 --- a/app/_gateway_entities/consumer.md +++ b/app/_gateway_entities/consumer.md @@ -4,60 +4,58 @@ content_type: reference entities: - consumer # we could use this to pull the schema too -description: A consumer typically refers to an entity that consumes or uses the APIs managed by {{site.base_gateway}}. +description: A Consumer typically refers to an entity that consumes or uses the APIs managed by {{site.base_gateway}}. related_resources: - - text: Authentication reference - url: https://docs.konghq.com/gateway/latest/kong-plugins/authentication/reference/ - - text: Consumer groups API reference + - text: Authentication in {{site.base_gateway}} + url: /authentication/ + - text: Consumer Groups API reference url: /api/gateway/admin-ee/#/operations/get-consumer_groups - - text: Plugins that can be enabled on consumers - url: https://docs.konghq.com/hub/plugins/compatibility/#scopes + - text: Plugins that can be enabled on Consumers + url: /plugins/scopes/ faqs: - q: What are credentials, and why do I need them? a: | - Credentials are necessary to authenticate consumers via various authentication mechanisms. + Credentials are necessary to authenticate Consumers via various authentication mechanisms. The credential type depends on which authentication plugin you want to use.

- For example, a Key Authentication plugin requires an API key, and a Basic Auth plugin requires a username and password pair. + For example, a Key Authentication plugin requires an API key, and a Basic Authentication plugin requires a username and password pair. - - q: What is the difference between consumers and applications? + - q: What is the difference between Consumers and Applications? a: | - Applications provide developers the ability to get access to APIs managed by {{site.base_gateway}} or Konnect - with no interaction from the Kong admin team to generate credentials required. + Applications provide developers the ability to get access to APIs managed by {{site.base_gateway}} or {{site.konnect_short_name}} + with no interaction from the Kong admin team to generate the required credentials.

- With consumers, the Kong team creates consumers, generates credentials and needs to share them with the developers that need access to the APIs. - You can think as applications as a type of consumer in Kong that allows developers to automatically obtain credentials for and subscribe to the required APIs. + With Consumers, the Kong team creates Consumers, generates credentials, and shares them with the developers that need access to the APIs. + You can think of Applications as a type of Consumer in Kong that allows developers to automatically obtain credentials for, and subscribe to the required APIs. - - q: What is the difference between consumers and developers? + - q: What is the difference between Consumers and Developers? a: | - Developers are real users of the Dev Portal, whereas consumers are abstractions. + Developers are real users of the Dev Portal, whereas Consumers are abstractions. - - q: What is the difference between consumers and RBAC users? + - q: What is the difference between Consumers and RBAC Users? a: | - RBAC users are users of Kong Manager, whereas consumers are users (real or abstract) of the Gateway itself. + RBAC Users are users of Kong Manager, whereas Consumers are users (real or abstract) of the Gateway itself. - - q: Which plugins can be scoped to consumers? + - q: Which plugins can be scoped to Consumers? a: | - Certain plugins can be scoped to consumers (as opposed to services, routes, or globally). For example, you might want to - configure the Rate Limiting plugin to rate limit a specific consumer, or use the Request Transformer plugin to edit requests for that consumer. - You can see the full list in the plugin scopes compatibility reference. + Certain plugins can be scoped to Consumers (as opposed to Gateway Services, Routes, Consumer Groups, or globally). For example, you might want to + configure the Rate Limiting plugin to rate limit a specific Consumer, or use the Request Transformer plugin to edit requests for that Consumer. + You can see the full list in the [plugin scopes compatibility reference](/plugins/scopes/). - - q: Can you scope authentication plugins to consumers? + - q: Can you scope authentication plugins to Consumers? a: | - No. You can associate consumers with an auth plugin by configuring credentials - a consumer with basic - auth credentials will use the Basic Auth plugin, for example. - But that plugin must be scoped to either a route, service, or globally, so that the consumer can access it. + No. You can associate Consumers with an auth plugin by configuring credentials. For example, a Consumer with basic + auth credentials will use the Basic Authentication plugin. + But that plugin must be scoped to either a Route, Service, or globally, so that the Consumer can access it. - - q: Are consumers used in Kuma/Mesh? - a: No. - - q: Can you manage consumers with decK? + - q: Can you manage Consumers with decK? a: | - Yes, you can manage consumers using decK, but take caution if you have a large number of consumers. + Yes, you can manage Consumers using decK, but take caution if you have a large number of Consumers.

- If you have many consumers in your database, don't export or manage them using decK. + If you have many Consumers in your database, don't export or manage them using decK. decK is built for managing entity configuration. It is not meant for end user data, which can easily grow into hundreds of thousands or millions of records. @@ -78,20 +76,20 @@ schema: path: /schemas/Consumer --- -## What is a consumer? +## What is a Consumer? {{ page.description }} Consumers can be applications, services, or users who interact with your APIs. -Since they are not always human, {{site.base_gateway}} calls them consumers, because they "consume" the service. -{{site.base_gateway}} allows you to define and manage consumers, apply access control policies, and monitor their API usage. +Since they are not always human, {{site.base_gateway}} calls them Consumers, because they "consume" the service. +{{site.base_gateway}} allows you to define and manage Consumers, apply access control policies, and monitor their API usage. Consumers are essential for controlling access to your APIs, tracking usage, and ensuring security. They are identified by key authentication, OAuth, or other authentication and authorization mechanisms. -For example, adding a Basic Auth plugin to a service or route allows it to identify a consumer, or block access if credentials are invalid. +For example, adding a Basic Auth plugin to a Gateway Service or Route allows it to identify a Consumer, or block access if credentials are invalid. -You can choose to use {{site.base_gateway}} as the primary datastore for consumers, or you can map the consumer list +You can choose to use {{site.base_gateway}} as the primary datastore for Consumers, or you can map the Consumer list to an existing database to keep consistency between {{site.base_gateway}} and your existing primary datastore. -By attaching a plugin directly to a consumer, you can manage specific controls at the consumer level, such as rate limits. +By attaching a plugin directly to a Consumer, you can manage specific controls at the Consumer level, such as rate limits. {% mermaid %} flowchart LR @@ -109,15 +107,15 @@ end B-->C {% endmermaid %} -## Use cases for consumers +## Use cases for Consumers -The following are examples of common use cases for consumers: +Common use cases for Consumers: |Use case | Description| |---------|------------| -|Authentication | Client authentication is the most common reason for setting up a consumer. If you're using an authentication plugin, you'll need a consumer with credentials.| -|Consumer groups | Group consumers by sets of criteria and apply certain rules to them.| -|Rate limiting | Rate limit specific consumers based on tiers.| +|Authentication | Client authentication is the most common reason for setting up a Consumer. If you're using an authentication plugin, you'll need a Consumer with credentials.| +|Consumer Groups | Group Consumers by sets of criteria and apply certain rules to them.| +|Rate limiting | Rate limit specific Consumers based on tiers.| ## Schema diff --git a/app/_gateway_entities/consumer_group.md b/app/_gateway_entities/consumer_group.md deleted file mode 100644 index 4f323748..00000000 --- a/app/_gateway_entities/consumer_group.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: Consumer Groups -content_type: reference -entities: - - consumer_group - -description: Consumer groups let you apply common configurations to groups of consumers, such as rate limiting policies or request and response transformation. - -tools: - - admin-api - - konnect-api - - kic - - deck - - terraform - -tier: enterprise - ---- - -## What is a consumer group? - -This page is a stub - -## Set up a Consumer Group - -{% entity_example %} -type: consumer_group -data: - name: my_group -{% endentity_example %} diff --git a/app/_gateway_entities/plugin.md b/app/_gateway_entities/plugin.md index c29d5f9c..be66cfe6 100644 --- a/app/_gateway_entities/plugin.md +++ b/app/_gateway_entities/plugin.md @@ -10,15 +10,11 @@ related_resources: - text: Plugin Hub url: /plugins/ - text: Supported scopes by plugin - url: 'https://docs.konghq.com/hub/plugins/compatibility/#scopes' - - text: Supported topologies by plugin - url: 'https://docs.konghq.com/hub/plugins/compatibility/' + url: '/plugins/scopes/' + - text: Supported topologies and deployment options by plugin + url: '/plugins/deployment-options/' - text: Supported protocols for each plugin - url: 'https://docs.konghq.com/hub/plugins/compatibility/#protocols' - - text: Self-managed {{site.base_gateway}} license tiers - url: 'https://docs.konghq.com/hub/plugins/license-tiers/' - - text: Konnect pricing tiers - url: 'https://docs.konghq.com/konnect/compatibility/#plugin-compatibility' + url: '/plugins/protocols/' tools: - admin-api @@ -31,6 +27,11 @@ schema: api: gateway/admin-ee path: /schemas/Plugin +api_specs: + - gateway/admin-oss + - gateway/admin-ee + - konnect/control-planes-config + --- ## What is a plugin? @@ -42,6 +43,42 @@ The set of plugins you have access to depends on your license tier. You can also develop custom plugins, adding your own custom functionality to {{site.base_gateway}}. +## Custom plugins + +Kong provides an entire development environment for developing plugins, including Plugin Development Kits (or PDKs), database abstractions, migrations, and more. + +Plugins consist of modules interacting with the request/response objects or streams via a PDK to implement arbitrary logic. Kong provides PDKs in the following languages: + +* Lua +* Go +* Python +* JavaScript + +These PDKs are sets of functions that a plugin can use to facilitate interactions between plugins and the core (or other components) of Kong. + +To start creating your own plugins, review the Getting Started documentation, or see the following references: + +* Plugin Development Kit reference +* Other Language Support + ## Schema {% entity_schema %} + +## Set up a Plugin + +Kong has many bundled plugins available, all of which have their own specific configurations and examples. See all +[Kong plugins](/plugins/) for their individual configurations. + +Here's an example of configuration for the ACL plugin: + +{% entity_example %} +type: plugin +data: + name: acl + config: + allow: + - dev + - admin + hide_groups_header: false +{% endentity_example %} diff --git a/app/_gateway_entities/service.md b/app/_gateway_entities/service.md index af8016e0..60f704ea 100644 --- a/app/_gateway_entities/service.md +++ b/app/_gateway_entities/service.md @@ -1,16 +1,18 @@ --- -title: Services +title: Gateway Services content_type: reference entities: - service -description: In {{site.base_gateway}}, a service is an abstraction of an upstream application that services requests. +description: A Gateway Service is an abstraction of an upstream application that services requests. related_resources: - text: Routes entity url: /gateway/entities/route/ - - text: Enable rate limiting on a service with {{site.base_gateway}} + - text: Enable rate limiting on a Gateway Service url: /how-to/add-rate-limiting-to-a-service-with-kong-gateway/ + - text: Plugins that can be enabled on Gateway Services + url: /plugins/scopes/ tools: - admin-api @@ -23,24 +25,33 @@ schema: api: gateway/admin-ee path: /schemas/Service +api_specs: + - gateway/admin-oss + - gateway/admin-ee + - konnect/control-planes-config + --- -## What is a service? +## What is a Gateway Service? -{{ page.description }} Services can store collections of objects like plugin configurations, and policies, and they can be associated with routes. +{{ page.description }} +Services can store collections of objects like plugin configurations, and policies, and they can be associated with routes. -When defining a service, the administrator provides a name and the upstream application connection information. The connection details can be provided in the url field as a single string, or by providing individual values for protocol, host, port, and path individually. +When defining a Service, the administrator provides a name and the upstream application connection information. +The connection details can be provided in the URL field as a single string, or by providing individual values for protocol, host, port, and path individually. -Services have a one-to-many relationship with upstream applications, which allows administrators to create sophisticated traffic management behaviors. +Gateway Services have a one-to-many relationship with upstream applications, which allows administrators to create sophisticated traffic management behaviors. -Services, in conjunction with [routes](/gateway/entities/route/), let you expose your services to clients with {{site.base_gateway}}. {{site.base_gateway}} abstracts the service from the clients by using routes. Since the client always calls the route, changes to the services (like versioning) don’t impact how clients make the call. Routes also allow the same service to be used by multiple clients and apply different policies based on the route used. +Gateway Services, in conjunction with [Routes](/gateway/entities/route/), let you expose your services to clients with {{site.base_gateway}}. +{{site.base_gateway}} abstracts the service from the clients by using Routes. +Since the client always calls the Route, changes to the Services (like versioning) don't impact how clients make the call. {% mermaid %} flowchart LR A(API client) B("`Route (/mock)`") - C("`Service + C("`Gateway Service (example-service)`") D(Upstream application) @@ -63,7 +74,7 @@ flowchart LR {% entity_schema %} -## Set up a Service +## Set up a Gateway Service {% entity_example %} type: service diff --git a/app/_how-tos/add-rate-limiting-for-a-consumer-with-kong-gateway.md b/app/_how-tos/add-rate-limiting-for-a-consumer-with-kong-gateway.md index 25bb584b..d7ba0902 100644 --- a/app/_how-tos/add-rate-limiting-for-a-consumer-with-kong-gateway.md +++ b/app/_how-tos/add-rate-limiting-for-a-consumer-with-kong-gateway.md @@ -17,7 +17,7 @@ works_on: - konnect min_version: - gateway: 3.4 + gateway: '3.4' plugins: - rate-limiting diff --git a/app/_how-tos/add-rate-limiting-tiers-with-kong-gateway.md b/app/_how-tos/add-rate-limiting-tiers-with-kong-gateway.md index d80cd90f..4ca0e614 100644 --- a/app/_how-tos/add-rate-limiting-tiers-with-kong-gateway.md +++ b/app/_how-tos/add-rate-limiting-tiers-with-kong-gateway.md @@ -1,12 +1,11 @@ --- -title: How to create rate limiting tiers with {{site.base_gateway}} +title: Create rate limiting tiers with {{site.base_gateway}} content_type: how_to + related_resources: - text: Consumer Group API documentation - url: /api/gateway/admin-ee/ - - text: Rate Limiting Advanced plugin - url: /plugins/rate-limiting-advanced/ - + url: /api/gateway/admin-ee/#/operations/get-consumer_groups + products: - gateway @@ -25,7 +24,7 @@ prereqs: - example-route min_version: - gateway: 3.4 + gateway: '3.4' plugins: - rate-limiting-advanced @@ -33,7 +32,7 @@ plugins: entities: - consumer - - consumer_group + - consumer-group tier: enterprise @@ -42,10 +41,10 @@ tags: tldr: q: How do I rate limit different tiers of users, such as free vs. premium subscribers, in my API using {{site.base_gateway}}? - a: To effectively manage API traffic for various user tiers (such as free, basic, and premium subscribers) you can create consumer groups for each tier and assign individual consumers to these groups. Then, configure the Rate Limiting Advanced plugin to apply specific rate limits based on these groups. This setup allows you to enforce customized request limits for each tier, ensuring fair usage and optimizing performance for high-value users. + a: To effectively manage API traffic for various user tiers (such as free, basic, and premium subscribers), you can create **Consumer Groups** for each tier and assign individual Consumers to these groups. Then, configure the Rate Limiting Advanced plugin to apply specific rate limits based on these groups. This setup allows you to enforce customized request limits for each tier, ensuring fair usage and optimizing performance for high-value users. faqs: - - q: Why can't I use the regular Rate Limiting plugin to rate limit tiers of consumers? + - q: Why can't I use the regular Rate Limiting plugin to rate limit tiers of Consumers? a: We use the Rate Limiting Advanced plugin because it supports sliding windows, which we use to apply the rate limiting logic while taking into account previous hit rates (from the window that immediately precedes the current) using a dynamic weight. cleanup: @@ -58,9 +57,9 @@ cleanup: icon_url: /assets/icons/gateway.svg --- -## 1. Set up consumer authentication +## 1. Set up Consumer authentication -We need to set up [authentication](/authentication/) to identify the consumer and apply rate limiting. In this guide, we'll be using the [Key Auth plugin](https://docs.konghq.com/hub/kong-inc/key-auth/) plugin, but you can use any [Kong authentication plugin](https://docs.konghq.com/hub/?category=authentication). +We need to set up [authentication](/authentication/) to identify the Consumer and apply rate limiting. In this guide, we'll be using the [Key Auth plugin](https://docs.konghq.com/hub/kong-inc/key-auth/) plugin, but you can use any Kong authentication plugin. Add the following content to your `kong.yaml` file in the `deck_files` directory to configure the Key Auth plugin: @@ -73,11 +72,11 @@ entities: - apikey {% endentity_examples %} -## 2. Create consumer groups for each tier +## 2. Create Consumer Groups for each tier -Before you can enable rate limiting for tiers of users, we first have to create consumer groups for each tier and then add consumers to those groups. Consumer groups are solely a way to organize consumers of your APIs. In this guide, we'll create three tiers (Free, Basic, and Premium), so we need to create a unique consumer group for each tier. +Before you can enable rate limiting for tiers of users, we first have to create Consumer Groups for each tier and then add Consumers to those groups. Consumer Groups are solely a way to organize Consumers of your APIs. In this guide, we'll create three tiers (Free, Basic, and Premium), so we need to create a unique Consumer Group for each tier. -Append the following content to your `kong.yaml` file in the `deck_files` directory to create consumer groups for each tier: +Append the following content to your `kong.yaml` file in the `deck_files` directory to create Consumer Groups for each tier: {% entity_examples %} entities: @@ -87,13 +86,13 @@ entities: - name: Premium {% endentity_examples %} -## 3. Create consumers +## 3. Create Consumers -Now that you've added consumer groups for each tier, you can create three consumers, one for each tier. Here, we're manually adding consumers for the sake of ease, but in a production environment, you could use a script that would automatically add consumers to the correct groups as they sign up for a tier of service. +Now that you've added Consumer Groups for each tier, you can create three Consumers, one for each tier. Here, we're manually adding Consumers for the sake of ease, but in a production environment, you could use a script that would automatically add Consumers to the correct groups as they sign up for a tier of service. -We're also adding key auth credentials (`key`) to each consumer so they can authenticate and we can test later that rate limiting was correctly configured for the different tiers. +We're also adding key auth credentials (`key`) to each Consumer so they can authenticate and we can test later that rate limiting was correctly configured for the different tiers. -Append the following content to your `kong.yaml` file in the `deck_files` directory to create consumers and their authentication credentials: +Append the following content to your `kong.yaml` file in the `deck_files` directory to create Consumers and their authentication credentials: {% entity_examples %} entities: @@ -117,7 +116,7 @@ entities: ## 4. Enable rate limiting on each tier -Enable the Rate Limiting Advanced plugins for each tier: +Enable the Rate Limiting Advanced plugin for each tier: {% entity_examples %} entities: diff --git a/app/_how-tos/add-rate-limiting-to-a-service-with-kong-gateway.md b/app/_how-tos/add-rate-limiting-to-a-service-with-kong-gateway.md index 1efe6976..1e7e1920 100644 --- a/app/_how-tos/add-rate-limiting-to-a-service-with-kong-gateway.md +++ b/app/_how-tos/add-rate-limiting-to-a-service-with-kong-gateway.md @@ -16,7 +16,7 @@ works_on: - konnect min_version: - gateway: 3.4 + gateway: '3.4' plugins: - rate-limiting diff --git a/app/_how-tos/get-started-with-gateway.md b/app/_how-tos/get-started-with-gateway.md new file mode 100644 index 00000000..dbd9eeb0 --- /dev/null +++ b/app/_how-tos/get-started-with-gateway.md @@ -0,0 +1,347 @@ +--- +title: Get started with {{site.base_gateway}} +content_type: how_to + +products: + - gateway + +works_on: + - on-prem + - konnect + +plugins: + - rate-limiting + - key-auth + - proxy-cache + +entities: + - service + - plugin + - consumer + - target + - upstream + +tags: + - get-started + +tldr: + q: What is {{site.base_gateway}}, and how can I get started with it? + a: | + [{{site.base_gateway}}](/gateway/) is a lightweight, fast, and flexible cloud-native API gateway. + {{site.base_gateway}} sits in front of your service applications, dynamically controlling, analyzing, and + routing requests and responses. {{site.base_gateway}} implements your API traffic policies + by using a flexible, low-code, plugin-based approach. +

+ This tutorial will help you get started with {{site.base_gateway}} by setting up a local installation + and walking through some common API management tasks. + + {:.info} + > **Note:** + > This quickstart runs a Docker container to explore {{ site.base_gateway }}'s capabilities. + If you want to run {{ site.base_gateway }} as a part of a production-ready API platform, start with the [Install](/gateway/install/) page. + +tools: + - deck + +prereqs: + inline: + - title: cURL + content: | + [cURL](https://curl.se/) is used to send requests to {{site.base_gateway}}. + `curl` is pre-installed on most systems. + icon_url: /assets/icons/code.svg + +cleanup: + inline: + - title: Clean up Konnect environment + include_content: cleanup/platform/konnect + icon_url: /assets/icons/gateway.svg + - title: Destroy the {{site.base_gateway}} container + include_content: cleanup/products/gateway + icon_url: /assets/icons/gateway.svg +--- + +## 1. Check that {{site.base_gateway}} is running + +{% include how-tos/steps/ping-gateway.md %} + +## 2. Create a Service + +{{site.base_gateway}} administrators work with an object model to define their +desired traffic management policies. Two important objects in that model are +[Services](/gateway/entities/service/) and +[Routes](/gateway/entities/route/). Together, +Services and Routes define the path that requests and responses will take +through the system. + +Add the following content to `kong.yaml` to create a +Service mapped to the upstream URL `https://httpbin.konghq.com`: + +{% entity_examples %} +entities: + services: + - name: example_service + url: "https://httpbin.konghq.com" +{% endentity_examples %} + +In this example, you are configuring the following attributes: + +* `name`: The name of the Service +* `url` : An attribute that populates the `host`, `port`, and `path` of the Service + +## 3. Create a Route + +Routes define how requests are proxied by {{site.base_gateway}}. You can +create a Route associated with a specific Service by sending a `POST` +request to the URL defined in the Service. + +Configure a new Route on the `/mock` path to direct traffic to the `example_service` Service: + +{% entity_examples %} +entities: + routes: + - name: example_route + service: + id: example_service + paths: + - /mock +{% endentity_examples %} + +### Apply configuration + +{% include how-tos/steps/apply_config.md %} + +### Validate the Service and Route by proxying a request + +Using the Service and Route, you can now +access `https://httpbin.konghq.com/` using `http://localhost:8000/mock`. + +Httpbin provides an `/anything` resource which will return information about requests made to it. +Proxy a request through {{site.base_gateway}} to the `/anything` resource: + +```sh +curl -X GET http://localhost:8000/mock/anything +``` + +## 4. Enable rate limiting + +[Rate limiting](/rate-limiting/) is used to control the rate of requests sent to an upstream Service. +It can be used to prevent DoS attacks, limit web scraping, and other forms of overuse. +Without rate limiting, clients have unlimited access to your upstream Services, which +may negatively impact availability. + +In this example, we'll use the [Rate Limiting plugin](/plugins/rate-limiting/). +Installing the plugin globally means that *every* proxy request to {{site.base_gateway}} +will be subject to rate limit enforcement: + +{% entity_examples %} +entities: + plugins: + - name: rate-limiting + config: + minute: 5 + policy: local +{% endentity_examples %} + +In this example, you configured a limit of 5 requests per minute for all Routes, Services, and Consumers. + +We'll validate that this worked in the next step, but first let's set up caching. + +## 4. Enable caching + +One of the ways Kong delivers performance is through caching. +The [Proxy Cache plugin](/plugins/proxy-cache/) accelerates performance by caching +responses based on configurable response codes, content types, and request methods. +When caching is enabled, upstream services are not bogged down with repetitive requests, +because {{site.base_gateway}} responds on their behalf with cached results. + +Let's enable the Proxy Cache plugin globally: + +{% entity_examples %} +entities: + plugins: + - name: proxy-cache + config: + request_method: + - GET + response_code: + - 200 + content_type: + - application/json + cache_ttl: 30 + strategy: memory +append_to_existing_section: true +{% endentity_examples %} + +This configures a Proxy Cache plugin with the following attributes: +* {{site.base_gateway}} will cache all `GET` requests that result in response codes of `200` +* It will also cache responses with the `Content-Type` headers that *equal* `application/json` +* `cache_ttl` instructs the plugin to flush values after 30 seconds +* `config.strategy=memory` specifies the backing data store for cached responses. More +information on `strategy` can be found in the [parameter reference](/plugins/proxy-cache/reference/) +for the Proxy Cache plugin. + +### Validate caching and rate limiting + +You can check that the Rate Limiting and Proxy Cache plugins are working by sending `GET` requests and examining +the returned headers. + +[Sync your decK file](#apply-configuration) again, then run the following command to send 6 mock requests. +The Proxy Cache plugin returns status information headers prefixed with `X-Cache`, so you can use `grep` to filter for that information: + +```sh +for _ in {1..6}; do curl -s -i localhost:8000/mock/anything; echo; sleep 1; done | grep -E 'X-Cache|HTTP/1.1' +``` + +On the initial request, there should be no cached responses, and the headers will indicate this with +`X-Cache-Status: Miss`: + +``` +HTTP/1.1 200 OK +X-Cache-Key: c9e1d4c8e5fd8209a5969eb3b0e85bc6 +X-Cache-Status: Miss +``` +{:.no-copy-code} + +Subsequent responses will be cached and show `X-Cache-Status: Hit`: + +``` +HTTP/1.1 200 OK +X-Cache-Key: c9e1d4c8e5fd8209a5969eb3b0e85bc6 +X-Cache-Status: Hit +``` +{:.no-copy-code} + +After the 6th request, you should receive a 429 error, which means your requests were rate limited according to the policy: +``` +HTTP/1.1 429 Too Many Requests +``` +{:.no-copy-code} + +## 5. Enable authentication + +Authentication is the process of verifying that the requester has permissions to access a resource. +As its name implies, API gateway authentication authenticates the flow of data to and from your upstream services. + +### Enable Key Auth plugin + +For this example, we'll use the [Key Authentication plugin](/plugins/key-auth/). In key authentication, +{{site.base_gateway}} generates and associates an API key with a [Consumer](/gateway/entities/consumer/). +That key is the authentication secret presented by the client when making subsequent requests. +{{site.base_gateway}} approves or denies requests based on the validity of the presented key. + +{% entity_examples %} +entities: + plugins: + - name: key-auth + config: + key_names: + - apikey +append_to_existing_section: true +{% endentity_examples %} + +The `key_names` configuration field defines the name of the field that the +plugin looks for to read the key when authenticating requests. +The plugin looks for the field in headers, query string parameters, and the request body. + +### Create a Consumer + +Consumers let you identify the client that's interacting with {{site.base_gateway}}. You need to create a Consumer for key authentication to work. + +Create a new Consumer with the username `luka` and the key `top-secret-key`: + +{% entity_examples %} +entities: + consumers: + - username: luka + keyauth_credentials: + - key: top-secret-key +{% endentity_examples %} + +{:.warning} +> For the purposes of this tutorial, we have assigned an example key value. +In production, it is recommended that you let the API gateway autogenerate a complex key for you. +Only specify a key for testing or when migrating existing systems. + +### Validate using key authentication + +[Sync your decK file](#apply-configuration), then try to access the Service without providing the key: + +```sh +curl -i http://localhost:8000/mock/anything +``` + +Since you enabled key authentication globally, you will receive an unauthorized response: + +```text +HTTP/1.1 401 Unauthorized +... +{ + "message": "No API key found in request" +} +``` +{:.no-copy-code} + +Now, let's send a request with the valid key in the `apikey` header: + +```sh +curl -i http://localhost:8000/mock/anything \ + -H 'apikey:top-secret-key' +``` + +You will receive a `200 OK` response. + +## 6. Enable load balancing + +Load balancing is a method of distributing API request traffic across +multiple upstream services. Load balancing improves overall system responsiveness +and reduces failures by preventing overloading of individual resources. + +In the following example, you’ll use an application deployed across two different hosts, or upstream targets. +{{site.base_gateway}} needs to load balance across the upstreams, so that if one of them is unavailable, +it automatically detects the problem and routes all traffic to the working upstream. + +You'll need to configure two new types of entities: an [Upstream](/gateway/entities/upstream/) and two [Targets](/gateway/entities/target/). Create an Upstream named `example_upstream` and add two Targets to it: + +{% entity_examples %} +entities: + upstreams: + - name: example_upstream + targets: + - target: httpbun.com:80 + weight: 100 + - target: httpbin.konghq.com:80 + weight: 100 +{% endentity_examples %} + +Update the `example_service` Service to point to this Upstream, instead of pointing directly to a URL. +Remove its `url` field and add the Upstream as a host: + +{% entity_examples %} +entities: + services: + - name: example_service + host: example_upstream +{% endentity_examples %} + +You now have an Upstream with two Targets, `httpbin.konghq.com` and `httpbun.com`, and a service pointing to that Upstream. + +{:.info} +> For the purposes of our example, the Upstream is pointing to two different Targets. +More commonly, Targets will be instances of the same backend service running on different host systems. + +### Validate load balancing + +[Sync your decK file](#apply-configuration) one more time. + +Validate that the Upstream you configured is working by visiting the `/mock` route several times, +waiting a few seconds between each time. +You will see the hostname change between `httpbin` and `httpbun`: + +```sh +curl -s http://localhost:8000/mock/headers -H 'apikey:top-secret-key' | grep -i -A1 '"host"' +``` + +Since the Proxy Cache plugin is configured with a time-to-live of 5 seconds, +the host will take at least 5 seconds to change. + diff --git a/app/_how-tos/set-up-ai-proxy-advanced-with-anthropic.md b/app/_how-tos/set-up-ai-proxy-advanced-with-anthropic.md new file mode 100644 index 00000000..3c1c0724 --- /dev/null +++ b/app/_how-tos/set-up-ai-proxy-advanced-with-anthropic.md @@ -0,0 +1,87 @@ +--- +title: Set up AI Proxy Advanced with Anthropic in {{site.base_gateway}} +content_type: how_to +related_resources: + - text: AI Proxy Advanced + url: /plugins/ai-proxy-advanced/ + +products: + - gateway + +works_on: + - on-prem + - konnect + +min_version: + gateway: '3.8' + +tier: enterprise + +plugins: + - ai-proxy-advanced + +entities: + - service + - plugin + +tags: + - ai-gateway + +tldr: + q: How do I use the AI Proxy Advanced plugin with Anthropic? + a: Create a service and a route, then add the AI Proxy Advanced plugin, configure it with the Anthropic provider, then add the model and your API key. + +tools: + - deck + +prereqs: + inline: + - title: Anthropic + include_content: prereqs/anthropic + icon_url: /assets/icons/anthropic.svg + entities: + services: + - example-service + routes: + - example-route + +cleanup: + inline: + - title: Clean up Konnect environment + include_content: cleanup/platform/konnect + icon_url: /assets/icons/gateway.svg + - title: Destroy the {{site.base_gateway}} container + include_content: cleanup/products/gateway + icon_url: /assets/icons/gateway.svg +--- + +## 1. Configure the plugin + +To set up AI Proxy Advanced with Anthropic, we need to specify the [model](https://docs.anthropic.com/en/docs/about-claude/models#model-names) and [Anthropic API version](https://docs.anthropic.com/en/api/versioning#version-history) to use. + +In this example, we'll use the Claude 2.1 model and version 2023-06-01 of the API: + +{% entity_examples %} +entities: + plugins: + - name: ai-proxy + config: + targets: + - route_type: llm/v1/chat + auth: + header_name: x-api-key + header_value: "" + model: + provider: anthropic + name: claude-2.1 + options: + anthropic_version: "2023-06-01" +{% endentity_examples %} + +## 2. Apply the configuration + +{% include how-tos/steps/apply_config.md %} + +## 3. Validate + +{% include how-tos/steps/ai-proxy-validate.md %} \ No newline at end of file diff --git a/app/_how-tos/set-up-ai-proxy-with-anthropic.md b/app/_how-tos/set-up-ai-proxy-with-anthropic.md new file mode 100644 index 00000000..8fdab5a6 --- /dev/null +++ b/app/_how-tos/set-up-ai-proxy-with-anthropic.md @@ -0,0 +1,84 @@ +--- +title: Set up AI Proxy with Anthropic in {{site.base_gateway}} +content_type: how_to +related_resources: + - text: AI Proxy + url: /plugins/ai-proxy/ + +products: + - gateway + +works_on: + - on-prem + - konnect + +min_version: + gateway: '3.6' + +plugins: + - ai-proxy + +entities: + - service + - plugin + +tags: + - ai-gateway + +tldr: + q: How do I use the AI Proxy plugin with Anthropic? + a: Create a service and a route, then add the AI Proxy plugin and configure it with the Anthropic provider and add the model and your API key. + +tools: + - deck + +prereqs: + inline: + - title: Anthropic + include_content: prereqs/anthropic + icon_url: /assets/icons/anthropic.svg + entities: + services: + - example-service + routes: + - example-route + +cleanup: + inline: + - title: Clean up Konnect environment + include_content: cleanup/platform/konnect + icon_url: /assets/icons/gateway.svg + - title: Destroy the {{site.base_gateway}} container + include_content: cleanup/products/gateway + icon_url: /assets/icons/gateway.svg +--- + +## 1. Configure the plugin + +To set up AI Proxy with Anthropic, we need to specify the [model](https://docs.anthropic.com/en/docs/about-claude/models#model-names) and [Anthropic API version](https://docs.anthropic.com/en/api/versioning#version-history) to use. + +In this example, we'll use the Claude 2.1 model and version 2023-06-01 of the API: + +{% entity_examples %} +entities: + plugins: + - name: ai-proxy + config: + route_type: llm/v1/chat + auth: + header_name: x-api-key + header_value: "" + model: + provider: anthropic + name: claude-2.1 + options: + anthropic_version: "2023-06-01" +{% endentity_examples %} + +## 2. Apply the configuration + +{% include how-tos/steps/apply_config.md %} + +## 3. Validate + +{% include how-tos/steps/ai-proxy-validate.md %} \ No newline at end of file diff --git a/app/_includes/card.html b/app/_includes/card.html index 6fd56c39..1b93c521 100644 --- a/app/_includes/card.html +++ b/app/_includes/card.html @@ -3,10 +3,10 @@ {% endif %} -

{{ include.title | liquify }}

+

{{ include.title | liquify }}

-{{ include.description | liquify | markdownify }} + {{ include.description | liquify | markdownify }}
{% if include.cta_text %} @@ -16,14 +16,14 @@

{{ include.title | liquify }}

{% endif %} {% endcapture %} -
+
{% if include.cta_url %} - + {{ card_content }} {% else %} -
+
{{ card_content }}
{% endif %} diff --git a/app/_includes/cards/plugin.html b/app/_includes/cards/plugin.html new file mode 100644 index 00000000..f1217fb9 --- /dev/null +++ b/app/_includes/cards/plugin.html @@ -0,0 +1,29 @@ +{% assign plugin = include.plugin %} + + diff --git a/app/_includes/checkbox.html b/app/_includes/checkbox.html new file mode 100644 index 00000000..507a07e3 --- /dev/null +++ b/app/_includes/checkbox.html @@ -0,0 +1,3 @@ +
+ +
\ No newline at end of file diff --git a/app/_includes/components/entity_example/format/admin-api.md b/app/_includes/components/entity_example/format/admin-api.md index 8b6d0f06..02cbd47c 100644 --- a/app/_includes/components/entity_example/format/admin-api.md +++ b/app/_includes/components/entity_example/format/admin-api.md @@ -1,21 +1,21 @@ {% if include.render_context %} {% case include.presenter.entity_type %} {% when 'consumer' %} - To create a consumer, call the [Admin API’s /consumers endpoint](/api/gateway/admin-ee/#/operations/create-consumer). + To create a Consumer, call the [Admin API’s /consumers endpoint](/api/gateway/admin-ee/#/operations/create-consumer). {% when 'consumer_group' %} - To create a consumer group, call the [Admin API’s /consumer_groups endpoint](/api/gateway/admin-ee/#/operations/post-consumer_groups). + To create a Consumer Group, call the [Admin API’s /consumer_groups endpoint](/api/gateway/admin-ee/#/operations/post-consumer_groups). {% when 'route' %} - To create a route, call the [Admin API’s /routes endpoint](/api/gateway/admin-ee/#/operations/create-route). + To create a Route, call the [Admin API’s /routes endpoint](/api/gateway/admin-ee/#/operations/create-route). {% when 'service' %} - To create a service, call the [Admin API’s /services endpoint](/api/gateway/admin-ee/#/operations/create-service). + To create a Gateway Service, call the [Admin API’s /services endpoint](/api/gateway/admin-ee/#/operations/create-service). {% when 'target' %} - To create a target, call the [Admin API’s /targets endpoint](/api/gateway/admin-ee/#/operations/create-target-with-upstream). + To create a Target, call the [Admin API’s /targets endpoint](/api/gateway/admin-ee/#/operations/create-target-with-upstream). {% when 'upstream' %} - To create a upstream, call the [Admin API’s /upstreams endpoint](/api/gateway/admin-ee/#/operations/create-upstream). -{% when 'workspace' %} - To create a workspace, call the [Admin API’s /workspaces endpoint](/api/gateway/admin-ee/#/operations/create-workspace). + To create a Upstream, call the [Admin API’s /upstreams endpoint](/api/gateway/admin-ee/#/operations/create-upstream). {% when 'event_hook' %} To create an Event Hook, call the [Admin API’s /event-hooks endpoint](/api/gateway/admin-ee/#/operations/post-event-hooks). +{% when 'workspace' %} + To create a Workspace, call the [Admin API’s /workspaces endpoint](/api/gateway/admin-ee/#/operations/create-workspace). {% when 'plugin' %} Make the following request: {% else %} diff --git a/app/_includes/components/entity_example/format/deck.md b/app/_includes/components/entity_example/format/deck.md index f96fac11..256631b9 100644 --- a/app/_includes/components/entity_example/format/deck.md +++ b/app/_includes/components/entity_example/format/deck.md @@ -1,19 +1,19 @@ {% if include.render_context %} {% case include.presenter.entity_type %} {% when 'consumer' %} - The following creates a new consumer called **{{ include.presenter.data['username'] }}**: + The following creates a new Consumer called **{{ include.presenter.data['username'] }}**: {% when 'consumer_group' %} The following creates a new Consumer Group called **{{ include.presenter.data['name'] }}**: {% when 'route' %} - The following creates a new route called **{{ include.presenter.data['name'] }}** with basic configuration: + The following creates a new Route called **{{ include.presenter.data['name'] }}** with basic configuration: {% when 'service' %} - The following creates a new service called **{{ include.presenter.data['name'] }}** with basic configuration: + The following creates a new Gateway Service called **{{ include.presenter.data['name'] }}** with basic configuration: {% when 'target' %} To create a target, call the [Admin API’s /targets endpoint](/api/gateway/admin-ee/#/operations/create-target-with-upstream). {% when 'upstream' %} - The following creates a new upstream called **{{ include.presenter.data['name'] }}**: + The following creates a new Upstream called **{{ include.presenter.data['name'] }}**: {% when workspace %} - The following creates a new workspace called **{{ include.presenter.data['name'] }}**: + The following creates a new Workspace called **{{ include.presenter.data['name'] }}**: {% when 'plugin' %} Add this section to your declarative configuration file: {% else %} diff --git a/app/_includes/components/entity_example/format/konnect-api.md b/app/_includes/components/entity_example/format/konnect-api.md index 2bd8b659..d8021aff 100644 --- a/app/_includes/components/entity_example/format/konnect-api.md +++ b/app/_includes/components/entity_example/format/konnect-api.md @@ -1,18 +1,18 @@ {% case include.presenter.entity_type %} {% when 'consumer' %} - To create a consumer, call the Konnect [control plane config API’s /consumers endpoint](/api/konnect/control-planes-config/#/operations/create-consumer). + To create a Consumer, call the Konnect [control plane config API’s /consumers endpoint](/api/konnect/control-planes-config/#/operations/create-consumer). {% when 'consumer_group' %} - To create a consumer group, call the Konnect [control plane config API’s /consumer_groups endpoint](/api/konnect/control-planes-config/#/operations/create-consumer_group). + To create a Consumer Group, call the Konnect [control plane config API’s /consumer_groups endpoint](/api/konnect/control-planes-config/#/operations/create-consumer_group). {% when 'route' %} - To create a route, call the Konnect [control plane config API's /routes endpoint](/api/konnect/control-planes-config/#/operations/create-route). + To create a Route, call the Konnect [control plane config API's /routes endpoint](/api/konnect/control-planes-config/#/operations/create-route). {% when 'service' %} - To create a service, call the Konnect [control plane config API’s /services endpoint](/api/konnect/control-planes-config/#/operations/create-service). + To create a Gateway Service, call the Konnect [control plane config API’s /services endpoint](/api/konnect/control-planes-config/#/operations/create-service). {% when 'target' %} - To create a target, call the Konnect [control plane config API’s /targets endpoint](/api/konnect/control-planes-config/#/operations/create-target-with-upstream). + To create a Target, call the Konnect [control plane config API’s /targets endpoint](/api/konnect/control-planes-config/#/operations/create-target-with-upstream). {% when 'upstream' %} - The following creates a new upstream called **{{ include.presenter.data['name'] }}**: + The following creates a new Upstream called **{{ include.presenter.data['name'] }}**: {% when workspace %} - To create a workspace, call the [Admin API’s /workspaces endpoint](/api/gateway/admin-ee/#/operations/create-workspace). + To create a Workspace, call the [Admin API’s /workspaces endpoint](/api/gateway/admin-ee/#/operations/create-workspace). {% when 'plugin' %} Make the following request: {% else %} diff --git a/app/_includes/components/plugin.html b/app/_includes/components/plugin.html index 01c3cf34..1165ac7f 100644 --- a/app/_includes/components/plugin.html +++ b/app/_includes/components/plugin.html @@ -1,8 +1,5 @@ -{% capture icon %} -https://docs.konghq.com/assets/images/icons/hub/{{ plugin.publisher }}_{{ plugin.slug }}.png -{% endcapture %} {% capture cta %} See plugin → {% endcapture %} -{% include card.html icon=icon title=plugin.name description=plugin.description cta_url=plugin.url cta_text='See plugin →' %} \ No newline at end of file +{% include card.html icon=plugin.icon title=plugin.name description=plugin.description cta_url=plugin.url cta_text='See plugin →' %} diff --git a/app/_includes/components/plugin_config_example.html b/app/_includes/components/plugin_config_example.html index 418b1ba8..527b530d 100644 --- a/app/_includes/components/plugin_config_example.html +++ b/app/_includes/components/plugin_config_example.html @@ -30,7 +30,7 @@ {% assign target = entity_example.target.key %} {% assign formatted_examples = entity_example.formatted_examples %} -