Enforcing Policy with Runtime Validations

Overview

This example shows you how to write a runtime validation in Ludwig and apply it to your processes using Fugue, ensuring your infrastructure is compliant with your organization’s policies.

Prerequisites

You’ll need to have the Fugue CLI set up and the Conductor installed before you can run this example. If you haven’t done so yet, it just takes a few quick steps.

You’ll also need to be running the paid version of Fugue, not Free Fugue, since the paid version offers runtime validation.

This composition demonstrates runtime validation by prohibiting resources from being created in AWS’s Canada region. If you have any running processes in ca-central-1, you’ll need to modify the walkthrough to prohibit a region you aren’t using.

  1. Edit CanadaRegionValidation.lw on line 7 to prohibit a different AWS region.
  2. Edit CanadaRegionFail.lw on line 8 to use the prohibited region.

What We’ll Do In This Example

We’ll cover how to write Ludwig to make a runtime validation enforcing certain rules about your infrastructure. We’ll also discuss how to create the validation library on the Conductor, how to delete it, and how to list all validation libraries on the Conductor. Finally, we’ll demonstrate how the validation prevents noncompliant processes from being created.

What We’ll Have When We’re Done

A compliant process that creates a Virtual Private Cloud (VPC) in AWS, complete with tags.

How Long It Will Take

About 30 minutes.

Download

You can download the source code for this example here:

Save these files to the directory in which you ran fugue init during the Quick Setup.

Get editor plug-ins here.

Let’s Go!

Writing the Validation Library

Runtime validation is very similar to design-time validation, but instead of having the validation enforced locally through the compiler, it’s enforced by the Conductor. This means that anyone who tries to run a noncompliant composition will encounter an error message stating why validation failed.

With design-time validation, the validation library must either be imported into the composition or specified with the --validation-modules option in lwc. With runtime validation, the validation library is created on the Conductor, so it’s not strictly necessary to import the validation library in your composition for runtime validation – but it is a best practice for local development.

First, we need to write the validation library that will be applied to the Conductor. We’ll say that our organization has a policy that prohibits resources from being created in Canada (ca-central-1). So, this validation checks AWS.Region types for a specific constructor. If the constructor AWS.Ca-central-1 is present in the composition, the validation will fail.

Boilerplate Ludwig

We’ll start by importing the Fugue.AWS library.

import Fugue.AWS as AWS

Validation Function

Next up is writing the validation function. If you want a refresher on writing functions, check out the Functions Tutorial.

fun noCaCentral1(region: AWS.Region) -> Validation:
  case region of
  | AWS.Ca-central-1 -> Validation.failure("Error: Region Ca-central-1 is prohibited")
  | _                -> Validation.success

We named this function noCaCentral1, and it takes an AWS.Region and returns a Validation.

If the AWS.Region constructor is AWS.Ca-central-1, the function returns Validation.failure and the Conductor returns the error message we specified, “Error: Region Ca-central-1 is prohibited.”

If the AWS.Region constructor is anything else, then the function returns Validation.success.

That means when this validation library is uploaded to the Conductor, any composition containing AWS.Ca-central-1 will fail validation and will not be run. Compositions in non-Canadian regions will pass validation and will be run.

For more information on writing validation functions, see Design-Time Validations or Runtime Validations.

Validation Registration

Now that we’ve written the validation function, we must register its name with the validate keyword so that it takes effect on all AWS.Region resources in scope.

validate noCaCentral1

Registering the validation ensures that when the validation library is applied to the Conductor, all current and future instances of AWS.Region in Fugue processes will be tested for compliance.

Creating the Validation Library on the Conductor

The next step is to create the validation library on the Conductor. This is the step that allows our validation to take effect across all current and future Fugue processes.

We can accomplish this through the policy subcommand validation-create. This subcommand requires a <validation_file> filename and a --name <name> argument, which is the name of our validation library as it is known to Fugue. We’ll name it no-canada. The whole command looks like this:

fugue policy validation-create --name no-canada CanadaRegionValidation.lw

The CLI compiles the composition, uploads it to S3, and then asks the Conductor to create the new validation library:

[fugue validation] Compiling Ludwig File CanadaRegionValidation.lw
[ OK ] Successfully compiled. No errors.

Uploading validation library to S3 ...
[ OK ] Successfully uploaded.

Requesting the Conductor create new validation library ...
[ DONE ] Validation library 'no-canada' uploaded and added to the Conductor.

Note: If you have any currently running processes that would fail validation, the validation library is not uploaded and you’ll see an error message. In this case, you’ll need to see our instructions in the Prerequisites for modifying the validation and test composition.

Listing Validation Libraries on the Conductor

Let’s view a list of the validation libraries on the Conductor:

fugue policy validation-list

We’ll see our no-canada validation library, along with some information about when it was created, what the library’s filename was, and the first 8 characters of its SHA-256 hash:

[fugue validation] List Validation Libraries

Fugue Validation Libraries for user/xxxxxxxxxxxx - Fri Jul 7 2017 3:06pm

Name       Created    File Name                  Sha256
---------  ---------  -------------------------  --------
no-canada  3:05pm     CanadaRegionValidation.lw  be99a230

Testing A Noncompliant Composition

Looks good, right? Let’s put our new validation library to the test. We’ll run the following composition:

composition

import Fugue.AWS as AWS
import Fugue.AWS.EC2 as EC2

simpleVpc: EC2.Vpc.new {
  cidrBlock: "10.0.0.0/16",
  region: AWS.Ca-central-1,
  tags: [simpleTag]
}

