From bf4c02489eaa6973de2023366910aaba58566cd5 Mon Sep 17 00:00:00 2001 From: Mladen Todorovic Date: Fri, 9 Jan 2026 15:27:33 +0100 Subject: [PATCH] Add helm chart --- charts/stackrox-mcp/.helmignore | 7 + charts/stackrox-mcp/Chart.yaml | 16 + charts/stackrox-mcp/README.md | 431 ++++++++++++++++++ charts/stackrox-mcp/templates/NOTES.txt | 45 ++ charts/stackrox-mcp/templates/_helpers.tpl | 59 +++ charts/stackrox-mcp/templates/configmap.yaml | 39 ++ charts/stackrox-mcp/templates/deployment.yaml | 92 ++++ charts/stackrox-mcp/templates/secret.yaml | 17 + charts/stackrox-mcp/templates/service.yaml | 20 + charts/stackrox-mcp/values.yaml | 175 +++++++ 10 files changed, 901 insertions(+) create mode 100644 charts/stackrox-mcp/.helmignore create mode 100644 charts/stackrox-mcp/Chart.yaml create mode 100644 charts/stackrox-mcp/README.md create mode 100644 charts/stackrox-mcp/templates/NOTES.txt create mode 100644 charts/stackrox-mcp/templates/_helpers.tpl create mode 100644 charts/stackrox-mcp/templates/configmap.yaml create mode 100644 charts/stackrox-mcp/templates/deployment.yaml create mode 100644 charts/stackrox-mcp/templates/secret.yaml create mode 100644 charts/stackrox-mcp/templates/service.yaml create mode 100644 charts/stackrox-mcp/values.yaml diff --git a/charts/stackrox-mcp/.helmignore b/charts/stackrox-mcp/.helmignore new file mode 100644 index 0000000..2d5e960 --- /dev/null +++ b/charts/stackrox-mcp/.helmignore @@ -0,0 +1,7 @@ +# Patterns to ignore when packaging +.git/ +.gitignore +*.swp +*.bak +*.tmp +.DS_Store diff --git a/charts/stackrox-mcp/Chart.yaml b/charts/stackrox-mcp/Chart.yaml new file mode 100644 index 0000000..2f8d515 --- /dev/null +++ b/charts/stackrox-mcp/Chart.yaml @@ -0,0 +1,16 @@ +apiVersion: v2 +name: stackrox-mcp +description: A Helm chart for StackRox Model Context Protocol (MCP) Server +type: application +version: 0.1.0 +appVersion: "dev" +home: https://github.com/stackrox/stackrox-mcp +sources: + - https://github.com/stackrox/stackrox-mcp +keywords: + - stackrox + - mcp + - security + - vulnerability +maintainers: + - name: StackRox Team diff --git a/charts/stackrox-mcp/README.md b/charts/stackrox-mcp/README.md new file mode 100644 index 0000000..b394828 --- /dev/null +++ b/charts/stackrox-mcp/README.md @@ -0,0 +1,431 @@ +# StackRox MCP Helm Chart + +A Helm chart for deploying the StackRox Model Context Protocol (MCP) Server to Kubernetes and OpenShift clusters. + +## Prerequisites + +- Kubernetes 1.19+ or OpenShift 4.x+ +- Helm 3.0+ +- Access to a StackRox Central instance +- Valid StackRox API token (for static authentication mode) + +## Installing the Chart + +To install the chart with the release name `stackrox-mcp`: + +```bash +helm install stackrox-mcp charts/stackrox-mcp \ + --namespace stackrox-mcp \ + --create-namespace \ + --set config.tools.vulnerability.enabled=true \ + --set config.central.url= +``` + +## Upgrading the Chart + +To upgrade an existing release: + +```bash +helm upgrade stackrox-mcp charts/stackrox-mcp \ + --namespace stackrox-mcp \ + --reuse-values +``` + +## Uninstalling the Chart + +To uninstall/delete the `stackrox-mcp` release: + +```bash +helm uninstall stackrox-mcp --namespace stackrox-mcp +``` + +## Configuration + +The following table lists the configurable parameters of the StackRox MCP chart and their default values. + +### Image Configuration + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `image.registry` | Container image registry | `quay.io` | +| `image.repository` | Container image repository | `stackrox-io/mcp` | +| `image.tag` | Container image tag (overrides appVersion) | `""` | +| `image.pullPolicy` | Image pull policy | `IfNotPresent` | +| `imagePullSecrets` | Image pull secrets for private registries | `[]` | + +### Deployment Configuration + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `replicaCount` | Number of replicas | `1` | +| `annotations` | Annotations for Deployment and Pod metadata | `{}` | + +### Security Contexts + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `podSecurityContext.runAsNonRoot` | Run as non-root user | `true` | +| `podSecurityContext.runAsUser` | User ID to run as | `4000` | +| `podSecurityContext.runAsGroup` | Group ID to run as | `4000` | +| `podSecurityContext.fsGroup` | Filesystem group ID | `4000` | +| `podSecurityContext.seccompProfile.type` | Seccomp profile type | `RuntimeDefault` | +| `securityContext.allowPrivilegeEscalation` | Allow privilege escalation | `false` | +| `securityContext.readOnlyRootFilesystem` | Read-only root filesystem | `true` | +| `securityContext.runAsNonRoot` | Run as non-root user | `true` | +| `securityContext.runAsUser` | User ID to run as | `4000` | +| `securityContext.capabilities.drop` | List of capabilities to drop | `["ALL"]` | + +### Service Configuration + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `service.type` | Service type | `ClusterIP` | +| `service.port` | Service port | `8080` | +| `service.targetPort` | Target port | `8080` | +| `service.annotations` | Service annotations | `{}` | + +### Resource Limits + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `resources.requests.cpu` | CPU request | `200m` | +| `resources.requests.memory` | Memory request | `500Mi` | +| `resources.limits.cpu` | CPU limit | | +| `resources.limits.memory` | Memory limit | `500Mi` | + +### Probes + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `livenessProbe.enabled` | Enable liveness probe | `true` | +| `livenessProbe.httpGet.path` | Path for liveness probe | `/health` | +| `livenessProbe.httpGet.port` | Port for liveness probe | `http` | +| `livenessProbe.initialDelaySeconds` | Initial delay for liveness probe | `10` | +| `livenessProbe.periodSeconds` | Period for liveness probe | `10` | +| `livenessProbe.timeoutSeconds` | Timeout for liveness probe | `5` | +| `livenessProbe.successThreshold` | Success threshold for liveness probe | `1` | +| `livenessProbe.failureThreshold` | Failure threshold for liveness probe | `3` | +| `readinessProbe.enabled` | Enable readiness probe | `true` | +| `readinessProbe.httpGet.path` | Path for readiness probe | `/health` | +| `readinessProbe.httpGet.port` | Port for readiness probe | `http` | +| `readinessProbe.initialDelaySeconds` | Initial delay for readiness probe | `5` | +| `readinessProbe.periodSeconds` | Period for readiness probe | `5` | +| `readinessProbe.timeoutSeconds` | Timeout for readiness probe | `3` | +| `readinessProbe.successThreshold` | Success threshold for readiness probe | `1` | +| `readinessProbe.failureThreshold` | Failure threshold for readiness probe | `3` | + +### OpenShift Configuration + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `openshift.enabled` | Enable OpenShift-specific features | `false` | +| `openshift.route.enabled` | Create OpenShift Route | `false` | +| `openshift.route.host` | Route hostname | `""` | +| `openshift.route.tls.enabled` | Enable TLS for route | `true` | +| `openshift.route.tls.termination` | TLS termination type | `edge` | +| `openshift.route.tls.insecureEdgeTerminationPolicy` | Policy for insecure edge traffic | `Redirect` | + +### Scheduling + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `nodeSelector` | Node labels for pod assignment | `{}` | +| `tolerations` | Tolerations for pod assignment | `[]` | +| `affinity` | Affinity rules for pod assignment | `{}` | +| `priorityClassName` | Priority class name for pod scheduling | `""` | + +### Advanced Configuration + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `extraEnv` | Additional environment variables | `[]` | + +### StackRox MCP Configuration + +#### Central Connection + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `config.central.url` | StackRox Central URL | `central.stackrox:8443` | +| `config.central.authType` | Authentication type (`passthrough` or `static`) | `passthrough` | +| `config.central.apiToken` | API token for static auth (base64 encoded) | `""` | +| `config.central.existingSecret.name` | Name of existing secret with API token | `""` | +| `config.central.existingSecret.key` | Key in existing secret | `api-token` | +| `config.central.insecureSkipTLSVerify` | Skip TLS verification (testing only) | `false` | +| `config.central.forceHTTP1` | Force HTTP/1 bridge | `false` | +| `config.central.requestTimeout` | Request timeout | `30s` | +| `config.central.maxRetries` | Maximum retry attempts | `3` | +| `config.central.initialBackoff` | Initial retry backoff | `1s` | +| `config.central.maxBackoff` | Maximum retry backoff | `10s` | + +#### Global Configuration + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `config.global.readOnlyTools` | Restrict to read-only operations | `true` | + +#### Server Configuration + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `config.server.type` | Server type (`streamable-http` or `stdio`) | `streamable-http` | +| `config.server.address` | Server listen address | `0.0.0.0` | +| `config.server.port` | Server listen port | `8080` | + +#### Tools Configuration + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `config.tools.vulnerability.enabled` | Enable vulnerability management tools | `false` | +| `config.tools.configManager.enabled` | Enable configuration management tools | `false` | + +**Note**: At least one tool must be enabled. + +## Common Configurations + +### Passthrough Authentication (Default) + +This mode passes API tokens from MCP client request headers to StackRox Central: + +```yaml +config: + central: + url: "central.stackrox:8443" + authType: "passthrough" + tools: + vulnerability: + enabled: true +``` + +### Static Authentication with Inline Token + +For static authentication with an inline token (not recommended for production): + +```yaml +config: + central: + url: "central.stackrox:8443" + authType: "static" + apiToken: "" + tools: + vulnerability: + enabled: true +``` + +### Static Authentication with Existing Secret + +For production use, reference an existing Kubernetes secret: + +1. Create the secret: + +```bash +kubectl create secret generic stackrox-api-token \ + --from-literal=api-token= \ + --namespace stackrox-mcp +``` + +2. Reference it in values: + +```yaml +config: + central: + url: "central.stackrox:8443" + authType: "static" + existingSecret: + name: "stackrox-api-token" + key: "api-token" + tools: + vulnerability: + enabled: true +``` + +### OpenShift Deployment + +For OpenShift with external Route: + +```yaml +openshift: + enabled: true + route: + enabled: true + host: "stackrox-mcp.apps.example.com" + tls: + enabled: true + termination: edge + +config: + central: + url: "central.stackrox:8443" + tools: + vulnerability: + enabled: true +``` + +### High Availability Setup + +For high availability with multiple replicas: + +```yaml +replicaCount: 3 + +affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - stackrox-mcp + topologyKey: kubernetes.io/hostname +``` + +## Configuration Loading + +The StackRox MCP Helm chart uses a YAML configuration file approach for cleaner and more maintainable configuration management. + +### How It Works + +1. **ConfigMap with YAML File**: The chart creates a ConfigMap containing a complete `config.yaml` file with all non-sensitive configuration +2. **File Mounting**: The ConfigMap is mounted as a file at `/config/config.yaml` in the pod +3. **Command Args**: The application is started with `--config /config/config.yaml` to load the configuration +4. **Environment Variable Override**: The API token (for static auth) is injected via environment variable `STACKROX_MCP__CENTRAL__API_TOKEN`, which takes precedence over the YAML file + +### Viewing Configuration + +To view the current configuration: + +```bash +# View the YAML config file in ConfigMap +kubectl get configmap -n stackrox-mcp -config -o jsonpath='{.data.config\.yaml}' + +# Verify config file is mounted in pod +kubectl exec -n stackrox-mcp deployment/ -- cat /config/config.yaml +``` + +### Configuration Precedence + +The application loads configuration in this order (highest to lowest precedence): +1. Environment variables (e.g., `STACKROX_MCP__CENTRAL__API_TOKEN`) +2. YAML configuration file (`/config/config.yaml`) +3. Application defaults + +This means you can override any YAML configuration value using environment variables via `extraEnv` in values.yaml. + +## Security Considerations + +### Secret Management + +1. **Never commit secrets to version control**: Use external secret management solutions like: + - Kubernetes External Secrets Operator + - HashiCorp Vault + - Sealed Secrets + +2. **Use RBAC**: Limit access to the secret containing the API token: + +```bash +kubectl create role secret-reader \ + --verb=get,list \ + --resource=secrets \ + --resource-name=stackrox-api-token \ + --namespace stackrox-mcp +``` + +3. **Rotate tokens regularly**: Update the API token periodically and restart the deployment. + +### Network Policies + +Consider implementing NetworkPolicies to restrict traffic: + +```yaml +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: stackrox-mcp + namespace: stackrox-mcp +spec: + podSelector: + matchLabels: + app.kubernetes.io/name: stackrox-mcp + policyTypes: + - Ingress + - Egress + ingress: + - from: + - namespaceSelector: {} + ports: + - protocol: TCP + port: 8080 + egress: + - to: + - namespaceSelector: {} + ports: + - protocol: TCP + port: 8443 # StackRox Central + - to: + - namespaceSelector: + matchLabels: + name: kube-system + ports: + - protocol: UDP + port: 53 # DNS +``` + +### Pod Security Standards + +This chart is compatible with the Kubernetes Pod Security Standards (restricted level). + +## Troubleshooting + +### Deployment fails to start + +Check the pod logs: + +```bash +kubectl logs -n stackrox-mcp deployment/stackrox-mcp +``` + +Common issues: +- **Missing API token**: Ensure token is set when using static authentication +- **Invalid Central URL**: Verify the StackRox Central URL is correct +- **Network connectivity**: Ensure the pod can reach StackRox Central on port 8443 + +### Health check failures + +Test the health endpoint: + +```bash +kubectl run -i --tty --rm debug --image=curlimages/curl --restart=Never -- \ + curl http://stackrox-mcp.stackrox-mcp.svc.cluster.local:8080/health +``` + +Expected response: `{"status":"ok"}` + +### Configuration not updating + +Configuration changes trigger automatic pod restarts via checksum annotations. If changes don't apply: + +```bash +kubectl rollout restart deployment/stackrox-mcp -n stackrox-mcp +``` + +### No tools enabled error + +At least one tool must be enabled. Set either: +- `config.tools.vulnerability.enabled: true` +- `config.tools.configManager.enabled: true` + +## Examples + +See the `examples/` directory for sample values files: +- `examples/passthrough-auth.yaml` - Passthrough authentication +- `examples/static-auth.yaml` - Static authentication +- `examples/openshift.yaml` - OpenShift deployment + +## Support + +For issues and questions: +- GitHub Issues: https://github.com/stackrox/stackrox-mcp/issues +- Documentation: https://github.com/stackrox/stackrox-mcp diff --git a/charts/stackrox-mcp/templates/NOTES.txt b/charts/stackrox-mcp/templates/NOTES.txt new file mode 100644 index 0000000..140c0e1 --- /dev/null +++ b/charts/stackrox-mcp/templates/NOTES.txt @@ -0,0 +1,45 @@ +Thank you for installing {{ .Chart.Name }}. + +Your release is named {{ .Release.Name }}. + +To learn more about the release, try: + + $ helm status {{ .Release.Name }} + $ helm get all {{ .Release.Name }} + +StackRox MCP Server Configuration: +----------------------------------- + +1. The server is configured to connect to: {{ .Values.config.central.url }} + +2. Authentication mode: {{ .Values.config.central.authType }} +{{- if eq .Values.config.central.authType "static" }} + - Using static API token from Secret: {{ include "stackrox-mcp.secretName" . }} +{{- else }} + - Using passthrough authentication (tokens from MCP client headers) +{{- end }} + +3. Enabled tools: + - Vulnerability Management: {{ .Values.config.tools.vulnerability.enabled | ternary "ENABLED" "DISABLED" }} + - Configuration Manager: {{ .Values.config.tools.configManager.enabled | ternary "ENABLED" "DISABLED" }} + +4. The service is available at: + {{ include "stackrox-mcp.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.service.port }} + +To test connectivity: + $ kubectl run -i --tty --rm debug --image=curlimages/curl --restart=Never -- \ + curl http://{{ include "stackrox-mcp.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.service.port }}/health + +{{- if and (eq .Values.config.central.authType "static") (not .Values.config.central.apiToken) (not .Values.config.central.existingSecret.name) }} + +WARNING: Static authentication is enabled but no API token was provided! +Please update the secret with your StackRox API token: + + $ kubectl create secret generic {{ include "stackrox-mcp.fullname" . }}-api-token \ + --from-literal=api-token= \ + --namespace {{ .Release.Namespace }} \ + --dry-run=client -o yaml | kubectl apply -f - + +Then restart the deployment: + $ kubectl rollout restart deployment/{{ include "stackrox-mcp.fullname" . }} -n {{ .Release.Namespace }} +{{- end }} diff --git a/charts/stackrox-mcp/templates/_helpers.tpl b/charts/stackrox-mcp/templates/_helpers.tpl new file mode 100644 index 0000000..9e8e9b7 --- /dev/null +++ b/charts/stackrox-mcp/templates/_helpers.tpl @@ -0,0 +1,59 @@ +{{/* +Create a default fully qualified app name. +*/}} +{{- define "stackrox-mcp.fullname" -}} +{{- printf "%s-%s" "stackrox-mcp" .Release.Name | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "stackrox-mcp.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "stackrox-mcp.labels" -}} +helm.sh/chart: {{ include "stackrox-mcp.chart" . }} +{{ include "stackrox-mcp.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "stackrox-mcp.selectorLabels" -}} +app.kubernetes.io/name: stackrox-mcp . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Image reference +*/}} +{{- define "stackrox-mcp.image" -}} +{{- $tag := .Values.image.tag | default .Chart.AppVersion }} +{{- printf "%s/%s:%s" .Values.image.registry .Values.image.repository $tag }} +{{- end }} + +{{/* +Secret name for API token +*/}} +{{- define "stackrox-mcp.secretName" -}} +{{- if .Values.config.central.existingSecret.name }} +{{- .Values.config.central.existingSecret.name }} +{{- else }} +{{- include "stackrox-mcp.fullname" . }}-api-token +{{- end }} +{{- end }} + +{{/* +ConfigMap name +*/}} +{{- define "stackrox-mcp.configMapName" -}} +{{- include "stackrox-mcp.fullname" . }}-config +{{- end }} diff --git a/charts/stackrox-mcp/templates/configmap.yaml b/charts/stackrox-mcp/templates/configmap.yaml new file mode 100644 index 0000000..b88e72c --- /dev/null +++ b/charts/stackrox-mcp/templates/configmap.yaml @@ -0,0 +1,39 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "stackrox-mcp.configMapName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "stackrox-mcp.labels" . | nindent 4 }} +data: + config.yaml: | + # Central connection configuration + central: + url: {{ .Values.config.central.url | quote }} + auth_type: {{ .Values.config.central.authType | quote }} + {{- if eq .Values.config.central.authType "static" }} + # API token will be injected via environment variable for security + {{- end }} + insecure_skip_tls_verify: {{ .Values.config.central.insecureSkipTLSVerify }} + force_http1: {{ .Values.config.central.forceHTTP1 }} + request_timeout: {{ .Values.config.central.requestTimeout | quote }} + max_retries: {{ .Values.config.central.maxRetries }} + initial_backoff: {{ .Values.config.central.initialBackoff | quote }} + max_backoff: {{ .Values.config.central.maxBackoff | quote }} + + # Global MCP server configuration + global: + read_only_tools: {{ .Values.config.global.readOnlyTools }} + + # HTTP server configuration + server: + type: {{ .Values.config.server.type | quote }} + address: {{ .Values.config.server.address | quote }} + port: {{ .Values.config.server.port }} + + # MCP tools configuration + tools: + vulnerability: + enabled: {{ .Values.config.tools.vulnerability.enabled }} + config_manager: + enabled: {{ .Values.config.tools.configManager.enabled }} diff --git a/charts/stackrox-mcp/templates/deployment.yaml b/charts/stackrox-mcp/templates/deployment.yaml new file mode 100644 index 0000000..ae3d9ca --- /dev/null +++ b/charts/stackrox-mcp/templates/deployment.yaml @@ -0,0 +1,92 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + {{- with .Values.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + name: {{ include "stackrox-mcp.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "stackrox-mcp.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "stackrox-mcp.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + # Force pod restart on config/secret changes + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + {{- with .Values.annotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "stackrox-mcp.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: stackrox-mcp + securityContext: + {{- toYaml .Values.securityContext | nindent 10 }} + image: {{ include "stackrox-mcp.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: + - --config + - /config/config.yaml + ports: + - name: http + containerPort: {{ .Values.config.server.port }} + protocol: TCP + env: + {{- if eq .Values.config.central.authType "static" }} + # API token injected via environment variable (overrides YAML config) + - name: STACKROX_MCP__CENTRAL__API_TOKEN + valueFrom: + secretKeyRef: + name: {{ include "stackrox-mcp.secretName" . }} + key: {{ .Values.config.central.existingSecret.key }} + {{- end }} + {{- with .Values.extraEnv }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + {{- omit .Values.livenessProbe "enabled" | toYaml | nindent 10 }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + {{- omit .Values.readinessProbe "enabled" | toYaml | nindent 10 }} + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 10 }} + volumeMounts: + - name: config + mountPath: /config + readOnly: true + volumes: + - name: config + configMap: + name: {{ include "stackrox-mcp.configMapName" . }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} diff --git a/charts/stackrox-mcp/templates/secret.yaml b/charts/stackrox-mcp/templates/secret.yaml new file mode 100644 index 0000000..585c51c --- /dev/null +++ b/charts/stackrox-mcp/templates/secret.yaml @@ -0,0 +1,17 @@ +{{- if and (eq .Values.config.central.authType "static") (not .Values.config.central.existingSecret.name) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "stackrox-mcp.fullname" . }}-api-token + namespace: {{ .Release.Namespace }} + labels: + {{- include "stackrox-mcp.labels" . | nindent 4 }} +type: Opaque +data: + {{- if .Values.config.central.apiToken }} + api-token: {{ .Values.config.central.apiToken | b64enc | quote }} + {{- else }} + # Empty token - must be set via Helm values or external secret management + api-token: "" + {{- end }} +{{- end }} diff --git a/charts/stackrox-mcp/templates/service.yaml b/charts/stackrox-mcp/templates/service.yaml new file mode 100644 index 0000000..ea92434 --- /dev/null +++ b/charts/stackrox-mcp/templates/service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "stackrox-mcp.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "stackrox-mcp.labels" . | nindent 4 }} + {{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.targetPort }} + protocol: TCP + name: http + selector: + {{- include "stackrox-mcp.selectorLabels" . | nindent 4 }} diff --git a/charts/stackrox-mcp/values.yaml b/charts/stackrox-mcp/values.yaml new file mode 100644 index 0000000..4fcc8be --- /dev/null +++ b/charts/stackrox-mcp/values.yaml @@ -0,0 +1,175 @@ +# Image configuration +image: + registry: quay.io + repository: stackrox-io/mcp + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion + tag: "" + +# Image pull secrets for private registries +imagePullSecrets: [] + +# Number of replicas +replicaCount: 1 + +# Annotations +annotations: {} + +# Pod security context +podSecurityContext: + runAsNonRoot: true + runAsUser: 4000 + runAsGroup: 4000 + fsGroup: 4000 + seccompProfile: + type: RuntimeDefault + +# Container security context +securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 4000 + capabilities: + drop: + - ALL + +# Service configuration +service: + type: ClusterIP + port: 8080 + targetPort: 8080 + annotations: {} + +# Resource limits and requests +resources: + limits: + memory: 500Mi + requests: + cpu: 200m + memory: 500Mi + +# Liveness probe configuration +livenessProbe: + enabled: true + httpGet: + path: /health + port: http + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 3 + +# Readiness probe configuration +readinessProbe: + enabled: true + httpGet: + path: /health + port: http + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 3 + successThreshold: 1 + failureThreshold: 3 + +# Node selector +nodeSelector: {} + +# Tolerations +tolerations: [] + +# Affinity rules +affinity: {} + +# Priority class name +priorityClassName: "" + +# OpenShift specific configuration +openshift: + enabled: false + route: + enabled: false + host: "" + tls: + enabled: true + termination: edge + insecureEdgeTerminationPolicy: Redirect + +# StackRox MCP Configuration +# Maps to environment variables with STACKROX_MCP__ prefix +config: + # Central connection configuration + central: + # URL of StackRox Central instance (required) + url: "central.stackrox:8443" + + # Authentication type: "passthrough" or "static" + # - passthrough: Use API token from MCP client request headers + # - static: Use statically configured API token + authType: "passthrough" + + # API token for static authentication + # Required only when authType is "static", must not be set when "passthrough" + # When using static auth, populate this via values override or Helm secrets + apiToken: "" + + # Alternatively, reference an existing secret for the API token + # If set, this takes precedence over apiToken + existingSecret: + name: "" + key: "api-token" + + # Skip TLS certificate verification (default: false) + # WARNING: Only use for testing in non-production environments + insecureSkipTLSVerify: false + + # Force HTTP/1 bridge via gRPC-Web/WebSockets (default: false) + # Enable only when Central is behind HTTP/1-only proxy/load balancer + forceHTTP1: false + + # Request timeout (default: 30s) + requestTimeout: "30s" + + # Maximum retry attempts (0-10, default: 3) + maxRetries: 3 + + # Initial backoff for retries (default: 1s) + initialBackoff: "1s" + + # Maximum backoff for retries (default: 10s) + maxBackoff: "10s" + + # Global MCP server configuration + global: + # Allow only read-only MCP tools (default: true) + readOnlyTools: true + + # HTTP server configuration + server: + # Server type: "streamable-http" or "stdio" + # Note: Helm deployment typically uses streamable-http + type: "streamable-http" + + # Server listen address (default: 0.0.0.0) + address: "0.0.0.0" + + # Server listen port (1-65535, default: 8080) + port: 8080 + + # MCP tools configuration + # At least one tool must be enabled + tools: + # Vulnerability management tools + vulnerability: + enabled: false + + # Configuration management tools + configManager: + enabled: false + +# Additional environment variables (advanced use) +# These will be added directly to the container +extraEnv: [] +# - name: CUSTOM_VAR +# value: "custom-value"