feat(ai): mcp-k8s через ToolHive — read-only доступ агента к кластеру #14
@@ -1,21 +1,31 @@
|
|||||||
---
|
---
|
||||||
# Kubernetes MCP из реестра ToolHive (сервер k8s, проект StacklokLabs/mkp).
|
# Kubernetes MCP Server: containers/kubernetes-mcp-server (Apache-2.0, Go, без обёрток над kubectl).
|
||||||
# Транспорт streamable-http — mkp отдаёт MCP по HTTP сам, прокси-обёртка над
|
# Транспорт streamable-http — сервер сам отдаёт MCP по HTTP на --port 8080, путь /mcp,
|
||||||
# stdio не нужна. Порты оставлены дефолтными: proxyPort и mcpPort оба 8080.
|
# ровно то, что ожидает прокси ToolHive (обёртка над stdio не нужна).
|
||||||
#
|
#
|
||||||
# ВАЖНО: без oidcConfigRef прокси ToolHive работает без аутентификации — любой,
|
# --read-only — штатный режим сервера: ни одной write-операции (create/update/delete).
|
||||||
# кто достучится до его порта, получит доступ к API под правами SA ниже.
|
# Это второй барьер после RBAC SA (см. rbac.yaml); третий — denied_resources в TOML,
|
||||||
# Поэтому наружу сервер не выводим: пока агент вне кластера, адрес только
|
# если понадобится спрятать ресурс от инструментов совсем.
|
||||||
# внутрикластерный, а внешний доступ появится вместе с OIDC после Authelia.
|
#
|
||||||
|
# --toolsets core оставляет базовый набор: без helm (чарты ставит Flux, агенту там
|
||||||
|
# делать нечего), tekton, kubevirt, kiali и netobserv.
|
||||||
|
#
|
||||||
|
# ВАЖНО: без oidcConfigRef прокси ToolHive работает без аутентификации — любой, кто
|
||||||
|
# достучится до порта, получит доступ к API под правами SA ниже. Поэтому наружу сервер
|
||||||
|
# не выводим: внешний доступ появится вместе с OIDC после Authelia.
|
||||||
apiVersion: toolhive.stacklok.dev/v1beta1
|
apiVersion: toolhive.stacklok.dev/v1beta1
|
||||||
kind: MCPServer
|
kind: MCPServer
|
||||||
metadata:
|
metadata:
|
||||||
name: mcp-k8s
|
name: mcp-k8s
|
||||||
spec:
|
spec:
|
||||||
image: ghcr.io/stackloklabs/mkp/server:0.4.3
|
image: quay.io/containers/kubernetes_mcp_server:v0.0.66@sha256:6d650f4bd6ac303ad82713c997e73a2d001602f9bf17392c9b9a0e30e29c6423
|
||||||
transport: streamable-http
|
transport: streamable-http
|
||||||
# SA существует заранее (см. serviceaccount.yaml) — вместе с ним приезжает
|
args:
|
||||||
# ClusterRoleBinding mcp-k8s-readonly.
|
- --port
|
||||||
|
- "8080"
|
||||||
|
- --read-only
|
||||||
|
- --toolsets
|
||||||
|
- core
|
||||||
serviceAccount: mcp-k8s
|
serviceAccount: mcp-k8s
|
||||||
permissionProfile:
|
permissionProfile:
|
||||||
type: builtin
|
type: builtin
|
||||||
|
|||||||
@@ -1,83 +1,46 @@
|
|||||||
---
|
---
|
||||||
# Права MCP-сервера на API. Только чтение: mkp умеет и apply_resource, и
|
# Базовое чтение даём встроенной ролью view — её же рекомендует официальный гайд
|
||||||
# delete_resource, и exec в поды — ограничение живёт исключительно здесь,
|
# containers/kubernetes-mcp-server (docs/getting-started-kubernetes.md). view
|
||||||
# поэтому список verbs закрыт чтением.
|
# описывает namespaced-ресурсы и secrets в неё не входят, поэтому именно она, а не
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
# самодельный список с resources: ["*"].
|
||||||
kind: ClusterRole
|
|
||||||
metadata:
|
|
||||||
name: mcp-k8s-readonly
|
|
||||||
rules:
|
|
||||||
# Core-группа перечислена поимённо: resources: ["*"] открыл бы и secrets,
|
|
||||||
# а cluster-secrets, токен Proxmox CSI и прочие креды агенту читать незачем.
|
|
||||||
- apiGroups: [""]
|
|
||||||
resources:
|
|
||||||
- configmaps
|
|
||||||
- endpoints
|
|
||||||
- events
|
|
||||||
- limitranges
|
|
||||||
- namespaces
|
|
||||||
- nodes
|
|
||||||
- persistentvolumeclaims
|
|
||||||
- persistentvolumes
|
|
||||||
- pods
|
|
||||||
- pods/log
|
|
||||||
- pods/status
|
|
||||||
- replicationcontrollers
|
|
||||||
- resourcequotas
|
|
||||||
- serviceaccounts
|
|
||||||
- services
|
|
||||||
verbs: ["get", "list", "watch"]
|
|
||||||
# Остальные группы перечислены явно, потому что apiGroups: ["*"] включает и
|
|
||||||
# core-группу — то есть снова открыл бы secrets. Список закрытый: не хватает
|
|
||||||
# группы — сервер просто не увидит её ресурсы, ничего не сломается.
|
|
||||||
- apiGroups:
|
|
||||||
- admissionregistration.k8s.io
|
|
||||||
- apiextensions.k8s.io
|
|
||||||
- apiregistration.k8s.io
|
|
||||||
- apps
|
|
||||||
- authentication.k8s.io
|
|
||||||
- authorization.k8s.io
|
|
||||||
- autoscaling
|
|
||||||
- batch
|
|
||||||
- certificates.k8s.io
|
|
||||||
- coordination.k8s.io
|
|
||||||
- discovery.k8s.io
|
|
||||||
- events.k8s.io
|
|
||||||
- flowcontrol.apiserver.k8s.io
|
|
||||||
- metrics.k8s.io
|
|
||||||
- networking.k8s.io
|
|
||||||
- node.k8s.io
|
|
||||||
- policy
|
|
||||||
- rbac.authorization.k8s.io
|
|
||||||
- scheduling.k8s.io
|
|
||||||
- storage.k8s.io
|
|
||||||
- acme.cert-manager.io
|
|
||||||
- cert-manager.io
|
|
||||||
- cilium.io
|
|
||||||
- dragonflydb.io
|
|
||||||
- external-secrets.io
|
|
||||||
- gateway.envoyproxy.io
|
|
||||||
- gateway.networking.k8s.io
|
|
||||||
- generators.external-secrets.io
|
|
||||||
- helm.toolkit.fluxcd.io
|
|
||||||
- image.toolkit.fluxcd.io
|
|
||||||
- kustomize.toolkit.fluxcd.io
|
|
||||||
- monitoring.coreos.com
|
|
||||||
- notification.toolkit.fluxcd.io
|
|
||||||
- snapshot.storage.k8s.io
|
|
||||||
- source.toolkit.fluxcd.io
|
|
||||||
- toolhive.stacklok.dev
|
|
||||||
resources: ["*"]
|
|
||||||
verbs: ["get", "list", "watch"]
|
|
||||||
---
|
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
metadata:
|
metadata:
|
||||||
name: mcp-k8s-readonly
|
name: mcp-k8s-view
|
||||||
roleRef:
|
roleRef:
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
kind: ClusterRole
|
kind: ClusterRole
|
||||||
name: mcp-k8s-readonly
|
name: view
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: mcp-k8s
|
||||||
|
namespace: ai
|
||||||
|
---
|
||||||
|
# view включает только namespaced-ресурсы, поэтому кластерные объекты и метрики
|
||||||
|
# добавляем отдельно. Ни secrets, ни записи здесь нет.
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
name: mcp-k8s-cluster-read
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["nodes", "namespaces", "persistentvolumes"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["storage.k8s.io"]
|
||||||
|
resources: ["storageclasses", "volumeattachments", "csidrivers", "csistoragecapacities"]
|
||||||
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: ["metrics.k8s.io"]
|
||||||
|
resources: ["*"]
|
||||||
|
verbs: ["get", "list"]
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: mcp-k8s-cluster-read
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: mcp-k8s-cluster-read
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: mcp-k8s
|
name: mcp-k8s
|
||||||
|
|||||||
Reference in New Issue
Block a user