Spacelift
PrivacyT&Cs
  • 👋Hello, Spacelift!
  • 🚀Getting Started
  • 🌠Main concepts
    • Stack
      • Creating a stack
      • Stack settings
      • Organizing stacks
      • Stack locking
      • Drift detection
    • Configuration
      • Environment
      • Context
      • Runtime configuration
        • YAML reference
    • Run
      • Task
      • Proposed run (preview)
      • Tracked run (deployment)
      • Module test case
      • User-Provided Metadata
      • Run Promotion
      • Pull Request Comments
    • Policy
      • Login policy
      • Access policy
      • Approval policy
      • Initialization policy
      • Plan policy
      • Push policy
      • Task policy
      • Trigger policy
    • Resources
    • Worker pools
    • VCS Agent Pools
  • 🛰️Platforms
    • Terraform
      • Module registry
      • External modules
      • Provider
      • State management
      • Terragrunt
      • Version management
      • Handling .tfvars
      • CLI Configuration
      • Cost Estimation
      • Resource Sanitization
      • Storing Complex Variables
      • Debugging Guide
    • Pulumi
      • Getting started
        • C#
        • Go
        • JavaScript
        • Python
      • State management
      • Version management
    • CloudFormation
      • Getting Started
      • Reference
      • Integrating with SAM
      • Integrating with the serverless framework
    • Kubernetes
      • Getting Started
      • Authenticating
      • Custom Resources
      • Helm
      • Kustomize
  • ⚙️Integrations
    • Audit trail
    • Cloud Integrations
      • Amazon Web Services (AWS)
      • Microsoft Azure
      • Google Cloud Platform (GCP)
    • Source Control
      • GitHub
      • GitLab
      • Azure DevOps
      • Bitbucket Cloud
      • Bitbucket Datacenter/Server
    • Docker
    • GraphQL API
    • Single sign-on
      • GitLab OIDC Setup Guide
      • Okta OIDC Setup Guide
      • OneLogin OIDC Setup Guide
      • Azure AD OIDC Setup Guide
      • AWS IAM Identity SAML 2.0 Setup Guide
    • Slack
    • Webhooks
  • 📖Product
    • Privacy
    • Security
    • Support
      • Statement of Support
    • Disaster Continuity
    • Billing
      • Stripe
      • AWS Marketplace
    • Terms and conditions
    • Refund Policy
  • Cookie Policy
Powered by GitBook
On this page
  • Purpose
  • Data input
  • Helpers
  • Examples

Was this helpful?

  1. Main concepts
  2. Policy

Task policy

PreviousPush policyNextTrigger policy

Last updated 3 years ago

Was this helpful?

This feature is deprecated. Using an allows you to achieve the same goals in a more flexible and powerful way.

Purpose

Spacelift tasks are a handy feature that allows an arbitrary command to be executed within the context of your fully initialized stack. This feature is designed to make running one-off administrative tasks (eg. ) safer and more convenient. It can also be an attack vector allowing evil people to do bad things, or simply a footgun allowing well-meaning people to err in a spectacular way.

Enter task policies. The sole purpose of task policies is to prevent certain commands from being executed, to prevent certain groups or individuals from executing any commands, or to prevent certain commands from being executed by certain groups or individuals.

Preventing admins from running tasks using policies can only play an advisory role and should not be considered a safety measure. A bad actor with admin privileges can detach a policy from the stack and run whatever they want. Choose your admins wisely.

Task policies are simple in that they only use a single rule - deny - with a string message. A single match for that rule will prevent a run from being created, with an appropriate API error. Let's see how that works in practice by defining a simple rule and attaching it to a stack:

package spacelift

deny["not in my town, you don't"] { true }

And here's the outcome when trying to run a task:

Data input

This is the schema of the data input that each policy request will receive:

{
  "request": {
    "command": "string - command that the user is trying to execute as task",
    "remote_ip": "string - IP of the user trying to log in",
    "timestamp_ns": "number - current Unix timestamp in nanoseconds"
  },
  "session": {
    "admin": "boolean - is the current user a Spacelift admin",
    "login": "string - GitHub username of the current user",
    "name": "string - full name of the current user",
    "teams": ["string - names of org teams the current user is a member of"]
  },
  "stack": {
    "administrative": "boolean - is the stack administrative",
    "autodeploy": "boolean - is the stack currently set to autodeploy",
    "branch": "string - tracked branch of the stack",
    "labels": ["string - list of arbitrary, user-defined selectors"],
    "locked_by": "optional string - if the stack is locked, this is the name of the user who did it",
    "name": "string - name of the stack",
    "namespace": "string - repository namespace, only relevant to GitLab repositories",
    "project_root": "optional string - project root as set on the Stack, if any",
    "repository": "string - name of the source GitHub repository",
    "state": "string - current state of the stack",
    "terraform_version": "string or null - last Terraform version used to apply changes"
  }
}

Helpers

  • request - an alias for input.request.

  • session - an alias for input.session.

  • stack - an alias for input.stack.

Examples

Let's have a look at a few examples to see what you can accomplish with task policies. You've seen one example already - disabling tasks entirely. That's perhaps both heavy-handed and naive given that admins can detach the policy if needed. So let's only block non-admins from running tasks:

package spacelift

deny["only admins can run tasks"] { not input.session.admin }
package spacelift

deny[sprintf("command not allowed (%s)", [command])] {
  command := input.request.command

  not input.session.admin
  not re_match("^terraform\\s(un)?taint\\s[\\w\\-\\.]*$", command)
}

If you want to keep whitelisting different commands, it may be more elegant to flip the rule logic, create a series of allowed rules, and define one deny rule as not allowed. Let's have a look at this approach, and while we're at it let's remind everyone not to run anything during the weekend:

package spacelift

command := input.request.command

deny[sprintf("command not allowed (%s)", [command])] { not allowed }

deny["no tasks on weekends"] {
  today   := time.weekday(input.request.timestamp_ns)
  weekend := { "Saturday", "Sunday" }

  weekend[today]
}

allowed { input.session.admin }
allowed { re_match("^terraform\\s(un)?taint\\s[\\w\\-\\.]*$", command) }
allowed { re_match("^terraform\\simport\\s[\\w\\-\\.]*$", command) }

In addition to our , we also provide the following helpers for task policies:

Let's look at an example of this simple policy in .

That's still pretty harsh. We could possibly allow writers to run some commands we consider safe - like resource . Let's try then, and please excuse the regex:

Feel free to play with the above example in .

As usual, this example is .

🌠
global helper functions
the Rego playground
tainting and untainting
the Rego playground
available to play around with
Approval policy
resource tainting