HashiQube - DevOps Lab
Youtube Channel Medium Posts Riaan Nolan Linkedin Riaan Nolan Hashicorp Ambassador

.

Sentinel

A language and framework for policy decisions across HashiCorp products

🚀 Introduction

Sentinel is a language and framework for policy built to be embedded in existing software to enable fine-grained, logic-based policy decisions. A policy describes under what circumstances certain behaviors are allowed.

Sentinel is an enterprise-only feature of HashiCorp Consul, Nomad, Terraform, and Vault, helping organizations enforce consistent governance across their infrastructure.

🛠️ Provision

Choose one of the following methods to set up your environment:

Open in GitHub Codespaces

bash docker/docker.sh
bash sentinel/sentinel.sh
vagrant up --provision-with basetools,docsify,sentinel
docker compose exec hashiqube /bin/bash
bash hashiqube/basetools.sh
bash docker/docker.sh
bash docsify/docsify.sh
bash sentinel/sentinel.sh

📝 Basic Policy Example

Once installed, you can see Sentinel in action with a simple policy example. Here's a basic policy that checks if the current hour is in the morning (between 0 and 12):

hour = 4
main = rule { hour >= 0 and hour < 12 }

This policy is saved to /tmp/policy.sentinel and then applied using:

sentinel apply /tmp/policy.sentinel

Output:

Pass

🔍 Advanced Sentinel Policies

Sentinel can handle complex policy scenarios. Let's explore more advanced examples from the HashiCorp TFE Policies Example repository.

AWS Block Allow All CIDR

This policy prevents security groups from using overly permissive CIDR blocks.

Testing the Policy

sentinel test aws-block-allow-all-cidr.sentinel

Output:

PASS - aws-block-allow-all-cidr.sentinel
  PASS - test/aws-block-allow-all-cidr/empty.json
  PASS - test/aws-block-allow-all-cidr/fail.json
  PASS - test/aws-block-allow-all-cidr/pass.json
  ERROR - test/aws-block-allow-all-cidr/plan.json

Applying the Policy

With a passing configuration:

sentinel apply -config ./test/aws-block-allow-all-cidr/pass.json aws-block-allow-all-cidr.sentinel

Output:

Pass

With a failing configuration:

sentinel apply -config ./test/aws-block-allow-all-cidr/fail.json aws-block-allow-all-cidr.sentinel

Output:

Fail

Execution trace. The information below will show the values of all
the rules evaluated and their intermediate boolean expressions. Note that
some boolean expressions may be missing if short-circuit logic was taken.
FALSE - aws-block-allow-all-cidr.sentinel:69:1 - Rule "main"
  TRUE - aws-block-allow-all-cidr.sentinel:70:2 - ingress_cidr_blocks
    TRUE - aws-block-allow-all-cidr.sentinel:50:2 - all get_resources("aws_security_group") as sg {
 all sg.applied.ingress as ingress {
  all disallowed_cidr_blocks as block {
   ingress.cidr_blocks not contains block
  }
 }
}
  FALSE - aws-block-allow-all-cidr.sentinel:71:2 - egress_cidr_blocks
    FALSE - aws-block-allow-all-cidr.sentinel:60:2 - all get_resources("aws_security_group") as sg {
 all sg.applied.egress as egress {
  all disallowed_cidr_blocks as block {
   egress.cidr_blocks not contains block
  }
 }
}

FALSE - aws-block-allow-all-cidr.sentinel:59:1 - Rule "egress_cidr_blocks"

TRUE - aws-block-allow-all-cidr.sentinel:49:1 - Rule "ingress_cidr_blocks"

AWS ALB Redirect

This policy ensures that AWS Application Load Balancer listeners use proper redirect status codes.

Testing the Policy

sentinel test aws-alb-redirect.sentinel

Output:

PASS - aws-alb-redirect.sentinel
  PASS - test/aws-alb-redirect/empty.json
  PASS - test/aws-alb-redirect/fail.json
  PASS - test/aws-alb-redirect/pass.json
  ERROR - test/aws-alb-redirect/plan.json

Applying the Policy

With a failing configuration:

sentinel apply -config ./test/aws-alb-redirect/fail.json aws-alb-redirect.sentinel

Output:

Fail

Execution trace. The information below will show the values of all
the rules evaluated and their intermediate boolean expressions. Note that
some boolean expressions may be missing if short-circuit logic was taken.
FALSE - aws-alb-redirect.sentinel:69:1 - Rule "main"
  FALSE - aws-alb-redirect.sentinel:70:2 - default_action
    FALSE - aws-alb-redirect.sentinel:49:2 - all get_resources("aws_lb_listener") as ln {
 all ln.applied.default_action as action {

  all action.redirect as rdir {

   rdir.status_code == redirect_status_code
  }
 }
}

