# Create Approval Workflows

Source: https://docs.ops0.com/docs/how-to/approval-workflows

Require human approval before production deployments to prevent unreviewed changes from reaching critical environments.

---

## Before you start

- At least one IaC project exists

- Team members have ops0 accounts with at least Developer role

- Slack integration configured (optional, for Slack-based approvals)

---

## Scenario

Your team needs to:
- Require manager or senior engineer sign-off before production changes
- Allow staging deployments to run automatically without gates
- Block deployment if no one approves within 4 hours
- Have a full audit trail of who approved what and when
- Support escalation when the primary approver is unavailable

---

## How approvals work in ops0

ops0 approval gates sit inside Workflows. When a workflow reaches an **Approval** step, execution pauses. Configured approvers receive a notification (Slack, email, or both) with the deployment context — plan output, cost estimate, policy results. They can approve or reject directly from Slack or from the ops0 UI. Only after approval does the workflow proceed to the deploy step.

```
Workflow execution
────────────────────────────────────────────────────────
Step 1: Run Plan          → produces plan output
Step 2: Approval Gate     → pauses, notifies approvers
         ↓ approved
Step 3: Apply             → deploys infrastructure
Step 4: Notify Slack      → posts result to #deployments
```

---

## Step 1: Create the workflow

### Open Workflows
Click **Workflows** in the left sidebar, then **+ New Workflow**.

### Name and describe it
Use a clear name like `production-deploy-with-approval`. Add a description so the team understands when to use it.

### Set the trigger
Choose how the workflow starts:
- **Manual** — team member clicks Run in ops0
- **GitHub PR Merged** — auto-triggers when a PR merges to main
- **Webhook** — triggered by an external CI system

---

## Step 2: Add workflow steps

Build the following step sequence in the workflow canvas:

### Step 1 — IaC Plan

| Setting | Value |
|---------|-------|
| **Type** | IaC Deploy |
| **Project** | Select your production project |
| **Action** | Plan only (no apply) |
| **On failure** | Stop workflow |

### Step 2 — Approval Gate

| Setting | Recommended value |
|---------|-----------------|
| **Type** | Approval |
| **Approvers** | Select users, teams, or roles |
| **Required approvals** | 1 (or 2 for critical infrastructure) |
| **Timeout** | 4 hours |
| **On timeout** | Cancel workflow |
| **Include in request** | Plan output, cost estimate, policy results |

### Step 3 — IaC Apply

| Setting | Value |
|---------|-------|
| **Type** | IaC Deploy |
| **Project** | Same production project |
| **Action** | Apply (uses the plan from Step 1) |
| **On failure** | Notify and stop |

### Step 4 — Notify

| Setting | Value |
|---------|-------|
| **Type** | HTTP Request |
| **URL** | Your Slack webhook URL |
| **Body** | Deployment result summary |
| **Run on** | Always (success and failure) |

---

## Step 3: Configure approver notifications

### Slack notification

When an approval is requested, approvers receive a Slack message with full context and interactive buttons:

o

ops0
APP

🔐 **Approval required:** production-deploy-with-approval

Requested by:** jane@acme.com

Project:** aws-production-network

Changes:** 3 to add, 1 to change, 0 to destroy

Cost impact:** +$45.20/month

Policies:** ✓ All 12 checks passed

Expires:** in 4 hours

✓ Approve

✗ Reject

View plan →

### Email notification

Approvers also receive an email with a direct link to the approval page in ops0 if Slack is unavailable.

---

## Step 4: Approve or reject in ops0

Approvers don't have to use Slack. They can also act from inside ops0:

### Go to Workflows → Runs
Find the workflow run with status **Waiting for approval**.

### Click the run
View the full plan output, cost estimate, and policy results inline.

### Approve or Reject
Click **Approve** to proceed or **Reject** to cancel. Add an optional comment — this gets saved to the audit log.

---

## Common patterns

### Pattern 1: Staging auto, production gated

