IAM and RBAC Requirements for Multi-Cloud Deployment
Last Updated: 2025-11-02
Applies To: GCP GKE, AWS EKS, Azure AKS
Purpose: Comprehensive IAM/RBAC permissions required for CI/CD deployments
Overview
This document defines all required IAM roles, permissions, and RBAC policies needed to deploy MCP Server LangGraph to Kubernetes across all three major cloud providers.
Principle: Least Privilege
All permissions follow the principle of least privilege - granting only the minimum permissions necessary for each operation.
GCP (Google Kubernetes Engine)
Service Account: mcp-staging-sa@PROJECT_ID.iam.gserviceaccount.com
Required IAM Roles
| Role | Permission | Purpose | Required For |
|---|
roles/artifactregistry.writer | CRITICAL | Push Docker images to Artifact Registry | Docker build & push |
roles/container.developer | CRITICAL | Deploy to GKE, manage workloads | kubectl apply, rollout |
roles/logging.logWriter | Standard | Write application logs | Runtime logging |
roles/monitoring.metricWriter | Standard | Write metrics and traces | Observability |
roles/secretmanager.secretAccessor | Standard | Access application secrets | Runtime configuration |
roles/cloudsql.client | Optional | Connect to Cloud SQL databases | Database access |
Grant Commands
PROJECT_ID="your-project-id"
SERVICE_ACCOUNT="mcp-staging-sa@${PROJECT_ID}.iam.gserviceaccount.com"
# CRITICAL: Artifact Registry Writer
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:${SERVICE_ACCOUNT}" \
--role="roles/artifactregistry.writer"
# CRITICAL: Container Developer
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:${SERVICE_ACCOUNT}" \
--role="roles/container.developer"
# Standard: Logging
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:${SERVICE_ACCOUNT}" \
--role="roles/logging.logWriter"
# Standard: Monitoring
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:${SERVICE_ACCOUNT}" \
--role="roles/monitoring.metricWriter"
# Standard: Secrets
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:${SERVICE_ACCOUNT}" \
--role="roles/secretmanager.secretAccessor"
# Optional: Cloud SQL (if using managed PostgreSQL)
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:${SERVICE_ACCOUNT}" \
--role="roles/cloudsql.client"
Workload Identity Federation (GitHub Actions)
Pool: github-actions-pool
Provider: github-provider
# Allow GitHub Actions to impersonate service account
gcloud iam service-accounts add-iam-policy-binding \
"${SERVICE_ACCOUNT}" \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/github-actions-pool/attribute.repository/${GITHUB_REPO}"
Kubernetes RBAC (In-Cluster)
Service Account: mcp-server-langgraph (in namespace)
apiVersion: v1
kind: ServiceAccount
metadata:
name: mcp-server-langgraph
namespace: staging-mcp-server-langgraph
annotations:
iam.gke.io/gcp-service-account: mcp-staging-sa@PROJECT_ID.iam.gserviceaccount.com
Verification
# Check all IAM roles
gcloud projects get-iam-policy $PROJECT_ID \
--flatten="bindings[].members" \
--filter="bindings.members:${SERVICE_ACCOUNT}" \
--format="table(bindings.role)"
# Expected output:
# roles/artifactregistry.writer ✓
# roles/container.developer ✓
# roles/logging.logWriter ✓
# roles/monitoring.metricWriter ✓
# roles/secretmanager.secretAccessor ✓
# roles/cloudsql.client ✓
AWS (Elastic Kubernetes Service)
IAM Role: mcp-eks-deployment-role
Required IAM Policies
| Policy | Type | Purpose | Required For |
|---|
AmazonEKSClusterPolicy | AWS Managed | EKS cluster management | Cluster operations |
AmazonEKSServicePolicy | AWS Managed | EKS service linking | Service integration |
AmazonEKSVPCResourceController | AWS Managed | VPC resource management | Network policies |
| Custom: ECR Push/Pull | Custom | Push/pull container images | Docker build & push |
| Custom: EKS Deploy | Custom | Deploy to EKS workloads | kubectl apply |
| Custom: CloudWatch Logs | Custom | Write application logs | Logging |
| Custom: CloudWatch Metrics | Custom | Publish metrics | Observability |
| Custom: Secrets Manager | Custom | Access secrets | Runtime config |
Custom IAM Policy: ECR Access
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ECRPushPull",
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:BatchGetImage"
],
"Resource": "*"
}
]
}
Custom IAM Policy: EKS Deployment
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EKSDeploy",
"Effect": "Allow",
"Action": [
"eks:DescribeCluster",
"eks:ListClusters",
"eks:DescribeNodegroup",
"eks:ListNodegroups"
],
"Resource": "arn:aws:eks:*:ACCOUNT_ID:cluster/mcp-*"
}
]
}
IRSA (IAM Roles for Service Accounts)
Service Account Annotation:
apiVersion: v1
kind: ServiceAccount
metadata:
name: mcp-server-langgraph
namespace: mcp-server-langgraph
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT_ID:role/mcp-eks-pod-role
Trust Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/oidc.eks.REGION.amazonaws.com/id/CLUSTER_ID"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.REGION.amazonaws.com/id/CLUSTER_ID:sub": "system:serviceaccount:mcp-server-langgraph:mcp-server-langgraph"
}
}
}
]
}
Grant Commands (AWS CLI)
# Create IAM role for EKS deployment
aws iam create-role \
--role-name mcp-eks-deployment-role \
--assume-role-policy-document file://trust-policy.json
# Attach AWS managed policies
aws iam attach-role-policy \
--role-name mcp-eks-deployment-role \
--policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy
# Create and attach custom ECR policy
aws iam put-role-policy \
--role-name mcp-eks-deployment-role \
--policy-name ECRAccess \
--policy-document file://ecr-policy.json
Azure (Azure Kubernetes Service)
Service Principal / Managed Identity: mcp-aks-sp
Required Azure RBAC Roles
| Role | Scope | Purpose | Required For |
|---|
Azure Kubernetes Service Cluster User Role | AKS Cluster | Access cluster credentials | kubectl access |
AcrPush | Container Registry | Push container images | Docker build & push |
AcrPull | Container Registry | Pull container images | Deployment |
Contributor (limited scope) | Resource Group | Manage AKS resources | Deployment updates |
Monitoring Metrics Publisher | Subscription | Publish metrics | Observability |
Key Vault Secrets User | Key Vault | Access secrets | Runtime config |
Grant Commands (Azure CLI)
RESOURCE_GROUP="mcp-production-rg"
CLUSTER_NAME="mcp-production"
ACR_NAME="mcpcontainerregistry"
SUBSCRIPTION_ID=$(az account show --query id -o tsv)
# Create service principal
SP_INFO=$(az ad sp create-for-rbac \
--name mcp-aks-sp \
--role "Azure Kubernetes Service Cluster User Role" \
--scopes /subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP)
SP_OBJECT_ID=$(echo $SP_INFO | jq -r '.appId')
# Grant ACR Push role
az role assignment create \
--assignee $SP_OBJECT_ID \
--role AcrPush \
--scope /subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.ContainerRegistry/registries/$ACR_NAME
# Grant ACR Pull role
az role assignment create \
--assignee $SP_OBJECT_ID \
--role AcrPull \
--scope /subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.ContainerRegistry/registries/$ACR_NAME
# Grant Contributor (scoped to resource group)
az role assignment create \
--assignee $SP_OBJECT_ID \
--role Contributor \
--scope /subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP
# Grant Monitoring Metrics Publisher
az role assignment create \
--assignee $SP_OBJECT_ID \
--role "Monitoring Metrics Publisher" \
--scope /subscriptions/$SUBSCRIPTION_ID
Workload Identity (Azure AD Pod Identity)
Pod Identity:
apiVersion: "aadpodidentity.k8s.io/v1"
kind: AzureIdentity
metadata:
name: mcp-identity
namespace: mcp-server-langgraph
spec:
type: 0 # User-assigned managed identity
resourceID: /subscriptions/SUBSCRIPTION_ID/resourcegroups/RESOURCE_GROUP/providers/Microsoft.ManagedIdentity/userAssignedIdentities/mcp-identity
clientID: CLIENT_ID
Pod Identity Binding:
apiVersion: "aadpodidentity.k8s.io/v1"
kind: AzureIdentityBinding
metadata:
name: mcp-identity-binding
namespace: mcp-server-langgraph
spec:
azureIdentity: mcp-identity
selector: mcp-server-langgraph
Namespace-Level Permissions
ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: mcp-server-langgraph
namespace: mcp-server-langgraph
Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: mcp-server-langgraph
namespace: mcp-server-langgraph
rules:
# Allow reading ConfigMaps
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
# Allow reading Secrets
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"]
# Allow reading Services
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list"]
# Allow creating Events
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "patch"]
RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: mcp-server-langgraph
namespace: mcp-server-langgraph
subjects:
- kind: ServiceAccount
name: mcp-server-langgraph
namespace: mcp-server-langgraph
roleRef:
kind: Role
name: mcp-server-langgraph
apiGroup: rbac.authorization.k8s.io
CI/CD Service Account Permissions
Required Permissions:
- Pull from source repository - GitHub token (automatic)
- Authenticate to cloud provider - Workload Identity Federation / OIDC
- Push container images - Container registry write access
- Deploy to Kubernetes - Cluster access with deployment permissions
Deployment Pipeline Permissions
# GitHub Actions workflow permissions
permissions:
contents: read # Read repository contents
id-token: write # Request OIDC tokens for cloud auth
packages: write # Push to GitHub Container Registry (optional)
deployments: write # Create deployment statuses
Validation Scripts
GCP Validation
#!/bin/bash
# validate-gcp-permissions.sh
SERVICE_ACCOUNT="mcp-staging-sa@PROJECT_ID.iam.gserviceaccount.com"
REQUIRED_ROLES=(
"roles/artifactregistry.writer"
"roles/container.developer"
"roles/logging.logWriter"
"roles/monitoring.metricWriter"
"roles/secretmanager.secretAccessor"
)
echo "Validating GCP IAM roles..."
GRANTED_ROLES=$(gcloud projects get-iam-policy $PROJECT_ID \
--flatten="bindings[].members" \
--filter="bindings.members:${SERVICE_ACCOUNT}" \
--format="value(bindings.role)")
for role in "${REQUIRED_ROLES[@]}"; do
if echo "$GRANTED_ROLES" | grep -q "$role"; then
echo "✓ $role"
else
echo "✗ $role (MISSING)"
exit 1
fi
done
echo "✓ All required IAM roles present"
AWS Validation
#!/bin/bash
# validate-aws-permissions.sh
ROLE_NAME="mcp-eks-deployment-role"
echo "Validating AWS IAM policies..."
aws iam list-attached-role-policies --role-name $ROLE_NAME
aws iam list-role-policies --role-name $ROLE_NAME
echo "✓ IAM policies validated"
Azure Validation
#!/bin/bash
# validate-azure-permissions.sh
SP_OBJECT_ID="your-service-principal-id"
RESOURCE_GROUP="mcp-production-rg"
echo "Validating Azure RBAC roles..."
az role assignment list --assignee $SP_OBJECT_ID --resource-group $RESOURCE_GROUP
echo "✓ RBAC roles validated"
Troubleshooting
Common Permission Errors
GCP: “Permission denied on Artifact Registry”
Error:
denied: Permission "artifactregistry.repositories.uploadArtifacts" denied
Fix:
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:${SERVICE_ACCOUNT}" \
--role="roles/artifactregistry.writer"
AWS: “AccessDenied ECR”
Error:
denied: User: arn:aws:sts::ACCOUNT:assumed-role/... is not authorized to perform: ecr:PutImage
Fix:
Apply ECR custom policy (see above)
Azure: “Authorization failed for ACR”
Error:
unauthorized: authentication required
Fix:
az role assignment create \
--assignee $SP_OBJECT_ID \
--role AcrPush \
--scope /subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.ContainerRegistry/registries/$ACR_NAME
Security Best Practices
1. Use Workload Identity / IRSA
- ✅ Do: Use platform-native workload identity (GCP Workload Identity, AWS IRSA, Azure Pod Identity)
- ❌ Don’t: Use long-lived service account keys
2. Principle of Least Privilege
- ✅ Do: Grant only required permissions
- ❌ Don’t: Grant
Owner, Editor, or Admin roles
3. Scope Permissions Narrowly
- ✅ Do: Scope to specific resources (namespace, resource group, etc.)
- ❌ Don’t: Grant organization-wide or subscription-wide permissions
4. Regular Audits
- ✅ Do: Regularly review and audit permissions
- ❌ Don’t: Set-and-forget permissions
5. Use Resource-Level Permissions
- ✅ Do: Grant access to specific container registries, clusters
- ❌ Don’t: Grant wildcard (*) resource access
References
Documentation
- GCP: GCP Configuration Guide
- AWS: AWS EKS Configuration (see scripts and Terraform modules below)
- Azure: Azure AKS Configuration (see scripts and Terraform modules below)
AWS EKS and Azure AKS deployment documentation is available via deployment scripts and Terraform modules. Dedicated configuration guides are planned for future releases.
Scripts
- GCP Setup:
scripts/gcp/setup-staging-infrastructure.sh
- AWS Setup:
scripts/deploy-aws-eks.sh
- Azure Setup:
scripts/deploy-azure-aks.sh
- GCP:
terraform/modules/gke/
- AWS:
terraform/modules/eks/
- Azure:
terraform/modules/aks/
Maintained By: DevOps Team
Last Reviewed: 2025-11-02
Next Review: 2025-12-01