Run6 min read

Run a cloud operations workflow across services, with credentials and an approval

A cloud runbook that reads metrics is easy to trust. One that changes capacity is not, until you can say which credential it uses, what it does when a call is refused, and who agreed to the change. Here is one example, scoped tightly enough to answer all three.

The OCNORA team ·

Reviewed on · Reviewed by OCNORA engineering

The example: read, decide, ask, then scale

Keep the first cloud workflow small. This one watches a single AWS Auto Scaling group behind a web service. On a schedule, it reads the group’s CPU metric from CloudWatch and the group’s current capacity from Auto Scaling. A branch compares the metric with a threshold you set. Below the line, the run ends and nothing is written. Above it, the workflow posts the evidence to Slack, asks a person to approve a new capacity, and only then calls autoscaling.set_desired_capacity.

Every node in that chain is a typed node in the catalog: cloudwatch.get_metric_statistics, autoscaling.describe_auto_scaling_groups, control.branch, slack.post_message, human.prompt, autoscaling.set_desired_capacity, jira.create_issue and pagerduty.create_incident. There is no script in the middle. What you read on the canvas is what runs.

cloud ops run   (illustrative, synthetic data)

  schedule ─▶ read CPU metric ─▶ read group capacity ─▶ over threshold?
                                                           │
                                           no ◀────────────┤
                                      (run ends)           ▼ yes
                                                 post evidence to Slack
                                                           ▼
                                              approval: scale web-asg?
                                     ┌─────────────┼──────────────┐
                                  approve        reject        timeout
                                     ▼             ▼              ▼
                            set desired      Jira ticket     page on-call
                            capacity         (no write)      (no write)

Credentials: two connections, each with only what it needs

An AWS node authenticates with a connection that holds an access key id and a secret access key, plus a default region the node can override. The connection is chosen per node. That is the lever: give the reads one connection and the write another, so the credential that can change capacity is used by exactly one step.

  • Read connection. An IAM identity allowed cloudwatch:GetMetricStatistics and autoscaling:DescribeAutoScalingGroups, and nothing else. It sits on the two read nodes.
  • Write connection. A separate identity allowed autoscaling:SetDesiredCapacity, limited in the IAM policy to the one group this workflow manages. It sits on the scaling node alone.
  • Chat, tickets and paging. A Slack connection that can post to the ops channel, a Jira project for tickets and a PagerDuty service for incidents. None of them can touch AWS.

Inside OCNORA, each connection’s secret is envelope-encrypted with a data key of its own, and that data key is wrapped by a key-management service, so the database holds nothing that decrypts on its own. Who may edit the workflow or its connections is set by role: owner, admin, editor or viewer. A role that lacks a permission cannot use it, whether the request comes from the dashboard or from a script. The security page sets out both in more detail.

API limits and the error path

AWS applies its own request limits per account and region, and a call over them is refused. OCNORA does not raise those limits or queue around them. A throttled or failed call fails the step, and the step keeps its input and the error, so you can read the error AWS returned rather than guess. Per-node retries with backoff give a transient refusal another chance; set them on the read nodes, where a repeat is harmless.

Think harder before retrying the write. Setting a desired capacity is idempotent in effect, because asking twice for the same number leaves the same number, but a retry after a long delay can apply a decision that is no longer current. Keep retries on the scaling node few, and switch on honor_cooldown so the call respects the group’s own cooldown instead of stacking changes on top of it.

  • Results come in pages. describe_auto_scaling_groups returns a next_token when there is more, so name the group rather than listing every group in the account.
  • When a step still fails after its retries, a separate error workflow runs with the failing run’s context. Point it at the on-call channel, not at the same Slack thread that carries routine alerts.
  • A schedule polls. A spike that starts and ends between two runs is not seen. If you need to act on the alarm itself, start the workflow from your monitoring tool’s webhook instead.

The approval before the write

The scaling call sits behind a human.prompt step. It suspends the run until a person answers or its timeout lapses, then routes on the answer or on the timeout branch, and the decision is recorded with the run. The approver sees what you put in the prompt text, so put the evidence there: the group name, the metric reading from this run, the current capacity and the capacity the workflow proposes.

  • Approve. The scaling node runs with the write connection, and a message confirms the new capacity in the ops channel.
  • Reject. No write. A Jira ticket records the reading and the decision, so a rejected change still leaves a trace someone can pick up.
  • Timeout. No write. PagerDuty opens an incident for on-call. A change nobody approved should never become a change by default.

Test it somewhere that does not matter

Build the workflow against a non-production AWS account and a test Auto Scaling group first. Workflow Health validates the graph and pre-flights each connection on save and publish, so a missing permission on the read identity or an unreachable host shows up before the schedule fires. The dry run then executes the graph with side effects held back, which shows you the shape of the metric and group output without changing capacity.

Then run it live against the test group, with the threshold set low enough to trigger, and answer the approval yourself. Try all three branches: approve, reject and let it time out. Read each run afterwards. Every step is kept with its input, output, status and the connection it used, so you can check that the write used the write connection and nothing else did. Only move the workflow to production once the run record shows what you expected on every branch.

Prerequisites, limitations and a next step

  • Prerequisites: two AWS identities with the scoped policies above, stored as two connections; a Slack channel, a Jira project and a PagerDuty service with their own connections; a threshold and a proposed capacity written as branch conditions and expressions; and a named person who answers the approval.
  • The workflow above is an example pattern, not a template in the library. You assemble it from the nodes shown and test it in your own account.
  • OCNORA records what it did. It does not record what AWS did afterwards; read the group’s own activity history for that.
  • The CloudWatch nodes read and write metrics. Log queries go through the HTTP node with an AWS credential.
  • Least privilege is set in your IAM policies. OCNORA uses the credential you give it and cannot narrow it further.

The IT operations solution shows the read side of this pattern as a diagram, with its prerequisites and limitations. Start from the HTTP health check template for the schedule and branch, and borrow the approval from the approval-gate template. If you want to map your own runbook onto it, book a demo: we start from one service, scope its credentials, and place the approval in front of the first write.

See a workflow run on your own use case.

Book a technical demo. Bring an n8n file or pick a template, and we build it with you on the canvas while Workflow Health checks it before it ever runs.