simpleTag: AWS.tag("Application", "Validation Test")

As you can see, it’s a simple composition that creates a tagged VPC in the Canada region. Since our validation function tests for the constructor AWS.Ca-central-1, this composition will fail validation. Let’s give it a whirl and see what happens when we try to run it.

fugue run CanadaRegionFail.lw --alias canada-vpc

We see this output:

[ fugue run ] Running CanadaRegionFail.lw

Run Details:
    Account: default
    Alias: canada-vpc

Compiling Ludwig file /Users/main-user/projects/CanadaRegionFail.lw
[ OK ] Successfully compiled. No errors.


Uploading compiled Ludwig composition to S3...
[ OK ] Successfully uploaded.

Requesting the Conductor to create and run process based on composition ...
[ ERROR ] ludwig (validation error):
  "/tmp/784284401/composition/src/CanadaRegionFail.lw" (line 8, column 11):
  Validations failed:

    8|   region: AWS.Ca-central-1,
                 ^^^^^^^^^^^^^^^^

    - Error: Region Ca-central-1 is prohibited
      (from CanadaRegionValidation.noCaCentral1)

Hooray, an error! That’s exactly what we expect to see. Let’s dig into what’s happening here: The CLI compiles the composition locally, uploads it to S3, and then asks the Conductor to run the composition. The Conductor then checks the composition against the uploaded validation libraries, and the composition fails validation. That’s why we see an error message: “Error: Region Ca-central-1 is prohibited.” We also see where the error message comes from – we wrote it in the noCaCentral1 function in the CanadaRegionValidation.lw composition. Finally, the output tells us exactly where validation failed – line 8, column 11 of CanadaRegionFail.lw.

In sum, Fugue has prevented us from running a composition that would have violated company policy. Neat, huh?

Testing a Compliant Composition

Now let’s see what happens when we attempt to run a composition that is compliant. We’ll run this composition:

composition

import Fugue.AWS as AWS
import Fugue.AWS.EC2 as EC2

simpleVpc: EC2.Vpc.new {
  cidrBlock: "10.0.0.0/16",
  region: AWS.Us-west-2,
  tags: [simpleTag]
}

simpleTag: AWS.tag("Application", "Validation Test")

This is the exact same composition as the one we tried to run a moment ago, except the VPC is created in the company-approved Oregon region, AWS.Us-west-2.

Let’s run it:

fugue run CanadaRegionSuccess.lw --alias oregon-vpc

We’ll see this:

[ fugue run ] Running CanadaRegionSuccess.lw

Run Details:
    Account: default
    Alias: oregon-vpc

Compiling Ludwig file /Users/main-user/projects/CanadaRegionSuccess.lw
[ OK ] Successfully compiled. No errors.


Uploading compiled Ludwig composition to S3...
[ OK ] Successfully uploaded.

Requesting the Conductor to create and run process based on composition ...
[ DONE ] Process created and running.


State    Updated    Created    Account              FID                                   Alias       Last Message    Next Command
-------  ---------  ---------  -------------------  ------------------------------------  ----------  --------------  --------------
Running  3:12pm     3:12pm     fugue-1499179370468  9f0af271-2f68-4be9-a93d-ab09287d50dc  oregon-vpc                  run

[ HELP ] Run the "fugue status" command to view details and status for all Fugue processes.

As you can see, the CLI once again compiles the composition locally, uploads it to S3, and asks the Conductor to run it. The Conductor again checks the composition against the uploaded validation libraries, and this time, the composition passes validation. The compliant process is successfully created!

Deleting Validation Libraries on the Conductor

Now that we’ve demonstrated how validation libraries work on the Conductor, let’s delete the no-canada validation library we created. It’s simple:

fugue policy validation-delete no-canada

The CLI will prompt for confirmation and, upon y, delete the validation library:

[fugue validation] Deleting Validation Library: 'no-canada'

[ WARN ] Are you sure you want to delete this validation library: 'no-canada'? [y/N]: y

Requesting the Conductor to delete validation library: 'no-canada' ...
[ DONE ] The Conductor is deleting the validation library: 'no-canada'

You can then execute fugue policy validation-list again to confirm that there are no validation libraries on the Conductor. You’ll see output like this:

[fugue validation] List Validation Libraries

Fugue Validation Libraries for user/xxxxxxxxxxxx - Tue Jul 4 2017 11:52am

Name    Created    File Name    Sha256
------  ---------  -----------  --------

Killing the Fugue Process

Now that we’ve deleted the validation library on the Conductor, the only thing left to do is to kill the compliant, running process. We don’t need that VPC hanging around in our account anymore.

fugue kill oregon-vpc -y

The CLI returns this output:

[ fugue kill ] Killing running process with Alias: oregon-vpc

Requesting the Conductor to kill running composition with Alias: oregon-vpc...
[ Done ] The conductor is killing the process with Alias: oregon-vpc

All done! We’ve successfully created a validation library on the Conductor, tested it with a noncompliant composition, tested it with a compliant composition, deleted the validation library, and killed the running process. We’ve demonstrated how we can write validations to enforce company policy, and we’ve seen how Fugue protects against process noncompliance at the Conductor level. Nice job!

Next Steps

Now that you’ve seen how runtime validation works, read all about design-time validation. Or, learn more about writing Ludwig functions at the Functions Tutorial. You can also check out our other examples and walkthroughs. And as always, reach out to support@fugue.co with any questions.