FALSE - aws-alb-redirect.sentinel:48:1 - Rule "default_action"

With a passing configuration:

sentinel apply -config ./test/aws-alb-redirect/pass.json aws-alb-redirect.sentinel

Output:

Pass

💡 Common Use Cases

Sentinel policies can be used to enforce a wide variety of governance requirements:

  • Security: Ensure resources follow security best practices
  • Compliance: Enforce regulatory requirements across infrastructure
  • Cost Management: Prevent deployment of expensive resources
  • Standardization: Maintain consistent naming and tagging conventions
  • Architecture: Enforce architectural standards like network configuration

📚 Resources

#!/bin/bash

function sentinel-install() {
  arch=$(lscpu | grep "Architecture" | awk '{print $NF}')
  if [[ $arch == x86_64* ]]; then
    ARCH="amd64"
  elif  [[ $arch == aarch64 ]]; then
    ARCH="arm64"
  fi
  echo -e '\e[38;5;198m'"CPU is $ARCH"

  sudo DEBIAN_FRONTEND=noninteractive apt-get --assume-yes install -qq curl unzip jq < /dev/null > /dev/null
  if [ -f /usr/local/bin/sentinel ]; then
    echo -e '\e[38;5;198m'"++++ `/usr/local/bin/sentinel version` already installed at /usr/local/bin/sentinel"
  else
    LATEST_URL=$(curl --silent https://releases.hashicorp.com/index.json | jq '{sentinel}' | egrep "linux.*$ARCH" | sort -rh | head -1 | awk -F[\"] '{print $4}')
    wget -q $LATEST_URL -O /tmp/sentinel.zip
    mkdir -p /usr/local/bin
    (cd /usr/local/bin && unzip /tmp/sentinel.zip)

    echo -e '\e[38;5;198m'"++++ Installed: `/usr/local/bin/sentinel version`"
  fi
  # add basic configuration settings for Vault to /etc/vault/config.hcl file
  cat <<EOF | sudo tee /tmp/policy.sentinel
hour = 4
main = rule { hour >= 0 and hour < 12 }
EOF
echo -e '\e[38;5;198m'"++++ cat /tmp/policy.sentinel"
cat /tmp/policy.sentinel
echo -e '\e[38;5;198m'"++++ sentinel apply /tmp/policy.sentinel"
sentinel apply /tmp/policy.sentinel
echo -e '\e[38;5;198m'"++++ Let's test some more advanced Sentinel Policies"
# https://github.com/hashicorp/tfe-policies-example
# https://docs.hashicorp.com/sentinel/language/
echo -e '\e[38;5;198m'"++++ https://github.com/hashicorp/tfe-policies-example"
echo -e '\e[38;5;198m'"++++ https://docs.hashicorp.com/sentinel/language/"
cd /vagrant/sentinel/sentinel/
echo -e '\e[38;5;198m'"++++ sentinel test aws-block-allow-all-cidr.sentinel"
sentinel test aws-block-allow-all-cidr.sentinel || true
echo -e '\e[38;5;198m'"++++ sentinel apply -config ./test/aws-block-allow-all-cidr/pass.json aws-block-allow-all-cidr.sentinel"
sentinel apply -config ./test/aws-block-allow-all-cidr/pass.json aws-block-allow-all-cidr.sentinel
echo -e '\e[38;5;198m'"++++ sentinel apply -config ./test/aws-block-allow-all-cidr/fail.json aws-block-allow-all-cidr.sentinel"
sentinel apply -config ./test/aws-block-allow-all-cidr/fail.json aws-block-allow-all-cidr.sentinel || true
echo -e '\e[38;5;198m'"++++ sentinel test aws-alb-redirect.sentinel"
sentinel test aws-alb-redirect.sentinel || true
echo -e '\e[38;5;198m'"++++ sentinel apply -config ./test/aws-alb-redirect/fail.json aws-alb-redirect.sentinel"
sentinel apply -config ./test/aws-alb-redirect/fail.json aws-alb-redirect.sentinel || true
echo -e '\e[38;5;198m'"++++ sentinel apply -config ./test/aws-alb-redirect/pass.json aws-alb-redirect.sentinel"
sentinel apply -config ./test/aws-alb-redirect/pass.json aws-alb-redirect.sentinel
}

sentinel-install