diff --git a/charts/mcp-stack/CHANGELOG.md b/charts/mcp-stack/CHANGELOG.md index 0a41d66f3..febc902d9 100644 --- a/charts/mcp-stack/CHANGELOG.md +++ b/charts/mcp-stack/CHANGELOG.md @@ -10,6 +10,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) ### Added +#### **🔐 ServiceAccount Support** ([#1718](https://github.com/IBM/mcp-context-forge/pull/1718)) +* Optional ServiceAccount configuration for cloud IAM integration (AWS IRSA, GCP Workload Identity) +* `serviceAccount.create` - Create a dedicated ServiceAccount for all pods (default: `false`) +* `serviceAccount.name` - Custom ServiceAccount name (uses release fullname if empty) +* `serviceAccount.annotations` - IAM role annotations for cloud provider integration +* `serviceAccount.automountServiceAccountToken` - Control token mounting (default: `true`) +* Applied to all Deployments and Jobs in the chart +* Disabled by default to maintain backward compatibility + #### **🔧 Extra Environment Variables Support** ([#2047](https://github.com/IBM/mcp-context-forge/issues/2047)) * `extraEnv` - Inject additional environment variables directly into the gateway container * `extraEnvFrom` - Mount environment variables from existing Secrets or ConfigMaps @@ -17,6 +26,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) * Placed after derived URLs so user values can override `DATABASE_URL`/`REDIS_URL` if needed * Schema validation catches common mistakes (missing `name`, invalid `secretKeyRef` shape) +### Fixed + +* **PgBouncer ServiceAccount** ([#1718](https://github.com/IBM/mcp-context-forge/pull/1718)) - Added missing `serviceAccountName` to pgbouncer deployment for consistency with other components + ### Changed #### **⚡ Metrics Performance Defaults** ([#1799](https://github.com/IBM/mcp-context-forge/issues/1799)) diff --git a/charts/mcp-stack/README.md b/charts/mcp-stack/README.md index 619ea2c99..f46073bf3 100644 --- a/charts/mcp-stack/README.md +++ b/charts/mcp-stack/README.md @@ -1,6 +1,6 @@ # mcp-stack -![Version: 1.0.0-BETA-1](https://img.shields.io/badge/Version-1.0.0--BETA--1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.0.0-BETA-1](https://img.shields.io/badge/AppVersion-1.0.0--BETA--1-informational?style=flat-square) +![Version: 1.0.0-BETA-2](https://img.shields.io/badge/Version-1.0.0--BETA--2-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.0.0-BETA-2](https://img.shields.io/badge/AppVersion-1.0.0--BETA--2-informational?style=flat-square) A full-stack Helm chart for IBM's **Model Context Protocol (MCP) Gateway & Registry - Context-Forge**. It bundles: @@ -314,8 +314,8 @@ Kubernetes: `>=1.21.0-0` | mcpContextForge.env.redis.port | int | `6379` | | | mcpContextForge.envFrom[0].secretRef.name | string | `"mcp-gateway-secret"` | | | mcpContextForge.envFrom[1].configMapRef.name | string | `"mcp-gateway-config"` | | -| mcpContextForge.extraEnv | list | `[]` | Additional environment variables to inject directly | -| mcpContextForge.extraEnvFrom | list | `[]` | Additional environment variables from secrets or configmaps | +| mcpContextForge.extraEnv | list | `[]` | | +| mcpContextForge.extraEnvFrom | list | `[]` | | | mcpContextForge.hpa | object | `{"enabled":true,"maxReplicas":10,"minReplicas":2,"targetCPUUtilizationPercentage":90,"targetMemoryUtilizationPercentage":90}` | ------------------------------------------------------------------ | | mcpContextForge.image.pullPolicy | string | `"Always"` | | | mcpContextForge.image.repository | string | `"ghcr.io/ibm/mcp-context-forge"` | | @@ -608,6 +608,7 @@ Kubernetes: `>=1.21.0-0` | postgres.credentials.password | string | `"test123"` | | | postgres.credentials.user | string | `"admin"` | | | postgres.enabled | bool | `true` | | +| postgres.existingSecret | string | `""` | | | postgres.external.database | string | `""` | | | postgres.external.databaseKey | string | `"dbname"` | | | postgres.external.enabled | bool | `false` | | @@ -620,7 +621,6 @@ Kubernetes: `>=1.21.0-0` | postgres.external.portKey | string | `"port"` | | | postgres.external.user | string | `""` | | | postgres.external.userKey | string | `"user"` | | -| postgres.existingSecret | string | `""` | | | postgres.image.pullPolicy | string | `"IfNotPresent"` | | | postgres.image.repository | string | `"postgres"` | | | postgres.image.tag | string | `"17"` | | @@ -715,4 +715,8 @@ Kubernetes: `>=1.21.0-0` | redisCommander.resources.requests.memory | string | `"128Mi"` | | | redisCommander.service.port | int | `8081` | | | redisCommander.service.type | string | `"ClusterIP"` | | +| serviceAccount.annotations | object | `{}` | Annotations for the ServiceAccount (e.g., AWS IRSA, GCP Workload Identity) | +| serviceAccount.automountServiceAccountToken | bool | `true` | Mount the ServiceAccount token in pods. Only applies when create=true (existing ServiceAccounts control their own token mounting) | +| serviceAccount.create | bool | `false` | Create a ServiceAccount for all pods in this release | +| serviceAccount.name | string | `""` | ServiceAccount name. If empty and create=true, uses release fullname. If create=false, uses this name or "default" | diff --git a/charts/mcp-stack/templates/_helpers.tpl b/charts/mcp-stack/templates/_helpers.tpl index 031a72a7b..e49e7cd02 100644 --- a/charts/mcp-stack/templates/_helpers.tpl +++ b/charts/mcp-stack/templates/_helpers.tpl @@ -23,6 +23,20 @@ helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end }} +{{- /* -------------------------------------------------------------------- + Helper: mcp-stack.serviceAccountName + Returns the ServiceAccount name to use. + If serviceAccount.create is true and name is empty, uses fullname. + If serviceAccount.create is false, uses the provided name or "default". + -------------------------------------------------------------------- */}} +{{- define "mcp-stack.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "mcp-stack.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + {{- /* -------------------------------------------------------------------- Helper: mcp-stack.postgresSecretName Returns the Secret name that the Postgres deployment should mount. diff --git a/charts/mcp-stack/templates/deployment-mcp-fast-time-server.yaml b/charts/mcp-stack/templates/deployment-mcp-fast-time-server.yaml index 6bd8f82d2..4626532cd 100644 --- a/charts/mcp-stack/templates/deployment-mcp-fast-time-server.yaml +++ b/charts/mcp-stack/templates/deployment-mcp-fast-time-server.yaml @@ -30,6 +30,7 @@ spec: - name: {{ . }} {{- end }} {{- end }} + serviceAccountName: {{ include "mcp-stack.serviceAccountName" . }} containers: - name: mcp-fast-time-server image: "{{ .Values.mcpFastTimeServer.image.repository }}:{{ .Values.mcpFastTimeServer.image.tag }}" diff --git a/charts/mcp-stack/templates/deployment-mcpgateway.yaml b/charts/mcp-stack/templates/deployment-mcpgateway.yaml index f51fdb00a..9f966b529 100644 --- a/charts/mcp-stack/templates/deployment-mcpgateway.yaml +++ b/charts/mcp-stack/templates/deployment-mcpgateway.yaml @@ -35,6 +35,7 @@ spec: - name: {{ . }} {{- end }} {{- end }} + serviceAccountName: {{ include "mcp-stack.serviceAccountName" . }} containers: - name: mcp-context-forge image: "{{ .Values.mcpContextForge.image.repository }}:{{ .Values.mcpContextForge.image.tag }}" diff --git a/charts/mcp-stack/templates/deployment-pgadmin.yaml b/charts/mcp-stack/templates/deployment-pgadmin.yaml index eafdfc8df..eab497c3c 100644 --- a/charts/mcp-stack/templates/deployment-pgadmin.yaml +++ b/charts/mcp-stack/templates/deployment-pgadmin.yaml @@ -28,6 +28,7 @@ spec: - name: {{ . }} {{- end }} {{- end }} + serviceAccountName: {{ include "mcp-stack.serviceAccountName" . }} containers: - name: pgadmin image: "{{ .Values.pgadmin.image.repository }}:{{ .Values.pgadmin.image.tag }}" diff --git a/charts/mcp-stack/templates/deployment-pgbouncer.yaml b/charts/mcp-stack/templates/deployment-pgbouncer.yaml index 61239c3e0..56beafa30 100644 --- a/charts/mcp-stack/templates/deployment-pgbouncer.yaml +++ b/charts/mcp-stack/templates/deployment-pgbouncer.yaml @@ -30,6 +30,7 @@ spec: - name: {{ . }} {{- end }} {{- end }} + serviceAccountName: {{ include "mcp-stack.serviceAccountName" . }} containers: - name: pgbouncer image: "{{ .Values.pgbouncer.image.repository }}:{{ .Values.pgbouncer.image.tag }}" diff --git a/charts/mcp-stack/templates/deployment-postgres.yaml b/charts/mcp-stack/templates/deployment-postgres.yaml index ec547f41a..e8190b560 100644 --- a/charts/mcp-stack/templates/deployment-postgres.yaml +++ b/charts/mcp-stack/templates/deployment-postgres.yaml @@ -46,6 +46,7 @@ spec: - name: {{ . }} {{- end }} {{- end }} + serviceAccountName: {{ include "mcp-stack.serviceAccountName" . }} initContainers: {{- if and .Values.postgres.upgrade.enabled (eq $targetVersion "18") .Values.postgres.upgrade.backupCompleted }} # Init container to upgrade PostgreSQL data from version 17 to 18 diff --git a/charts/mcp-stack/templates/deployment-redis-commander.yaml b/charts/mcp-stack/templates/deployment-redis-commander.yaml index 28d56c95d..0b573b5f7 100644 --- a/charts/mcp-stack/templates/deployment-redis-commander.yaml +++ b/charts/mcp-stack/templates/deployment-redis-commander.yaml @@ -28,6 +28,7 @@ spec: - name: {{ . }} {{- end }} {{- end }} + serviceAccountName: {{ include "mcp-stack.serviceAccountName" . }} containers: - name: redis-commander image: "{{ .Values.redisCommander.image.repository }}:{{ .Values.redisCommander.image.tag }}" diff --git a/charts/mcp-stack/templates/deployment-redis.yaml b/charts/mcp-stack/templates/deployment-redis.yaml index 85c7078d8..282c01e27 100644 --- a/charts/mcp-stack/templates/deployment-redis.yaml +++ b/charts/mcp-stack/templates/deployment-redis.yaml @@ -31,6 +31,7 @@ spec: - name: {{ . }} {{- end }} {{- end }} + serviceAccountName: {{ include "mcp-stack.serviceAccountName" . }} containers: - name: redis image: "{{ .Values.redis.image.repository }}:{{ .Values.redis.image.tag }}" diff --git a/charts/mcp-stack/templates/job-migration.yaml b/charts/mcp-stack/templates/job-migration.yaml index 2eccc0e84..42fdfc046 100644 --- a/charts/mcp-stack/templates/job-migration.yaml +++ b/charts/mcp-stack/templates/job-migration.yaml @@ -23,6 +23,7 @@ spec: app.kubernetes.io/component: migration spec: restartPolicy: {{ .Values.migration.restartPolicy }} + serviceAccountName: {{ include "mcp-stack.serviceAccountName" . }} containers: - name: migration diff --git a/charts/mcp-stack/templates/job-postgres-backup.yaml b/charts/mcp-stack/templates/job-postgres-backup.yaml index 301908e35..2736335a9 100644 --- a/charts/mcp-stack/templates/job-postgres-backup.yaml +++ b/charts/mcp-stack/templates/job-postgres-backup.yaml @@ -15,6 +15,7 @@ spec: template: spec: restartPolicy: Never + serviceAccountName: {{ include "mcp-stack.serviceAccountName" . }} containers: - name: postgres-backup image: "{{ .Values.postgres.image.repository }}:{{ .Values.postgres.image.tag }}" diff --git a/charts/mcp-stack/templates/job-postgres-migration-check.yaml b/charts/mcp-stack/templates/job-postgres-migration-check.yaml index 3066d723d..13c028471 100644 --- a/charts/mcp-stack/templates/job-postgres-migration-check.yaml +++ b/charts/mcp-stack/templates/job-postgres-migration-check.yaml @@ -15,6 +15,7 @@ spec: template: spec: restartPolicy: Never + serviceAccountName: {{ include "mcp-stack.serviceAccountName" . }} containers: - name: postgres-migration-check image: "{{ .Values.postgres.image.repository }}:18" diff --git a/charts/mcp-stack/templates/minio-deployment.yaml b/charts/mcp-stack/templates/minio-deployment.yaml index 5aed0f236..926b25bf9 100644 --- a/charts/mcp-stack/templates/minio-deployment.yaml +++ b/charts/mcp-stack/templates/minio-deployment.yaml @@ -19,6 +19,7 @@ spec: app.kubernetes.io/component: minio app: {{ include "mcp-stack.fullname" . }}-minio spec: + serviceAccountName: {{ include "mcp-stack.serviceAccountName" . }} containers: - name: minio image: "{{ .Values.minio.image.repository }}:{{ .Values.minio.image.tag }}" diff --git a/charts/mcp-stack/templates/serviceaccount.yaml b/charts/mcp-stack/templates/serviceaccount.yaml new file mode 100644 index 000000000..f2f836a61 --- /dev/null +++ b/charts/mcp-stack/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "mcp-stack.serviceAccountName" . }} + labels: + {{- include "mcp-stack.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }} +{{- end }} diff --git a/charts/mcp-stack/values.schema.json b/charts/mcp-stack/values.schema.json index 20e946520..f50363e5d 100644 --- a/charts/mcp-stack/values.schema.json +++ b/charts/mcp-stack/values.schema.json @@ -30,6 +30,36 @@ }, "additionalProperties": false }, + "serviceAccount": { + "type": "object", + "description": "ServiceAccount configuration for all pods in the release", + "properties": { + "create": { + "type": "boolean", + "description": "Create a ServiceAccount", + "default": false + }, + "name": { + "type": "string", + "description": "ServiceAccount name (uses fullname if empty)", + "default": "" + }, + "annotations": { + "type": "object", + "description": "Annotations for the ServiceAccount (e.g., IRSA, Workload Identity)", + "additionalProperties": { + "type": "string" + }, + "default": {} + }, + "automountServiceAccountToken": { + "type": "boolean", + "description": "Mount the ServiceAccount token in pods", + "default": true + } + }, + "additionalProperties": false + }, "mcpContextForge": { "type": "object", "description": "MCP Context-Forge Gateway configuration", diff --git a/charts/mcp-stack/values.yaml b/charts/mcp-stack/values.yaml index 078955d78..a2e106dac 100644 --- a/charts/mcp-stack/values.yaml +++ b/charts/mcp-stack/values.yaml @@ -7,6 +7,26 @@ global: nameOverride: "" # short name applied to all resources (optional) fullnameOverride: "" # fully-qualified name override (optional) +######################################################################## +# SERVICE ACCOUNT +# Configure ServiceAccount for all pods in the release. +# Note: All pods (gateway, postgres, redis, minio, etc.) share the same +# ServiceAccount. For fine-grained IAM control, deploy components in +# separate releases or use Kustomize overlays. +######################################################################## +serviceAccount: + # -- Create a ServiceAccount for all pods in this release + create: false + # -- ServiceAccount name. If empty and create=true, uses release fullname. If create=false, uses this name or "default" + name: "" + # -- Annotations for the ServiceAccount (e.g., AWS IRSA, GCP Workload Identity) + # @default -- `{}` + annotations: {} + # eks.amazonaws.com/role-arn: arn:aws:iam::123456789:role/my-role + # iam.gke.io/gcp-service-account: my-sa@project.iam.gserviceaccount.com + # -- Mount the ServiceAccount token in pods. Only applies when create=true (existing ServiceAccounts control their own token mounting) + automountServiceAccountToken: true + ######################################################################## # MCP CONTEXT-FORGE (Gateway / API tier) ########################################################################