Two separate workflows — one for staging (no approval), one for production (with approval):

```
staging-deploy workflow:
  Step 1: Plan
  Step 2: Apply     ← no gate, runs automatically

production-deploy workflow:
  Step 1: Plan
  Step 2: Approval  ← required
  Step 3: Apply
  Step 4: Notify
```

Trigger both via GitHub PR — use a **Condition** step or separate workflows per environment branch.

### Pattern 2: Two-person rule for critical infra

For database schema changes or IAM modifications, require 2 approvals:

| Setting | Value |
|---------|-------|
| **Required approvals** | 2 |
| **Approvers** | `@platform-leads` team (4 members) |
| **Timeout** | 8 hours |

Any 2 of the 4 team members can approve — the workflow proceeds once the threshold is met.

### Pattern 3: Approval with escalation

Use a Condition step after the approval to check who approved and escalate if needed:

```
Step 1: Plan
Step 2: Approval (1 required, 2 hour timeout)
Step 3: Condition — if cost > $500/month
  → true: second Approval step (requires Finance team)
  → false: proceed to Apply
Step 4: Apply
Step 5: Notify
```

### Pattern 4: Emergency bypass

For incidents where you need to deploy without waiting:

- Keep a separate workflow `production-emergency-deploy` with no approval gate
- Restrict who can trigger it to Admin role only
- The action is still logged in Audit Logs for post-incident review

**Always audit emergency bypasses**

Emergency deploys without approval should be reviewed after the incident. Check Settings → Audit Logs → filter by the emergency workflow name.

---

## Audit trail

Every approval action is captured in the audit log:

| Field | What's recorded |
|-------|----------------|
| **Actor** | User email and name |
| **Action** | Approved / Rejected / Timed out |
| **Timestamp** | Exact time of action |
| **Workflow run** | Link to the full run details |
| **Plan summary** | What was being approved |
| **Comment** | Optional note from the approver |
| **Response time** | How long from request to decision |

View at **Settings → Audit Logs** and filter by workflow name or user.

---

## Troubleshooting

| Issue | Solution |
|-------|---------|
| Approver not receiving Slack message | Verify Slack integration in Settings → Integrations → Alerts. Check the channel name is correct (without `#`). |
| Approval timed out unexpectedly | Check the timeout setting — default is 4 hours. Increase for workflows that run overnight or across time zones. |
| Wrong person approved | Audit logs capture every action. You can reject a subsequent run and re-configure approvers. |
| Workflow stuck at approval | Check if the approver's ops0 account has the right role. Viewer accounts cannot approve. |
| Plan changed between approval and apply | ops0 re-runs the plan at apply time. If the plan differs from what was approved, apply is blocked and you must re-trigger. |

---

## Best practices

Assign teams, not individuals

If you assign approval to a specific person, deployments block when they're on leave. Assign to a team (e.g., @platform-leads) so any member can approve.

Always include plan output

Approvers can't make a good decision without knowing what will change. Always include the plan summary, cost impact, and policy results in the approval request.

Set a realistic timeout

4 hours works for business hours. For teams across time zones, use 24 hours or schedule deployments to trigger at the start of the approver's day.

Don't gate staging

Approval gates on staging environments slow down development. Reserve gates for production and production-like environments.

Review timeouts monthly

Check how many approval requests are timing out. If it's frequent, either the timeout is too short or the wrong people are being asked to approve.

---

## Next Steps

- [Workflow Steps](https://docs.ops0.com/docs/workflows/steps): All available step types — IaC Deploy, Script, HTTP, Condition, and more.

- [Workflow Triggers](https://docs.ops0.com/docs/workflows/triggers): Configure when workflows start — manual, scheduled, webhook, or Git push.

- [IAM & Teams](https://docs.ops0.com/docs/settings/iam): Set up approver teams and manage role assignments.

- [Audit Logs](https://docs.ops0.com/docs/settings/audit-logs): Review the full history of approvals, rejections, and bypasses.
