Policy as Code: Intro to Sentinel

11ba9630c9136eef9a70d26473d355d5?s=47 Armon Dadgar
September 29, 2017

Policy as Code: Intro to Sentinel

In the last few years, we've seen an explosion of DSLs and tools that focus on enabling Infrastructure as Code. The Infrastructure as Code approach allows the best practices of software development like code reuse, versioning, and peer review to be applied to new domains such as infrastructure management. In helping organizations adopt these tools, we found a common shortcoming was the ability to impose specific compliance or security policies on infrastructure changes. In trying to apply the "As Code" approach to this problem, we created a new language called Sentinel, focusing specifically on policy applications. Sentinel is meant to be read and written by non-programmers, specific compliance and security officers who are unfamiliar with traditional programming languages and constructs. We discuss the design principles of the Sentinel language, it's basic syntax, runtime implementation, and some of the use cases we've deployed it for.

11ba9630c9136eef9a70d26473d355d5?s=128

Armon Dadgar

September 29, 2017
Tweet

Transcript

  1.  Policy as Code: Intro to Sentinel @armon

  2.  Armon Dadgar @armon

  3. @armon

  4. “POLICY AS CODE”

  5. “INFRASTRUCTURE AS CODE”

  6. • Before: Artisanal and Handcrafted • Point-and-Click UX • SSH

    + Manual Setup • Rsync between machines • etc INFRASTRUCTURE BEFORE
  7. • After: Automated and Standardized • Single source of truth

    • Automated provisioning • Enables Scale INFRASTRUCTURE AS CODE
  8. None
  9. • Learn from Software Development • Versioning (Rollbacks) • Peer

    Review • Abstraction / Encapsulation • Code Reuse • Automation and Leverage BENEFITS
  10. PROVISIONING A DATACENTER

  11. Developers IT Operations Networking Security Procurement Sysadmins Finance Legal

  12. • Replace ticketing workflows with APIs • Public Cloud consolidated

    many concerns • Private Cloud brings similar APIs • Enables Infrastructure as Code • Huge increase in leverage UBIQUITOUS APIS
  13. PARADOX OF AUTOMATION

  14. SANITY CHECKING IT Ops Procurement “Please provision 5000 VMs”

  15. SANITY CHECKING IT Ops Procurement “Are you sure 5000?”

  16. SANITY CHECKING IT Ops Cloud “Please provision 5000 VMs”

  17. SANITY CHECKING IT Ops Cloud “Done!”

  18. • Paradox of Automation • Accidental Error • Compliance Bypass

    • Malicious Intent SCALING AUTOMATION
  19. • Governs Infrastructure as Code • Defines a sandbox to

    automate in • Codify business regulation and “sanity checking” POLICY AS CODE
  20. • Separate teams for Procurement / IT Operations / etc

    • Bulkhead against failures • Separate authors • Policy as Code (Compliance / Security) • Infrastructure as Code (Operators / Developers) SEPARATION OF RESPONSIBILITY
  21. POLICY AS CODE

  22. • Changes only during business hours • Min / Max

    number of service instances • Instance types allowed • Public Cloud regions • Ensure resources are tagged (billing, tenancy) • Certified containers / AMIs only EXAMPLE POLICIES
  23. • Security / Compliance teams define and enforce • Not

    familiar with “As Code” approach • Need to test policies ORGANIZATIONAL CHALLENGES
  24. SENTINEL

  25. • “Policy as Code Framework” • Sentinel Language Specification* •

    Golang Embedded Runtime • Simulator tool • Import SDK WHAT IS SENTINEL * https://docs.hashicorp.com/sentinel/language/spec
  26. • Non-programmer friendly • Easy to Embed • Simple •

    Debuggable • Go Friendly DESIGN GOALS
  27. • Language must be read and written by those with

    little to no programming experience • Traditional constructs should be available, but not needed for most policies NON-PROGRAMMER FRIENDLY
  28. • Impacts Runtime more than Language • No support for

    unsafe operations (arbitrary memory access) • Must be easy to sandbox • Active Enforcement • Prevent Violation A Priori • Passive Enforcement • Detect Violation Post Hoc EASY TO EMBED
  29. • Simple types (string, int, bool) at the expense of

    performance or exactness • Policies are typically small and don’t need to much flexibility • Ideally only one way to do something • “Zen of Python” SIMPLE
  30. • Easy to debug and test for those not familiar

    • Often the sharpest corner when learning DEBUGABBLE
  31. • Majority of HashiCorp tooling is Go • Simple to

    integration • Minimal changes to tooling / process • Performance implications GO FRIENDLY
  32. NOT INVENTED HERE?

  33. • JavaScript, Python, Lua, Ruby • Non-programmer friendliness • Embeddable

    • Go friendliness EXISTING LANGUAGES
  34. • Sentinel has dynamic types • Wanted static typing •

    Much friendlier to non-programmers • External integrations more complex DESIGN DECISIONS: DYNAMIC TYPING
  35. import "time" deployment_window = rule { time.hour > 8 and

    time.hour < 17 } main = rule { deployment_window } First Class Rules
  36. • Equivalent to functions • Lazy • Memoized • Performance

    for redundant rules • More Friendly DESIGN DECISIONS: FIRST CLASS RULES
  37. import "external" external_ready = rule { external.expensive_call() } internal_override =

    rule { … } main = rule { external_ready or (!external_ready and interal_override) }
  38. • Dedicated Existential Operators • any: expression is true for

    any term • all: expression is true for all terms • “All artifacts must come from a trusted source” • “Any of the tags must be the tenant ID” DESIGN DECISIONS: EXISTENTIAL OPERATORS
  39. • Plain English Operators • and, or, contains, in, is,

    matches, not • Traditional Operators • Easier for non-programmers DESIGN DECISIONS: SIMPLE OPERATORS
  40. • Avoid Exceptions / Panic • Must propagate errors •

    “Infectious” Undefined • Can be escaped by boolean logic with else DESIGN DECISIONS: UNDEFINED VALUE
  41. import “time” # valid_bar will be undefined obj = null

    valid_bar = rule { obj.foo.bar == 42 } valid_time = rule { time.hour > 8 } main = rule { (valid_bar or valid_time) else false }
  42. BASIC SYNTAX

  43. main = rule { all obj.items as item { item

    matches "my-item-[a-z0-9]+" } }
  44. sum = func(list) { count = 0 for list as

    elem { count += elem } return count } main = rule { sum(obj.items) is 42 }
  45. allowed_size = ["m3.small", "m4.small", "c1.large"] allowed_regions = {“stage”:“east","prod":“west"} valid_provider =

    rule { all providers as p { p.region is allowed_regions[env.region] }
 } valid_resource = rule { all resources as r { r.type is "instance" and r.size in allowed_size } } main = rule { valid_provider and valid_resource}
  46. RUNTIME IMPLEMENTATION

  47. • Lexer / Parser • Semantic Checker • Evaluator /

    Interpreter • Standard Library KEEP IT SIMPLE
  48. • Learn From Go • Maintain the position offsets (line,

    column) • Support a “fmt” command • Canonical Format LEXER / PARSER
  49. • Early warning to users • Main rules exist •

    Imports valid SEMANTIC CHECKING
  50. • Rule Memoization • Policy Caching • Import Recycling •

    Sandboxing • Execution time limited • Memory limited • Stack depth limited EVALUATOR
  51. • Avoid User Functions • Built in Standard Library •

    Time, Math, CIDR parsing, Strings, etc STANDARD LIBRARY
  52. ENFORCEMENT LEVELS "I'm sorry, Dave. I'm afraid I can't do

    that"
  53. • Different Levels • Runtime aware • Advisory • Soft

    Mandatory • Hard Mandatory ENFORCEMENT LEVELS
  54. • Policy is allowed to fail • Warning is showed

    to user • “Warn if user provisions deprecated instance type” ENFORCEMENT LEVEL: ADVISORY
  55. • Action is blocked when policy fails • Action is

    allowed when an override is specified • Override is tied to additional permissions • User has explicitly acknowledged out of policy action • “Do not allow changes outside of business hours (unless there is an outage)” ENFORCEMENT LEVEL: SOFT MANDATORY
  56. • Action is blocked when policy fails • Override is

    not possible • “Encryption keys are at least 128 bits and non-exportable” ENFORCEMENT LEVEL: HARD MANDATORY
  57. • Multiple policies may be evaluated per action • Smaller

    policies vs Monolithic policy • Mandatory failures can short circuit RUNTIME AWARENESS
  58. • Sentinel Runtime is embedded • In Data Path •

    Active Enforcement • How to develop and test policies? EMBEDDED FRAMEWORK
  59. SENTINEL SIMULATOR

  60. Terminal Usage: sentinel [--version] [--help] <command> [<args>] Available commands are:

    apply Execute a policy and output the result doc Show documentation for an import from a doc file fmt Format Sentinel policy to a canonical format test Test policies version Prints the Sentinel version
  61. Terminal $ sentinel apply -trace example_1.sentinel Pass 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. TRUE - example_1.sentinel:3:1 - Rule "main" TRUE - example_1.sentinel:3:15 - time.hour > 8 TRUE - example_1.sentinel:3:33 - time.hour < 17
  62. Terminal $ sentinel apply -trace example_1.sentinel 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 - example_1.sentinel:3:1 - Rule "main" FALSE - example_1.sentinel:3:15 - time.hour > 16
  63. • Apply allows for playing with policies during development •

    Test suites • Regression testing TESTING POLICIES
  64. Terminal $ tree . ├── example_1.sentinel ├── test │ ├──

    example_1 │ │ ├── fail.json │ │ └── pass.json
  65. { "config": { ... }, "mock": { "time": { "hour":

    9 } }, "test": { "main": false } } pass.json
  66. Terminal $ sentinel test -v example_1.sentinel PASS - example_1.sentinel PASS

    - test/example_1/fail.json trace: FALSE - example_1.sentinel:3:1 - Rule "main" FALSE - example_1.sentinel:3:15 - time.hour >= 16 PASS - test/example_1/pass.json trace: TRUE - example_1.sentinel:3:1 - Rule "main" TRUE - example_1.sentinel:3:15 - time.hour >= 16 TRUE - example_1.sentinel:3:35 - time.hour < 17
  67. CONTINUOUS INTEGRATION

  68. IMPORT SDK

  69. • Infrastructure composed of many pieces • Many policies require

    external information • Easy to incorporate external state IMPORTS
  70. • SDK makes it easy to expose new import •

    Host systems allow imports to be specified • Configured in advance for security • Plugins use IPC • Runtime multiplexes and garbage collects IMPORT SDK
  71. • Integrate common systems • Integrate custom internal systems •

    Extend with arbitrary logic IMPORT SDK
  72. CROSS SYSTEM PROTECTION Submit Service Service Configured?

  73. CROSS SYSTEM PROTECTION Delete Service Config Service Running?

  74. USE CASES

  75. • Infrastructure as Code guardrails • Simplify Compliance • “Fool

    me once, shame on you.” POLICY AS CODE USE CASES
  76. • Define Sandbox • Limits the potential damage of automation

    • Impose “sanity check” without manual process INFRASTRUCTURE AS CODE GUARDRAILS
  77. • Compliance often expressed as Word doc • Codify compliance

    requirements • Active enforcement simpler than passive detection • “An once of prevention is worth a pound of cure.” SIMPLIFY COMPLIANCE
  78. • Policies will never be exhaustive • Memory is finite!

    • Codify policies to defend against repeat mistakes • Scaling policies easier to expanding memory AVOID REPEAT MISTAKES
  79. • Policy as Code builds upon “As Code” • Shared

    benefits as Infrastructure as Code • Sentinel a framework for Policy as Code • Language, Import SDK OSS • Next Step in Infrastructure Automation CONCLUSION
  80. THANKS!