Initialization policy

circle-exclamation

Purpose

Initialization policy can prevent a Run or a Task from being initialized, thus blocking any custom code or commands from being executed. It superficially looks like a plan policy in that it affects an existing Run and prints feedback to logs, but it does not get access to the plan. Instead, it can be used to protect your stack from unwanted changes or enforce organizational rules concerning how and when runs are supposed to be triggered.

circle-exclamation

Let's create a simple initialization policy, attach it to the stack, and see what gives:

package spacelift

deny["you shall not pass"] {
  true
}

...and boom:

Rules

Initialization policies are simple in that they only use a single rule - deny - with a string message. A single result for that rule will fail the run before it has a chance to start - as we've just witnessed above.

Data input

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

Helpers

In addition to our global helper functions, we also provide the following helpers for initialization policies:

  • commit - an alias for input.commit.

  • run - an alias for input.run.

  • runtime_config - an alias for input.run.runtime_config.

  • stack - an alias for input.stack.

Use cases

There are two main use cases for run initialization policies - protecting your stack from unwanted changes and enforcing organizational rules. Let's look at these one by one.

Protect your stack from unwanted changes

While specialized, Spacelift is still a CI/CD platform and thus allows running custom code before Terraform initialization phase using before_init scripts. This is a very powerful feature, but as always, with great power comes great responsibility. Since those scripts get full access to your Terraform environment, how hard is it to create a commit on a feature branch that would run terraform destroy -auto-approvearrow-up-right? Sure, all Spacelift runs are tracked and this prank will sooner or later be tracked down to the individual who ran it, but at that point do you still have a business?

That's where initialization policies can help. Let's explicitly blacklist all Terraform commands if they're running as before_init scripts. OK, let's maybe add a single exception for a formatting check.

Feel free to play with this example in the Rego playgroundarrow-up-right.

OK, but what if someone gets clever and creates a Docker image that symlinks something very innocent-looking to terraform? Well, you have two choices - you could replace a blacklist with a whitelist, but a clever attacker can be really clever. So the other choice is to make sure that a known good Docker is used to execute the run. Here's an example:

Here's the above example in the Rego playgroundarrow-up-right.

triangle-exclamation

Enforce organizational rules

While the previous section was all about making sure that bad stuff does not get executed, this use case presents run initialization policies as a way to ensure best practices - ensuring that the right things get executed the right way and at the right time.

One of the above examples explicitly whitelisted Terraform formatting check. Keeping your code formatted in a standard way is generally a good idea, so let's make sure that this command always gets executed first. Note that as per Anna Karenina principlearrow-up-right this check is most elegantly defined as a negation of another rule matching the required state of affairs:

Here's this example in the Rego playgroundarrow-up-right.

This time we'll skip the mandatory "don't deploy on weekends" check because while it could also be implemented here, there are probably better places to do it. Instead, let's enforce a feature branch naming convention. We'll keep this example simple, requiring that feature branches start with either feature/ or fix/, but you can go fancy and require references to Jira tickets or even look at commit messages:

Here's this example in the Rego playgroundarrow-up-right.

Last updated

Was this helpful?