feat(ai): mcp-k8s через ToolHive — read-only доступ агента к кластеру #14
@@ -8,4 +8,5 @@ components:
|
|||||||
|
|
||||||
resources:
|
resources:
|
||||||
- ./namespace.yaml
|
- ./namespace.yaml
|
||||||
|
- ./mcp-k8s/ks.yaml
|
||||||
- ./toolhive/ks.yaml
|
- ./toolhive/ks.yaml
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
resources:
|
||||||
|
- ./serviceaccount.yaml
|
||||||
|
- ./rbac.yaml
|
||||||
|
- ./mcpserver.yaml
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
# Kubernetes MCP из реестра ToolHive (сервер k8s, проект StacklokLabs/mkp).
|
||||||
|
# Транспорт streamable-http — mkp отдаёт MCP по HTTP сам, прокси-обёртка над
|
||||||
|
# stdio не нужна. Порты оставлены дефолтными: proxyPort и mcpPort оба 8080.
|
||||||
|
#
|
||||||
|
# ВАЖНО: без oidcConfigRef прокси ToolHive работает без аутентификации — любой,
|
||||||
|
# кто достучится до его порта, получит доступ к API под правами SA ниже.
|
||||||
|
# Поэтому наружу сервер не выводим: пока агент вне кластера, адрес только
|
||||||
|
# внутрикластерный, а внешний доступ появится вместе с OIDC после Authelia.
|
||||||
|
apiVersion: toolhive.stacklok.dev/v1beta1
|
||||||
|
kind: MCPServer
|
||||||
|
metadata:
|
||||||
|
name: mcp-k8s
|
||||||
|
spec:
|
||||||
|
image: ghcr.io/stackloklabs/mkp/server:0.4.3
|
||||||
|
transport: streamable-http
|
||||||
|
# SA существует заранее (см. serviceaccount.yaml) — вместе с ним приезжает
|
||||||
|
# ClusterRoleBinding mcp-k8s-readonly.
|
||||||
|
serviceAccount: mcp-k8s
|
||||||
|
permissionProfile:
|
||||||
|
type: builtin
|
||||||
|
name: network
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
---
|
||||||
|
# Права MCP-сервера на API. Только чтение: mkp умеет и apply_resource, и
|
||||||
|
# delete_resource, и exec в поды — ограничение живёт исключительно здесь,
|
||||||
|
# поэтому список verbs закрыт чтением.
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
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
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: mcp-k8s-readonly
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: mcp-k8s-readonly
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: mcp-k8s
|
||||||
|
namespace: ai
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
# SA создаётся здесь намеренно: spec.serviceAccount в MCPServer означает «уже
|
||||||
|
# существующий» — если его не создать, оператор сделает свой и права выдавать
|
||||||
|
# будет некуда.
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: mcp-k8s
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||||
|
kind: Kustomization
|
||||||
|
metadata:
|
||||||
|
name: mcp-k8s
|
||||||
|
spec:
|
||||||
|
interval: 1h
|
||||||
|
path: ./kubernetes/apps/ai/mcp-k8s/app
|
||||||
|
prune: true
|
||||||
|
sourceRef:
|
||||||
|
kind: GitRepository
|
||||||
|
name: flux-system
|
||||||
|
namespace: flux-system
|
||||||
|
targetNamespace: ai
|
||||||
|
wait: true
|
||||||
|
# Зависимость внутри своего ns, поэтому поле namespace не нужно (по CRD оно
|
||||||
|
# по умолчанию равно ns самого объекта-зависимости).
|
||||||
|
dependsOn:
|
||||||
|
- name: toolhive-operator
|
||||||
Reference in New Issue
Block a user