Security & Workflowsο
Security considerations for using the strata MCP server in production, including API key management, audit logging, and approval gates.
Security Modelο
Core Principle: βAI Previews, Humans Executeβο
The MCP server is designed with a fundamental security boundary:
Operation Type |
Tool Availability |
Executor |
|---|---|---|
Query (read-only) |
β Available via MCP |
AI tool |
Preview (dry-run) |
β Available via MCP |
AI tool |
Execute (destructive) |
β NOT available via MCP |
User via CLI only |
Example:
build_plan()β Shows what would be built β Available via MCPbuild_run()β Actually builds artifacts β οΈ See note belowdeploy_plan()β Shows what would be deployed β Available via MCPdeploy runβ Actually deploys resources β CLI only, not via MCP
This design ensures only explicitly confirmed CLI operations actually provision infrastructure.
Destructive Operations Noteο
build_run() and build_sbom() are available via MCP because they:
Write to the local
build/directory (not cloud infrastructure)Donβt modify deployed resources
Can be safely retried or rolled back by deleting the build directory
True destructive operations (strata deploy run, strata deploy destroy) are CLI-only.
API Keys & Secrets Managementο
β Secrets Are Never Exposed via MCPο
Strata separates secrets from configuration:
Configuration YAML (deployment.yaml):
spec:
provisioners:
- name: tf
provisioner: terraform
source:
repository: infrastructure
source_path: terraform
configuration:
variables:
# Variables are in the YAML (visible)
environment: staging
region: eastus
ssh_key_secret: my_ssh_key # β Reference only, not the actual key
Secrets Storage (.strata/secrets/ or external secret manager):
SSH keys stored in local secret store or Bitwarden, not YAML
MCP tools can validate that a referenced secret exists, but never return its content
Secrets are resolved at deployment time (when running the CLI), not via MCP
How MCP Tools Handle Secretsο
When you call validate_file() via MCP:
β Validates that secret references are valid
β Does NOT fetch or return the actual secret content
Example:
{
"success": true,
"data": {
"valid": true,
"issues": ["SSH key secret 'my_ssh_key' is referenced but not found"]
}
}
The actual secret content is only accessed when you run strata deploy run via the CLI in your terminal.
Best Practice: Never Paste Secrets in Promptsο
β Donβt do this:
You: "Validate this YAML. The SSH key is: -----BEGIN PRIVATE KEY-----..."
β Do this instead:
You: "Validate my deployment YAML."
Claude: [calls validate_file()] β
You: "I see the SSH key secret reference is valid. Ready to deploy."
Audit Loggingο
Whatβs Logged?ο
Every deployment operation creates an audit log entry:
Logged Information:
Timestamp
Deployment file
User (OS user running the CLI)
Operation (build_run, deploy_run, deploy_destroy, etc.)
Stages executed
Duration
Success/failure status
Error messages (if failed)
Location: .strata/logs/ directory
Querying Audit Logs via MCPο
Use audit_query() to analyze deployment history:
# Get last 20 deployments
result = audit_query(work_path="/my/workspace", last=20)
# Returns: [
# {timestamp, deployment, success, duration_seconds, stages},
# ...
# ]
# Get deployments since a specific time
result = audit_query(since="2026-07-01T00:00:00")
# Get deployments for a specific stage
result = audit_query(stage="infrastructure")
Example: Claude Auditing a Deploymentο
You: βShow me all deployments in the last 24 hours.β
Claude calls audit_query(since="2026-07-04T12:00:00") and shows:
π Deployment History (Last 24h)
1. 2026-07-05 14:23:45 β deploy-staging.yaml
β
Success | infrastructure stage | 8m 34s
2. 2026-07-05 09:15:22 β deploy-prod.yaml
β
Success | infrastructure, services stages | 15m 12s
3. 2026-07-04 23:41:10 β deploy-staging.yaml
β Failed | infrastructure stage | 4m 15s
Error: Resource group already exists
3 deployments total (2 successful, 1 failed).
Integration with Compliance Toolsο
Export audit logs to SIEM systems (Splunk, ELK, etc.):
# View raw audit logs
cat .strata/logs/deploy-*.json
# Parse and export
jq '.[]' .strata/logs/deploy-*.json | grep "failure"
Approval Workflowsο
Pattern 1: AI Suggests, Human Approves, CLI Executesο
Workflow:
1. You ask Claude: "Deploy staging?"
2. Claude calls deploy_plan()
3. Claude shows you the Terraform plan
4. You review and say: "Looks good, deploy it."
5. You run CLI manually: strata deploy run -f deploy-staging.yaml
6. Claude queries audit logs: "Deployment complete. Status: β
"
Why this is safe:
AI cannot execute the deploy
Human reviews the plan before execution
CLI operation is audited
User has opportunity to abort
Pattern 2: Slack/Teams Bot with Approval Gateο
Setup:
1. Deployment request triggered (via webhook or polling)
2. Bot calls deploy_plan() to generate preview
3. Bot posts preview to Slack/Teams with "Approve" button
4. Reviewer clicks "Approve"
5. Approval triggering script runs CLI: strata deploy run -f ...
6. Bot queries audit logs and posts result
Pseudocode (Python):
from slack_sdk import WebClient
import subprocess
slack = WebClient(token="xoxb-...")
def request_deployment(file_path):
# 1. Get deployment preview via MCP
preview = mcp_client.deploy_plan(file=file_path)
# 2. Post to Slack for review
slack.chat_postMessage(
channel="#deployments",
blocks=[
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"Deploy `{file_path}`?\n\n{preview}"
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {"type": "plain_text", "text": "Approve"},
"action_id": f"approve_{file_path}"
}
]
}
]
)
def handle_approval(file_path):
# 3. Execute deployment via CLI when approved
result = subprocess.run(
["strata", "deploy", "run", "-f", file_path, "--force"],
capture_output=True,
text=True
)
# 4. Post result back to Slack
status = "β
Success" if result.returncode == 0 else "β Failed"
slack.chat_postMessage(
channel="#deployments",
text=f"{status}: {file_path}"
)
Pattern 3: Role-Based Access Control (RBAC)ο
Setup:
# .strata/rbac.yaml
roles:
developer:
permissions:
- validate_file
- build_plan
- build_run
- scaffold_file
platform_engineer:
permissions:
- validate_file
- build_plan
- build_run
- deploy_plan
- deploy_status
sre:
permissions:
- validate_file
- build_plan
- build_run
- deploy_plan
- deploy_status
- deploy_health
- audit_query
- deploy_history
Enforcement:
MCP servers can validate the callerβs role before granting access:
def validate_file(file_path, work_path, deep, user_role):
if "validate_file" not in ROLES[user_role]["permissions"]:
raise PermissionError(f"Role '{user_role}' cannot validate files")
# ... proceed with validation
Network Securityο
MCP Transport: Stdio (Local Only)ο
The MCP server uses stdio transport, which means:
β Secure by default:
Runs in the same process as the caller (no network)
No HTTP/TCP ports exposed
No remote access
Caller must have local shell access to the workspace
β Not suitable for remote access:
No built-in authentication
No encryption (local process only)
Cannot expose server to the internet directly
Remote MCP via SSH (Advanced)ο
If you need remote access, use SSH tunneling:
# On your workstation
ssh -L 9000:localhost:9000 user@server.example.com \
"strata mcp serve"
# On server
strata mcp serve --listen 127.0.0.1:9000
This forwards the server over SSH (encrypted), but strata MCP doesnβt natively support this. Use a wrapper like mcp-tunnel if needed.
Secrets Management Integrationο
Pattern 1: Local .strata/secrets/ Directoryο
Store secrets locally:
.strata/
βββ secrets/
β βββ azure-client-secret.txt
β βββ ssh-key.pem
β βββ docker-registry-token.txt
Configure deployment to use them:
spec:
provisioners:
- name: tf
provisioner: terraform
configuration:
secrets:
- key: azure_client_secret
source: file
value: .strata/secrets/azure-client-secret.txt
Pattern 2: Bitwarden Integrationο
Use Bitwarden as the secret store:
spec:
provisioners:
- name: tf
provisioner: terraform
configuration:
secrets:
- key: docker_registry_token
source: bitwarden
value: item-uuid-12345
Strata resolves the secret from Bitwarden at deploy time.
Pattern 3: AWS Secrets Managerο
Use AWS Secrets Manager:
spec:
provisioners:
- name: tf
provisioner: terraform
configuration:
secrets:
- key: database_password
source: aws-secrets-manager
value: "prod/database/password"
Best Practice: Least Privilegeο
MCP tools never fetch secrets β they validate references only
Secrets stored outside YAML β not in deployment files
Secrets resolved at CLI time β when the actual deployment runs
Audit logs donβt record secret values β only the operation
Production Checklistο
Before using strata MCP in production:
β Install MCP dependency β
pip install xyz-strata[mcp]β Configure approval workflow β Decide on human review process
β Enable audit logging β Logs go to
.strata/logs/β Set up RBAC β Define roles and permissions per team
β Secrets strategy β Use Bitwarden, AWS Secrets, or local store
β Test end-to-end β Validate β Build β Deploy β Monitor workflow
β Document runbooks β How to handle failures via MCP queries
β Monitor audit logs β Export to SIEM if required for compliance
β Define escalation β Who to contact if deployment fails
Common Threats & Mitigationsο
Threat |
Mitigation |
|---|---|
AI tool executes destructive operations without approval |
Only CLI can execute; MCP is preview/query only |
Secrets leaked in AI chat |
Secrets never exposed via MCP; resolved at CLI time |
Unauthorized user runs deployments |
RBAC + file permissions; audit logs track who ran what |
Deployment fails silently |
Audit logs capture success/failure; Claude can query history |
Invalid YAML deploys to production |
|
Infrastructure drift undetected |
|
See Alsoο
Claude Deployment Assistant β End-to-end workflow example
AI-Assisted Troubleshooting β Using audit logs for diagnostics
Tools Reference β Full MCP tools API